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

feat: support waffle js test #49

Closed
wants to merge 4 commits into from
Closed
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
6 changes: 6 additions & 0 deletions test-e2e/waffle/.env.example
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can remove this file (and all .env related here`) and use the USDC address directly in the test for simplicity.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The operator private keys start with "0x" and are in hexadecimal format
# Your account ECDSA hex-encoded private key (Ex: 0xb46751179bc8aa9e129d34463e46cd...)
# All available local node private keys can be found here https://github.com/hashgraph/hedera-local-node#commands
OPERATOR_PRIVATE_KEY=0x105d050185ccb907fba04dd92d8de9e32c18305e097ab41dadda21489a211524
Copy link
Contributor

Choose a reason for hiding this comment

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

This should not be needed right? The whole point of fork testing is to avoid update the state of a remote network. We should use one of the test accounts provided by Waffle, and they should be embedded in the test.

RELAY_ENDPOINT='http://localhost:7546'
ERC20_TOKEN_ADDRESS=0x0000000000000000000000000000000000068cDa
3 changes: 3 additions & 0 deletions test-e2e/waffle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/cache/
/build/
.env
35 changes: 35 additions & 0 deletions test-e2e/waffle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Waffle example

Simple scripts for testing waffle fixtures on the methods that requires HTS Emulation to work correctly.

## Configuration

Create `.env` file based on `.env.example`

```
OPERATOR_PRIVATE_KEY=
RELAY_ENDPOINT=
```

- `OPERATOR_PRIVATE_KEY` is your account ECDSA hex-encoded private key.
- `RELAY_ENDPOINT` is a path to your JSON RPC Api. `https://testnet.hashio.io/api` for testnet. Remember to start your Hedera local node if you want to use the http://localhost:7546 endpoint. Provided network MUST have HTS behaviour simulation implemented: altered behavior of the eth_getStorageAt for TokenProxy calls and eth_getCode for 0x167 address.
- `ERC20_TOKEN_ADDRESS` is the address of the token used for testing. We are verifying the correct behavior of the forked network, which requires some preset data. The OPERATOR_PRIVATE_KEY account must have a non-zero balance of this token on this network and be authorized to perform transfer operations.

## Setup & Install

In the project directory:
1. Run `npm install`
2. Run `npm run build`
2. Run `npm run test`

#### Dependencies

Waffle uses **ethers.js** to perform operations such as deploying Smart Contracts and sending transactions. It leverages **Mocha** and **Chai** as the foundational testing tools, while adding its own custom matchers tailored for Smart Contracts.

## Installation:
To install Waffle, you need to add the `ethereum-waffle` node module to your project. You can do this using the following command:

```shell
npm install --save-dev ethereum-waffle
```

15 changes: 15 additions & 0 deletions test-e2e/waffle/contracts/IERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.25;

interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);

function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
}
14 changes: 14 additions & 0 deletions test-e2e/waffle/package.json
Copy link
Contributor

Choose a reason for hiding this comment

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

We should also include the corresponding package-lock.json.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "waffle-project",
"scripts": {
"build": "waffle",
"test": "NODE_ENV=test mocha"
},
"type": "module",
"devDependencies": {
"chai": "^5.1.1",
"dotenv": "^16.4.5",
"ethereum-waffle": "^4.0.10",
"mocha": "^10.5.2"
}
}
71 changes: 71 additions & 0 deletions test-e2e/waffle/test/samplecontract.test.mjs
Copy link
Contributor

Choose a reason for hiding this comment

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

We can rename this to .js, the extension .mjs is not needed anymore after setting type: module in package.json.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { expect } from 'chai';
import dotenv from 'dotenv';
import { providers, Wallet, ContractFactory, Contract } from 'ethers';
import { createFixtureLoader, MockProvider } from 'ethereum-waffle';
import IERC20Contract from '../build/IERC20.json' assert { type: "json" };

dotenv.config();
const { JsonRpcProvider } = providers;
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like is not being used, remove.


const usdcAddress = process.env.ERC20_TOKEN_ADDRESS || '';
const bob = '0x0000000000000000000000000000000000000887';

describe('RPC', function () {
this.timeout(100000);
/**
* @type {function(any): Promise<Contract>}
*/
let loadFixture;

/**
* @type {function(Wallet[]): Contract}
*/
let fixture;

/**
* @type {Wallet}
*/
let wallet;

beforeEach(async () => {
wallet = new MockProvider().getWallets()[0];
// Assign the fixture loader
loadFixture = createFixtureLoader([wallet]);

// The fixture returns a Contract instance for IERC20
fixture = ([wallet]) => ContractFactory.getContract(usdcAddress, IERC20Contract.abi, wallet);
});

it('should have initial balance', async () => {
/**
* @type {Contract}
*/
const contract = await loadFixture(fixture);

const balance = (await contract.balanceOf(wallet.address)).toNumber();

expect(balance).to.not.equal(0, `Please use an account with a non-zero ${usdcAddress} token balance for this test to function correctly.`);

const currentBalance = (await contract.balanceOf(wallet.address)).toNumber();
await contract.transfer(bob, currentBalance); // We transfer everything out.
expect((await contract.balanceOf(wallet.address)).toNumber()).to.equal(0);
});

it('should have some initial balance again!', async () => {
/**
* @type {Contract}
*/
Comment on lines +55 to +57
Copy link
Contributor

Choose a reason for hiding this comment

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

This type declaration can be inferred the return type of loadFixture, we should remove it.

const contract = await loadFixture(fixture);

const balance = (await contract.balanceOf(wallet.address)).toNumber();

expect(balance).to.not.equal(0);
});

it('should work with default wallet', async () => {
const tempWallet = new MockProvider().getWallets()[0];
const contract = await createFixtureLoader([tempWallet])(fixture);
const balance = (await contract.balanceOf(tempWallet)).toNumber();
expect(balance).to.equal(0); // Waffle accounts will have 0 balance
});
});
6 changes: 6 additions & 0 deletions test-e2e/waffle/waffle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerType": "solcjs",
"compilerVersion": "0.8.24",
"sourceDirectory": "./contracts",
"outputDirectory": "./build"
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"noUnusedParameters": true
},
"exclude": [
"./launch-token/"
"./launch-token/",
"./test-e2e/"
]
}