Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: pytest

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]

permissions:
contents: read

concurrency:
group: pytest-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13.11"

- name: Install uv
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
with:
enable-cache: true

- name: Install dependencies
run: make install

- name: Start Hardhat node
run: |
nohup npx hardhat --config ./hardhat.config.js node &

- name: Run tests
run: make test
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ run-one: deploy

run-separate: deploy
uv run python example/eip7702_separate_tx.py $(ARGS)

test: deploy
uv run pytest -v tests/ $(ARGS)
16 changes: 8 additions & 8 deletions example/RESULTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ uv run python example/eip7702_one_tx.py
19:07:00 | INFO | [S3] Balances β†’ Payer=1 ETH, Executor=0 ETH
19:07:00 | INFO | [S4] Reading Counter state: 0xf1e09bf3E9024a5D10007F77c7d96C681b926494
19:07:00 | INFO | [S4] Counter start: locked=False number=0
19:07:00 | INFO | [S4] Executor pre: code_len=0 nonce=0
19:07:00 | INFO | [S4] Executor pre: bytecode_len=0 (eth_getCode result) nonce=0
19:07:00 | INFO | [S4] Payer pre: nonce=0
19:07:00 | INFO | [S4] Payer balance pre: 1 ETH
19:07:00 | INFO | [S5] Authorization (by Executor) β†’ target=0xa6a5F456046209D4e3291Eb1a0C175344612674C nonce=0
Expand All @@ -42,12 +42,12 @@ uv run python example/eip7702_one_tx.py
19:07:00 | INFO | [S8] Estimated gas paid: 0.000104429291670197 ETH (effectiveGasPrice * gasUsed)
19:07:00 | INFO | [S9] Verifying results
19:07:00 | INFO | [S9] Counter end: locked=True number=6
19:07:00 | INFO | [S9] Executor post: code_len=23 nonce=1
19:07:00 | INFO | [S9] Executor post: bytecode_len=23 (eth_getCode may reflect delegation) nonce=1
19:07:00 | INFO | [S9] Payer post: nonce=1
19:07:00 | INFO | [S9] Payer post balance: 0.999895570708329803 ETH
19:07:00 | INFO | ──────────────── Summary ────────────────
19:07:00 | INFO | Tx: 5a0984613819973623880bd600794f800c23c39ba47ed207b10e5e6495525773 | Block: 98 | GasUsed: 104429
19:07:00 | INFO | Executor: 0xA73997395c4a08AFAeCaF9A183b7348C34ECCB9a | code_len=0 β†’ 23 | nonce=0 β†’ 1
19:07:00 | INFO | Executor: 0xA73997395c4a08AFAeCaF9A183b7348C34ECCB9a | bytecode_len=0 β†’ 23 | nonce=0 β†’ 1
19:07:00 | INFO | Payer : 0xa4Fd1749027e905Be0E1C3971AAaD3f5B4b26A4c | nonce=0 β†’ 1 | paid gas | balance: 1 β†’ 0.999895570708329803 (Ξ” -0.000104429291670197 ETH)
19:07:00 | INFO | Counter: address=0xf1e09bf3E9024a5D10007F77c7d96C681b926494 | locked=True | number=6
19:07:00 | INFO | ─────────────────────────────────────────
Expand Down Expand Up @@ -82,16 +82,16 @@ uv run python example/eip7702_separate_tx.py
19:08:36 | INFO | [S3] Payer : 0x0A0652DBaE388376885E772D9307Ebb290001Dc5
19:08:36 | INFO | [S3] Funding Payer 1.0 ETH from 0xeD6ef822d2cc46a8D7CfDb8A4b7BcF7E9B95F946 β†’ 0x0A0652DBaE388376885E772D9307Ebb290001Dc5
19:08:36 | INFO | [S4] Counter start: locked=False number=0
19:08:36 | INFO | [S4] Executor code_len pre: 0
19:08:36 | INFO | [S4] Executor bytecode_len pre (eth_getCode result): 0
19:08:36 | INFO | [S5] Signed single authorization by Executor (nonce=0)
19:08:36 | INFO | [S6] Running first transaction (delegate-only; install code via authorization)
19:08:36 | INFO | [S6] Running first transaction (delegation-only; set delegation via authorization)
19:08:36 | INFO | [TX1] Nonce β†’ Payer=0 | Payer balance pre=1 ETH
19:08:36 | INFO | [TX1] Sent (delegate-only): e9be3612f08bc8392e7133a18e9f4eb3fb85d2f0a6d965a2b6de11470e719c64
19:08:36 | INFO | [TX1] Sent (delegation-only): e9be3612f08bc8392e7133a18e9f4eb3fb85d2f0a6d965a2b6de11470e719c64
19:08:36 | INFO | [TX1] Mined: block=102 status=0 gasUsed=46046
19:08:36 | INFO | [TX1] Payer balance: 1 β†’ 0.99995395392356364 (Ξ” -0.00004604607643636 ETH)
19:08:36 | INFO | [TX1] Estimated gas paid: 0.00004604607643636 ETH
19:08:36 | INFO | [S6] Executor code_len post: 23
19:08:36 | INFO | [S7] Running second transaction (set_number=7) by Payer (execute code)
19:08:36 | INFO | [S6] Executor bytecode_len post (eth_getCode may reflect delegation): 23
19:08:36 | INFO | [S7] Running second transaction (set_number=7) by Payer (execute via delegation)
19:08:36 | INFO | [TX2] Nonce β†’ Payer=1 | Payer balance pre=0.99995395392356364 ETH
19:08:36 | INFO | [TX2] Sent: 38d74d7bce5383728965d869526f6f42105819c048d73c2d3fcccfd0e84eb6b3 (set_number=7)
19:08:36 | INFO | [TX2] Mined: block=103 status=1 gasUsed=79465
Expand Down
10 changes: 6 additions & 4 deletions example/eip7702_one_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def main():
executor_nonce = w3.eth.get_transaction_count(executor_acct.address)
payer_nonce = w3.eth.get_transaction_count(payer_acct.address)
logger.info(
"[S4] Executor pre: code_len=%d nonce=%d",
"[S4] Executor pre: bytecode_len=%d (eth_getCode result) nonce=%d",
len(executor_code),
executor_nonce,
)
Expand Down Expand Up @@ -191,7 +191,9 @@ def main():
logger,
)

logger.info("[S7] Building type-4 transaction (Payer signs, Executor is 'to')")
logger.info(
"[S7] Building type-4 transaction (Payer signs, Executor is 'to'; sets delegation via authorizationList and executes calldata)"
)
tx = {
"chainId": chain_id,
"type": 4,
Expand Down Expand Up @@ -241,7 +243,7 @@ def main():
new_payer_nonce = w3.eth.get_transaction_count(payer_acct.address)
logger.info("[S9] Counter end: locked=%s number=%s", is_locked, current_number)
logger.info(
"[S9] Executor post: code_len=%d nonce=%d",
"[S9] Executor post: bytecode_len=%d (eth_getCode may reflect delegation) nonce=%d",
len(new_executor_code),
new_executor_nonce,
)
Expand All @@ -258,7 +260,7 @@ def main():
receipt.get("gasUsed"),
)
logger.info(
"Executor: %s | code_len=%d β†’ %d | nonce=%d β†’ %d",
"Executor: %s | bytecode_len=%d β†’ %d | nonce=%d β†’ %d",
executor_acct.address,
len(executor_code),
len(new_executor_code),
Expand Down
23 changes: 14 additions & 9 deletions example/eip7702_separate_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def install_code_with_authorization(
w3.from_wei(payer_balance_pre, "ether"),
)

# delegate-only: send no calldata to just install code via authorization
# delegation-only: send no calldata (only applies delegation via authorization)
tx = {
"chainId": chain_id,
"type": 4,
Expand All @@ -92,11 +92,11 @@ def install_code_with_authorization(
"maxPriorityFeePerGas": 10**9,
"to": executor_acct.address,
"authorizationList": [signed_auth],
"data": b"", # no call, just install code
"data": b"", # no call, only applies delegation
}
signed_tx = payer_acct.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
logger.info("[TX1] Sent (delegate-only): %s", tx_hash.hex())
logger.info("[TX1] Sent (delegation-only): %s", tx_hash.hex())

receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
payer_balance_post = w3.eth.get_balance(payer_acct.address)
Expand Down Expand Up @@ -145,12 +145,12 @@ def execute_multicall_as_payer(
w3.from_wei(payer_balance_pre, "ether"),
)

# build calldata same as before (execute on executor's code)
# build calldata (this will be executed via executor's delegation)
data = build_multicall_payload(
w3, counter_addr, counter_abi, multicall_addr, multicall_abi, new_value, logger
)

# normal EIP-1559 tx signed by Payer to Executor (Executor code already set by TX1)
# normal EIP-1559 tx signed by Payer to Executor (delegation is set by TX1)
tx = {
"chainId": chain_id,
"nonce": payer_nonce,
Expand Down Expand Up @@ -281,7 +281,9 @@ def main():
"[S4] Counter start: locked=%s number=%s", start_locked, start_number
)
exec_code_pre = w3.eth.get_code(executor.address)
logger.info("[S4] Executor code_len pre: %d", len(exec_code_pre))
logger.info(
"[S4] Executor bytecode_len pre (eth_getCode result): %d", len(exec_code_pre)
)

# 5. sign single authorization by Executor (nonce = current)
executor_nonce = w3.eth.get_transaction_count(executor.address)
Expand All @@ -293,7 +295,7 @@ def main():

# 6. run first tx with payer using the single authorization
logger.info(
"[S6] Running first transaction (delegate-only; install code via authorization)"
"[S6] Running first transaction (delegation-only; set delegation via authorization)"
)
txh1, r1, v1 = install_code_with_authorization(
w3,
Expand All @@ -305,11 +307,14 @@ def main():
logger,
)
exec_code_post = w3.eth.get_code(executor.address)
logger.info("[S6] Executor code_len post: %d", len(exec_code_post))
logger.info(
"[S6] Executor bytecode_len post (eth_getCode may reflect delegation): %d",
len(exec_code_post),
)

# 7. run second tx also by Payer (no authorization)
logger.info(
"[S7] Running second transaction (set_number=%d) by Payer (execute code)",
"[S7] Running second transaction (set_number=%d) by Payer (execute via delegation)",
args.value2,
)
txh2, r2, v2 = execute_multicall_as_payer(
Expand Down
Loading
Loading