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

examples/onchain-signer/test: Add support for Sapphire Testnet/Mainnet #208

Merged
merged 2 commits into from
Oct 19, 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
15 changes: 4 additions & 11 deletions examples/onchain-signer/contracts/Gasless.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,15 @@ struct EthereumKeypair {
uint64 nonce;
}

struct EthTx {
Copy link
Member Author

Choose a reason for hiding this comment

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

Should we rename EIP155Signer.EthTx to EIP155Signer.Tx or EIP155Signer.Transaction?

uint64 nonce;
uint256 gasPrice;
uint64 gasLimit;
address to;
uint256 value;
bytes data;
uint256 chainId;
}

// Proxy for gasless transaction.
contract Gasless {
EthereumKeypair private kp;

function setKeypair(EthereumKeypair memory keypair) external payable {
constructor (EthereumKeypair memory keypair) payable {
Copy link
Member Author

Choose a reason for hiding this comment

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

Contract create transactions are usually unencrypted for verification, so that's why I decided to have the setKeypair setter.

kp = keypair;
if( msg.value > 0 ) {
payable(kp.addr).transfer(msg.value);
}
}

function makeProxyTx(address innercallAddr, bytes memory innercall)
Expand Down
3 changes: 3 additions & 0 deletions examples/onchain-signer/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const config: HardhatUserConfig = {
},
},
solidity: '0.8.19',
mocha: {
timeout: 120_000_000, // Sapphire Mainnet/Testnet require more time.
},
};

export default config;
61 changes: 40 additions & 21 deletions examples/onchain-signer/test/CommentBox.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { expect } from 'chai';
import hre, { config, ethers } from 'hardhat';
import { ethers, config } from 'hardhat';
import { CommentBox, Gasless } from '../typechain-types';
import { EthereumKeypairStruct } from "../typechain-types/contracts/Gasless"
import { parseEther } from 'ethers/lib/utils';
import { HDAccountsUserConfig } from 'hardhat/types';

describe('CommentBox', function () {
let commentBox: CommentBox;
let gasless: Gasless;

before(async () => {
const CommentBoxFactory = await ethers.getContractFactory('CommentBox');
commentBox = await CommentBoxFactory.deploy();
await commentBox.deployed();

const GaslessFactory = await ethers.getContractFactory('Gasless');
gasless = await GaslessFactory.deploy();
await gasless.deployed();

// Derive the private key of the 1st (counting from 0) builtin hardhat test account.
const accounts = config.networks.hardhat
.accounts as unknown as HDAccountsUserConfig;
Expand All @@ -25,39 +19,64 @@ describe('CommentBox', function () {
);

// Use it as the relayer private key.
await expect(
await gasless.setKeypair({
addr: wallet1.address,
secret: Uint8Array.from(
Buffer.from(wallet1.privateKey.substring(2), 'hex'),
),
nonce: ethers.provider.getTransactionCount(wallet1.address),
}),
).not.to.be.reverted;
// NOTE can be done by the contract with EthereumUtils.generateKeypair()
Copy link
Member Author

Choose a reason for hiding this comment

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

// NOTE: Can be done by the contract with EthereumUtils.generateKeypair().

const keypair : EthereumKeypairStruct = {
addr: wallet1.address,
secret: wallet1.privateKey,
nonce: ethers.provider.getTransactionCount(wallet1.address),
};

const CommentBoxFactory = await ethers.getContractFactory('CommentBox');
commentBox = await CommentBoxFactory.deploy();
await commentBox.deployed();

const GaslessFactory = await ethers.getContractFactory('Gasless');
gasless = await GaslessFactory.deploy(keypair, {value: parseEther('0.1')});
await gasless.deployed();
});

it('Should comment', async function () {
const prevCommentCount = await commentBox.commentCount();

const tx = await commentBox.comment('Hello, world!');
await tx.wait();

// Sapphire Mainnet/Testnet: Wait a few moments for nodes to catch up.
if (
(await gasless.provider.getNetwork()).chainId == 23294 ||
(await gasless.provider.getNetwork()).chainId == 23295
) {
await new Promise((r) => setTimeout(r, 6_000));
}

expect(await commentBox.commentCount()).eq(prevCommentCount.add(1));
});

it('Should comment gasless', async function () {
// You can set up sapphire-dev image and run the test like this:
// docker run -it -p8545:8545 -p8546:8546 ghcr.io/oasisprotocol/sapphire-dev -to 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
// npx hardhat test --grep proxy --network sapphire-localnet
if ((await ethers.provider.getNetwork()).chainId == 1337) {
if ((await gasless.provider.getNetwork()).chainId == 1337) {
this.skip();
}

const innercall = commentBox.interface.encodeFunctionData('comment', [
'Hello, free world!',
]);

// Sapphire Mainnet/Testnet: Wait a few moments for nodes to catch up.
if (
(await gasless.provider.getNetwork()).chainId == 23294 ||
(await gasless.provider.getNetwork()).chainId == 23295
) {
await new Promise((r) => setTimeout(r, 6_000));
}

const tx = await gasless.makeProxyTx(commentBox.address, innercall);

const plainResp = await gasless.provider.sendTransaction(tx);
const receipt = await ethers.provider.waitForTransaction(plainResp.hash);
// TODO: https://github.com/oasisprotocol/sapphire-paratime/issues/179
Copy link
Member Author

Choose a reason for hiding this comment

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

Not relevant anymore.

const response = await gasless.provider.sendTransaction(tx);
const receipt = await gasless.provider.waitForTransaction(response.hash);
if (!receipt || receipt.status != 1) throw new Error('tx failed');
});
});
Loading