-
Notifications
You must be signed in to change notification settings - Fork 827
tx: 7702 examples #4039
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gabrocheleau
wants to merge
10
commits into
master
Choose a base branch
from
tx/7702-examples
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
tx: 7702 examples #4039
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
a9a709e
tx: small adjustments to 7702 tx example2
gabrocheleau 8d76c4b
lint: fix
gabrocheleau 723e789
examples: atomic approve-transferFrom + uniswap swap
gabrocheleau 4742254
vm: add 7702 example
gabrocheleau 47991de
vm: approve swap transfer
gabrocheleau 5eae393
chore: cleanup
gabrocheleau 880ffed
fix: lint
gabrocheleau 130350e
chore: cleanup
gabrocheleau cd80ac7
vm: address comments2
gabrocheleau 73f8ee4
chore: adjust nonce
gabrocheleau File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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,110 @@ | ||
import { Common, Hardfork, Mainnet } from '@ethereumjs/common' | ||
import { RPCStateManager } from '@ethereumjs/statemanager' | ||
import { EOACode7702Tx, type EOACode7702TxData } from '@ethereumjs/tx' | ||
import type { PrefixedHexString } from '@ethereumjs/util' | ||
import { | ||
createAddressFromPrivateKey, | ||
eoaCode7702SignAuthorization, | ||
hexToBytes, | ||
} from '@ethereumjs/util' | ||
import { createVM, runTx } from '@ethereumjs/vm' | ||
import { Interface, parseEther, parseUnits } from 'ethers' | ||
|
||
async function run() { | ||
// ─── your EOA key & address ─────────────────────────────────────────── | ||
const privateKeyHex = '0x1122334455667788112233445566778811223344556677881122334455667788' | ||
const privateKey = hexToBytes(privateKeyHex) | ||
const userAddress = createAddressFromPrivateKey(privateKey) | ||
console.log('EOA:', userAddress.toString()) | ||
|
||
// ─── set up EthereumJS VM with EIP-7702 enabled ─────────────────────── | ||
const common = new Common({ | ||
chain: Mainnet, | ||
hardfork: Hardfork.Prague, | ||
}) | ||
const stateManager = new RPCStateManager({ | ||
provider: 'YourProviderURLHere', | ||
blockTag: 22_000_000n, | ||
}) | ||
const vm = await createVM({ common, stateManager }) | ||
|
||
// ─── constants & ABIs ──────────────────────────────────────────────── | ||
const DAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F' | ||
const UNISWAP_V3_ROUTER = '0xE592427A0AEce92De3Edee1F18E0157C05861564' | ||
const WETH = '0xC02aaa39b223FE8D0A0e5c4F27EaD9083C756Cc2' | ||
const COLD_WALLET = `0x${'42'.repeat(20)}` | ||
|
||
const erc20Abi = [ | ||
'function approve(address _spender, uint256 _amount) external returns (bool success)', | ||
'function transfer(address _to, uint256 _value) public returns (bool success)', | ||
] | ||
const routerAbi = ['function exactInput(bytes)'] | ||
|
||
// This Batch contract is a placeholder. Replace with your actual batch contract address. | ||
// This contract is responsible for executing multiple calls in a single TX. | ||
const BATCH_CONTRACT = '0xYourBatchContractAddressHere' | ||
const batchAbi = ['function executeBatch(bytes[] calldata, address[] targets) external'] | ||
|
||
const erc20 = new Interface(erc20Abi) | ||
const router = new Interface(routerAbi) | ||
const batch = new Interface(batchAbi) | ||
|
||
// ─── trade parameters ──────────────────────────────────────────────── | ||
const amountIn = parseUnits('10000', 18) // 10000 DAI | ||
const amountOut = parseEther('4') // expect at least 4 WETH | ||
|
||
// ─── encode your underlying swap data ─────────────────────────────────── | ||
const uniswapV3SwapPayload = `0xYourSwapCallDataHere` | ||
|
||
// ─── encode your three sub-calls ─────────────────────────────────────── | ||
// 1) DAI approve | ||
const callApprove = erc20.encodeFunctionData('approve', [ | ||
UNISWAP_V3_ROUTER, | ||
amountIn, | ||
]) as PrefixedHexString | ||
|
||
// 2) Uniswap V3 swapExactInput | ||
const callSwap = router.encodeFunctionData('exactInput', [ | ||
uniswapV3SwapPayload, | ||
]) as PrefixedHexString | ||
|
||
// 3) sweep WETH to cold wallet | ||
const callTransfer = erc20.encodeFunctionData('transfer', [ | ||
COLD_WALLET, | ||
amountOut, | ||
]) as PrefixedHexString | ||
|
||
const targets: PrefixedHexString[] = [DAI, UNISWAP_V3_ROUTER, WETH] | ||
const calls = [callApprove, callSwap, callTransfer].map(hexToBytes) | ||
|
||
// ─── build & send your single 7702 tx ─────────────────────────────── | ||
const batchData = batch.encodeFunctionData('executeBatch', [calls, targets]) as `0x${string}` | ||
|
||
// ─── sign authorization for Batch Contract ────── | ||
const authorizationListItem = eoaCode7702SignAuthorization( | ||
{ chainId: '0x1', address: BATCH_CONTRACT, nonce: `0x1` }, | ||
privateKey, | ||
) | ||
|
||
const txData: EOACode7702TxData = { | ||
nonce: 0n, | ||
gasLimit: 1_000_000n, | ||
maxFeePerGas: parseUnits('10', 9), // 10 gwei | ||
maxPriorityFeePerGas: parseUnits('5', 9), // 5 gwei | ||
to: userAddress, // Using our own wallet, which will be acting as the BATCH_CONTRACT smart contract | ||
value: 0n, | ||
data: hexToBytes(batchData), | ||
accessList: [], | ||
authorizationList: [authorizationListItem], | ||
} | ||
|
||
const tx = new EOACode7702Tx(txData, { common }).sign(privateKey) | ||
const { execResult } = await runTx(vm, { tx }) | ||
|
||
console.log( | ||
'🔀 Batch swap DAI→WETH → your wallet:', | ||
execResult.exceptionError ? '❌ Failed' : '✅ Success', | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could also query the VM here to see the changes (deposit to wallet for instance) |
||
} | ||
|
||
run().catch(console.error) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not show how to sign the authorization list item, which is necessary, because the authorization signer does not necessarily have to be the tx signer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I just refactored this one initially (didn't actually work on it) so that it had at least correct types. We can certainly improve it.