-
Notifications
You must be signed in to change notification settings - Fork 371
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: Document EOA account call behavior
These tests assert and document the behavior of empty and eoa accounts with value when called by external transactions with or without data. In addition, they assert the gas usage is as expected and only depedent on the base transaction cost plus calldata cost since no code is executed.
- Loading branch information
Showing
2 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
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,68 @@ | ||
import hre from "hardhat"; | ||
import { expect } from "chai"; | ||
import { Address, toHex } from "viem"; | ||
import { randomBytes } from "crypto"; | ||
import { whaleAddress } from "./addresses"; | ||
|
||
// Empty Account describes how transactions behave against an account with | ||
// with no balance, no code, and no nonce. | ||
// | ||
// Accounts without code can be called with any data and value. | ||
describe("Empty Account", function () { | ||
const emptyAddress: Address = toHex(randomBytes(20)); | ||
|
||
// The definition of an empty account | ||
it("has no balance, no code, and zero nonce", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
|
||
const balance = await publicClient.getBalance({ address: emptyAddress }); | ||
const code = await publicClient.getCode({ address: emptyAddress }); | ||
const nonce = await publicClient.getTransactionCount({ address: emptyAddress }); | ||
|
||
expect(balance).to.equal(0n); | ||
expect(code).to.be.undefined; | ||
expect(nonce).to.equal(0); | ||
}); | ||
|
||
// An empty account can receive a 0 value transaction | ||
it("can be called with no data or value", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
const walletClient = await hre.viem.getWalletClient(whaleAddress); | ||
|
||
const txHash = await walletClient.sendTransaction({ | ||
to: emptyAddress, | ||
}); | ||
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); | ||
const tx = await publicClient.getTransaction({ hash: txHash }); | ||
|
||
expect(txReceipt.status).to.equal("success"); | ||
expect(txReceipt.gasUsed).to.equal(21000n); | ||
expect(tx.value).to.equal(0n); | ||
expect(tx.to).to.equal(emptyAddress); | ||
expect(tx.input).to.equal("0x"); | ||
}); | ||
|
||
// An empty account can receive a call with any data payload | ||
it("can be called with data", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
const walletClient = await hre.viem.getWalletClient(whaleAddress); | ||
|
||
// 16 bytes with 1 of them zero | ||
// 16 * 15 + 4 * 1 = 244 gas | ||
const calldata = "0x1eb478108900a0b492ef5dd03921d02d"; | ||
|
||
const txHash = await walletClient.sendTransaction({ | ||
to: emptyAddress, | ||
data: calldata, | ||
}); | ||
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); | ||
const tx = await publicClient.getTransaction({ hash: txHash }); | ||
|
||
expect(txReceipt.status).to.equal("success"); | ||
// exact gas -- no memory expansion or op code charges | ||
expect(txReceipt.gasUsed).to.equal(21000n + 244n); | ||
expect(tx.value).to.equal(0n); | ||
expect(tx.to).to.equal(emptyAddress); | ||
expect(tx.input).to.equal(calldata); | ||
}); | ||
}); |
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,84 @@ | ||
import hre from "hardhat"; | ||
import { expect } from "chai"; | ||
import { Address, toHex } from "viem"; | ||
Check failure on line 3 in tests/e2e-evm/test/eoa_account.test.ts GitHub Actions / lint / e2e-evm-lint
|
||
import { randomBytes } from "crypto"; | ||
import { whaleAddress, userAddress } from "./addresses"; | ||
|
||
// EOA Account describes how transactions behave against an account with | ||
// with no code while holding a balance. | ||
// | ||
// Accounts without code can be called with any data and value. | ||
describe("EOA Account", function () { | ||
it("has a balance and no code", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
|
||
const balance = await publicClient.getBalance({ address: userAddress }); | ||
const code = await publicClient.getCode({ address: userAddress }); | ||
|
||
expect(balance).to.not.equal(0n); | ||
expect(code).to.be.undefined; | ||
}); | ||
|
||
it("can be called with no data or value", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
const walletClient = await hre.viem.getWalletClient(whaleAddress); | ||
|
||
const txHash = await walletClient.sendTransaction({ | ||
to: userAddress, | ||
}); | ||
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); | ||
const tx = await publicClient.getTransaction({ hash: txHash }); | ||
|
||
expect(txReceipt.status).to.equal("success"); | ||
expect(txReceipt.gasUsed).to.equal(21000n); | ||
expect(tx.value).to.equal(0n); | ||
expect(tx.to).to.equal(userAddress); | ||
expect(tx.input).to.equal("0x"); | ||
}); | ||
|
||
it("can be called with data", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
const walletClient = await hre.viem.getWalletClient(whaleAddress); | ||
|
||
// 16 bytes with 1 of them zero | ||
// 16 * 15 + 4 * 1 = 244 gas | ||
const calldata = "0x1eb478108900a0b492ef5dd03921d02d"; | ||
|
||
const txHash = await walletClient.sendTransaction({ | ||
to: userAddress, | ||
data: calldata, | ||
}); | ||
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); | ||
const tx = await publicClient.getTransaction({ hash: txHash }); | ||
|
||
expect(txReceipt.status).to.equal("success"); | ||
// exact gas -- no memory expansion or op code charges | ||
expect(txReceipt.gasUsed).to.equal(21000n + 244n); | ||
expect(tx.value).to.equal(0n); | ||
expect(tx.to).to.equal(userAddress); | ||
expect(tx.input).to.equal(calldata); | ||
}); | ||
|
||
it("can be called with data and value", async function () { | ||
const publicClient = await hre.viem.getPublicClient(); | ||
const walletClient = await hre.viem.getWalletClient(whaleAddress); | ||
|
||
// 4 non-zero bytes | ||
// 16 * 4 = 64 gas | ||
const calldata = "0x1eb47810"; | ||
|
||
const txHash = await walletClient.sendTransaction({ | ||
to: userAddress, | ||
data: calldata, | ||
}); | ||
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); | ||
const tx = await publicClient.getTransaction({ hash: txHash }); | ||
|
||
expect(txReceipt.status).to.equal("success"); | ||
// exact gas -- no memory expansion or op code charges | ||
expect(txReceipt.gasUsed).to.equal(21000n + 64n); | ||
expect(tx.value).to.equal(0n); | ||
expect(tx.to).to.equal(userAddress); | ||
expect(tx.input).to.equal(calldata); | ||
}); | ||
}); |