Skip to content

Commit

Permalink
test: Additional tests for static and call codes
Browse files Browse the repository at this point in the history
Additional tests for call and staticcall have been added for
completness.  These will be refactored to table tests in future to
reduce boilerplate and test length.
  • Loading branch information
nddeluca committed Sep 25, 2024
1 parent 5c7102c commit 679b265
Showing 1 changed file with 134 additions and 1 deletion.
135 changes: 134 additions & 1 deletion tests/e2e-evm/test/abi_basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getAbiFallbackFunction, getAbiReceiveFunction } from "./helpers/abi";
import { whaleAddress } from "./addresses";

const defaultGas = 25000n;
const contractCallerGas = defaultGas + 3000n;
const contractCallerGas = defaultGas + 10000n;

interface ContractTestCase {
interface: keyof ArtifactsMap;
Expand Down Expand Up @@ -171,6 +171,40 @@ describe("ABI_BasicTests", function () {
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

if (funcDesc.stateMutability === "view" || funcDesc.stateMutability === "pure") {
it("can be called by static call", async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionStaticCall",
args: [ctx.address, funcSelector],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

await expect(publicClient.call(txData)).to.be.fulfilled;

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("success");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

it("can be called by static call with extra data", async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionStaticCall",
args: [ctx.address, concat([funcSelector, "0x01"])],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

await expect(publicClient.call(txData)).to.be.fulfilled;

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("success");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});
}

it("can be called by high level contract call", async function () {
const txData = { to: ctx.caller, data: funcSelector, gas: contractCallerGas };

Expand Down Expand Up @@ -199,6 +233,45 @@ describe("ABI_BasicTests", function () {
expect(balance).to.equal(expectedBalance);
});

it(`can ${isPayable ? "" : "not "}be called by low level contract call with value`, async function () {
const txData = { to: ctx.caller, data: funcSelector, gas: 50000n, value: 1n };
const startingBalance = await publicClient.getBalance({ address: ctx.address });

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal(isPayable ? "success" : "reverted");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;

let expectedBalance = startingBalance;
if (isPayable) {
expectedBalance = startingBalance + txData.value;
}
const balance = await publicClient.getBalance({ address: ctx.address });
expect(balance).to.equal(expectedBalance);
});

it(`can ${isPayable ? "" : "not "}be called by high level contract call with value`, async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionCall",
args: [ctx.address, funcSelector],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas, value: 1n};
const startingBalance = await publicClient.getBalance({ address: ctx.address });

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal(isPayable ? "success" : "reverted");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;

let expectedBalance = startingBalance;
if (isPayable) {
expectedBalance = startingBalance + txData.value;
}
const balance = await publicClient.getBalance({ address: ctx.address });
expect(balance).to.equal(expectedBalance);
});

it("can be called with extra data", async function () {
const data = concat([funcSelector, "0x01"]);
const txData = { to: ctx.address, data: data, gas: defaultGas };
Expand Down Expand Up @@ -246,6 +319,38 @@ describe("ABI_BasicTests", function () {
expect(txReceipt.status).to.equal("success");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

it("can be called by another contract with no data", async function() {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionCall",
args: [ctx.address, "0x"],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

await expect(publicClient.call(txData)).to.be.fulfilled;

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("success");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

it("can be called by static call with no data", async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionStaticCall",
args: [ctx.address, "0x"],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

await expect(publicClient.call(txData)).to.be.fulfilled;

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("success");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});
}

if (!receiveFunction && !fallbackFunction) {
Expand All @@ -257,6 +362,34 @@ describe("ABI_BasicTests", function () {
expect(txReceipt.status).to.equal("reverted");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

it("can not receive zero value transfers with no data", async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionCall",
args: [ctx.address, "0x"],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("reverted");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});

it("can not be called by static call with no data", async function () {
const data = encodeFunctionData({
abi: caller.abi,
functionName: "functionStaticCall",
args: [ctx.address, "0x"],
});
const txData = { to: caller.address, data: data, gas: contractCallerGas };

const txHash = await walletClient.sendTransaction(txData);
const txReceipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
expect(txReceipt.status).to.equal("reverted");
expect(txReceipt.gasUsed < txData.gas, "gas to not be exhausted").to.be.true;
});
}

if (!receiveFunction && (!fallbackFunction || fallbackFunction.stateMutability !== "payable")) {
Expand Down

0 comments on commit 679b265

Please sign in to comment.