Skip to content
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
22 changes: 16 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,19 @@
"@nomicfoundation/hardhat-chai-matchers": "^1.0.6",
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-truffle5": "^2.0.7",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@openzeppelin/contracts": "^4.8.3",
"@typechain/ethers-v5": "^10.2.0",
"@typechain/hardhat": "^6.1.5",
"@types/chai": "^4.3.4",
"@types/mocha": "^10.0.1",
"@webb-tools/test-utils": "0.1.4-126",
"chai": "^4.3.7",
"circomlibjs": "^0.0.8",
"copyfiles": "^2.4.1",
"dotenv": "^16.0.3",
"elliptic": "^6.5.4",
"ethers": "^5.7.0",
"ethers": "^5.8.0",
"hardhat": "^2.14.0",
"hardhat-artifactor": "^0.2.0",
"hardhat-gas-reporter": "^1.0.9",
"hardhat-gas-reporter": "^2.3.0",
"hardhat-preprocessor": "^0.1.5",
"itertools": "^2.1.1",
"lerna": "^6.6.1",
Expand All @@ -75,5 +71,19 @@
"dependencies": {
"circomlib": "^2.0.5",
"typescript": "^5.0.4"
},
"resolutions": {
"@ethersproject/signing-key": "5.8.0",
"@tootallnate/once": "3.0.1",
"cookie": "1.1.1",
"es5-ext": "0.10.64",
"handlebars": "4.7.9",
"ip": "2.0.1",
"on-headers": "1.1.0",
"qs": "6.15.1",
"secp256k1": "4.0.4",
"tmp": "0.2.5",
"undici": "5.29.0",
"webpack": "5.106.2"
}
}
2 changes: 1 addition & 1 deletion packages/anchors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@webb-tools/tokens": "^1.1.1",
"@webb-tools/utils": "^1.1.1",
"circomlibjs": "^0.0.8",
"ethers": "5.7.0",
"ethers": "5.8.0",
"jssha": "^3.2.0",
"snarkjs": "^0.7.2"
},
Expand Down
1 change: 0 additions & 1 deletion packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'hardhat-gas-reporter';
import '@typechain/hardhat';

import '@nomiclabs/hardhat-ethers';
import '@nomiclabs/hardhat-truffle5';
// import '@primitivefi/hardhat-dodoc';
import { subtask } from 'hardhat/config';

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"dependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"ethers": "^5.7.0",
"ethers": "^5.8.0",
"typescript": "^5.0.4"
}
}
69 changes: 12 additions & 57 deletions packages/contracts/test/governance/governable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@
// @ts-nocheck
const assert = require('assert');
import { ethers, network } from 'hardhat';
import BN from 'bn.js';
import { toFixedHex, toHex } from '@webb-tools/utils';
import EC from 'elliptic';
const ec = new EC.ec('secp256k1');
const TruffleAssert = require('truffle-assertions');

import { Governable, Governable__factory } from '@webb-tools/contracts';
import { ethers } from 'ethers';
import type { Signer } from 'ethers';
import { ZERO_BYTES32 } from '@webb-tools/utils';
import { keccak256, recoverAddress, solidityPack } from 'ethers/lib/utils';

describe('Governable Contract', () => {
let governableInstance: Governable;
let sender: ethers.Signer;
let nextGovernor: ethers.Signer;
let arbSigner: ethers.Signer;
let sender: Signer;
let nextGovernor: Signer;
let arbSigner: Signer;

beforeEach(async () => {
const signers = await ethers.getSigners();
Expand Down Expand Up @@ -60,8 +57,7 @@ describe('Governable Contract', () => {

it('should check ownership is transferred to new governor via signed public key', async () => {
const wallet = ethers.Wallet.createRandom();
const key = ec.keyFromPrivate(wallet.privateKey.slice(2), 'hex');
const pubkey = key.getPublic().encode('hex').slice(2);
const pubkey = ethers.utils.computePublicKey(wallet.privateKey, false).slice(4);

const publicKey = '0x' + pubkey;
let nextGovernorAddress = ethers.utils.getAddress(
Expand All @@ -71,11 +67,7 @@ describe('Governable Contract', () => {
await governableInstance.transferOwnership(nextGovernorAddress, 1);

const dummy = ethers.Wallet.createRandom();
const dummyPubkey = ec
.keyFromPrivate(dummy.privateKey, 'hex')
.getPublic()
.encode('hex')
.slice(2);
const dummyPubkey = ethers.utils.computePublicKey(dummy.privateKey, false).slice(4);

nextGovernorAddress = ethers.utils.getAddress(
'0x' + ethers.utils.keccak256('0x' + dummyPubkey).slice(-40)
Expand All @@ -100,24 +92,8 @@ describe('Governable Contract', () => {
]
);

let msg = ethers.utils.arrayify(ethers.utils.keccak256(prehashed));
let signature = key.sign(msg);
let expandedSig = {
r: '0x' + signature.r.toString('hex'),
s: '0x' + signature.s.toString('hex'),
v: signature.recoveryParam + 27,
};

// Transaction malleability fix if s is too large (Bitcoin allows it, Ethereum rejects it)
// https://ethereum.stackexchange.com/questions/55245/why-is-s-in-transaction-signature-limited-to-n-21
let sig;
try {
sig = ethers.utils.joinSignature(expandedSig);
} catch (e) {
expandedSig.s = '0x' + new BN(ec.curve.n).sub(signature.s).toString('hex');
expandedSig.v = expandedSig.v === 27 ? 28 : 27;
sig = ethers.utils.joinSignature(expandedSig);
}
const digest = ethers.utils.keccak256(prehashed);
const sig = ethers.utils.joinSignature(wallet._signingKey().signDigest(digest));

const tx = await governableInstance.transferOwnershipWithSignature(
refreshProposal.voterMerkleRoot,
Expand Down Expand Up @@ -158,8 +134,7 @@ describe('Governable Contract', () => {

assert.strictEqual((await governableInstance.refreshNonce()).toString(), '0');
const wallet = ethers.Wallet.createRandom();
const key = ec.keyFromPrivate(wallet.privateKey.slice(2), 'hex');
const pubkey = key.getPublic().encode('hex').slice(2);
const pubkey = ethers.utils.computePublicKey(wallet.privateKey, false).slice(4);
const publicKey = '0x' + pubkey;
let nextGovernorAddress = ethers.utils.getAddress(
'0x' + ethers.utils.keccak256(publicKey).slice(-40)
Expand All @@ -168,11 +143,7 @@ describe('Governable Contract', () => {
await governableInstance.transferOwnership(nextGovernorAddress, 1);

const dummy = ethers.Wallet.createRandom();
const dummyPubkey = ec
.keyFromPrivate(dummy.privateKey, 'hex')
.getPublic()
.encode('hex')
.slice(2);
const dummyPubkey = ethers.utils.computePublicKey(dummy.privateKey, false).slice(4);

const nonce = 2;

Expand Down Expand Up @@ -222,24 +193,8 @@ describe('Governable Contract', () => {
]
);

let msg = ethers.utils.arrayify(ethers.utils.keccak256(prehashed));
let signature = key.sign(msg);
let expandedSig = {
r: '0x' + signature.r.toString('hex'),
s: '0x' + signature.s.toString('hex'),
v: signature.recoveryParam + 27,
};

// Transaction malleability fix if s is too large (Bitcoin allows it, Ethereum rejects it)
// https://ethereum.stackexchange.com/questions/55245/why-is-s-in-transaction-signature-limited-to-n-21
let sig: any;
try {
sig = ethers.utils.joinSignature(expandedSig);
} catch (e) {
expandedSig.s = '0x' + new BN(ec.curve.n).sub(signature.s).toString('hex');
expandedSig.v = expandedSig.v === 27 ? 28 : 27;
sig = ethers.utils.joinSignature(expandedSig);
}
const digest = ethers.utils.keccak256(prehashed);
const sig = ethers.utils.joinSignature(wallet._signingKey().signDigest(digest));

const tx = await governableInstance.transferOwnershipWithSignature(
refreshProposal.voterMerkleRoot,
Expand Down
48 changes: 28 additions & 20 deletions packages/contracts/test/trees/MerkleTreePoseidon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,25 @@

import { MerkleTree, toFixedHex } from '@webb-tools/utils';
import { BigNumber } from 'ethers';
import { artifacts, contract, ethers } from 'hardhat';
import { ethers } from 'hardhat';
import { poseidon } from 'circomlibjs';
import { PoseidonHasher } from '@webb-tools/anchors';
const TruffleAssert = require('truffle-assertions');
const assert = require('assert');

const MerkleTreeWithHistory = artifacts.require('MerkleTreeMock');

contract('MerkleTree w/ Poseidon hasher', (accounts) => {
describe('MerkleTree w/ Poseidon hasher', () => {
let merkleTreeWithHistory;
let hasherInstance: PoseidonHasher;
let levels = 30;
const sender = accounts[0];
let tree: MerkleTree;

beforeEach(async () => {
const signers = await ethers.getSigners();
const wallet = signers[0];
hasherInstance = await PoseidonHasher.createPoseidonHasher(wallet);
tree = new MerkleTree(levels);
merkleTreeWithHistory = await MerkleTreeWithHistory.new(
levels,
hasherInstance.contract.address
);
const MerkleTreeWithHistory = await ethers.getContractFactory('MerkleTreeMock', wallet);
merkleTreeWithHistory = await MerkleTreeWithHistory.deploy(levels, hasherInstance.contract.address);
await merkleTreeWithHistory.deployed();
});

describe('#constructor', () => {
Expand Down Expand Up @@ -67,7 +62,7 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => {
let rootFromContract;

for (let i = 1; i < 11; i++) {
await merkleTreeWithHistory.insert(toFixedHex(i), { from: sender });
await merkleTreeWithHistory.insert(toFixedHex(i));
await tree.insert(i);
let { merkleRoot } = await tree.path(i - 1);
rootFromContract = await merkleTreeWithHistory.getLastRoot();
Expand All @@ -77,21 +72,23 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => {

it('should reject if tree is full', async () => {
const levels = 6;
const merkleTreeWithHistory = await MerkleTreeWithHistory.new(
const MerkleTreeWithHistory = await ethers.getContractFactory('MerkleTreeMock');
const merkleTreeWithHistory = await MerkleTreeWithHistory.deploy(
levels,
hasherInstance.contract.address
);
await merkleTreeWithHistory.deployed();

for (let i = 0; i < 2 ** levels; i++) {
TruffleAssert.passes(await merkleTreeWithHistory.insert(toFixedHex(i + 42)));
await merkleTreeWithHistory.insert(toFixedHex(i + 42));
}

await TruffleAssert.reverts(
await assertRejects(
merkleTreeWithHistory.insert(toFixedHex(1337)),
'Merkle tree is full. No more leaves can be added'
);

await TruffleAssert.reverts(
await assertRejects(
merkleTreeWithHistory.insert(toFixedHex(1)),
'Merkle tree is full. No more leaves can be added'
);
Expand All @@ -103,36 +100,38 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => {
let path;

for (let i = 1; i < 5; i++) {
TruffleAssert.passes(await merkleTreeWithHistory.insert(toFixedHex(i), { from: sender }));
await merkleTreeWithHistory.insert(toFixedHex(i));
await tree.insert(i);
path = await tree.path(i - 1);
let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(path.merkleRoot));
assert(isKnown);
}

TruffleAssert.passes(await merkleTreeWithHistory.insert(toFixedHex(42), { from: sender }));
await merkleTreeWithHistory.insert(toFixedHex(42));
// check outdated root
let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(path.merkleRoot));
assert(isKnown);
});

it('should not return uninitialized roots', async () => {
TruffleAssert.passes(await merkleTreeWithHistory.insert(toFixedHex(42), { from: sender }));
await merkleTreeWithHistory.insert(toFixedHex(42));
let isKnown = await merkleTreeWithHistory.isKnownRoot(toFixedHex(0));
assert(!isKnown);
});
});

describe('#insertions using deposit commitments', async () => {
it('should rebuild root correctly between native and contract', async () => {
const merkleTreeWithHistory = await MerkleTreeWithHistory.new(
const MerkleTreeWithHistory = await ethers.getContractFactory('MerkleTreeMock');
const merkleTreeWithHistory = await MerkleTreeWithHistory.deploy(
levels,
hasherInstance.contract.address
);
await merkleTreeWithHistory.deployed();
const commitment = '0x0101010101010101010101010101010101010101010101010101010101010101';
await tree.insert(commitment);
const { merkleRoot, pathElements, pathIndices } = await tree.path(0);
await merkleTreeWithHistory.insert(toFixedHex(commitment), { from: sender });
await merkleTreeWithHistory.insert(toFixedHex(commitment));
const rootFromContract = await merkleTreeWithHistory.getLastRoot();
assert.strictEqual(
merkleRoot.toString(),
Expand All @@ -156,3 +155,12 @@ contract('MerkleTree w/ Poseidon hasher', (accounts) => {
});
});
});

async function assertRejects(promise: Promise<unknown>, message: string) {
try {
await promise;
assert.fail('Expected promise to reject');
} catch (error: any) {
assert(error.message.includes(message), `Expected "${error.message}" to include "${message}"`);
}
}
2 changes: 1 addition & 1 deletion packages/create2-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"dependencies": {
"@webb-tools/contracts": "^1.1.1",
"ethers": "5.7.0"
"ethers": "5.8.0"
},
"publishConfig": {
"access": "public"
Expand Down
2 changes: 1 addition & 1 deletion packages/evm-test-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@webb-tools/utils": "^1.1.1",
"@webb-tools/vbridge": "^1.1.1",
"ecpair": "^2.0.1",
"ethers": "5.7.0",
"ethers": "5.8.0",
"ganache": "7.5.0",
"tiny-secp256k1": "^2.2.1"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/tokens/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@webb-tools/contracts": "^1.1.1",
"@webb-tools/create2-utils": "^1.1.1",
"@webb-tools/utils": "^1.1.1",
"ethers": "5.7.0"
"ethers": "5.8.0"
},
"publishConfig": {
"access": "public"
Expand Down
6 changes: 3 additions & 3 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
},
"dependencies": {
"@metamask/eth-sig-util": "^6.0.0",
"big-integer": "^1.6.52",
"circomlibjs": "^0.0.8",
"elliptic": "6.5.4",
"ethers": "5.7.0",
"ethers": "5.8.0",
"snarkjs": "^0.7.2"
},
"publishConfig": {
Expand All @@ -28,7 +28,7 @@
"version": "1.1.1",
"gitHead": "e1f3b300b6e004ac5a346dc0458bb1d303969d97",
"devDependencies": {
"@webb-tools/sdk-core": "0.1.4-126",
"@webb-tools/sdk-core": "0.1.8",
"chai": "^4.3.7"
},
"exports": {
Expand Down
Loading
Loading