Skip to content
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

EVM Precompile integration test #1379

Open
wants to merge 36 commits into
base: evm
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4e95314
wip
jewei1997 Feb 26, 2024
f6bffc7
Gov integration tests
IpDeveloper101 Feb 28, 2024
db35ad2
add distribution
IpDeveloper101 Feb 28, 2024
faf3d75
Add staking
IpDeveloper101 Feb 28, 2024
9382adf
Merge branch 'evm' into evm-bank-precompile-integration-test
Kbhat1 Feb 28, 2024
9f29964
Point to precompile addresses
IpDeveloper101 Feb 28, 2024
3d1308f
Update precompile tests
IpDeveloper101 Feb 29, 2024
f05533e
Update tests
Kbhat1 Feb 29, 2024
f3a0c48
Add precompile to integration tests
Kbhat1 Feb 29, 2024
d461572
undo association
Kbhat1 Feb 29, 2024
49843a1
Remove path to seid
Kbhat1 Feb 29, 2024
9ac39d0
Remove shopt
Kbhat1 Mar 1, 2024
83f1602
Update tests to run in docker container
Kbhat1 Mar 1, 2024
2d1f809
Run setup in hardhat_test.yaml
Kbhat1 Mar 4, 2024
88edb2d
Add atom to genesis
Kbhat1 Mar 4, 2024
51d99b5
Filesystem
Kbhat1 Mar 4, 2024
9ebfdf6
Add more tests + address comments
Kbhat1 Mar 14, 2024
b94f343
Reverse order
Kbhat1 Mar 14, 2024
0ba8886
Execution reverted
Kbhat1 Mar 14, 2024
68c1235
Reverted
Kbhat1 Mar 14, 2024
05a9b24
try catch debug
Kbhat1 Mar 14, 2024
ec4c3dd
remove before balance
Kbhat1 Mar 14, 2024
14a0ab3
change owner
Kbhat1 Mar 14, 2024
1b16991
Reverse order
Kbhat1 Mar 14, 2024
686dc4e
Reverted custom
Kbhat1 Mar 14, 2024
49bfbb0
reverted with
Kbhat1 Mar 14, 2024
f68fd42
insufficient funds
Kbhat1 Mar 14, 2024
4a7a2e8
balance of
Kbhat1 Mar 14, 2024
3972053
tx wait
Kbhat1 Mar 14, 2024
0b148c0
remove balance check
Kbhat1 Mar 14, 2024
1ab90a2
Expert revert
Kbhat1 Mar 14, 2024
3167fe6
expectRevert
Kbhat1 Mar 14, 2024
b7bb3a9
unspecified
Kbhat1 Mar 14, 2024
ce620c8
Update gov
Kbhat1 Mar 14, 2024
01117b1
Increase voting period
Kbhat1 Mar 14, 2024
56c40c4
Remove unnecessary error comparison
Kbhat1 Mar 14, 2024
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
1,504 changes: 588 additions & 916 deletions contracts/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@openzeppelin/hardhat-upgrades": "^3.0.2",
"dotenv": "^16.3.1",
"ethers": "^6.9.0",
"hardhat": "^2.19.4"
"hardhat": "^2.20.1"
},
"dependencies": {
"@openzeppelin/contracts": "^5.0.1",
Expand Down
190 changes: 190 additions & 0 deletions contracts/test/EVMPrecompileTester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
const { execSync } = require('child_process');
const { expect } = require("chai");
const fs = require('fs');
const path = require('path');

describe("EVM Test", function () {
describe("EVM Precompile Tester", function () {
describe("EVM Bank Precompile Tester", function () {
let contractAddress;
let erc20;
let owner;
let owner2;
let signer;
let signer2
before(async function() {
contractAddress = readDeploymentOutput('erc20_deploy_addr.txt');
await sleep(1000);

// Create a signer
[signer, signer2] = await ethers.getSigners();
owner = await signer.getAddress();
owner2 = await signer2.getAddress();

// TODO: create a contract object
// contractArtifact.abi
const contractABI = [{"type":"constructor","inputs":[{"name":"denom_","type":"string","internalType":"string"},{"name":"name_","type":"string","internalType":"string"},{"name":"symbol_","type":"string","internalType":"string"},{"name":"decimals_","type":"uint8","internalType":"uint8"}],"stateMutability":"nonpayable"},{"type":"function","name":"BankPrecompile","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IBank"}],"stateMutability":"view"},{"type":"function","name":"allowance","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"approve","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"ddecimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"denom","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"nname","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"ssymbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"transfer","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"transferFrom","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"ERC20InsufficientAllowance","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"allowance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InsufficientBalance","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"balance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InvalidApprover","inputs":[{"name":"approver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidReceiver","inputs":[{"name":"receiver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSender","inputs":[{"name":"sender","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSpender","inputs":[{"name":"spender","type":"address","internalType":"address"}]}];
Kbhat1 marked this conversation as resolved.
Show resolved Hide resolved

// Get a contract instance
erc20 = new ethers.Contract(contractAddress, contractABI, signer);
console.log("end of before");
Kbhat1 marked this conversation as resolved.
Show resolved Hide resolved
});

it("Transfer function", async function() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

can we do a transfer from an address with no token balance and make sure it fails

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated

const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8';
const beforeBalance = await erc20.balanceOf(owner);
const tx = await erc20.transfer(receiver, 1);
const receipt = await tx.wait();
expect(receipt.status).to.equal(1);
const afterBalance = await erc20.balanceOf(owner);
const diff = beforeBalance - afterBalance;
expect(diff).to.equal(1);
});

it("Approve and TransferFrom functions", async function() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

can you do a transferFrom without doing an approve and make sure it fails?

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated

const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8';
// lets have owner approve the transfer and have owner2 do the transferring
const approvalAmount = await erc20.allowance(owner, owner2);
expect(approvalAmount).to.equal(0);
const approveTx = await erc20.approve(owner2, 100);
const approveReceipt = await approveTx.wait();
expect(approveReceipt.status).to.equal(1);
expect(await erc20.allowance(owner, owner2)).to.equal(100);

const erc20AsOwner2 = erc20.connect(signer2);


// transfer from owner to owner2
const balanceBefore = await erc20.balanceOf(receiver);
const transferFromTx = await erc20AsOwner2.transferFrom(owner, receiver, 100);

// await sleep(3000);
const transferFromReceipt = await transferFromTx.wait();
expect(transferFromReceipt.status).to.equal(1);
const balanceAfter = await erc20.balanceOf(receiver);
const diff = balanceAfter - balanceBefore;
expect(diff).to.equal(100);
});

it("Balance of function", async function() {
const balance = await erc20.balanceOf(owner);
expect(balance).to.be.greaterThan(Number(0));
});

it("Name function", async function () {
const name = await erc20.name()
expect(name).to.equal('UATOM');
});

it("Symbol function", async function () {
const symbol = await erc20.symbol()
// expect symbol to be 'UATOM'
expect(symbol).to.equal('UATOM');
});
});

// TODO: Update when we add gov query precompiles
describe("EVM Gov Precompile Tester", function () {
let govProposal;
// TODO: Import this
const GovPrecompileContract = '0x0000000000000000000000000000000000001006';
before(async function() {
govProposal = readDeploymentOutput('gov_proposal_output.txt');
await sleep(1000);

// Create a proposal
const [signer, _] = await ethers.getSigners();
owner = await signer.getAddress();

// contractArtifact.abi
const contractABIPath = path.join(__dirname, '../../precompiles/gov/abi.json');
const contractABI = require(contractABIPath);
// Get a contract instance
gov = new ethers.Contract(GovPrecompileContract, contractABI, signer);
console.log("end of before");
});

it("Gov deposit", async function () {
const depositAmount = ethers.parseEther('0.01');
const deposit = await gov.deposit(govProposal, {
value: depositAmount,
})
const receipt = await deposit.wait();
expect(receipt.status).to.equal(1);
// TODO: Add gov query precompile here
});
});

// TODO: Update when we add distribution query precompiles
describe("EVM Distribution Precompile Tester", function () {
// TODO: Import this
const DistributionPrecompileContract = '0x0000000000000000000000000000000000001007';
before(async function() {
const [signer, signer2] = await ethers.getSigners();
owner = await signer.getAddress();
owner2 = await signer2.getAddress();

// contractArtifact.abi
const contractABIPath = path.join(__dirname, '../../precompiles/distribution/abi.json');
const contractABI = require(contractABIPath);
// Get a contract instance
distribution = new ethers.Contract(DistributionPrecompileContract, contractABI, signer);
console.log("end of before");
});

it("Distribution set withdraw address", async function () {
const setWithdraw = await distribution.setWithdrawAddress(owner)
const receipt = await setWithdraw.wait();
expect(receipt.status).to.equal(1);
// TODO: Add distribution query precompile here
});
});

// TODO: Update when we add staking query precompiles
describe("EVM Staking Precompile Tester", function () {
const StakingPrecompileContract = '0x0000000000000000000000000000000000001005';
before(async function() {
validatorAddr = readDeploymentOutput('validator_address.txt');
await sleep(1000);
const [signer, _] = await ethers.getSigners();
owner = await signer.getAddress();

// contractArtifact.abi
const contractABIPath = path.join(__dirname, '../../precompiles/staking/abi.json');
const contractABI = require(contractABIPath);
// Get a contract instance
staking = new ethers.Contract(StakingPrecompileContract, contractABI, signer);
console.log("end of before");
});

it("Staking delegate", async function () {
const delegateAmount = ethers.parseEther('0.01');
const delegate = await staking.delegate(validatorAddr, {
value: delegateAmount,
});
const receipt = await delegate.wait();
expect(receipt.status).to.equal(1);
// TODO: Add staking query precompile here
});
});
});
});

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

function readDeploymentOutput(fileName) {
let fileContent;
try {
if (fs.existsSync(fileName)) {
fileContent = fs.readFileSync(fileName, 'utf8').trim();
console.log("Output from file:", fileContent);
} else {
console.error("File not found:", fileName);
}
} catch (error) {
console.error(`Error reading file: ${error}`);
}
return fileContent;
}
15 changes: 15 additions & 0 deletions contracts/test/associate_withdraw_address.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# This script is used to deploy the UATOM ERC20 contract and associate it with the SEI account.
set -e

endpoint=${EVM_RPC:-"http://127.0.0.1:8545"}
owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52
associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c
owner2=0x70997970C51812dc3A010C7d01b50e0d17dc79C8

echo "Associating address"
printf "12345678\n" | seid tx evm associate-address 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e --from admin --evm-rpc=$endpoint

# wait for deployment to finish on live chain
sleep 3
25 changes: 25 additions & 0 deletions contracts/test/deploy_atom_erc20.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

# This script is used to deploy the UATOM ERC20 contract and associate it with the SEI account.
set -e

endpoint=${EVM_RPC:-"http://127.0.0.1:8545"}
owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52
associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c
owner2=0x70997970C51812dc3A010C7d01b50e0d17dc79C8

echo "Funding account $account with UATOM for testing..."
printf "12345678\n" | seid tx bank send $(printf "12345678\n" | seid keys show admin -a) $associated_sei_account1 10000uatom --fees 20000usei -b block -y

echo "Fund owners with some SEI"
printf "12345678\n" | seid tx evm send $owner1 1000000000000000000 --from admin
printf "12345678\n" | seid tx evm send $owner2 1000000000000000000 --from admin

echo "Deploying ERC20 pointer contract for UATOM..."
deployment_output=$(printf "12345678\n" | seid tx evm deploy-erc20 uatom UATOM UATOM 6 --from admin --evm-rpc=$endpoint)

erc20_deploy_addr=$(echo "$deployment_output" | grep 'Deployed to:' | awk '{print $3}')
echo $erc20_deploy_addr > contracts/erc20_deploy_addr.txt

# wait for deployment to finish on live chain
sleep 3
12 changes: 12 additions & 0 deletions contracts/test/get_validator_address.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# This script is used to find the validator address.
set -e

endpoint=${EVM_RPC:-"http://127.0.0.1:8545"}
owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52
associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c

validator_address=$(printf "12345678\n" | seid q staking validators -o json | jq -r '.validators[0].operator_address')

echo $validator_address > contracts/validator_address.txt
14 changes: 14 additions & 0 deletions contracts/test/param_change_proposal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"title": "Gov Param Change",
"description": "Update quorum to 0.45",
"changes": [
{
"subspace": "gov",
"key": "tallyparams",
"value": {
"quorum":"0.45"
}
}
],
"is_expedited": false
}
12 changes: 12 additions & 0 deletions contracts/test/send_gov_proposal.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# This script is used to send a gov deposit.
set -e

endpoint=${EVM_RPC:-"http://127.0.0.1:8545"}
owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52
associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c

gov_proposal_output=$(printf "12345678\n" | seid tx gov submit-proposal param-change contracts/test/param_change_proposal.json --from admin --fees 20000usei -b block -y -o json | jq -r '.logs[0].events[3].attributes[1].value')

echo $gov_proposal_output > contracts/gov_proposal_output.txt
4 changes: 4 additions & 0 deletions docker/localnode/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ RUN tar -xvf go1.21.4.linux-amd64.tar.gz
RUN mv go /usr/local/
RUN curl -L https://foundry.paradigm.xyz | bash
RUN /root/.foundry/bin/foundryup
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash
RUN apt-get install -y nodejs
RUN mkdir -p /root/.config && \
chmod -R 777 /root/.config
SHELL ["/bin/bash", "-c"]


Expand Down
2 changes: 1 addition & 1 deletion docker/localnode/scripts/step1_configure_init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ GENESIS_ACCOUNT_ADDRESS=$(printf "12345678\n" | seid keys show "$ACCOUNT_NAME" -
echo "$GENESIS_ACCOUNT_ADDRESS" >> build/generated/genesis_accounts.txt

# Add funds to genesis account
seid add-genesis-account "$GENESIS_ACCOUNT_ADDRESS" 10000000usei
seid add-genesis-account "$GENESIS_ACCOUNT_ADDRESS" 10000000usei,10000000uusdc,10000000uatom

# Create gentx
printf "12345678\n" | seid gentx "$ACCOUNT_NAME" 10000000usei --chain-id sei
Expand Down
4 changes: 2 additions & 2 deletions docker/localnode/scripts/step2_genesis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ override_genesis '.app_state["gov"]["tally_params"]["expedited_threshold"]="0.9"
# add genesis accounts for each node
while read account; do
echo "Adding: $account"
seid add-genesis-account "$account" 1000000000000000000000usei
seid add-genesis-account "$account" 1000000000000000000000usei,1000000000000000000000uusdc,1000000000000000000000uatom
done <build/generated/genesis_accounts.txt

# add funds to admin account
printf "12345678\n" | seid add-genesis-account admin 1000000000000000000000usei
printf "12345678\n" | seid add-genesis-account admin 1000000000000000000000usei,1000000000000000000000uusdc,1000000000000000000000uatom

mkdir -p ~/exported_keys
cp -r build/generated/gentx/* ~/.sei/config/gentx
Expand Down
4 changes: 4 additions & 0 deletions integration_test/evm_module/hardhat_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
env: TX_HASH
- cmd: cast receipt "$TX_HASH" -j |jq -r ."status"
env: RESULT
# Setup for Hardhat Integration Test
- cmd: bash contracts/test/deploy_atom_erc20.sh
- cmd: bash contracts/test/get_validator_address.sh
- cmd: bash contracts/test/send_gov_proposal.sh
verifiers:
- type: eval
expr: RESULT == "0x1"
Empty file modified precompiles/addr/abi.json
100644 → 100755
Empty file.
Empty file modified precompiles/bank/abi.json
100644 → 100755
Empty file.
Empty file modified precompiles/distribution/abi.json
100644 → 100755
Empty file.
Empty file modified precompiles/gov/abi.json
100644 → 100755
Empty file.
Empty file modified precompiles/staking/abi.json
100644 → 100755
Empty file.
Empty file modified precompiles/wasmd/abi.json
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions scripts/hardhat.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cd contracts
npm ci
npx hardhat test --network seilocal test/EVMCompatabilityTester.js
npx hardhat test --network seilocal test/EVMPrecompileTester.js
Loading