Skip to content
Closed
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
456 changes: 455 additions & 1 deletion package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,8 @@
"engines": {
"node": ">=18",
"npm": ">=7"
},
"dependencies": {
"@ethersproject/abi": "^5.8.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an Ethers dev dependency in package.json root which you should be able to use, no need to add a dependency here + alter the package-lock.json file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}
}
1 change: 0 additions & 1 deletion packages/ethereum-tests
Submodule ethereum-tests deleted from e2d83c
4 changes: 2 additions & 2 deletions packages/util/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ See PR [#3524](https://github.com/ethereumjs/ethereumjs-monorepo/pull/3524):
See PR [#3544](https://github.com/ethereumjs/ethereumjs-monorepo/pull/3544):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting here, since I can't do above: accicental removal (+ committed) of the packages/ethereum-tests directory.

I think it might generally be wise to just pick the relevant changes from this PR (by just copying over) and submit a new PR, best from a branch on your side (git checkout -b new-eip-7702-examples) and not from master, otherwise things will likely get too messy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok ill do it


- `Address.zero()` -> `createZeroAddress()`
- `Address.fromString()` -> `createAddressFromString()`
- `new Address(hexToBytes())` -> `createAddressFromString()`
- `Address.fromPublicKey()` -> `createAddressFromPublicKey()`
- `Address.fromPrivateKey()` -> `createAddressFromPrivateKey()`
- `new Address(privateToAddress())` -> `createAddressFromPrivateKey()`
- `Address.generate()` -> `createContractAddress()`
- `Address.generate2()` -> `createContractAddress2()`
- New: `createAddressFromBigInt()`
Expand Down
69 changes: 69 additions & 0 deletions packages/vm/examples/eip7702-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# EIP-7702 Examples for EthereumJS

This directory contains examples demonstrating how to use [EIP-7702](https://eip7702.io/) with the EthereumJS libraries. EIP-7702 allows EOAs (Externally Owned Accounts) to set their code based on existing smart contracts, giving them capabilities similar to smart contract accounts without the need to deploy a separate contract.

## What is EIP-7702?

EIP-7702 gives EOAs superpowers by allowing them to set their code based on any existing smart contract. An EOA owner signs an authorization that can then be submitted by anyone as part of a new transaction type. This enables EOAs to mimic smart contract accounts, enabling features like:

- Transaction bundling (execute multiple actions in one transaction)
- Gas sponsorships
- Custom permissioning schemes

The EOA's code will be valid until replaced by another authorization, and the authorization can be given for a single chain or all chains at once.

## Benefits of EIP-7702

- **Better User Experience**: Users can execute multiple operations atomically in one transaction
- **Gas Efficiency**: Reduce gas costs by combining multiple transactions
- **No Contract Deployment**: Use existing smart contract implementations without deploying your own
- **Flexibility**: Users can provide both single-chain and cross-chain authorizations
- **Compatible with EIP-4337**: Works with account abstraction infrastructure like paymasters and bundlers
- **Compatible with Existing Smart Accounts**: Use existing smart account implementations with little to no effort

## Examples

### 1. Enabling EIP-7702 in the VM (`eip7702-enable.ts`)

This example demonstrates:
- How to enable EIP-7702 in the EthereumJS VM
- Creating and processing an EIP-7702 transaction
- Verifying the EOA's code has been set correctly

### 2. Atomic ERC20 Operations (`eip7702-erc20-atomic.ts`)

This example demonstrates:
- Using EIP-7702 for atomic ERC20 token operations (approve + transferFrom)
- Using RPCStateManager to simulate against a real network
- How an EOA can delegate to a bundler contract to perform multiple operations in one transaction

### 3. Uniswap Swap with EIP-7702 (`eip7702-uniswap.ts`)

This example demonstrates:
- Using EIP-7702 to perform a Uniswap swap
- Atomically approving tokens and executing a swap in one transaction
- Simulating the transaction using a mainnet fork

## Running the Examples

To run these examples, you'll need to:

1. Make sure you have EthereumJS libraries installed
2. Run a local Ethereum node or use a fork of mainnet for the examples with RPCStateManager
3. Execute the example scripts (e.g., `ts-node eip7702-enable.ts`)

## Important Notes

- These examples are for demonstration purposes only
- **NEVER** use real private keys with value in examples or test code
- For RPCStateManager examples, use a local development node or test network

## Implementation Status

EIP-7702 is still in the proposal stage. The EthereumJS implementation is intended to help developers understand how to use EIP-7702 and prepare for its potential adoption.

## Resources

- [EIP-7702 Website](https://eip7702.io/)
- [EIP-7702 Examples](https://eip7702.io/examples)
- [EthereumJS Documentation](https://github.com/ethereumjs/ethereumjs-monorepo)
63 changes: 63 additions & 0 deletions packages/vm/examples/eip7702-blog-post-outline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Blog Post Outline: Implementing EIP-7702 in EthereumJS - The Future of EOA Superpowers

## Introduction
- Brief explanation of what EIP-7702 is and why it matters
- The problem it solves - UX challenges with EOAs vs. smart contract accounts
- Announcement of EIP-7702 support in EthereumJS libraries

## Understanding EIP-7702
- Detailed explanation of EIP-7702 and its mechanism
- How it allows EOAs to delegate to smart contract implementations
- The authorization process and transaction structure
- Security model and considerations

## Benefits of EIP-7702
- Transaction bundling for better UX
- Gas efficiency by combining multiple operations
- Removing the need for separate smart contract wallet deployments
- Compatibility with existing tools and infrastructure
- Flexible authorization schemes (single-chain, cross-chain)

## Implementation in EthereumJS
- Overview of changes made to the EthereumJS libraries
- New transaction type for EIP-7702
- How the VM processes EIP-7702 transactions
- Verification and code delegation process

## Example Use Cases
1. **Atomic ERC20 Operations**
- Approving and transferring tokens in a single transaction
- Benefits for DeFi usability
- Code example and explanation

2. **Uniswap Swap Optimization**
- Token approval and swap in one transaction
- How this improves user experience
- Gas savings and security benefits
- Code example and explanation

3. **Smart Account Features for EOAs**
- Using ERC-4337 implementations with EOAs
- Compatibility with existing account abstraction infrastructure
- Potential for additional features like social recovery

## Getting Started with EIP-7702 in EthereumJS
- How to enable EIP-7702 in your EthereumJS implementation
- Building applications that leverage EIP-7702
- Testing and simulating EIP-7702 transactions

## Future Outlook
- Potential impact on the Ethereum ecosystem
- How EIP-7702 fits with other account abstraction efforts
- Next steps for EIP-7702 adoption

## Conclusion
- Summary of EIP-7702's benefits
- Call to action for developers to start experimenting
- Resources for further learning

## Resources
- Links to the EIP-7702 specification
- EthereumJS documentation and examples
- Community discussion and feedback channels
- GitHub repositories and code examples
115 changes: 115 additions & 0 deletions packages/vm/examples/eip7702-enable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { Chain, Common, Hardfork, Mainnet } from '@ethereumjs/common'
import { Capability, TransactionType, createEOACode7702Tx } from '@ethereumjs/tx'
import {

Check warning on line 3 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L1-L3

Added lines #L1 - L3 were not covered by tests
Address,
bytesToHex,
createAddressFromString,
hexToBytes,
privateToAddress,
} from '@ethereumjs/util'
import { VM } from '@ethereumjs/vm'

Check warning on line 10 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L10

Added line #L10 was not covered by tests

/**
* This example demonstrates how to enable EIP-7702 in the EthereumJS VM
* and how to create and process an EIP-7702 transaction.
*/
const main = async () => {

Check warning on line 16 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L16

Added line #L16 was not covered by tests
// Create a Common instance with EIP-7702 enabled
const common = new Common({
chain: Mainnet,
hardfork: Hardfork.Cancun,
eips: [7702],
})

Check warning on line 22 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L18-L22

Added lines #L18 - L22 were not covered by tests

console.log('Is EIP-7702 activated?', common.isActivatedEIP(7702))

Check warning on line 24 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L24

Added line #L24 was not covered by tests

// Create accounts for demonstration
const privateKey = hexToBytes(
'0x1122334455667788112233445566778811223344556677881122334455667788',
)
const senderAddress = new Address(privateToAddress(privateKey))
console.log('Sender address:', senderAddress.toString())

Check warning on line 31 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L27-L31

Added lines #L27 - L31 were not covered by tests

// Create VM instance with EIP-7702 enabled
const vm = await (VM as any).create({ common })

Check warning on line 34 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L34

Added line #L34 was not covered by tests

// Set up account state
const accountBalance = 10n ** 18n // 1 ETH
await vm.stateManager.putAccount(senderAddress, { balance: accountBalance, nonce: 0n })

Check warning on line 38 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L37-L38

Added lines #L37 - L38 were not covered by tests

// Smart contract implementation address that we want to delegate to
// This could be any deployed smart contract (e.g. ERC-4337 account implementation)
const implementationAddress = new Address(
hexToBytes('0x0000000000000000000000000000000000000123'),
)
console.log('Implementation address:', implementationAddress.toString())

Check warning on line 45 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L42-L45

Added lines #L42 - L45 were not covered by tests

// Create EIP-7702 transaction
// The authorization enables the EOA to use the code from the implementation address
const chainId = common.chainId()

Check warning on line 49 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L49

Added line #L49 was not covered by tests

// Create an authorization for EIP-7702
// This is normally signed by the EOA owner
const txData = {
nonce: 0n,
gasLimit: 100000n,
maxFeePerGas: 10000000000n, // 10 gwei
maxPriorityFeePerGas: 1000000000n, // 1 gwei
to: senderAddress, // target is the same as sender (self-call for initialization)
value: 0n,
data: hexToBytes('0x'), // Could be initialization data
accessList: [],

Check warning on line 61 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L53-L61

Added lines #L53 - L61 were not covered by tests
// Using just [] as a basic authorizationList that will be accepted
authorizationList: [],
}

Check warning on line 64 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L63-L64

Added lines #L63 - L64 were not covered by tests

// Create and sign the EIP-7702 transaction
const tx = createEOACode7702Tx(txData, { common })
const signedTx = tx.sign(privateKey)

Check warning on line 68 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L67-L68

Added lines #L67 - L68 were not covered by tests

console.log('Transaction type:', TransactionType[signedTx.type])
console.log('Supports EIP-7702:', signedTx.supports(Capability.EIP7702EOACode))
console.log('Transaction hash:', bytesToHex(signedTx.hash()))

Check warning on line 72 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L70-L72

Added lines #L70 - L72 were not covered by tests

// Run the transaction to set the code of the EOA
const result = await vm.runTx({ tx: signedTx })

Check warning on line 75 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L75

Added line #L75 was not covered by tests

console.log(
'Transaction processed:',
result.execResult.exceptionError !== null && result.execResult.exceptionError !== undefined
? 'Failed'
: 'Success',
)

Check warning on line 82 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L77-L82

Added lines #L77 - L82 were not covered by tests

// Check that the EOA now has code
const account = await vm.stateManager.getAccount(senderAddress)
const code = await vm.stateManager.getContractCode(senderAddress)

Check warning on line 86 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L85-L86

Added lines #L85 - L86 were not covered by tests

console.log('Account nonce after transaction:', account?.nonce)
console.log('Account has code:', code.length > 0)
console.log('Code (hex):', bytesToHex(code))

Check warning on line 90 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L88-L90

Added lines #L88 - L90 were not covered by tests

// The code should start with the EIP-7702 delegation flag (0xef0100)
// followed by the implementation address
const hasDelegationFlag = code[0] === 0xef && code[1] === 0x01 && code[2] === 0x00
console.log('Has delegation flag:', hasDelegationFlag)

Check warning on line 95 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L94-L95

Added lines #L94 - L95 were not covered by tests

// Extract the delegated address from the code
if (hasDelegationFlag && code.length === 23) {
const delegatedAddressBytes = code.slice(3)
const delegatedAddress = createAddressFromString(bytesToHex(delegatedAddressBytes))
console.log('Delegated to address:', delegatedAddress.toString())

Check warning on line 101 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L98-L101

Added lines #L98 - L101 were not covered by tests

// Verify it matches our implementation address
console.log('Matches implementation address:', delegatedAddress.equals(implementationAddress))
}
}

Check warning on line 106 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L104-L106

Added lines #L104 - L106 were not covered by tests

// Helper function for bigint to unpadded bytes conversion
function bigIntToUnpadded(value: bigint): Uint8Array {

Check warning on line 109 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L109

Added line #L109 was not covered by tests
// Convert bigint to bytes without padding
const hex = value.toString(16)
return hexToBytes(hex.length % 2 === 0 ? `0x${hex}` : `0x0${hex}`)
}

Check warning on line 113 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L111-L113

Added lines #L111 - L113 were not covered by tests

main()

Check warning on line 115 in packages/vm/examples/eip7702-enable.ts

View check run for this annotation

Codecov / codecov/patch

packages/vm/examples/eip7702-enable.ts#L115

Added line #L115 was not covered by tests
Loading
Loading