upload updates using snark

This commit is contained in:
poma 2021-02-18 20:46:48 +03:00
parent 4e83afe633
commit 363772026d
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
15 changed files with 1715 additions and 1262 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
.env
snarks

View File

@ -1,319 +0,0 @@
[
{
"inputs": [
{
"internalType": "bytes32[]",
"name": "domains",
"type": "bytes32[]"
}
],
"name": "bulkResolve",
"outputs": [
{
"internalType": "address[]",
"name": "result",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
}
],
"name": "getAllProposals",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "uint256",
"name": "startTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "endTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "forVotes",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "againstVotes",
"type": "uint256"
},
{
"internalType": "bool",
"name": "executed",
"type": "bool"
},
{
"internalType": "bool",
"name": "extended",
"type": "bool"
},
{
"internalType": "enum Governance.ProposalState",
"name": "state",
"type": "uint8"
}
],
"internalType": "struct GovernanceAggregator.Proposal[]",
"name": "proposals",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
},
{
"internalType": "address[]",
"name": "accs",
"type": "address[]"
}
],
"name": "getGovernanceBalances",
"outputs": [
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
}
],
"name": "getPricesInETH",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "getUserData",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalIdState",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "timelock",
"type": "uint256"
},
{
"internalType": "address",
"name": "delegatee",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
}
],
"name": "minerRates",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "node",
"type": "bytes32"
}
],
"name": "resolve",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "swapState",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "miningData",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
}
],
"name": "marketData",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@ -1,519 +0,0 @@
[
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "_newOperator",
"type": "address"
}
],
"name": "changeOperator",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "nullifierHashes",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
},
{
"internalType": "bytes32",
"name": "_root",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_nullifierHash",
"type": "bytes32"
},
{
"internalType": "address payable",
"name": "_recipient",
"type": "address"
},
{
"internalType": "address payable",
"name": "_relayer",
"type": "address"
},
{
"internalType": "uint256",
"name": "_fee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_refund",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "verifier",
"outputs": [
{
"internalType": "contract IVerifier",
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32",
"name": "_left",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_right",
"type": "bytes32"
}
],
"name": "hashLeftRight",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "FIELD_SIZE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "levels",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "operator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32",
"name": "_root",
"type": "bytes32"
}
],
"name": "isKnownRoot",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "commitments",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "denomination",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "currentRootIndex",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "address",
"name": "_newVerifier",
"type": "address"
}
],
"name": "updateVerifier",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32[]",
"name": "_nullifierHashes",
"type": "bytes32[]"
}
],
"name": "isSpentArray",
"outputs": [
{
"internalType": "bool[]",
"name": "spent",
"type": "bool[]"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"internalType": "bytes32",
"name": "_commitment",
"type": "bytes32"
}
],
"name": "deposit",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getLastRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "roots",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "ROOT_HISTORY_SIZE",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "bytes32",
"name": "_nullifierHash",
"type": "bytes32"
}
],
"name": "isSpent",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "zeros",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "ZERO_VALUE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "filledSubtrees",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "nextIndex",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IVerifier",
"name": "_verifier",
"type": "address"
},
{
"internalType": "uint256",
"name": "_denomination",
"type": "uint256"
},
{
"internalType": "uint32",
"name": "_merkleTreeHeight",
"type": "uint32"
},
{
"internalType": "address",
"name": "_operator",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "commitment",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "uint32",
"name": "leafIndex",
"type": "uint32"
},
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "nullifierHash",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "relayer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"name": "Withdrawal",
"type": "event"
}
]

View File

@ -2,24 +2,51 @@
{
"inputs": [
{
"internalType": "bytes32",
"internalType": "address",
"name": "_governance",
"type": "address"
},
{
"internalType": "address",
"name": "_tornadoProxy",
"type": "bytes32"
"type": "address"
},
{
"internalType": "bytes32",
"name": "_hasher2",
"type": "bytes32"
"internalType": "contract ITornadoTreesV1",
"name": "_tornadoTreesV1",
"type": "address"
},
{
"internalType": "bytes32",
"name": "_hasher3",
"type": "bytes32"
"internalType": "contract IBatchTreeUpdateVerifier",
"name": "_treeUpdateVerifier",
"type": "address"
},
{
"internalType": "uint32",
"name": "_levels",
"type": "uint32"
"components": [
{
"internalType": "uint256",
"name": "depositsFrom",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "depositsStep",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "withdrawalsFrom",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "withdrawalsStep",
"type": "uint256"
}
],
"internalType": "struct TornadoTrees.SearchParams",
"name": "_searchParams",
"type": "tuple"
}
],
"stateMutability": "nonpayable",
@ -88,19 +115,13 @@
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes32[]",
"name": "domains",
"type": "bytes32[]"
}
],
"name": "bulkResolve",
"inputs": [],
"name": "BYTES_SIZE",
"outputs": [
{
"internalType": "address[]",
"name": "result",
"type": "address[]"
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
@ -108,12 +129,90 @@
},
{
"inputs": [],
"name": "depositTree",
"name": "CHUNK_SIZE",
"outputs": [
{
"internalType": "contract OwnableMerkleTree",
"internalType": "uint256",
"name": "",
"type": "address"
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "CHUNK_TREE_HEIGHT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ITEM_SIZE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "SNARK_FIELD",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "depositRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "depositV1Length",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
@ -140,10 +239,112 @@
},
{
"inputs": [],
"name": "hasher",
"name": "depositsLength",
"outputs": [
{
"internalType": "contract IHasher",
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITornadoTreesV1",
"name": "_tornadoTreesV1",
"type": "address"
},
{
"internalType": "string",
"name": "_type",
"type": "string"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "elementExists",
"outputs": [
{
"internalType": "bool",
"name": "success",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITornadoTreesV1",
"name": "_tornadoTreesV1",
"type": "address"
},
{
"internalType": "string",
"name": "_type",
"type": "string"
},
{
"internalType": "uint256",
"name": "_from",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_step",
"type": "uint256"
}
],
"name": "findArrayLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getRegisteredDeposits",
"outputs": [
{
"internalType": "bytes32[]",
"name": "_deposits",
"type": "bytes32[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getRegisteredWithdrawals",
"outputs": [
{
"internalType": "bytes32[]",
"name": "_withdrawals",
"type": "bytes32[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "governance",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
@ -178,59 +379,21 @@
"type": "function"
},
{
"inputs": [
"inputs": [],
"name": "previousDepositRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "node",
"name": "",
"type": "bytes32"
}
],
"name": "resolve",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tornadoProxy",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdrawalTree",
"outputs": [
{
"internalType": "contract OwnableMerkleTree",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "withdrawals",
"name": "previousWithdrawalRoot",
"outputs": [
{
"internalType": "bytes32",
@ -254,7 +417,7 @@
"type": "bytes32"
}
],
"name": "registerNewDeposit",
"name": "registerDeposit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@ -268,11 +431,11 @@
},
{
"internalType": "bytes32",
"name": "_nullifier",
"name": "_nullifierHash",
"type": "bytes32"
}
],
"name": "registerNewWithdrawal",
"name": "registerWithdrawal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
@ -280,78 +443,116 @@
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "instance",
"type": "address"
},
{
"internalType": "bytes32",
"name": "hash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "block",
"type": "uint256"
}
],
"internalType": "struct TornadoTrees.TreeLeaf[]",
"name": "_deposits",
"type": "tuple[]"
"internalType": "address",
"name": "_tornadoProxy",
"type": "address"
}
],
"name": "setTornadoProxyContract",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IBatchTreeUpdateVerifier",
"name": "_treeUpdateVerifier",
"type": "address"
}
],
"name": "setVerifierContract",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tornadoProxy",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tornadoTreesV1",
"outputs": [
{
"internalType": "contract ITornadoTreesV1",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "treeUpdateVerifier",
"outputs": [
{
"internalType": "contract IBatchTreeUpdateVerifier",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
},
{
"internalType": "bytes32",
"name": "_argsHash",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_currentRoot",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_newRoot",
"type": "bytes32"
},
{
"internalType": "uint32",
"name": "_pathIndices",
"type": "uint32"
},
{
"components": [
{
"internalType": "address",
"name": "instance",
"type": "address"
},
{
"internalType": "bytes32",
"name": "hash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "block",
"type": "uint256"
}
],
"internalType": "struct TornadoTrees.TreeLeaf[]",
"name": "_withdrawals",
"type": "tuple[]"
}
],
"name": "updateRoots",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "instance",
"type": "address"
},
{
"internalType": "bytes32",
"name": "hash",
"type": "bytes32"
},
{
"internalType": "uint256",
"internalType": "uint32",
"name": "block",
"type": "uint256"
"type": "uint32"
}
],
"internalType": "struct TornadoTrees.TreeLeaf[]",
"name": "_deposits",
"type": "tuple[]"
"internalType": "struct TornadoTrees.TreeLeaf[4]",
"name": "_events",
"type": "tuple[4]"
}
],
"name": "updateDepositTree",
@ -361,27 +562,52 @@
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
},
{
"internalType": "bytes32",
"name": "_argsHash",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_currentRoot",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "_newRoot",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "_pathIndices",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "instance",
"type": "address"
},
{
"internalType": "bytes32",
"name": "hash",
"type": "bytes32"
},
{
"internalType": "uint256",
"internalType": "address",
"name": "instance",
"type": "address"
},
{
"internalType": "uint32",
"name": "block",
"type": "uint256"
"type": "uint32"
}
],
"internalType": "struct TornadoTrees.TreeLeaf[]",
"name": "_withdrawals",
"type": "tuple[]"
"internalType": "struct TornadoTrees.TreeLeaf[4]",
"name": "_events",
"type": "tuple[4]"
}
],
"name": "updateWithdrawalTree",
@ -407,19 +633,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "depositRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "withdrawalRoot",
@ -434,13 +647,19 @@
"type": "function"
},
{
"inputs": [],
"name": "getRegisteredDeposits",
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "withdrawals",
"outputs": [
{
"internalType": "bytes32[]",
"name": "_deposits",
"type": "bytes32[]"
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
@ -448,12 +667,12 @@
},
{
"inputs": [],
"name": "getRegisteredWithdrawals",
"name": "withdrawalsLength",
"outputs": [
{
"internalType": "bytes32[]",
"name": "_withdrawals",
"type": "bytes32[]"
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
@ -461,7 +680,7 @@
},
{
"inputs": [],
"name": "blockNumber",
"name": "withdrawalsV1Length",
"outputs": [
{
"internalType": "uint256",

1
cache/deposit.json vendored Normal file
View File

@ -0,0 +1 @@
[]

1
cache/withdrawal.json vendored Normal file
View File

@ -0,0 +1 @@
[]

View File

@ -11,16 +11,16 @@
"author": "Roman Semenov <semenov.roma@gmail.com>",
"license": "ISC",
"dependencies": {
"circomlib": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4",
"circomlib": "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1",
"cron": "^1.8.2",
"dotenv": "^8.2.0",
"eth-ens-namehash": "^2.0.8",
"ethers": "^5.0.31",
"fixed-merkle-tree": "^0.3.4",
"ioredis": "^4.17.3",
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
"snarkjs": "^0.3.59",
"torn-token": "^1.0.0",
"tx-manager": "^0.2.9",
"web3": "^1.2.11"
"tornado-trees": "^0.0.4",
"tx-manager": "^0.2.9"
},
"devDependencies": {
"babel-eslint": "^10.1.0",

View File

@ -1,55 +0,0 @@
// This module is used only for tests
function send(method, params = []) {
return new Promise((resolve, reject) => {
// eslint-disable-next-line no-undef
web3.currentProvider.send(
{
jsonrpc: '2.0',
id: Date.now(),
method,
params,
},
(err, res) => {
return err ? reject(err) : resolve(res)
},
)
})
}
const takeSnapshot = async () => {
return await send('evm_snapshot')
}
const traceTransaction = async (tx) => {
return await send('debug_traceTransaction', [tx, {}])
}
const revertSnapshot = async (id) => {
await send('evm_revert', [id])
}
const mineBlock = async (timestamp) => {
await send('evm_mine', [timestamp])
}
const increaseTime = async (seconds) => {
await send('evm_increaseTime', [seconds])
}
const minerStop = async () => {
await send('miner_stop', [])
}
const minerStart = async () => {
await send('miner_start', [])
}
module.exports = {
takeSnapshot,
revertSnapshot,
mineBlock,
minerStop,
minerStart,
increaseTime,
traceTransaction,
}

View File

@ -1,62 +1,82 @@
const { web3, getTornadoTrees } = require('./singletons')
const tornadoAbi = require('../abi/tornado.json')
const { poseidonHash } = require('./utils')
const { soliditySha3 } = require('web3-utils')
const { getTornadoTrees, redis, getProvider } = require('./singletons')
const { action } = require('./utils')
const ethers = require('ethers')
const abi = new ethers.utils.AbiCoder()
async function getTornadoEvents({ instances, startBlock, endBlock, type }) {
const hashName = type === 'deposit' ? 'commitment' : 'nullifierHash'
const promises = instances.map((instance) => getInstanceEvents({ type, instance, startBlock, endBlock }))
async function getTornadoTreesEvents(type, fromBlock, toBlock) {
const eventName = type === action.DEPOSIT ? 'DepositData' : 'WithdrawalData'
const events = await getProvider().getLogs({
address: getTornadoTrees().address,
topics: getTornadoTrees().filters[eventName]().topics,
fromBlock,
toBlock,
})
return events
.map((e) => {
const { instance, hash, block, index } = getTornadoTrees().interface.parseLog(e).args
const encodedData = abi.encode(
['address', 'bytes32', 'uint256'],
[instance, hash, block],
)
return {
instance,
hash,
block: block.toNumber(),
index: index.toNumber(),
sha3: ethers.utils.keccak256(encodedData)
}
})
.sort((a, b) => a.index - b.index)
}
const raw = await Promise.all(promises)
const events = raw.flat().reduce((acc, e) => {
const encodedData = web3.eth.abi.encodeParameters(
['address', 'bytes32', 'uint256'],
[e.address, e.returnValues[hashName], e.blockNumber],
)
const leafHash = soliditySha3({ t: 'bytes', v: encodedData })
acc[leafHash] = {
instance: e.address,
hash: e.returnValues[hashName],
block: e.blockNumber,
async function getEventsWithCache(type) {
const currentBlock = await getProvider().getBlockNumber()
const lastBlock = Number(await redis.get(`${type}LastBlock`) || 0) + 1
// if (currentBlock <= lastBlock) {
// throw new Error('Current block is lower than last block')
// }
let cachedEvents = (await redis.lrange(type, 0, -1)).map((e) => JSON.parse(e))
if (cachedEvents.length === 0) {
cachedEvents = require(`../cache/${type}.json`)
if (cachedEvents.length > 0) {
await redis.rpush(type, cachedEvents.map((e) => JSON.stringify(e)))
}
return acc
}, {})
return events
}
const newEvents = await getTornadoTreesEvents(type, lastBlock, currentBlock)
if (newEvents.length > 0) {
await redis.rpush(type, newEvents.map((e) => JSON.stringify(e)))
}
await redis.set(`${type}LastBlock`, currentBlock)
return cachedEvents.concat(newEvents)
}
async function getInstanceEvents({ type, instance, startBlock, endBlock }) {
const eventName = type === 'deposit' ? 'Deposit' : 'Withdrawal'
async function getEvents(type) {
const pendingMethod = type === action.DEPOSIT ? 'getRegisteredDeposits' : 'getRegisteredWithdrawals'
const pendingEventHashes = await getTornadoTrees()[pendingMethod]()
const contract = new web3.eth.Contract(tornadoAbi, instance)
const events = await contract.getPastEvents(eventName, {
fromBlock: startBlock,
toBlock: endBlock,
})
return events
}
const committedMethod = type === action.DEPOSIT ? 'lastProcessedDepositLeaf' : 'lastProcessedWithdrawalLeaf'
const committedCount = await getTornadoTrees()[committedMethod]()
async function getMiningEvents(startBlock, endBlock, type) {
const eventName = type === 'deposit' ? 'DepositData' : 'WithdrawalData'
const tornadoTrees = await getTornadoTrees()
const events = await tornadoTrees.getPastEvents(eventName, {
fromBlock: startBlock,
toBlock: endBlock,
})
return events
.sort((a, b) => a.returnValues.index - b.returnValues.index)
.map((e) => poseidonHash([e.returnValues.instance, e.returnValues.hash, e.returnValues.block]))
}
const events = await getEventsWithCache(type)
async function getRegisteredEvents({ type }) {
const method = type === 'deposit' ? 'getRegisteredDeposits' : 'getRegisteredWithdrawals'
const tornadoTrees = await getTornadoTrees()
const events = await tornadoTrees.methods[method]().call()
return events
const committedEvents = events.slice(0, committedCount)
const pendingEvents = pendingEventHashes.map((e) => events.find(a => a.sha3 === e))
if (pendingEvents.some((e) => e === undefined)) {
pendingEvents.forEach((e, i) => {
if (e === undefined) {
console.log('Unknown event', pendingEventHashes[i])
}
})
throw new Error('Tree contract expects unknown tornado event')
}
return {
committedEvents,
pendingEvents,
}
}
module.exports = {
getTornadoEvents,
getMiningEvents,
getRegisteredEvents,
getEvents,
}

View File

@ -1,91 +1,16 @@
require('dotenv').config()
const cron = require('cron')
const { web3, redis, getTornadoTrees, txManager } = require('./singletons')
const config = require('torn-token')
const { getTornadoEvents, getRegisteredEvents } = require('./events')
const { toWei, toHex } = require('web3-utils')
const { getEvents } = require('./events')
const { updateTree } = require('./update')
const { action } = require('./utils')
const STARTING_BLOCK = process.env.STARTING_BLOCK || 0
const prefix = {
1: '',
42: 'kovan.',
5: 'goerli.',
}
let previousUpload = action.DEPOSIT
async function main(isRetry = false) {
const tornadoTrees = await getTornadoTrees()
const newEvents = {}
const startBlock = Number((await redis.get('lastBlock')) || STARTING_BLOCK) + 1
const netId = await web3.eth.getChainId()
const currentBlock = await web3.eth.getBlockNumber()
const explorer = `https://${prefix[netId]}etherscan.io`
const instances = Object.values(config.instances[`netId${netId}`].eth.instanceAddress)
console.log(`Getting events for blocks ${startBlock} to ${currentBlock}`)
async function main() {
// todo retry
for (const type of Object.values(action)) {
const newRegisteredEvents = await getRegisteredEvents({ type })
const tornadoEvents = await getTornadoEvents({ instances, startBlock, endBlock: currentBlock, type })
newEvents[type] = newRegisteredEvents.map((e) => tornadoEvents[e])
if (newEvents[type].some((e) => e === undefined)) {
console.log('Tree contract expects unknown tornado event')
console.log(newRegisteredEvents.find((e) => !tornadoEvents[e]))
if (isRetry) {
console.log('Quitting')
} else {
console.log('Retrying')
await redis.set('lastBlock', STARTING_BLOCK)
await main(true)
}
return
}
const { committedEvents, pendingEvents } = await getEvents(type)
console.log(`There are ${pendingEvents.length} unprocessed ${type}s`)
await updateTree(committedEvents, pendingEvents, type)
}
console.log(
`There are ${newEvents[action.DEPOSIT].length} unprocessed deposits and ${
newEvents[action.WITHDRAWAL].length
} withdrawals`,
)
while (newEvents[action.DEPOSIT].length || newEvents[action.WITHDRAWAL].length) {
const chunks = {}
const type = previousUpload === action.DEPOSIT ? action.WITHDRAWAL : action.DEPOSIT
chunks[type] = newEvents[type].splice(0, process.env.INSERT_BATCH_SIZE)
console.log(`Submitting tree update with ${chunks[type].length} ${type}s`)
const args =
previousUpload === action.DEPOSIT ? [[], chunks[action.WITHDRAWAL]] : [chunks[action.DEPOSIT], []]
const data = tornadoTrees.methods.updateRoots(...args).encodeABI()
const tx = txManager.createTx({
to: tornadoTrees._address,
data,
gasPrice: toHex(toWei(process.env.GAS_PRICE, 'Gwei')),
})
try {
await tx
.send()
.on('transactionHash', (hash) => console.log(`Transaction: ${explorer}/tx/${hash}`))
.on('mined', (receipt) => console.log('Mined in block', receipt.blockNumber))
.on('confirmations', (n) => console.log(`Got ${n} confirmations`))
} catch (e) {
console.log('Tx failed...', e)
if (isRetry) {
console.log('Quitting')
} else {
await redis.set('lastBlock', STARTING_BLOCK)
console.log('Retrying')
await main(true)
}
return
}
previousUpload = type
}
await redis.set('lastBlock', currentBlock)
console.log('Done')
}

View File

@ -1,29 +0,0 @@
const Web3 = require('web3')
const web3 = new Web3(process.env.RPC_URL)
const aggregator = new web3.eth.Contract(require('../abi/Aggregator.abi.json'), process.env.AGGREGATOR)
const ens = require('eth-ens-namehash')
class ENSResolver {
constructor() {
this.addresses = {}
}
async resolve(domains) {
if (!Array.isArray(domains)) {
domains = [domains]
}
const unresolved = domains.filter((d) => !this.addresses[d])
if (unresolved.length) {
const resolved = await aggregator.methods.bulkResolve(unresolved.map(ens.hash)).call()
for (let i = 0; i < resolved.length; i++) {
this.addresses[domains[i]] = resolved[i]
}
}
const addresses = domains.map((domain) => this.addresses[domain])
return addresses.length === 1 ? addresses[0] : addresses
}
}
module.exports = ENSResolver

View File

@ -1,39 +1,40 @@
require('dotenv').config()
const Web3 = require('web3')
const ethers = require('ethers')
const { TxManager } = require('tx-manager')
const tornadoTreesAbi = require('../abi/tornadoTrees.json')
const Redis = require('ioredis')
const ENSResolver = require('./resolver')
const resolver = new ENSResolver()
const redis = new Redis(process.env.REDIS_URL)
const config = require('torn-token')
let tornadoTrees
const web3 = new Web3(process.env.RPC_URL)
web3.eth.accounts.wallet.add('0x' + process.env.PRIVATE_KEY)
web3.eth.defaultAccount = web3.eth.accounts.privateKeyToAccount('0x' + process.env.PRIVATE_KEY).address
let provider
const txManager = new TxManager({
privateKey: process.env.PRIVATE_KEY,
rpcUrl: process.env.RPC_URL,
broadcastNodes: process.env.BROADCAST_NODES.split(','),
broadcastNodes: process.env.BROADCAST_NODES ? process.env.BROADCAST_NODES.split(',') : undefined,
config: {
CONFIRMATIONS: process.env.CONFIRMATION_BLOCKS,
MAX_GAS_PRICE: process.env.GAS_PRICE,
},
})
async function getTornadoTrees() {
function getProvider() {
if (!provider) {
provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL)
}
return provider
}
function getTornadoTrees() {
if (!tornadoTrees) {
tornadoTrees = new web3.eth.Contract(tornadoTreesAbi, await resolver.resolve(config.tornadoTrees.address))
console.log('Resolved tornadoTrees contract:', tornadoTrees._address)
tornadoTrees = new ethers.Contract(process.env.TORNADO_TREES || config.tornadoTrees.address, tornadoTreesAbi, getProvider())
}
return tornadoTrees
}
module.exports = {
web3,
redis,
getTornadoTrees,
getProvider,
txManager,
}

43
src/update.js Normal file
View File

@ -0,0 +1,43 @@
require('dotenv').config()
const { getTornadoTrees, txManager, getProvider } = require('./singletons')
const { action, getExplorer, poseidonHash, poseidonHash2, toFixedHex } = require('./utils')
const { parseUnits } = require('ethers').utils
const tornadoTrees = require('tornado-trees')
const MerkleTree = require('fixed-merkle-tree')
const { INSERT_BATCH_SIZE, GAS_PRICE } = process.env
async function updateTree(committedEvents, pendingEvents, type) {
const netId = (await getProvider().getNetwork()).chainId
const leaves = committedEvents.map((e) => poseidonHash([e.instance, e.hash, e.block]))
const tree = new MerkleTree(20, leaves, { hashFunction: poseidonHash2 })
const rootMethod = type === action.DEPOSIT ? 'depositRoot' : 'withdrawalRoot'
const root = toFixedHex(await getTornadoTrees()[rootMethod]())
if (root !== tree.root()) {
throw new Error(`Invalid ${type} root! Contract: ${root}, local: ${tree.root()}`)
}
while (pendingEvents.length >= INSERT_BATCH_SIZE) {
const chunk = pendingEvents.splice(0, INSERT_BATCH_SIZE)
console.log('Generating snark proof')
const { input, args } = tornadoTrees.batchTreeUpdate(tree, chunk)
const proof = await tornadoTrees.prove(input, './snarks/BatchTreeUpdate')
console.log('Sending update tx')
const method = type === action.DEPOSIT ? 'updateDepositTree' : 'updateWithdrawalTree'
const txData = await getTornadoTrees().populateTransaction[method](proof, ...args, { gasPrice: parseUnits(GAS_PRICE, 'gwei') })
const tx = txManager.createTx(txData)
const receiptPromise = tx
.send()
.on('transactionHash', (hash) => console.log(`Transaction: ${getExplorer(netId)}/tx/${hash}`))
.on('mined', (receipt) => console.log('Mined in block', receipt.blockNumber))
.on('confirmations', (n) => console.log(`Got ${n} confirmations`))
await receiptPromise // todo optional
}
}
module.exports = {
updateTree,
}

View File

@ -1,18 +1,31 @@
const { bigInt } = require('snarkjs')
const { BigNumber } = require('ethers')
const { poseidon } = require('circomlib')
/** BigNumber to hex string of specified length */
const toFixedHex = (number, length = 32) =>
'0x' +
(number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)).padStart(length * 2, '0')
(number instanceof Buffer
? number.toString('hex')
: BigNumber.from(number).toHexString().slice(2)
).padStart(length * 2, '0')
const poseidonHash = (items) => toFixedHex(poseidon(items))
const poseidonHash2 = (a, b) => poseidonHash([a, b])
const action = Object.freeze({ DEPOSIT: 'deposit', WITHDRAWAL: 'withdrawal' })
const prefix = {
1: '',
5: 'goerli.',
42: 'kovan.',
}
const getExplorer = (netId) => `https://${prefix[netId]}etherscan.io`
module.exports = {
toFixedHex,
poseidonHash,
poseidonHash2,
getExplorer,
action,
}

1207
yarn.lock

File diff suppressed because it is too large Load Diff