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

Adding tests for the Transactions in Solidity #453

Merged
merged 3 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ cache
artifacts/@openzeppelin
artifacts/build-info
artifacts/contracts

.openzeppelin/unknown-298.json
.env
test-results.*
Expand Down
12 changes: 12 additions & 0 deletions contracts/solidity/transaction/MessageFrameAddresses.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

contract MessageFrameAddresses {
function getTxOrigin() external view returns (address) {
return tx.origin;
}

function getMsgSender() external view returns (address) {
return msg.sender;
}
}
52 changes: 52 additions & 0 deletions contracts/solidity/transaction/Transaction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import { MessageFrameAddresses } from "./MessageFrameAddresses.sol";

contract Transaction {
string public message;
uint myInteger;
address messageFrameAddresses;
MessageFrameAddresses mfContract;
event MsgValue(uint256);

constructor(address addr) {
messageFrameAddresses = addr;
mfContract = MessageFrameAddresses(payable(addr));
}

function checkGasleft() external view returns (uint256) {
return gasleft();
}

function getMessageData(uint integer, string memory inputMessage) external returns (bytes memory) {
message = inputMessage;
myInteger = integer;

return msg.data;
}

function getMessageSender() external view returns (address) {
return msg.sender;
}

function getMessageSignature() external pure returns (bytes4) {
return msg.sig;
}

function getMessageValue() external payable {
emit MsgValue(msg.value);
}

function getGasPrice() external view returns (uint256) {
return tx.gasprice;
}

function getTxOriginFromSecondary() external view returns (address) {
return mfContract.getTxOrigin();
}

function getMsgSenderFromSecondary() external view returns (address) {
return mfContract.getMsgSender();
}
}
2 changes: 2 additions & 0 deletions test/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ const Contract = {
PrngSystemContract: 'PrngSystemContract',
Concatenation: 'Concatenation',
Errors: 'Errors',
Transaction: 'Transaction',
MessageFrameAddresses: 'MessageFrameAddresses',
}

const CALL_EXCEPTION = 'CALL_EXCEPTION'
Expand Down
119 changes: 119 additions & 0 deletions test/solidity/transaction/transaction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*-
*
* Hedera Smart Contracts
*
* 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')
const Constants = require('../../constants')
const Utils = require('../../hts-precompile/utils')

describe('PrngSystemContract tests', function () {
quiet-node marked this conversation as resolved.
Show resolved Hide resolved
let contractTr, contractTrAddr, wallet, mfContract, senderWalletAddr

before(async function () {
const factoryTrasnactionContract = await ethers.getContractFactory(
Constants.Contract.Transaction
)
const factoryMfContract = await ethers.getContractFactory(
Constants.Contract.MessageFrameAddresses
)

mfContract = await factoryMfContract.deploy()
await mfContract.deployed();
contractTr = await factoryTrasnactionContract.deploy(mfContract.address)
await contractTr.deployed();
contractTrAddr = contractTr.address

const signers = await ethers.getSigners()
wallet = signers[0];
senderWalletAddr = await wallet.getAddress()
})

it('gasleft() returns (uint256): remaining gas', async function () {
const STARTING_GAS = 30000;
const gasLeft = await contractTr.checkGasleft({ gasLimit: STARTING_GAS })

expect(ethers.BigNumber.isBigNumber(gasLeft)).to.be.true
Nana-EC marked this conversation as resolved.
Show resolved Hide resolved
expect(gasLeft.gt(ethers.BigNumber.from(0))).to.be.true;
expect(gasLeft.lt(ethers.BigNumber.from(STARTING_GAS))).to.be.true;
})

it('msg.data (bytes calldata): complete calldata', async function () {
const myString = 'Hello, world!';
const txRes = await contractTr.getMessageData(12, myString);
const returnedData = txRes.data;

const ABI = [
"function getMessageData(uint integer, string memory inputMessage)"
];
const interface = new ethers.utils.Interface(ABI);
const encodedFunction = interface.encodeFunctionData("getMessageData", [ 12, myString ]);

expect(returnedData).to.exist;
expect(returnedData).to.be.equal(encodedFunction);
})

it('msg.sender (address): sender of the message (current call)', async function () {
const sender = await contractTr.getMessageSender();

expect(sender).to.exist;
expect(sender).to.be.equal(senderWalletAddr);
})

it('msg.sig (bytes4): first four bytes of the calldata (i.e. function identifier)', async function () {
const msgSig = await contractTr.getMessageSignature();

const ABI = [
"function getMessageSignature()"
];
const interface = new ethers.utils.Interface(ABI);
const encodedFunctionSig = interface.encodeFunctionData("getMessageSignature");

expect(msgSig).to.exist;
expect(msgSig).to.be.equal(encodedFunctionSig);
})

it('msg.value (uint): number of wei sent with the message', async function () {
const valueToSend = ethers.utils.parseEther(String(1));
const txRes = await contractTr.getMessageValue({value: valueToSend});
const receipt = await txRes.wait();
const amount = receipt.events[0].args[0];
ethers.utils.formatEther(amount);

// to compare with the value sent, we need to convert to tinybar
expect(amount.mul(Utils.tinybarToWeibarCoef)).to.equal(valueToSend);
})

it('tx.gasprice (uint): gas price of the transaction', async function () {
const gasPrice = await contractTr.getGasPrice();

expect(ethers.BigNumber.isBigNumber(gasPrice)).to.be.true;
expect(gasPrice.gt(ethers.BigNumber.from(0))).to.be.true;
})

it('tx.origin (address): sender of the transaction (full call chain)', async function () {
const originAddr = await contractTr.getTxOriginFromSecondary();
const msgSender = await contractTr.getMsgSenderFromSecondary();

expect(originAddr).to.exist;
expect(msgSender).to.exist;
expect(originAddr).to.be.equal(senderWalletAddr);
expect(msgSender).to.be.equal(contractTr.address);
})
})