From a66d111cc82db14791d136b79a60c27c45e6a7d3 Mon Sep 17 00:00:00 2001 From: CedarMist <134699267+CedarMist@users.noreply.github.com> Date: Mon, 18 Sep 2023 01:26:39 +0100 Subject: [PATCH] contracts: improve EIP-155 test cases --- clients/js/src/compat.ts | 15 +++++++---- contracts/package.json | 1 + contracts/test/eip155.ts | 54 +++++++++++++++++++++++++++++++++++++--- pnpm-lock.yaml | 3 +++ 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/clients/js/src/compat.ts b/clients/js/src/compat.ts index e7a905d95..bfcdbf0ce 100644 --- a/clients/js/src/compat.ts +++ b/clients/js/src/compat.ts @@ -573,11 +573,13 @@ async function repackRawTx( ); } catch (e) { if (e instanceof EnvelopeError) throw e; - if (globalThis?.process?.env?.NODE_ENV !== 'test') { - console.trace(REPACK_ERROR); - } } const tx = ethers6.Transaction.from(raw); + if( tx.isSigned() && (!signer || await signer!.getAddress() != tx.from!) ) { + // us we are be unable to re-sign the encrypted tx, so must passthrough when + // they submit a transaction signed by another keypair + return tx.serialized; + } const q = (v: bigint | null | undefined): string | undefined => { if (!v) return undefined; return ethers6.toQuantity(v); @@ -592,14 +594,17 @@ async function repackRawTx( value: q(tx.value), chainId: Number(tx.chainId), }; - if (!signer) throw new CallError(REPACK_ERROR, null); if (!parsed.gasLimit) parsed.gasLimit = q(BigInt(DEFAULT_GAS)); // TODO(39) try { - return signer.signTransaction({ + return signer!.signTransaction({ ...parsed, data: await cipher.encryptEncode(data), }); } catch (e) { + // Many JSON-RPC providers, Ethers included, will not let you directly + // sign transactions, which is necessary to re-encrypt the calldata! + // Throw an error here to prevent calls which should've been encrypted + // from being submitted unencrypted. throw new CallError(REPACK_ERROR, e); } } diff --git a/contracts/package.json b/contracts/package.json index 611a87518..0c7727027 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -29,6 +29,7 @@ "@nomicfoundation/hardhat-chai-matchers": "^1.0.5", "@nomiclabs/hardhat-ethers": "^2.1.1", "@oasisprotocol/sapphire-hardhat": "workspace:^", + "@oasisprotocol/sapphire-paratime": "workspace:^", "@openzeppelin/contracts": "^4.7.3", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.3", diff --git a/contracts/test/eip155.ts b/contracts/test/eip155.ts index 1ed1e6d50..c94325798 100644 --- a/contracts/test/eip155.ts +++ b/contracts/test/eip155.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { ethers } from 'hardhat'; +import * as sapphire from '@oasisprotocol/sapphire-paratime' import { EIP155Tests__factory } from '../typechain-types/factories/contracts/tests'; import { EIP155Tests } from '../typechain-types/contracts/tests/EIP155Tests'; @@ -29,7 +30,7 @@ describe('EIP-155', function () { await testContract.deployed(); }); - it('Wrapper encrypts transaction calldata', async function () { + it('Wrapper encrypts self-signed transaction calldata', async function () { const tx = await testContract.example(); expect(entropy(tx.data)).gte(3.8); expect(tx.data).not.eq( @@ -38,9 +39,9 @@ describe('EIP-155', function () { expect(tx.data.length).eq(218); }); - it('Signed transactions can be submitted', async function () { + it('Other-Signed transaction submission via un-wrapped provider', async function () { const txobj = { - nonce: 0, + nonce: await testContract.provider.getTransactionCount(await testContract.publicAddr()), gasPrice: await testContract.provider.getGasPrice(), gasLimit: 250000, to: testContract.address, @@ -65,4 +66,51 @@ describe('EIP-155', function () { '0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210', ); }); + + it('Other-Signed transaction submission via wrapped provider', async function () { + const txobj = { + nonce: await testContract.provider.getTransactionCount(await testContract.publicAddr()), + gasPrice: await testContract.provider.getGasPrice(), + gasLimit: 250000, + to: testContract.address, + value: 0, + data: '0x', + chainId: 0, + }; + const signedTx = await testContract.sign(txobj); + + let plainResp = await testContract.signer.provider!.sendTransaction(signedTx); + let receipt = await testContract.provider.waitForTransaction( + plainResp.hash, + ); + expect(plainResp.data).eq( + testContract.interface.encodeFunctionData('example'), + ); + expect(receipt.logs[0].data).equal( + '0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210', + ); + }); + + it('Self-Signed transaction submission via wrapped provider', async function () { + const p = testContract.provider; + const sk = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; + const wallet = sapphire.wrap(new ethers.Wallet(sk).connect(p)); + const calldata = testContract.interface.encodeFunctionData('example'); + + const signedTx = await wallet.signTransaction({ + gasLimit: 250000, + to: testContract.address, + value: 0, + data: calldata, + chainId: (await p.getNetwork()).chainId, + gasPrice: (await p.getGasPrice()), + nonce: await p.getTransactionCount(wallet.address) + }); + + let x = await testContract.signer.provider!.sendTransaction(signedTx); + let r = await testContract.provider.waitForTransaction(x.hash); + + expect(x.data).not.eq(calldata); + expect(r.logs[0].data).equal('0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210'); + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c5191e92..677d49867 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,6 +132,9 @@ importers: '@oasisprotocol/sapphire-hardhat': specifier: workspace:^ version: link:../integrations/hardhat + '@oasisprotocol/sapphire-paratime': + specifier: workspace:^ + version: link:../clients/js '@openzeppelin/contracts': specifier: ^4.7.3 version: 4.9.2