Skip to content

Commit

Permalink
Add wasmd execute batch to precompile (#1529)
Browse files Browse the repository at this point in the history
* Add wasmd execute batch to precompile

* Add some wasm hardhat it stuff

* update script

* Update deployment script

* fix tests

* update to add instantiate
  • Loading branch information
udpatil committed Apr 17, 2024
1 parent eb27fa4 commit 050f755
Show file tree
Hide file tree
Showing 7 changed files with 635 additions and 43 deletions.
151 changes: 138 additions & 13 deletions contracts/test/EVMPrecompileTester.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ describe("EVM Test", function () {
console.log("ERC20 address is:");
console.log(contractAddress);
await sleep(1000);

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

const contractABIPath = path.join(__dirname, '../../precompiles/common/erc20_abi.json');
const contractABI = require(contractABIPath);

// Get a contract instance
erc20 = new ethers.Contract(contractAddress, contractABI, signer);

Expand All @@ -45,7 +45,7 @@ describe("EVM Test", function () {
const receipt2 = await tx2.wait();
expect(receipt2.status).to.equal(1);
});

it("Transfer function", async function() {
const beforeBalance = await erc20.balanceOf(owner);
const tx = await erc20.transfer(owner2, 1);
Expand Down Expand Up @@ -77,31 +77,31 @@ describe("EVM Test", function () {
expect(approveReceipt.status).to.equal(1);
expect(await erc20.allowance(owner, owner2)).to.equal(100);

const erc20AsOwner2 = erc20.connect(signer2);
const erc20AsOwner2 = erc20.connect(signer2);



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

// await sleep(3000);
const transferFromReceipt = await transferFromTx.wait();
expect(transferFromReceipt.status).to.equal(1);
const balanceAfter = await erc20.balanceOf(owner2);
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'
Expand All @@ -117,17 +117,17 @@ describe("EVM Test", function () {
before(async function() {
govProposal = readDeploymentOutput('gov_proposal_output.txt');
await sleep(1000);

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

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

it("Gov deposit", async function () {
const depositAmount = ethers.parseEther('0.01');
const deposit = await gov.deposit(govProposal, {
Expand Down Expand Up @@ -231,6 +231,122 @@ describe("EVM Test", function () {
}
});
});

describe("EVM Wasm Precompile Tester", function () {
const WasmPrecompileContract = '0x0000000000000000000000000000000000001002';
before(async function() {
wasmContractAddress = readDeploymentOutput('wasm_contract_addr.txt');
wasmCodeID = parseInt(readDeploymentOutput('wasm_code_id.txt'));

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

const contractABIPath = path.join(__dirname, '../../precompiles/wasmd/abi.json');
const contractABI = require(contractABIPath);
// Get a contract instance
wasmd = new ethers.Contract(WasmPrecompileContract, contractABI, signer);
});

it("Wasm Precompile Instantiate", async function () {
encoder = new TextEncoder();

queryCountMsg = {get_count: {}};
queryStr = JSON.stringify(queryCountMsg);
queryBz = encoder.encode(queryStr);

instantiateMsg = {count: 2};
instantiateStr = JSON.stringify(instantiateMsg);
instantiateBz = encoder.encode(instantiateStr);

coins = [];
coinsStr = JSON.stringify(coins);
coinsBz = encoder.encode(coinsStr);

instantiate = await wasmd.instantiate(wasmCodeID, "", instantiateBz, "counter-contract", coinsBz);
const receipt = await instantiate.wait();
expect(receipt.status).to.equal(1);
// TODO: is there any way to get the instantiate results for contract address - or in events?
});

it("Wasm Precompile Execute", async function () {
expect(wasmContractAddress).to.not.be.empty;
encoder = new TextEncoder();

queryCountMsg = {get_count: {}};
queryStr = JSON.stringify(queryCountMsg);
queryBz = encoder.encode(queryStr);
initialCountBz = await wasmd.query(wasmContractAddress, queryBz);
initialCount = parseHexToJSON(initialCountBz)

incrementMsg = {increment: {}};
incrementStr = JSON.stringify(incrementMsg);
incrementBz = encoder.encode(incrementStr);

coins = [];
coinsStr = JSON.stringify(coins);
coinsBz = encoder.encode(coinsStr);

execute = await wasmd.execute(wasmContractAddress, incrementBz, coinsBz);
const receipt = await execute.wait();
expect(receipt.status).to.equal(1);

finalCountBz = await wasmd.query(wasmContractAddress, queryBz);
finalCount = parseHexToJSON(finalCountBz)
expect(finalCount.count).to.equal(initialCount.count + 1);
});

it("Wasm Precompile Batch Execute", async function () {
expect(wasmContractAddress).to.not.be.empty;
encoder = new TextEncoder();

queryCountMsg = {get_count: {}};
queryStr = JSON.stringify(queryCountMsg);
queryBz = encoder.encode(queryStr);
initialCountBz = await wasmd.query(wasmContractAddress, queryBz);
initialCount = parseHexToJSON(initialCountBz)

incrementMsg = {increment: {}};
incrementStr = JSON.stringify(incrementMsg);
incrementBz = encoder.encode(incrementStr);

coins = [];
coinsStr = JSON.stringify(coins);
coinsBz = encoder.encode(coinsStr);

executeBatch = [
{
contractAddress: wasmContractAddress,
msg: incrementBz,
coins: coinsBz,
},
{
contractAddress: wasmContractAddress,
msg: incrementBz,
coins: coinsBz,
},
{
contractAddress: wasmContractAddress,
msg: incrementBz,
coins: coinsBz,
},
{
contractAddress: wasmContractAddress,
msg: incrementBz,
coins: coinsBz,
},
];

executeBatch = await wasmd.execute_batch(executeBatch);
const receipt = await executeBatch.wait();
expect(receipt.status).to.equal(1);

finalCountBz = await wasmd.query(wasmContractAddress, queryBz);
finalCount = parseHexToJSON(finalCountBz)
expect(finalCount.count).to.equal(initialCount.count + 4);
});

});

});
});

Expand All @@ -251,3 +367,12 @@ function readDeploymentOutput(fileName) {
}
return fileContent;
}

function parseHexToJSON(hexStr) {
// Remove the 0x prefix
hexStr = hexStr.slice(2);
// Convert to bytes
const bytes = Buffer.from(hexStr, 'hex');
// Convert to JSON
return JSON.parse(bytes.toString());
}
26 changes: 26 additions & 0 deletions contracts/test/deploy_wasm_contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

seidbin=$(which ~/go/bin/seid | tr -d '"')
keyname=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"')
keyaddress=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].address" | tr -d '"')
chainid=$($seidbin status | jq ".NodeInfo.network" | tr -d '"')
seihome=$(git rev-parse --show-toplevel | tr -d '"')

cd $seihome || exit
echo "Deploying wasm counter contract"

echo "Storing wasm counter contract"
store_result=$(printf "12345678\n" | $seidbin tx wasm store integration_test/contracts/counter_parallel.wasm -y --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --output=json)
contract_id=$(echo "$store_result" | jq -r '.logs[].events[].attributes[] | select(.key == "code_id").value')
echo "$contract_id" > contracts/wasm_code_id.txt
echo "Instantiating wasm counter contract"
instantiate_result=$(printf "12345678\n" | $seidbin tx wasm instantiate "$contract_id" '{"count": 0}' -y --no-admin --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --label=dex --output=json)
echo $instantiate_result

contract_addr=$(echo "$instantiate_result" |jq -r 'first(.logs[].events[].attributes[] | select(.key == "_contract_address").value)')

echo "Deployed counter contract with address:"
echo $contract_addr

# write the contract address to wasm_contract_addr.txt
echo "$contract_addr" > contracts/wasm_contract_addr.txt
1 change: 1 addition & 0 deletions integration_test/evm_module/hardhat_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- cmd: bash contracts/test/get_validator_address.sh
- cmd: bash contracts/test/send_gov_proposal.sh
- cmd: bash contracts/test/query_oracle_data.sh
- cmd: bash contracts/test/deploy_wasm_contract.sh
verifiers:
- type: eval
expr: RESULT == "0x1"
8 changes: 8 additions & 0 deletions precompiles/wasmd/Wasmd.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ interface IWasmd {
bytes memory coins
) payable external returns (bytes memory response);

struct ExecuteMsg {
string contractAddress;
bytes msg;
bytes coins;
}

function execute_batch(ExecuteMsg[] memory executeMsgs) payable external returns (bytes[] memory responses);

// Queries
function query(string memory contractAddress, bytes memory req) external view returns (bytes memory response);
}
2 changes: 1 addition & 1 deletion precompiles/wasmd/abi.json
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"codeID","type":"uint64"},{"internalType":"string","name":"admin","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"instantiate","outputs":[{"internalType":"string","name":"contractAddr","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"req","type":"bytes"}],"name":"query","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"}]
[{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"internalType":"struct IWasmd.ExecuteMsg[]","name":"executeMsgs","type":"tuple[]"}],"name":"execute_batch","outputs":[{"internalType":"bytes[]","name":"responses","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"codeID","type":"uint64"},{"internalType":"string","name":"admin","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"instantiate","outputs":[{"internalType":"string","name":"contractAddr","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"req","type":"bytes"}],"name":"query","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"}]
Loading

0 comments on commit 050f755

Please sign in to comment.