# 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 { SafeMultiChainSigAccountV1 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 { SafeMultiChainSigAccountV1 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");
```
