RemoteSigner SDK examples
sign UserOp via RemoteSignerSDK Instance
import { EtherspotBundler, RemoteSignerSdk, UserOperation, toRemoteSigner, BigNumber, erc20Abi, sleep, printOp } from '@etherspot/remote-signer';
import * as dotenv from 'dotenv';
import { privateKeyToAccount } from 'viem/accounts';
import { encodeFunctionData, Hex, http, parseAbi, parseUnits } from 'viem';
dotenv.config();
// add/change these values
const recipient = '0xdE79F0eF8A1268DAd0Df02a8e527819A3Cd99d40'; // recipient wallet address
const value = '0.00000001'; // transfer value
const tokenAddress = ''; // token address
const bundlerApiKey = process.env.API_KEY as string;
const sessionKey = '';
const erc20SessionKeyValidator = process.env.ERC20_SESSION_KEY_VALIDATOR as string;
const apiKey = process.env.API_KEY as string;
const etherspotWalletAddress = process.env.ETHERSPOT_WALLET_ADDRESS as string;
const chainId = Number(process.env.CHAIN_ID);
const privateKey = process.env.WALLET_PRIVATE_KEY as string;
async function main() {
const externalViemAccount = privateKeyToAccount(privateKey as Hex);
const bundlerProvider = new EtherspotBundler(chainId, bundlerApiKey);
const remoteSignerSdk = await RemoteSignerSdk.create(externalViemAccount, {
etherspotWalletAddress: etherspotWalletAddress,
chainId: chainId,
apiKey: apiKey,
sessionKey: sessionKey,
bundlerProvider: bundlerProvider
});
const transactionData = await getTransferERC20Data(remoteSignerSdk.getPublicClient());
// clear the transaction batch
await remoteSignerSdk.clearUserOpsFromBatch();
// add transactions to the batch
const userOpsBatch = await remoteSignerSdk.addUserOpsToBatch({ to: tokenAddress, data: transactionData });
console.log(`sessionkey erc20SessionKeyValidator ${erc20SessionKeyValidator} as BigNumber is: ${BigNumber.from(erc20SessionKeyValidator)}`);
let nonceKey = BigNumber.from(erc20SessionKeyValidator);
// estimate transactions added to the batch and get the fee data for the UserOp
const op = await remoteSignerSdk.estimate({nonceKey: nonceKey});
const signedUserOp = await remoteSignerSdk.signUserOp(op);
console.log(`Signed UserOp: ${await printOp(signedUserOp)}`);
console.log(`UserOpNonce is: ${BigNumber.from(signedUserOp.nonce)}`);
const userOpHashFromSignedUserOp = await remoteSignerSdk.getUserOpHash(signedUserOp);
console.log(`UserOpHash from Signed UserOp: ${userOpHashFromSignedUserOp}`);
// sending to the bundler with isUserOpAlreadySigned true...
const uoHash = await remoteSignerSdk.send(signedUserOp);
console.log(`UserOpHash: ${uoHash}`);
// get transaction hash...
console.log('Waiting for transaction...');
let userOpsReceipt = null;
const timeout = Date.now() + 60000; // 1 minute timeout
while ((userOpsReceipt == null) && (Date.now() < timeout)) {
await sleep(2);
userOpsReceipt = await remoteSignerSdk.getUserOpReceipt(uoHash);
}
console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt);
}
main()
.catch(console.error)
.finally(() => process.exit());
async function getTransferERC20Data(publicClient) {
const decimals = await publicClient.readContract({
address: tokenAddress as Hex,
abi: parseAbi(erc20Abi),
functionName: 'decimals',
args: []
});
// get transferFrom encoded data
const transactionData = encodeFunctionData({
functionName: 'transfer',
abi: parseAbi(erc20Abi),
args: [recipient, parseUnits(value, decimals as number)]
});
return transactionData;
}