-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add batch transactions to CandideAccount
- Loading branch information
1 parent
9298bbd
commit 947779d
Showing
12 changed files
with
475 additions
and
16 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/.env.example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#goerli chain example values | ||
CHAIN_ID=5 | ||
BUNDLER_URL=https://goerli.test.voltaire.candidewallet.com/rpc | ||
ENTRYPOINT_ADDRESS=0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 | ||
JSON_RPC_NODE_PROVIDER=https://ethereum-goerli.publicnode.com | ||
|
||
#account signer privatekey | ||
PRIVATE_KEY= |
35 changes: 35 additions & 0 deletions
35
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<!-- PROJECT LOGO --> | ||
|
||
<div align="center"> | ||
<h1 align="center">CreateAccountAndSendBatchTransactions Example - AbstractionKit - Account Abstraction SDK by Candide</h2> | ||
</div> | ||
|
||
<div align="center"> | ||
<img src="https://user-images.githubusercontent.com/7014833/203773780-04a0c8c0-93a6-43a4-bb75-570cb951dfa0.png" height =200> | ||
</div> | ||
|
||
# About | ||
|
||
CreateAccountAndSendBatchTransactions Example - AbstractionKit - Account Abstraction SDK by Candide | ||
|
||
This example is in the Goerli chain. | ||
|
||
In this example you will need to fund the new account address(sender) with Goerli eth first. | ||
|
||
# How to use this example | ||
|
||
### copy .env.example and add the paymaster values and a privatekey for signer | ||
``` | ||
cp .env.example .env | ||
``` | ||
|
||
### install dependencies, build and run | ||
``` | ||
yarn install | ||
yarn build | ||
node dist/index.js | ||
``` | ||
<!-- LICENSE --> | ||
## License | ||
|
||
MIT |
22 changes: 22 additions & 0 deletions
22
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/package.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "CreateAccountAndSendBatchTransactions", | ||
"version": "1.0.0", | ||
"description": "create a new account and send a useroperation with multiple transactions.", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "rm -rf dist && tsc", | ||
"clean": "rm -rf dist", | ||
"format": "prettier --write src/**/*.ts", | ||
"lint": "eslint src/**/*.ts" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"abstractionkit": "^0.0.7", | ||
"dotenv": "^16.3.1", | ||
"ethers": "^6.6.7", | ||
"typescript": "^5.1.6" | ||
}, | ||
"devDependencies": { | ||
"@types/ws": "^8.5.6" | ||
} | ||
} |
139 changes: 139 additions & 0 deletions
139
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import * as dotenv from 'dotenv' | ||
import {Wallet, JsonRpcProvider, getBytes, id, ZeroAddress } from "ethers" | ||
|
||
import { | ||
Bundler, | ||
CandideAccount, | ||
GasEstimationResult, | ||
UserOperation, | ||
getUserOperationHash, | ||
UserOperationDummyValues, | ||
getCallData, | ||
MetaTransaction, | ||
getFunctionSelector, | ||
Operation | ||
} from "abstractionkit"; | ||
|
||
|
||
async function main(): Promise<void> { | ||
//get vlues from .env | ||
dotenv.config() | ||
const chainId = process.env.CHAIN_ID as string | ||
const bundlerUrl = process.env.BUNDLER_URL as string | ||
const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string | ||
const entrypointAddress = process.env.ENTRYPOINT_ADDRESS as string | ||
const privateKey = process.env.PRIVATE_KEY as string | ||
|
||
let bundler: Bundler = new Bundler( | ||
bundlerUrl, | ||
entrypointAddress | ||
); | ||
|
||
let eoaSigner = new Wallet(privateKey); | ||
|
||
let smartAccount = new CandideAccount() | ||
|
||
//create a new smart account, only needed for the first useroperation for a new account | ||
let [newAccountAddress, initCode] = smartAccount.createNewAccount([eoaSigner.address]) | ||
|
||
console.log("Account address(sender) : " + newAccountAddress) | ||
|
||
// 1st transction - create callData to deposit eth and get wEth in return | ||
const wEthTokenAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"; | ||
const depositFunctionSignature = 'deposit()'; | ||
const depositFunctionSelector = getFunctionSelector(depositFunctionSignature); | ||
const depositTransactionCallData = getCallData(depositFunctionSelector, [], []); | ||
|
||
const tx1 :MetaTransaction ={ | ||
to: wEthTokenAddress, | ||
value: 10, //amount to deposit | ||
data: depositTransactionCallData, | ||
operation: Operation.Call | ||
} | ||
|
||
// 2nd transaction - approve allowance to uniswap router | ||
const uniswapV2RouterAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"; | ||
const approveFunctionSignature = 'approve(address,uint256)'; | ||
const approveFunctionSelector = getFunctionSelector(approveFunctionSignature); | ||
const approveTransactionCallData = getCallData( | ||
approveFunctionSelector, | ||
["address", "uint256"], | ||
[uniswapV2RouterAddress, 10] | ||
); | ||
|
||
const tx2 :MetaTransaction ={ | ||
to: wEthTokenAddress, | ||
value: 0, | ||
data: approveTransactionCallData, | ||
operation: Operation.Call | ||
} | ||
|
||
// 3rd transaction - swap weth for usdc | ||
const token0 = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"; //weth | ||
const token1 = "0x9B2660A7BEcd0Bf3d90401D1C214d2CD36317da5"; //usdc | ||
const swapFunctionSignature = 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)'; | ||
const swapFunctionSelector = getFunctionSelector(swapFunctionSignature); | ||
const swapTransactionCallData = getCallData(swapFunctionSelector, | ||
["uint256","uint256","address[]","address", "uint256"], //amountIn, amountOutMin, path, to, deadline | ||
[ | ||
5, //amountIn | ||
1, //amountOutMin | ||
[token0, token1], //path | ||
newAccountAddress, //to | ||
Math.floor(Date.now() / 1000) + 60 * 20, // deadline - 20 minutes from the current Unix time | ||
] | ||
); | ||
const tx3 :MetaTransaction ={ | ||
to: uniswapV2RouterAddress, | ||
value: 0, | ||
data: swapTransactionCallData, | ||
operation: Operation.Call | ||
} | ||
|
||
let callData = smartAccount.createCallDataBatchTransaction([tx1, tx2, tx3]); | ||
|
||
const provider = new JsonRpcProvider(jsonRpcNodeProvider); | ||
|
||
let user_operation :UserOperation={ | ||
...UserOperationDummyValues, | ||
sender:newAccountAddress, | ||
nonce: "0x00", | ||
initCode:initCode,//only needed for the first useroperation for a new account | ||
callData:callData | ||
} | ||
|
||
//fetch gas price - use your prefered source | ||
const feeData = await provider.getFeeData() | ||
user_operation.maxFeePerGas = "0x" + Math.ceil(Number(feeData.maxFeePerGas)*1.5).toString(16)//convert to hex format | ||
user_operation.maxPriorityFeePerGas = "0x" + Math.ceil(Number(feeData.maxPriorityFeePerGas)*1.5).toString(16)//convert to hex format | ||
|
||
let estimation = await bundler.estimateUserOperationGas(user_operation) | ||
console.log("estimation") | ||
console.log(estimation) | ||
if("code" in estimation){ | ||
return | ||
} | ||
//either multiply gas limit with a factor to compensate for the missing paymasterAndData and signature during gas estimation | ||
//or supply dummy values that will not cause the useroperation to revert | ||
//for the most accurate values, estimate gas again after acquiring the initial gas limits | ||
//and a valide paymasterAndData and signature | ||
estimation = estimation as GasEstimationResult | ||
user_operation.preVerificationGas = "0x" + Math.ceil(Number(estimation.preVerificationGas)*1.2).toString(16) | ||
user_operation.verificationGasLimit = "0x" + Math.ceil(Number(estimation.verificationGasLimit)*1.5).toString(16) | ||
user_operation.callGasLimit = "0x" + Math.ceil(Number(estimation.callGasLimit)*1.2).toString(16) | ||
|
||
//sign the user operation hash | ||
let user_operation_hash = getUserOperationHash( | ||
user_operation, entrypointAddress, chainId | ||
) | ||
user_operation.signature = await eoaSigner.signMessage(getBytes(user_operation_hash)) | ||
|
||
//send the user operation to the bundler | ||
let bundlerResponse = await bundler.sendUserOperation(user_operation) | ||
console.log(bundlerResponse) | ||
if("message" in bundlerResponse && bundlerResponse.message as string == "AA21 didn't pay prefund"){ | ||
console.log("Please fund the new account address with some eth to pay for gas : " + newAccountAddress) | ||
} | ||
} | ||
|
||
main() |
22 changes: 22 additions & 0 deletions
22
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/tsconfig.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"compilerOptions": { | ||
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, | ||
"module": "commonjs" /* Specify what module code is generated. */, | ||
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, | ||
"declaration": true, | ||
"declarationMap": true, | ||
"removeComments": true, | ||
"allowSyntheticDefaultImports": true, | ||
"sourceMap": false, | ||
"outDir": "./dist", | ||
"baseUrl": "./", | ||
"incremental": true, | ||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, | ||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, | ||
|
||
"strict": true /* Enable all strict type-checking options. */, | ||
"skipLibCheck": true /* Skip type checking all .d.ts files. */ | ||
}, | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules", "test", "lib", "**/*spec.ts"] | ||
} |
119 changes: 119 additions & 0 deletions
119
examples/CandideAccountExamples/CreateAccountAndSendBatchTransactions/yarn.lock
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
# yarn lockfile v1 | ||
|
||
|
||
"@adraffy/ens-normalize@1.9.2": | ||
version "1.9.2" | ||
resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" | ||
integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== | ||
|
||
"@noble/hashes@1.1.2": | ||
version "1.1.2" | ||
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" | ||
integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== | ||
|
||
"@noble/secp256k1@1.7.1": | ||
version "1.7.1" | ||
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" | ||
integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== | ||
|
||
"@types/node@*": | ||
version "20.7.2" | ||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.2.tgz#0bdc211f8c2438cfadad26dc8c040a874d478aed" | ||
integrity sha512-RcdC3hOBOauLP+r/kRt27NrByYtDjsXyAuSbR87O6xpsvi763WI+5fbSIvYJrXnt9w4RuxhV6eAXfIs7aaf/FQ== | ||
|
||
"@types/node@18.15.13": | ||
version "18.15.13" | ||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" | ||
integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== | ||
|
||
"@types/ws@^8.5.6": | ||
version "8.5.6" | ||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.6.tgz#e9ad51f0ab79b9110c50916c9fcbddc36d373065" | ||
integrity sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg== | ||
dependencies: | ||
"@types/node" "*" | ||
|
||
abstractionkit@^0.0.7: | ||
version "0.0.7" | ||
resolved "https://registry.yarnpkg.com/abstractionkit/-/abstractionkit-0.0.7.tgz#56885deb583b9d15d08b9869a8ed699fc45ec4b0" | ||
integrity sha512-GQ8gIzIeu2f1G8lCNvS57ZGYeU8cG9AIgn/zAgmUxx9D1nsyBDJTTSpzW0X+6sJIdrW98pqS6zkai2RPBl7WCw== | ||
dependencies: | ||
ethers "^6.6.4" | ||
isomorphic-unfetch "^3.1.0" | ||
|
||
aes-js@4.0.0-beta.5: | ||
version "4.0.0-beta.5" | ||
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" | ||
integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== | ||
|
||
dotenv@^16.3.1: | ||
version "16.3.1" | ||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" | ||
integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== | ||
|
||
ethers@^6.6.4, ethers@^6.6.7: | ||
version "6.7.1" | ||
resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.7.1.tgz#9c65e8b5d8e9ad77b7e8cf1c46099892cfafad49" | ||
integrity sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA== | ||
dependencies: | ||
"@adraffy/ens-normalize" "1.9.2" | ||
"@noble/hashes" "1.1.2" | ||
"@noble/secp256k1" "1.7.1" | ||
"@types/node" "18.15.13" | ||
aes-js "4.0.0-beta.5" | ||
tslib "2.4.0" | ||
ws "8.5.0" | ||
|
||
isomorphic-unfetch@^3.1.0: | ||
version "3.1.0" | ||
resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" | ||
integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== | ||
dependencies: | ||
node-fetch "^2.6.1" | ||
unfetch "^4.2.0" | ||
|
||
node-fetch@^2.6.1: | ||
version "2.7.0" | ||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" | ||
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== | ||
dependencies: | ||
whatwg-url "^5.0.0" | ||
|
||
tr46@~0.0.3: | ||
version "0.0.3" | ||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" | ||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== | ||
|
||
tslib@2.4.0: | ||
version "2.4.0" | ||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" | ||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== | ||
|
||
typescript@^5.1.6: | ||
version "5.2.2" | ||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" | ||
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== | ||
|
||
unfetch@^4.2.0: | ||
version "4.2.0" | ||
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" | ||
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== | ||
|
||
webidl-conversions@^3.0.0: | ||
version "3.0.1" | ||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" | ||
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== | ||
|
||
whatwg-url@^5.0.0: | ||
version "5.0.0" | ||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" | ||
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== | ||
dependencies: | ||
tr46 "~0.0.3" | ||
webidl-conversions "^3.0.0" | ||
|
||
ws@8.5.0: | ||
version "8.5.0" | ||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" | ||
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== |
Oops, something went wrong.