> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Wallet Linking

> Create a verifiable association between an embedded wallet and an external wallet address for compliance, asset verification, and fund migration.

Wallet Linking creates a cryptographically verifiable, off-chain association between an embedded wallet and an external wallet (such as a MetaMask or hardware wallet). This is useful for:

* **Compliance and KYC**: verify that a user controls an external address without requiring them to move funds.
* **Fund migration**: link an external wallet to facilitate moving liquidity to the embedded wallet.
* **Multi-wallet governance**: verify token holdings across wallets for access control or disbursement rules.

The association is stored off-chain and signed by both wallets, so neither party can forge the link.

## How it works

<Steps>
  <Step title="Authenticate with embedded wallet">
    The user signs in with their embedded wallet (social login, email OTP, or passkey). This becomes the `parent` wallet.
  </Step>

  <Step title="Sign with external wallet">
    The user connects their external wallet (MetaMask, hardware wallet, etc.) and signs a message attesting to the embedded wallet address. The embedded wallet also signs a message attesting to the external address.
  </Step>

  <Step title="Submit both signatures">
    Both signatures are submitted to the Sequence Linking API. The link is created off-chain and is privately retrievable using a signature from the parent wallet.
  </Step>
</Steps>

## API integration

### Install

```bash theme={null}
pnpm install @0xsequence/waas wagmi
```

The [source code for the API interface](https://github.com/0xsequence-demos/demo-embedded-wallet-linking/blob/master/src/api/api.gen.ts) instantiates against the Sequence server:

```typescript theme={null}
import { API, LinkedWallet } from "./api.gen";

const api = new API("https://dev-api.sequence.app", fetch);
```

### Link an external wallet

Two signatures are required: the embedded wallet signing the external address, and the external wallet signing the embedded wallet address.

```typescript theme={null}
import { useSignMessage, useAccount } from "wagmi";

function App() {
  const { signMessageAsync } = useSignMessage();
  const { address: externalWalletAddress } = useAccount();

  const getSignaturesForLinking = async () => {
    const parentWalletAddress = await sequenceWaas.getAddress();
    const parentMessage = "linked wallet with address " + externalWalletAddress;
    const linkingMessage = "parent wallet with address " + parentWalletAddress;

    const externalSignature = await signMessageAsync({
      message: "Link to " + linkingMessage,
    });

    const parentSignatureRes = await sequenceWaas.signMessage({
      message: parentMessage,
    });

    return {
      parentWalletAddress,
      linkedWalletAddress: externalWalletAddress,
      parentMessage,
      linkingMessage: "Link to " + linkingMessage,
      parentSignature: parentSignatureRes.data.signature,
      linkedSignature: externalSignature,
    };
  };

  const linkWallet = async () => {
    const sigs = await getSignaturesForLinking();

    const response = await api.linkWallet({
      signatureChainId: "137",
      linkedWalletType: "metamask",
      parentWalletAddress: sigs.parentWalletAddress,
      parentWalletMessage: sigs.parentMessage,
      parentWalletSignature: sigs.parentSignature,
      linkedWalletAddress: sigs.linkedWalletAddress!,
      linkedWalletMessage: sigs.linkingMessage,
      linkedWalletSignature: sigs.linkedSignature,
    });

    console.log("Linked:", response.status);
  };
}
```

### Retrieve linked wallets

Retrieval requires a fresh signature from the parent wallet to protect privacy.

```typescript theme={null}
const getLinkedWallets = async () => {
  const parentWalletAddress = await sequenceWaas.getAddress();
  const message = "parent wallet with address " + parentWalletAddress;
  const signature = await sequenceWaas.signMessage({ message });

  const response = await api.getLinkedWallets({
    parentWalletAddress: parentWalletAddress as `0x${string}`,
    parentWalletMessage: message,
    parentWalletSignature: signature.data.signature,
    signatureChainId: "137",
  });

  return response.linkedWallets;
};
```

The returned objects follow this shape:

```typescript theme={null}
interface LinkedWallet {
  id: number;
  walletType?: string;
  walletAddress: string;
  linkedWalletAddress: string;
  createdAt?: string;
}
```

### Remove a linked wallet

```typescript theme={null}
const unlinkWallet = async () => {
  const parentWalletAddress = await sequenceWaas.getAddress();
  const parentMessage = "linked wallet with address " + externalWalletAddress;
  const linkingMessage = "parent wallet with address " + parentWalletAddress;

  const externalSignature = await signMessageAsync({
    message: "Unlink from " + linkingMessage,
  });

  const parentSig = await sequenceWaas.signMessage({ message: parentMessage });

  await api.removeLinkedWallet({
    signatureChainId: "137",
    parentWalletAddress,
    parentWalletMessage: parentMessage,
    parentWalletSignature: parentSig.data.signature,
    linkedWalletAddress: externalWalletAddress!,
    linkedWalletMessage: "Unlink from " + linkingMessage,
    linkedWalletSignature: externalSignature,
  });
};
```

## Demo

A full working demo with source code is available at:

* Demo: [demo-waas-wallet-link.pages.dev](https://demo-waas-wallet-link.pages.dev/)
* Source: [github.com/0xsequence-demos/demo-embedded-wallet-linking](https://github.com/0xsequence-demos/demo-embedded-wallet-linking)
