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

Adds create2 deploy methods + refactoring typescript interfaces #218

Merged
merged 22 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
724133b
feat: add create2 method to deploy VAnchor Verifier
semaraugusto Dec 8, 2022
b3d35a7
feat: add create2 tests for poseidonHasher and erc20 token
semaraugusto Dec 9, 2022
bae64ba
add tests for create2 on VAnchor. Needs to use same handler wallet
semaraugusto Dec 13, 2022
44c6b5b
chore: refactoring VAnchor ts interface
semaraugusto Dec 13, 2022
572e7aa
chore: refactoring IdentityVAnchor ts interface
semaraugusto Dec 13, 2022
3a26bb6
chore: fix tests for identityVAnchor
semaraugusto Dec 13, 2022
62ed6b6
chore: fix tests for create2 while running them together with the oth…
semaraugusto Dec 13, 2022
48b5cc4
chore: refactoring VAnchorForest ts interface
semaraugusto Dec 14, 2022
9663923
chore: refactoring Verifier interfaces
semaraugusto Dec 14, 2022
7fdd8ca
chore: more refactoring and some cleaning up
semaraugusto Dec 14, 2022
49064e3
feat: add deployer typescript interface. Refactor Verifier and Poseid…
semaraugusto Dec 14, 2022
19c62e3
chore: refactoring create2 tests to use new Deployer interface
semaraugusto Dec 15, 2022
21faa70
feat: add create2 method for vanchorForest and corresponding tests
semaraugusto Dec 15, 2022
b35d607
add create2 method for `packages/anchors/src/ChainalysisVAnchor.ts`
semaraugusto Dec 19, 2022
024ac02
feat: add create2 method+tests for identityVAnchor and dependencies
semaraugusto Dec 20, 2022
31fa1cd
chore: run prettier + fix ts-check
semaraugusto Dec 20, 2022
ecd867c
chore: merge with main
semaraugusto Dec 21, 2022
ca27db3
Merge branch 'main' into semar/create2
semaraugusto Dec 21, 2022
0f368a9
chore: removing logs and cleaning up
semaraugusto Dec 21, 2022
a46d0f0
chore: fix ts-check
semaraugusto Dec 21, 2022
647223b
Merge branch 'main' into semar/create2
drewstone Dec 23, 2022
75cc3e1
Update packages/anchors/src/Common.ts
drewstone Dec 23, 2022
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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"build": "yarn compile && yarn build:packages",
"setup": "yarn compile && yarn build:circuits && yarn build:ptau",
"test": "yarn workspace @webb-tools/contracts run test",
"fast": "yarn workspace @webb-tools/contracts run fast",
"build:circuits": "./scripts/bash/build_circuits.sh",
"build:packages": "lerna run build",
"build:ptau": "./scripts/bash/generate_phase1_ptau.sh",
Expand Down Expand Up @@ -68,10 +69,10 @@
"@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0",
"@webb-tools/sdk-core": "0.1.4-113",
"@webb-tools/semaphore": "0.0.1-4",
"@webb-tools/semaphore": "0.0.1-5",
"@webb-tools/semaphore-group": "0.0.1-4",
"@webb-tools/semaphore-identity": "0.0.1-3",
"@webb-tools/semaphore-proof": "0.0.1-3",
"@webb-tools/semaphore-proof": "0.0.1-5",
"@webb-tools/test-utils": "0.1.4-113",
"babel-plugin-styled-components": "^2.0.7",
"bn.js": "4.11.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/anchors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@webb-tools/contracts": "^0.5.1",
"@webb-tools/interfaces": "^0.5.1",
"@webb-tools/sdk-core": "0.1.4-113",
"@webb-tools/semaphore": "0.0.1-4",
"@webb-tools/semaphore": "0.0.1-5",
"@webb-tools/utils": "^0.5.1",
"ethers": "5.7.0"
},
Expand Down
47 changes: 47 additions & 0 deletions packages/anchors/src/ChainalysisVAnchor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,55 @@ import { ZkComponents } from '@webb-tools/utils';
import { BigNumberish, ethers, BigNumber } from 'ethers';
import { VAnchorEncodeInputs__factory, ChainalysisVAnchor__factory } from '@webb-tools/contracts';
import VAnchor from './VAnchor';
import { Deployer } from './Deployer';

export class ChainalysisVAnchor extends VAnchor {
public static async create2VAnchor(
deployer: Deployer,
saltHex: string,
verifier: string,
levels: BigNumberish,
hasher: string,
handler: string,
token: string,
maxEdges: number,
smallCircuitZkComponents: ZkComponents,
largeCircuitZkComponents: ZkComponents,
signer: ethers.Signer
) {
const { contract: libraryContract } = await deployer.deploy(
VAnchorEncodeInputs__factory,
saltHex,
signer
);

let libraryAddresses = {
['contracts/libs/VAnchorEncodeInputs.sol:VAnchorEncodeInputs']: libraryContract.address,
};

const argTypes = ['address', 'uint32', 'address', 'address', 'address', 'uint8'];
const args = [verifier, levels, hasher, handler, token, maxEdges];
const { contract: vanchor, receipt } = await deployer.deploy(
ChainalysisVAnchor__factory,
saltHex,
signer,
libraryAddresses,
argTypes,
args
);
const createdVAnchor = new VAnchor(
vanchor,
signer,
BigNumber.from(levels).toNumber(),
maxEdges,
smallCircuitZkComponents,
largeCircuitZkComponents
);
createdVAnchor.latestSyncedBlock = receipt.blockNumber!;
createdVAnchor.token = token;
return createdVAnchor;
}

public static async createVAnchor(
verifier: string,
levels: BigNumberish,
Expand Down
270 changes: 270 additions & 0 deletions packages/anchors/src/Common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
import { BigNumber, BigNumberish, ContractTransaction, ethers } from 'ethers';
import {
VAnchor as VAnchorContract,
VAnchor__factory,
ChainalysisVAnchor as ChainalysisVAnchorContract,
DeterministicDeployFactory as DeterministicDeployFactoryContract,
IdentityVAnchor as IdentityVAnchorContract,
VAnchorForest as VAnchorForestContract,
VAnchorEncodeInputs__factory,
TokenWrapper__factory,
} from '@webb-tools/contracts';
import {
toHex,
Keypair,
toFixedHex,
Utxo,
MerkleTree,
median,
mean,
max,
min,
randomBN,
CircomProvingManager,
ProvingManagerSetupInput,
MerkleProof,
UtxoGenInput,
CircomUtxo,
FIELD_SIZE,
LeafIdentifier,
} from '@webb-tools/sdk-core';
import { hexToU8a, u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils';

const zeroAddress = '0x0000000000000000000000000000000000000000';
function checkNativeAddress(tokenAddress: string): boolean {
if (tokenAddress === zeroAddress || tokenAddress === '0') {
return true;
}
return false;
}
type WebbContracts =
| VAnchorContract
| ChainalysisVAnchorContract
| IdentityVAnchorContract
| VAnchorForestContract;

export class WebbBridge {
signer: ethers.Signer;
contract: WebbContracts;

constructor(contract: WebbContracts, signer: ethers.Signer) {
this.contract = contract;
this.signer = signer;
}

public static async generateUTXO(input: UtxoGenInput): Promise<Utxo> {
return CircomUtxo.generateUtxo(input);
}

public static createRootsBytes(rootArray: string[]) {
let rootsBytes = '0x';
for (let i = 0; i < rootArray.length; i++) {
rootsBytes += toFixedHex(rootArray[i]).substr(2);
}
return rootsBytes; // root byte string (32 * array.length bytes)
}

getAddress(): string {
return this.contract.address;
}

// Convert a hex string to a byte array
public static hexStringToByte(str: string) {
if (!str) {
return new Uint8Array();
}

var a = [];
for (var i = 0, len = str.length; i < len; i += 2) {
a.push(parseInt(str.substr(i, 2), 16));
}

return new Uint8Array(a);
}

public async setHandler(handlerAddress: string) {
const tx = await this.contract.setHandler(
handlerAddress,
BigNumber.from(await this.contract.getProposalNonce()).add(1)
);
await tx.wait();
}

public async setSigner(newSigner: ethers.Signer) {
const currentChainId = await this.signer.getChainId();
const newChainId = await newSigner.getChainId();

if (currentChainId === newChainId) {
this.signer = newSigner;
this.contract = this.contract.connect(newSigner);
return true;
}
return false;
}
public async createResourceId(): Promise<string> {
return toHex(
this.contract.address + toHex(getChainIdType(await this.signer.getChainId()), 6).substr(2),
32
);
}
public async getMinWithdrawalLimitProposalData(
_minimalWithdrawalAmount: string
): Promise<string> {
const resourceID = await this.createResourceId();
const functionSig = ethers.utils
.keccak256(ethers.utils.toUtf8Bytes('configureMinimalWithdrawalLimit(uint256,uint32)'))
.slice(0, 10)
.padEnd(10, '0');
const nonce = Number(await this.contract.getProposalNonce()) + 1;
return (
'0x' +
toHex(resourceID, 32).substr(2) +
functionSig.slice(2) +
toHex(nonce, 4).substr(2) +
toFixedHex(_minimalWithdrawalAmount).substr(2)
);
}

public async getMaxDepositLimitProposalData(_maximumDepositAmount: string): Promise<string> {
const resourceID = await this.createResourceId();
const functionSig = ethers.utils
.keccak256(ethers.utils.toUtf8Bytes('configureMaximumDepositLimit(uint256,uint32)'))
.slice(0, 10)
.padEnd(10, '0');
const nonce = Number(await this.contract.getProposalNonce()) + 1;
return (
'0x' +
toHex(resourceID, 32).substr(2) +
functionSig.slice(2) +
toHex(nonce, 4).substr(2) +
toFixedHex(_maximumDepositAmount).substr(2)
);
}

// Proposal data is used to update linkedAnchors via bridge proposals
// on other chains with this anchor's state
public async genProposalData(
resourceID: string,
merkleRoot: string,
leafIndex: number
): Promise<string> {
// If no leaf index passed in, set it to the most recent one.
const chainID = getChainIdType(await this.signer.getChainId());
const functionSig = ethers.utils
.keccak256(ethers.utils.toUtf8Bytes('updateEdge(uint256,uint32,bytes32)'))
.slice(0, 10)
.padEnd(10, '0');

const srcContract = this.contract.address;
const srcResourceId =
'0x' +
toHex(0, 6).substring(2) +
toHex(srcContract, 20).substr(2) +
toHex(chainID, 6).substr(2);
return (
'0x' +
toHex(resourceID, 32).substr(2) +
functionSig.slice(2) +
toHex(leafIndex, 4).substr(2) +
toHex(merkleRoot, 32).substr(2) +
toHex(srcResourceId, 32).substr(2)
);
}

public getExtAmount(inputs: Utxo[], outputs: Utxo[], fee: BigNumberish) {
return BigNumber.from(fee)
.add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0)))
.sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0)));
}
public async getWrapUnwrapOptions(extAmount, wrapUnwrapToken) {
let options = {};
if (extAmount.gt(0) && checkNativeAddress(wrapUnwrapToken)) {
let tokenWrapper = TokenWrapper__factory.connect(await this.contract.token(), this.signer);
let valueToSend = await tokenWrapper.getAmountToWrap(extAmount);

options = {
value: valueToSend.toHexString(),
};
} else {
options = {};
}
return options;
}
public async encodeSolidityProof(fullProof: any, calldata: any): Promise<String> {
const proof = JSON.parse('[' + calldata + ']');
const pi_a = proof[0];
const pi_b = proof[1];
const pi_c = proof[2];

const proofEncoded = [
pi_a[0],
pi_a[1],
pi_b[0][0],
pi_b[0][1],
pi_b[1][0],
pi_b[1][1],
pi_c[0],
pi_c[1],
]
.map((elt) => elt.substr(2))
.join('');

return proofEncoded;
}

public async padUtxos(utxos: Utxo[], maxLen: number): Promise<Utxo[]> {
const evmId = await this.signer.getChainId();
const chainId = getChainIdType(evmId);
const randomKeypair = new Keypair();

while (utxos.length !== 2 && utxos.length < maxLen) {
utxos.push(
await CircomUtxo.generateUtxo({
curve: 'Bn254',
backend: 'Circom',
chainId: chainId.toString(),
originChainId: chainId.toString(),
amount: '0',
blinding: hexToU8a(randomBN(31).toHexString()),
keypair: randomKeypair,
})
);
}
if (utxos.length !== 2 && utxos.length !== maxLen) {
throw new Error('Invalid utxo length');
}
return utxos;
}

// Proposal data is used to update linkedAnchors via bridge proposals
// on other chains with this anchor's state

public async getHandler(): Promise<string> {
return this.contract.handler();
}

public validateInputs(inputs: Utxo[]): void {
inputs.map((utxo) => {
if (utxo.originChainId === undefined) {
throw new Error('Input Utxo does not have a configured originChainId');
}
});
}

public async getHandlerProposalData(newHandler: string): Promise<string> {
const resourceID = await this.createResourceId();
const functionSig = ethers.utils
.keccak256(ethers.utils.toUtf8Bytes('setHandler(address,uint32)'))
.slice(0, 10)
.padEnd(10, '0');
const nonce = Number(await this.contract.getProposalNonce()) + 1;

return (
'0x' +
toHex(resourceID, 32).substr(2) +
functionSig.slice(2) +
toHex(nonce, 4).substr(2) +
toHex(newHandler, 20).substr(2)
);
}
}
Loading