Skip to content

Commit

Permalink
ABI Encoding tests. (#466)
Browse files Browse the repository at this point in the history
* ABI Encoding tests.

Signed-off-by: ebadiere <[email protected]>

* Added blank lines at the end of the contracts.

Signed-off-by: ebadiere <[email protected]>

---------

Signed-off-by: ebadiere <[email protected]>
  • Loading branch information
ebadiere authored Oct 16, 2023
1 parent 71d3c46 commit b1a5fe1
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 2 deletions.
43 changes: 43 additions & 0 deletions contracts/solidity/encoding/Encoding.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Encoding.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Encoding {
event Added(uint256 result);

function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b;
}

function decodeData(bytes memory encodedData) public pure returns (address, uint256) {
address decodedAddress;
uint256 decodedUint;
assembly {
decodedAddress := mload(add(encodedData, 32))
decodedUint := mload(add(encodedData, 64))
}
return (decodedAddress, decodedUint);
}

function encodeData(address _address, uint256 _uint) public pure returns (bytes memory) {
return abi.encode(_address, _uint);
}

function encodeAddFunction(uint256 a, uint256 b) public pure returns (bytes memory) {
bytes4 selector = this.add.selector;

return abi.encodeWithSelector(selector, a, b);
}

function getPackedData(address _addr, uint256 _amount, string memory _data) public pure returns (bytes memory) {
return abi.encodePacked(_addr, _amount, _data);
}

function executeAddFunction(uint256 a, uint256 b) public {
bytes memory data = encodeAddFunction(a, b);
(bool success, bytes memory result) = address(this).call(data);

require(success, "Call failed");
emit Added(abi.decode(result, (uint256)));
}
}
10 changes: 10 additions & 0 deletions contracts/solidity/encoding/Receiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Receiver {
event ReceivedData(uint256 data);

function receiveData(uint256 data) external {
emit ReceivedData(data);
}
}
30 changes: 30 additions & 0 deletions contracts/solidity/encoding/Sender.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./Receiver.sol";

contract Sender {
Receiver public receiver;

constructor(address _receiver) {
receiver = Receiver(_receiver);
}

function sendDataEncodeWithSignature(uint256 data) public {
bytes memory payload = abi.encodeWithSignature("receiveData(uint256)", data);

(bool success,) = address(receiver).call(payload);
require(success, "External call using abi.encodeWithSignature failed");
}

function sendDataEncodeCall(uint256 data) public {
bytes memory payload = abi.encodeCall(
Receiver(address(receiver)).receiveData,
(data)
);

(bool success,) = address(receiver).call(payload);
require(success, "External call using abi.encodeCall failed");
}

}
4 changes: 2 additions & 2 deletions test/multicall/Multicall.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
*
* Hedera JSON RPC Relay - Hardhat Example
*
* Copyright (C) 2022 Hedera Hashgraph, LLC
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -157,7 +157,7 @@ describe('Multicall Test Suite', function () {

before(async () => {
multicaller = await deployContract('Multicall3')
receiver = await deployContract('Receiver')
receiver = await deployContract('contracts/multicaller/Receiver.sol:Receiver')
reverter = await deployContract('Reverter')
})

Expand Down
136 changes: 136 additions & 0 deletions test/solidity/encoding/Encoding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*-
*
* Hedera JSON RPC Relay - Hardhat Example
*
* Copyright (C) 2023 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("@solidityevmequiv Encoding", function() {
let encodingContract, receiver, sender;

const addressData = "0x1234567890123456789012345678901234567890";
const uintData = 123456789;

beforeEach(async function() {
const Encoding = await ethers.getContractFactory("Encoding");
encodingContract = await Encoding.deploy();
await encodingContract.deployed();

const Receiver = await ethers.getContractFactory("contracts/solidity/encoding/Receiver.sol:Receiver");
receiver = await Receiver.deploy();
await receiver.deployed();

const Sender = await ethers.getContractFactory("Sender");
sender = await Sender.deploy(receiver.address);
await sender.deployed();

});

it("Should decode data", async function() {
const encodedData = ethers.utils.defaultAbiCoder.encode(
["address", "uint256"],
[addressData, uintData]
);

const result = await encodingContract.decodeData(encodedData);

expect(result[0]).to.equal(addressData);
expect(result[1]).to.equal(uintData);
});

it("Should encode data", async function() {
const result = await encodingContract.encodeData(addressData, uintData);

const decodedData = ethers.utils.defaultAbiCoder.decode(
["address", "uint256"],
result
);

expect(decodedData[0]).to.equal(addressData);
expect(decodedData[1]).to.equal(uintData);
});

it("Should encode pack data", async function() {
const address = "0x1234567890123456789012345678901234567890";
const amount = 100;
const data = "Hello, World!";

const packedData = encodePacked(address, amount, data);
const result = await encodingContract.getPackedData(address, amount, data);
expect(result).to.equal(packedData);
});

it("Should execute the add function and return the correct result to illustrate abi.encodeWitSelector", async function() {
const a = 5;
const b = 7;

// Verify that the add function returns the correct result
const sum = await encodingContract.add(a, b);
expect(sum).to.equal(a + b);

// Call the encodeAddFunction
const encodedData = await encodingContract.encodeAddFunction(a, b);

// Extract the selector and encoded arguments
const selector = encodedData.slice(0, 10);
const encodedArgs = "0x" + encodedData.slice(10);

// Verify the selector matches the add function's selector
expect(selector).to.equal(encodingContract.interface.getSighash("add"));

const [decodedA, decodedB] = ethers.utils.defaultAbiCoder.decode(["uint256", "uint256"], encodedArgs);
expect(decodedA).to.equal(a);
expect(decodedB).to.equal(b);

const tx = await encodingContract.executeAddFunction(a, b);
const receipt = await tx.wait();

expect(receipt.events.length).to.equal(1);
expect(receipt.events[0].event).to.equal("Added");

const eventResult = receipt.events[0].args[0].toNumber();
expect(eventResult).to.equal(a + b);
});

it("Should call receiveData in Receiver contract via Sender using abi.encodeWithSignature", async function() {
const dataToSend = 12345;

await expect(sender.sendDataEncodeWithSignature(dataToSend))
.to.emit(receiver, "ReceivedData")
.withArgs(dataToSend);
});

it("Should call receiveData in Receiver contract via Sender using abi.encodeCall", async function() {
const dataToSend = 12345;

await expect(sender.sendDataEncodeCall(dataToSend))
.to.emit(receiver, "ReceivedData")
.withArgs(dataToSend);
});


});

function encodePacked(address, amount, data) {
const addressBytes = ethers.utils.arrayify(address);
const amountBytes = ethers.utils.zeroPad(ethers.utils.arrayify(amount), 32);
const dataBytes = ethers.utils.toUtf8Bytes(data);

return ethers.utils.hexConcat([addressBytes, amountBytes, dataBytes]);
}

0 comments on commit b1a5fe1

Please sign in to comment.