Skip to content
SwapDK is a powerful suite of tools for building blockchain applications.

Signing Transactions

SwapDK provides ways to sign transactions and messages across different blockchains. This guide shows how to use these signing capabilities with both granular and all-in-one package approaches.

You can use SwapDK in two ways:

  1. Granular approach - Import only what you need from individual packages (recommended for frontend):

    import { SwapKit, evmWallet } from "@swapdk/sdk";
  2. All-in-one approach - Import everything from the SDK (better for backend/Node.js):

    import { createSwapKit } from "@swapdk/sdk";

Signing messages is useful for authentication, proving ownership of an address, or interacting with decentralized applications.

import { Chain, SwapKit, evmWallet } from "@swapdk/sdk";
const swapDK = SwapKit({
wallets: { ...evmWallet },
});
async function signMessageExample() {
await swapDK.connectEVMWallet([Chain.Ethereum]);
const message = "I am proving ownership of this wallet address";
try {
const signature = await swapDK.signMessage({
chain: Chain.Ethereum,
message,
});
return signature;
} catch (error) {
throw error;
}
}
import { Chain, createSwapKit } from "@swapdk/sdk";
const swapDK = createSwapKit();
async function signMessageExample() {
await swapDK.connectKeystore([Chain.Ethereum], "your secret phrase here");
const message = "I am proving ownership of this wallet address";
try {
const signature = await swapDK.signMessage({
chain: Chain.Ethereum,
message,
});
return signature;
} catch (error) {
throw error;
}
}

Different blockchains have different message signing formats:

import { Chain, SwapKit, evmWallet, keystoreWallet } from "@swapdk/sdk";
const swapDK = SwapKit({
wallets: { ...evmWallet, ...keystoreWallet },
});
async function setupWallets() {
await swapDK.connectKeystore(
[Chain.Bitcoin, Chain.Cosmos, Chain.THORChain],
"your secret phrase here"
);
await swapDK.connectEVMWallet([Chain.Ethereum]);
}
async function signCosmosMessage() {
const message = "Sign this message to verify your THORChain address";
try {
const signature = await swapDK.signMessage({
chain: Chain.THORChain,
message,
});
return signature;
} catch (error) {
throw error;
}
}

After signing a message, you or others may want to verify the signature:

import { Chain, SwapKit, keystoreWallet } from "@swapdk/sdk";
const swapDK = SwapKit({
wallets: { ...keystoreWallet },
});
async function verifySignature() {
const message = "I am proving ownership of this wallet address";
const address = "thor1fkm5w5uum0j5h9g35vwqtf7angh9uvrm9mszyx";
const signature =
"ac7bfd5b5c9f44788fb533b7f08b213a3e3856e75ecdb19c5e9138ba29c4c1681e82b7de139e0b92cd9442297ec7fdd2c14e7034a3aa417ff9756e9b591d93201";
try {
const isValid = await swapDK.verifyMessage({
chain: Chain.THORChain,
message,
address,
signature,
});
return isValid;
} catch (error) {
return false;
}
}

In most cases, SwapDK handles transaction signing internally when using methods like transfer or swap. However, there are cases where you might want to create and sign a transaction separately.

For more control over the signing process, you can use toolboxes directly:

import { Chain, getEvmToolbox, ethers } from "@swapdk/sdk";
async function signEthereumTransaction() {
const provider = new ethers.JsonRpcProvider("https://example.com"
const signer = new ethers.Wallet("your-eth-private-key", provider);
const ethToolbox = await getEvmToolbox(Chain.Ethereum, {
provider,
signer,
});
const transaction = {
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
value: ethers.parseEther("0.01"),
data: "0x",
from: signer.address,
};
try {
const signedTx = await ethToolbox.sendTransaction(transaction);
return signedTx;
} catch (error) {
throw error;
}
}

For UTXO chains like Bitcoin, the process involves creating inputs and outputs:

import { AssetValue, Chain, FeeOption, getUtxoToolbox } from "@swapdk/sdk";
async function signBitcoinTransaction() {
const btcToolbox = await getUtxoToolbox(Chain.Bitcoin);
const keys = await btcToolbox.createKeysForPath({
phrase: "your twelve word mnemonic phrase here",
derivationPath: "m/84'/0'/0'/0/0",
});
const fromAddress = btcToolbox.getAddressFromKeys(keys);
const amount = AssetValue.from({
chain: Chain.Bitcoin,
symbol: "BTC",
value: "0.001",
});
const recipient = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
try {
const { psbt: builder, utxos } = await btcToolbox.buildTx({
sender: fromAddress,
recipient,
assetValue: amount,
feeRate: 1.2,
memo: "Test transaction",
});
utxos.forEach((utxo, index) => builder.sign(index, keys));
const txHash = await btcToolbox.broadcastTx(builder.toHex());
} catch (error) {
throw error;
}
}

Custom Transaction Signing with Hardware Wallets

Section titled “Custom Transaction Signing with Hardware Wallets”

Hardware wallets like Ledger or Trezor have special requirements for signing:

import {
AssetValue,
Chain,
FeeOption,
SwapKit,
ledgerWallet,
} from "@swapdk/sdk";
const swapDK = SwapKit({
wallets: { ...ledgerWallet },
});
async function signWithLedger() {
try {
await swapDK.connectLedger([Chain.Ethereum]);
const ledgerWallet = swapDK.getWallet(Chain.Ethereum);
const txHash = await ledgerWallet.transfer({
assetValue: AssetValue.from({ chain: Chain.Ethereum, value: "0.01" }),
feeOptionKey: FeeOption.Fast,
from: ledgerWallet.address,
memo: "Ledger transfer",
recipient: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
});
return txHash;
} catch (error) {
throw error;
}
}

For complete control over the signing process, you can use toolbox-specific methods:

import { Chain, getCosmosToolbox } from "@swapdk/sdk";
async function cosmosWallet() {
const cosmosToolbox = await getCosmosToolbox(Chain.THORChain);
const phrase = "your twelve word mnemonic phrase here";
const signer = await cosmosToolbox.getSigner(phrase);
const address = await cosmosToolbox.getAddressFromMnemonic(phrase);
return { signer, address };
}