Skip to main content

Use a dWallet on Ethereum

After creating a dWallet we can derive the dWallet's Ethereum address, create transactions from that address, sign them with the dWallet, and broadcast the signed transactions to the Ethereum network.

Setup

First, we must setup the environment. Begin by importing necessary functions:

import { DWalletClient } from '@dwallet-network/dwallet.js/client';
import { Ed25519Keypair } from '@dwallet-network/dwallet.js/keypairs/ed25519';
import { requestSuiFromFaucetV0 as requestDwltFromFaucetV0 } from '@dwallet-network/dwallet.js/faucet';
import {ethers} from "ethers";
var elliptic = require('elliptic');

import {
createDWallet,
createSignMessages,
approveAndSign,
submitDWalletCreationProof,
submitTxStateProof,
recoveryIdKeccak256,
} from '@dwallet-network/dwallet.js/signature-mpc';

Get the dWallet's Ethereum address

To create transactions in the Ethereum network we need an Ethereum address. Ethereum address is generated by hashing your public key in sha3 format and taking the last 40 bytes of the result.

// get the dWallet object
const dwallet = await dwalletClient.getObject({ id: dwalletId, options: {showContent: true}});
if (dwallet?.data?.content?.dataType == 'moveObject') {
// Get the public key
// @ts-ignore
const pubkeyhex = Buffer.from(dwallet?.data?.content?.fields['public_key']).toString('hex');

// The public key is in its compressed form so we uncompress it, as the address is derived from the uncompressed public key.
var ec = new elliptic.ec('secp256k1');
var publicKeyUncompressed = ec.keyFromPublic(pubkeyhex, 'hex').getPublic(false, 'hex');

let pubkey = Buffer.from(publicKeyUncompressed, 'hex');

// Here we are doing keccak256 hashing of our ECDSA public key
const ethereumAddress = ethers.getAddress(ethers.keccak256(pubkey).slice(-40));

console.log("dWallet Ethereum address is", ethereumAddress);

Access the Ethereum network

We need a service which offers a web API for accessing the Ethereum Blockchain. These Providers allow connecting to them, which simplifies development. In the following example we use EtherscanProvider with the Sepolia network which is Ethereum's proof-of-authority testnet.

    const provider = new ethers.EtherscanProvider(ethers.Network.from("sepolia"), "");

// Get chainId from network
const chainId = (await provider.getNetwork()).chainId;

Sign a Tx

You can create transactions using the ethers library documentation on Transactions. Once we have the transaction object, we sign the bytes of the hash generated from the transaction.

    const tx = new ethers.Transaction()
// * fill the tx parameters here *

// `tx.unsignedSerialized` is a hex string starting with `0x`, so we remove it by slicing the first two characters before parsing it as a hex string into a byte array.
const bytes = Uint8Array.from(Buffer.from(tx.unsignedSerialized.slice(2), 'hex'));

// Sign the transaction bytes
const signMessagesIdKECCAK256 = await createSignMessages(dkg?.dwalletId!, dkg?.dkgOutput, [bytes], "KECCAK256", keypair, dwalletClient);
const sigKECCAK256 = await approveAndSign(dkg?.dwalletCapId!, signMessagesIdKECCAK256!, [bytes], keypair, dwalletClient);
const sig = Buffer.from(sigKECCAK256?.signatures[0]).toString('hex');

// @ts-ignore
const recoveryId = "0" + recoveryIdKeccak256(dwallet?.data?.content?.fields['public_key'], bytes, sigKECCAK256?.signatures[0]).toString(16);

// Serialized signature in formate r[32-byte]-s[32-byte]-v[1-byte] where v is recovery id.
tx.signature = "0x" + sig + recoveryId;

Broadcast the Tx

After signing the transaction with our dWallet and updating the tx object with the right signature format, all there's left to do is broadcast the transaction to the Ethereum Blockchain.

    const response = await provider.broadcastTransaction(tx.serialized);
console.log(`Transaction successful with hash: ${response.hash}`);

And that is it! You can view the transaction at: https://sepolia.etherscan.io/tx/<response.hash>