This walkthrough will show you how to submit an ERC20 transfer to the BLS Wallet Aggregator.
# npm
npm install bls-wallet-clients
# yarn
yarn add bls-wallet-clients
# deno in example further below
import { providers } from "ethers";
import { Aggregator, BlsWalletWrapper, getConfig } from "bls-wallet-clients";
You can use esm.sh or a similar service to get Deno compatible modules.
import { providers } from "https://esm.sh/ethers@latest";
import {
Aggregator,
BlsWalletWrapper,
getConfig,
} from "https://esm.sh/bls-wallet-clients@latest";
You can find current contract deployments in the contracts networks folder. If you would like to deploy locally, see Local development. If you would like to deploy to a remote network, see Remote development.
import { readFile } from "fs/promises";
// import fetch from 'node-fetch'; // Add this if using nodejs<18
import { ethers, providers } from "ethers";
import { Aggregator, BlsWalletWrapper, getConfig } from "bls-wallet-clients";
// globalThis.fetch = fetch; // Add this if using nodejs<18
// Instantiate a provider via browser extension, such as Metamask
// const provider = new providers.Web3Provider(window.ethereum);
// Or via RPC
const provider = new providers.JsonRpcProvider(
"https://goerli-rollup.arbitrum.io/rpc"
);
// See https://docs.ethers.io/v5/getting-started/ for more options
// Get the deployed contract addresses for the network.
// Here, we will get the Arbitrum testnet.
// See local_development.md for deploying locally and
// remote_development.md for deploying to a remote network.
const netCfg = await getConfig(
"../contracts/networks/arbitrum-goerli.json",
async (path) => readFile(path)
);
// 32 random bytes
const privateKey =
"0x0001020304050607080910111213141516171819202122232425262728293031";
// Note that if a wallet doesn't yet exist, it will be
// lazily created on the first transaction.
const wallet = await BlsWalletWrapper.connect(
privateKey,
netCfg.addresses.verificationGateway,
provider
);
const erc20Address = netCfg.addresses.testToken; // Or some other ERC20 token
const erc20Abi = ["function mint(address to, uint amount) returns (bool)"];
const erc20 = new ethers.Contract(erc20Address, erc20Abi, provider);
console.log("Contract wallet:", wallet.address);
console.log("Test token:", erc20.address);
const nonce = await wallet.Nonce();
// All of the actions in a bundle are atomic, if one
// action fails they will all fail.
const bundle = wallet.sign({
nonce,
actions: [
{
// Mint ourselves one test token
ethValue: 0,
contractAddress: erc20.address,
encodedFunction: erc20.interface.encodeFunctionData("mint", [
wallet.address,
ethers.utils.parseUnits("1", 18),
]),
},
],
});
const aggregator = new Aggregator("https://arbitrum-goerli.blswallet.org");
console.log("Sending bundle to the aggregator");
const addResult = await aggregator.add(bundle);
if ("failures" in addResult) {
throw new Error(addResult.failures.join("\n"));
}
console.log("Bundle hash:", addResult.hash);
const checkConfirmation = async () => {
console.log("Checking for confirmation");
const maybeReceipt = await aggregator.lookupReceipt(addResult.hash);
if (maybeReceipt === undefined) {
return;
}
console.log("Confirmed in block", maybeReceipt.blockNumber);
provider.off("block", checkConfirmation);
};
provider.on("block", checkConfirmation);
See clients for additional functionality.