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

ABI Encoding tests. #466

Merged
merged 2 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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]);
}