Skip to main content

Use a dWallet on Ethereum

After creating a dWallet, you 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 need to set up the environment. Begin by importing the necessary functions:

import {
DWalletClient,
SuiHTTPTransport,
} 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'
import * as elliptic from 'elliptic'

import {
createDWallet,
getOrCreateEncryptionKey,
storeEncryptionKey,
setActiveEncryptionKey,
EncryptionKeyScheme,
createActiveEncryptionKeysTable,
createPartialUserSignedMessages,
approveAndSign,
} from '@dwallet-network/dwallet.js/signature-mpc'

import {
recovery_id_keccak256 as recoveryIdKeccak256,
} from '@dwallet-network/signature-mpc-wasm';

Get the dWallet's Ethereum Address

To create transactions on the Ethereum network, we need an Ethereum address. The 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 client.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.
const ec = new elliptic.ec("secp256k1");
const 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 that offers a web API for accessing the Ethereum blockchain. Providers allow connecting to the blockchain, simplifying 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 createPartialUserSignedMessages(
dkg?.dwalletID!,
dkg?.decentralizedDKGOutput!,
new Uint8Array(dkg?.secretKeyShare!),
[bytes],
'KECCAK256',
keypair,
client,
)
const sigKECCAK256 = await approveAndSign(
dkg?.dwalletCapID!,
signMessagesIdKECCAK256!,
[bytes],
dkg?.dwalletID!,
'KECCAK256',
keypair,
client,
)
const sig = Buffer.from(sigKECCAK256[0]).toString('hex')


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

// Serialized signature in a 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 correct signature format, the final step is to 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>