Skip to main content

Interact with multisig wallets using TypeScript

warning

This page is heavily outdated and will be updated soon.
Refer to the multisig-contract-v2, the most up-to-date multisignature contract on TON.
Use npm and avoid updating this guide.

Introduction

If you’re unfamiliar with multisig wallets on TON, you can learn more here.

By following these steps, you’ll learn how to:

  • Create and deploy a multisig wallet.
  • Create, sign, and send transactions using the wallet.

We’ll create a TypeScript project and use the ton library, so you’ll need to install it first. We’ll also use ton-access:

yarn add typescript @types/node ton ton-crypto ton-core buffer @orbs-network/ton-access
yarn tsc --init -t es2022

The full code for this guide is available here:
https://github.com/Gusarich/multisig-ts-example


Create and deploy a multisig wallet

Let’s create a source file, such as main.ts. Open it in your favorite code editor and follow along!

1. Import required modules

First, import the necessary modules:

import {
Address,
beginCell,
MessageRelaxed,
toNano,
TonClient,
WalletContractV4,
MultisigWallet,
MultisigOrder,
MultisigOrderBuilder,
} from "ton";
import { KeyPair, mnemonicToPrivateKey } from "ton-crypto";
import { getHttpEndpoint } from "@orbs-network/ton-access";

2. Create a TonClient instance

Initialize the TonClient:

const endpoint = await getHttpEndpoint();
const client = new TonClient({ endpoint });

3. Generate key pairs

Create key pairs for the multisig wallet:

let keyPairs: KeyPair[] = [];

let mnemonics = [
['orbit', 'feature', ...], // Replace with a 24-word seed phrase
['sing', 'pattern', ...],
['piece', 'deputy', ...],
['toss', 'shadow', ...],
['guard', 'nurse', ...]
];

for (let i = 0; i < mnemonics.length; i++) {
keyPairs[i] = await mnemonicToPrivateKey(mnemonics[i]);
}

4. Create a MultisigWallet object

You can create a MultisigWallet object in two ways:

  • Import an existing wallet by address:

    let addr: Address = Address.parse(
    "EQADBXugwmn4YvWsQizHdWGgfCTN_s3qFP0Ae0pzkU-jwzoE"
    );
    let mw: MultisigWallet = await MultisigWallet.fromAddress(addr, { client });
  • Create a new wallet:

    let mw: MultisigWallet = new MultisigWallet(
    [keyPairs[0].publicKey, keyPairs[1].publicKey],
    0,
    0,
    1,
    { client }
    );

5. Deploy the multisig wallet

You can deploy the wallet in two ways:

  • Via internal message:

    let wallet: WalletContractV4 = WalletContractV4.create({
    workchain: 0,
    publicKey: keyPairs[4].publicKey,
    });
    // Ensure the wallet is active and has a balance
    await mw.deployInternal(
    wallet.sender(client.provider(wallet.address, null), keyPairs[4].secretKey),
    toNano("0.05")
    );
  • Via external message:

    await mw.deployExternal();

Create, sign, and send an order

1. Create an order

Use MultisigOrderBuilder to create a new order:

let order1: MultisigOrderBuilder = new MultisigOrderBuilder(0);

2. Add messages to the order

Add messages to the order:

let msg: MessageRelaxed = {
body: beginCell()
.storeUint(0, 32)
.storeBuffer(Buffer.from("Hello, world!"))
.endCell(),
info: {
bounce: true,
bounced: false,
createdAt: 0,
createdLt: 0n,
dest: Address.parse("EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"),
forwardFee: 0n,
ihrDisabled: true,
ihrFee: 0n,
type: "internal",
value: { coins: toNano("0.01") },
},
};

order1.addMessage(msg, 3);

3. Build and sign the order

Convert the MultisigOrderBuilder to MultisigOrder and sign it:

let order1b: MultisigOrder = order1.build();
order1b.sign(0, keyPairs[0].secretKey);

4. Create and sign another order

Create another order, add a message, and sign it with a different key:

let order2: MultisigOrderBuilder = new MultisigOrderBuilder(0);
order2.addMessage(msg, 3);
let order2b = order2.build();
order2b.sign(1, keyPairs[1].secretKey);

order1b.unionSignatures(order2b); // Merge signatures from order2b into order1b

5. Send the signed order

Send the signed order:

await mw.sendOrder(order1b, keyPairs[0].secretKey);

6. Build and run the project

Compile the project:

yarn tsc

Run the compiled file:

node main.js

If no errors occur, you’ve done everything correctly! Verify the transaction using an explorer or wallet.


Other methods and properties

Clear messages

Clear messages from a MultisigOrderBuilder:

order2.clearMessages();

Clear signatures

Clear signatures from a MultisigOrder:

order2b.clearSignatures();

Access public properties

You can access public properties from MultisigWallet, MultisigOrderBuilder, and MultisigOrder objects:

  • MultisigWallet:

    • owners: Dictionary<number, Buffer> of signatures (ownerId => signature).
    • workchain: Workchain where the wallet is deployed.
    • walletId: Wallet ID.
    • k: Number of signatures required to confirm a transaction.
    • address: Wallet address.
    • provider: ContractProvider instance.
  • MultisigOrderBuilder:

    • messages: Array of MessageWithMode to be added to the order.
    • queryId: Global time until which the order is valid.
  • MultisigOrder:

    • payload: Cell with order payload.
    • signatures: Dictionary<number, Buffer> of signatures (ownerId => signature).

References