# Sign & Validate a Message with a Smart Wallet

Smart wallets can sign arbitrary messages similar to EOAs. Learn how to sign messages using Safe wallet and verify signatures using EIP-1271 Signature Validation.

## Single Owner Safe[​](#single-owner-safe "Direct link to Single Owner Safe")

### Sign Message[​](#sign-message "Direct link to Sign Message")

Signing

```
import * as dotenv from 'dotenv';

import { SafeAccountV0_3_0 as SafeAccount } from "abstractionkit"; 
import { Contract, JsonRpcProvider, Wallet, hashMessage} from "ethers"; // v6

dotenv.config()
const ownerPublicAddress = process.env.PUBLIC_ADDRESS as string
const smartAccount = SafeAccount.initializeNewAccount(
    [ownerPublicAddress],
)

const chainId = BigInt(process.env.CHAIN_ID as string)
const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string
const provider = new JsonRpcProvider(jsonRpcNodeProvider, chainId);

const abiSmartWallet = [
    "function isValidSignature(bytes32 _dataHash, bytes calldata _signature) external view returns (bytes4)",
    "function getMessageHash(bytes memory message) public view returns (bytes32)"
];

const safeContract = new Contract(
    smartAccount.accountAddress,
    abiSmartWallet,
    provider,
);

const message = hashMessage("Hello World");
const safeMessageHash = await safeContract.getMessageHash(message);

const ownerPrivateKey = process.env.PRIVATE_KEY as string
const signer = new Wallet(ownerPrivateKey);
const signature = await signer.signingKey.sign(safeMessageHash).serialized;
```

Verifying the Signature

```
const returnValue = await safeContract.isValidSignature(
    message,
    signature,
);

console.log(returnValue, "Success! You should see the magic value 0x1626ba7e");
```

### Sign Typed Data EIP-712[​](#sign-typed-data-eip-712 "Direct link to Sign Typed Data EIP-712")

Signing a Message

```
import * as dotenv from 'dotenv';

import { SafeAccountV0_3_0 as SafeAccount } from "abstractionkit";
import { Contract, JsonRpcProvider, Wallet, hashMessage} from "ethers"; // v6

dotenv.config();
const ownerPublicAddress = process.env.PUBLIC_ADDRESS as string
const smartAccount = SafeAccount.initializeNewAccount(
    [ownerPublicAddress],
)

const chainId = BigInt(process.env.CHAIN_ID as string)
const message = hashMessage("Hello World");

const domain = {
    chainId,
    verifyingContract: smartAccount.accountAddress
};
const types = {
    SafeMessage: [
        { type: "bytes", name: "message" },
    ],
};
const value = { message };

// For demo purposes, we are signing directly using etheres Wallet. 
// You can also request this signature from the users MPC service if you are using one  
const ownerPrivateKey = process.env.PRIVATE_KEY as string
const signer = new Wallet(ownerPrivateKey);
const signature = await signer.signTypedData(domain, types, value);
```

Verifying the Signature

```
const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string
const provider = new JsonRpcProvider(jsonRpcNodeProvider, chainId);

const abiSafeWallet = [
    "function isValidSignature(bytes32 _dataHash, bytes calldata _signature) external view returns (bytes4)",
];

const safeContract = new Contract(
    smartAccount.accountAddress,
    abiSafeWallet,
    provider,
);
const returnValue = await safeContract.isValidSignature(
    message,
    signature,
);

console.log(returnValue, "Success! You should see the magic value 0x1626ba7e");
```
