Init
This commit is contained in:
commit
c267a7b742
3
.env.bat.example
Normal file
3
.env.bat.example
Normal file
@ -0,0 +1,3 @@
|
||||
set MAINNET_RPC_URL=
|
||||
set PRIVATE_KEY=
|
||||
set ETHERSCAN_KEY=
|
3
.env.example
Normal file
3
.env.example
Normal file
@ -0,0 +1,3 @@
|
||||
MAINNET_RPC_URL=
|
||||
PRIVATE_KEY=
|
||||
ETHERSCAN_KEY=
|
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# Compiler files
|
||||
cache/
|
||||
out/
|
||||
|
||||
# Ignores development broadcast logs
|
||||
!/broadcast
|
||||
/broadcast/*/31337/
|
||||
/broadcast/**/dry-run/
|
||||
|
||||
# Docs
|
||||
docs/
|
||||
|
||||
# Dotenv file
|
||||
.env
|
||||
.env.bat
|
||||
|
||||
# Node modules
|
||||
node_modules/
|
||||
package-lock.json
|
||||
|
||||
# yarn
|
||||
yarn.lock
|
||||
|
||||
# VScode files
|
||||
.vscode
|
||||
|
||||
test.ts
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "lib/forge-std"]
|
||||
path = lib/forge-std
|
||||
url = https://github.com/foundry-rs/forge-std
|
1
.nvmrc
Normal file
1
.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
v16.20.2
|
66
README.md
Normal file
66
README.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Proposal to update Tornado IPFS hashes in ENS and rescue tokens
|
||||
|
||||
### Changes / effect description
|
||||
|
||||
- Create new `tornadocash.eth` subdomains written in [`contants.ts`](scripts/constants.ts) and set Governance as owner for all
|
||||
- Assign corresponding IPFS contenthash to each domain
|
||||
|
||||
### Requirements
|
||||
|
||||
- Rust ([Need only for Windows](https://doc.rust-lang.org/cargo/getting-started/installation.html))
|
||||
- Foundryup ([Windows](https://github.com/altugbakan/foundryup-windows), [Linux](https://book.getfoundry.sh/getting-started/installation))
|
||||
- Node 16 or higher ([Windows](https://github.com/coreybutler/nvm-windows), [Linux](https://github.com/nvm-sh/nvm))
|
||||
|
||||
### Installation
|
||||
|
||||
```text
|
||||
git clone --recurse-submodules https://git.tornado.ws/Theo/proposal-31-finalize-decentralized-sources-and-rescue-usdt
|
||||
cd proposal-31-finalize-decentralized-sources-and-rescue-usdt
|
||||
npm install
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```text
|
||||
npm run test:windows
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```text
|
||||
npm run test:linux
|
||||
```
|
||||
|
||||
### Contracts
|
||||
|
||||
Proposal deployed contract: [0x775Cf01c12D3E4296c7c9b52C8B835c071068F51](https://etherscan.io/address/0x775cf01c12d3e4296c7c9b52c8b835c071068f51#code)
|
||||
|
||||
Goerli test ENS address: [`tornadotest.eth`](https://app.ens.domains/tornadotest.eth) (to see content, you need to connect wallet and switch to Goerli Testnet on app.ens.domains)
|
||||
|
||||
### Verification
|
||||
|
||||
Since the proposal code can be confusing because it relies on numerous specifications and EIPs, users can use scripts to verify the correctness of the data, see the output in the corresponding files, and insert the code directly into Solidity, comparing it with the existing code in the proposal (there should be no discrepancies be).
|
||||
|
||||
1. Verification of the transformation of eth domains into [ENS nodes](https://docs.ens.domains/ens-improvement-proposals/ensip-1-ens):
|
||||
|
||||
Script source: [calculateENSNodes.ts](scripts/calculateENSNodes.ts)
|
||||
|
||||
Command to run: `npm run calculateENS`
|
||||
|
||||
Result data: [ensNodesDeclarations.txt](data/ensNodesDeclarations.txt)
|
||||
|
||||
2. Verification of the transformation of IPFS CIDs to ENS [content hashes](https://eips.ethereum.org/EIPS/eip-1577)
|
||||
|
||||
Script source: [calculateIPFSContenthashes.ts](scripts/calculateIPFSContenthashes.ts)
|
||||
|
||||
Command to run: `npm run calculateIpfs`
|
||||
|
||||
Result data: [ensDomainsIPFSContenthashes.txt](data/ensDomainsIPFSContenthashes.txt)
|
||||
|
||||
3. Verification of the equality [IPFS CIDs](https://docs.ipfs.tech/concepts/content-addressing/) v0 with v1 (because ENS on its interface shows v1 CIDs, but Pinata and contenthash library uses v0)
|
||||
|
||||
Script source: [calculateIpfsV1Cids.ts](scripts/calculateIpfsV1Cids.ts)
|
||||
|
||||
Command to run: `npm run calculateIpfsV1Cids`
|
||||
|
||||
Result data: [ipfsV1CIDs.txt](data/ipfsV1CIDs.txt)
|
9
data/ensDomainsIPFSContenthashes.txt
Normal file
9
data/ensDomainsIPFSContenthashes.txt
Normal file
@ -0,0 +1,9 @@
|
||||
bytes memory relayersUiSourceContenthash = hex"e3010170122072dd7fe08bc98404c3a2e402dac817562b2533aa549c475e8e85b9a266bc507c";
|
||||
bytes memory relayersUiSiteContenthash = hex"e3010170122052a5331f2ff57ce75b2fb48870e2f1f0752d0da2a0d612104028ce5930976adb";
|
||||
bytes memory relayersUiOldSiteContenthash = hex"e3010170122052a5331f2ff57ce75b2fb48870e2f1f0752d0da2a0d612104028ce5930976adb";
|
||||
bytes memory downloadScriptSourceContenthash = hex"e301017012208f759bcffb194cb59161916ee7f1f1d225016f03514b5430d3fb4c5fb254a3bb";
|
||||
bytes memory ipfsHostHelpScriptSourceContenthash = hex"e301017012200c8e358709e32756da156639a8aedbf6950090d4e73c2dc6e1c012fe5b78e4e9";
|
||||
bytes memory downloadInstructionsHtmlContenthash = hex"e301017012201a9748cd5f0f64c682d309f6af6354944e0d2e572e81c301ea8ce76c11dee1f5";
|
||||
bytes memory tornadoRelayerSoftwareSourceContenthash = hex"e3010170122067e3626e5999eccfbe9ad14db95a40bd1c32305f580f37eb3f2c9535026aa7d9";
|
||||
bytes memory docsSourceContenthash = hex"e30101701220a02b6c5846715cae70d0f7a7df09cbc929b5af97d38dd130ffd44aa0adf21daa";
|
||||
bytes memory docsSiteContenthash = hex"e30101701220615111f92c8087a46a397f77046d8c0eed57b27fbb9221e4d270307f0fb317a4";
|
21
data/ensNodesDeclarations.txt
Normal file
21
data/ensNodesDeclarations.txt
Normal file
@ -0,0 +1,21 @@
|
||||
bytes32 internal constant rootTornadoDomainNode = 0xe6ae31d630cc7a8279c0f1c7cbe6e7064814c47d1785fa2703d9ae511ee2be0c;
|
||||
bytes32 internal constant sourcesDomainNode = 0x4e5775b58e8aeaa32fc2b429c9485da9de5a1c6fead70b8704ce0f970a6f127d;
|
||||
bytes32 internal constant docsDomainNode = 0xd7b8aac14a9b2507ab99b5fde3060197fddb9735afa9bf38b1f7e34923cb935e;
|
||||
bytes32 internal constant relayersUiSiteDomainNode = 0x5d1d6b09c964d7e0f4511d6dc896d8cc8899508fb73a202ecfa80a7f50ae3d8a;
|
||||
bytes32 internal constant relayersUiSiteOldDomainNode = 0x4e37047f2c961db41dfb7d38cf79ca745faf134a8392cfb834d3a93330b9108d;
|
||||
bytes32 internal constant downloadScriptSourceDomainNode = 0x4a6bb62eaa2524f194a206df4c15dcc8e9a93036119d40516dab5b7c021fa43b;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainNode = 0xb0406167f975c3168de8d385bb5a6c6bd572727ad505e37734e0a6ec54201a75;
|
||||
bytes32 internal constant docsSourceDomainNode = 0xdd158a78d03e8c953fe2b54edcf9f9919efaec1d782a6603b3f8f5871107672c;
|
||||
bytes32 internal constant relayersUISourceDomainNode = 0x0315c3730f5894b97933d148a24f1b29f823c6a64caadc4a55b5600b510234b2;
|
||||
bytes32 internal constant relayerSoftwareSourceNode = 0xedfb4f99b2a0b005fa627cfd899fabc4ca52f23df310c32597fa23c593220877;
|
||||
|
||||
bytes32 internal constant rootTornadoDomainLabelhash = 0xe5b71d8431579082519dd1ae04b9f23df1cecbfd6f54a6cd9ae12eb0ab7f96f3;
|
||||
bytes32 internal constant sourcesDomainLabelhash = 0x6ee89d35dcb4b9803f51dc5e513c1c1714149cf0821537078d8ad61616e49f2b;
|
||||
bytes32 internal constant docsDomainLabelhash = 0x6bf9054545420e9e9f4aa4f353a32c7d0d52c11dbcdda56c53be8375cafeebb1;
|
||||
bytes32 internal constant relayersUiSiteDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant relayersUiSiteOldDomainLabelhash = 0x25e5cde5b364d3ffc5a7c8fecda7cf863701488fc2dd91fb4c9e6c59e62bad4a;
|
||||
bytes32 internal constant downloadScriptSourceDomainLabelhash = 0xedb311f245ef85f918a5790470448cf17c7d06961f4dfa42cc41616de7f8c2e1;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainLabelhash = 0x0825203969ee8c01895e26a522db220e9541acc7b27e3cb4a1a9317cb0c30bfb;
|
||||
bytes32 internal constant docsSourceDomainLabelhash = 0x6bf9054545420e9e9f4aa4f353a32c7d0d52c11dbcdda56c53be8375cafeebb1;
|
||||
bytes32 internal constant relayersUISourceDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant relayerSoftwareSourceLabelhash = 0x802cf867c2da464d4ff0ebc4dfcccdfbd65d75a8bc1c273fb02e80bf3446b516;
|
9
data/ipfsV1CIDs.txt
Normal file
9
data/ipfsV1CIDs.txt
Normal file
@ -0,0 +1,9 @@
|
||||
const relayersUiSourceIpfsCid = "bafybeids3v76bc6jqqcmhixealnmqf2wfmsthksutrdv5dufxgrgnpcqpq";
|
||||
const relayersUiSiteIpfsCid = "bafybeicsuuzr6l7vpttvwl5urbyof4pqouwq3iva2yjbaqbizzmtbf3k3m";
|
||||
const relayersUiOldSiteIpfsCid = "bafybeicsuuzr6l7vpttvwl5urbyof4pqouwq3iva2yjbaqbizzmtbf3k3m";
|
||||
const downloadScriptSourceIpfsCid = "bafybeiepown476yzjs2zcymrn3t7d4oseuaw6a2rjnkdbu73jrp3evfdxm";
|
||||
const ipfsHostHelpScriptSourceIpfsCid = "bafybeiamry2yocpde5lnuflghguk5w7wsuajbvhhhqw4nyoacl7fw6he5e";
|
||||
const downloadInstructionsHtmlIpfsCid = "bafybeia2s5em2xypmtdifuyj62xwgveujygs4vzoqhbqd2um45wbdxxb6u";
|
||||
const tornadoRelayerSoftwareSourceIpfsCid = "bafybeidh4nrg4wmz5th35gwrjw4vuqf5dqzdax2yb436wpzmsu2qe2vh3e";
|
||||
const docsSourceIpfsCid = "bafybeifafnwfqrtrlsxhbuhxu7pqts6jfg227f6trxitb76ujkqk34q5vi";
|
||||
const docsSiteIpfsCid = "bafybeidbkei7sleaq6sguol7o4cg3dao5vl3e753siq6jutqgb7q7myxuq";
|
21
data/test/ensNodesDeclarations.txt
Normal file
21
data/test/ensNodesDeclarations.txt
Normal file
@ -0,0 +1,21 @@
|
||||
bytes32 internal constant rootTornadoDomainNode = 0xa8f2228d0331c20e8d36b0bf33b102b5b8d8d416db25502b04e5b854d7a5c556;
|
||||
bytes32 internal constant sourcesDomainNode = 0x857d0c409cbb3112c1b9a6a2c1fb1ac516630d9c263cb04bf3d5a32407b936d5;
|
||||
bytes32 internal constant docsDomainNode = 0x06e536502f65df80c0a9013069725d2b0e90c8bd0191f526734b520d495d0659;
|
||||
bytes32 internal constant relayersUiSiteDomainNode = 0x4df656d467b9ec37b486def2c97d7175ee02a0a48b475f847fb8203d0df526b3;
|
||||
bytes32 internal constant relayersUiSiteOldDomainNode = 0x63faf07f77e39e4343415ee019ba0502f3a9ec0374e8aa201ec72fddd8603eeb;
|
||||
bytes32 internal constant downloadScriptSourceDomainNode = 0x3ca990173243a16600a2c480447f5506291f48aaccc152c6ceb05ab13b26dd1a;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainNode = 0x1faa2f3d84c92ca774b5b6ac77b83f0789a7f3ff652bedac0806ef08cf335a22;
|
||||
bytes32 internal constant docsSourceDomainNode = 0x2c6d4d7c3f94987894b9893d813e5f15447b2e63534f423cbdf97490ceccd57c;
|
||||
bytes32 internal constant relayersUISourceDomainNode = 0x1e0e78434fb4ccd771715e5ef7cb66253591943a3d863d3d75f2be3418904dea;
|
||||
bytes32 internal constant relayerSoftwareSourceNode = 0x9ecada456dfbf930ac79577caae66a43d989d1c2960cf6cac116699707808bec;
|
||||
|
||||
bytes32 internal constant rootTornadoDomainLabelhash = 0x28d5131e4f60044a3e4d52eb398a7f8f08b6b7e01040696e895a1f81029fca83;
|
||||
bytes32 internal constant sourcesDomainLabelhash = 0x6ee89d35dcb4b9803f51dc5e513c1c1714149cf0821537078d8ad61616e49f2b;
|
||||
bytes32 internal constant docsDomainLabelhash = 0x6bf9054545420e9e9f4aa4f353a32c7d0d52c11dbcdda56c53be8375cafeebb1;
|
||||
bytes32 internal constant relayersUiSiteDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant relayersUiSiteOldDomainLabelhash = 0x25e5cde5b364d3ffc5a7c8fecda7cf863701488fc2dd91fb4c9e6c59e62bad4a;
|
||||
bytes32 internal constant downloadScriptSourceDomainLabelhash = 0xedb311f245ef85f918a5790470448cf17c7d06961f4dfa42cc41616de7f8c2e1;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainLabelhash = 0x0825203969ee8c01895e26a522db220e9541acc7b27e3cb4a1a9317cb0c30bfb;
|
||||
bytes32 internal constant docsSourceDomainLabelhash = 0x6bf9054545420e9e9f4aa4f353a32c7d0d52c11dbcdda56c53be8375cafeebb1;
|
||||
bytes32 internal constant relayersUISourceDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant relayerSoftwareSourceLabelhash = 0x802cf867c2da464d4ff0ebc4dfcccdfbd65d75a8bc1c273fb02e80bf3446b516;
|
26
foundry.toml
Normal file
26
foundry.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[profile.default]
|
||||
# General
|
||||
src = 'src'
|
||||
out = 'out'
|
||||
libs = ["node_modules", "lib"]
|
||||
|
||||
# Compiler
|
||||
auto_detect_solc = true
|
||||
via_ir = true
|
||||
optimizer = true
|
||||
optimizer_runs = 200
|
||||
auto_detect_remappings = true
|
||||
|
||||
# Network
|
||||
chain_id = 1
|
||||
|
||||
# Tests
|
||||
verbosity = 3
|
||||
|
||||
[rpc_endpoints]
|
||||
mainnet = "${MAINNET_RPC_URL}"
|
||||
|
||||
[fmt]
|
||||
line_length = 140
|
||||
number_underscore = 'thousands'
|
||||
bracket_spacing = true
|
0
lib/.gitkeep
Normal file
0
lib/.gitkeep
Normal file
1
lib/forge-std
Submodule
1
lib/forge-std
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c4aaed668ae0900dbae646ef1bb43cad2e95097c
|
30
package.json
Normal file
30
package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "proposal-31",
|
||||
"version": "1.0.0",
|
||||
"repository": "https://git.tornado.ws/Theo/proposal-31-finalize-decentralized-sources-and-rescue-usdt",
|
||||
"author": "Theo",
|
||||
"license": "MIT",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"calculateENS": "npx ts-node scripts/calculateENSNodes.ts",
|
||||
"calculateIpfsV1Cids": "npx ts-node scripts/calculateIpfsV1Cids",
|
||||
"calculateIpfs": "npx ts-node scripts/calculateIPFSContenthashes",
|
||||
"init": "cd lib && git clone --recurse-submodules https://github.com/foundry-rs/forge-std",
|
||||
"test:calculateENS": "npx ts-node scripts/test/calculateENSNodes.ts",
|
||||
"test:windows": ".\\.env.bat && forge test",
|
||||
"test:linux": ". .env && forge test",
|
||||
"test:gas:windows": ".\\.env.bat && forge test --gas-report",
|
||||
"test:gas:linux": ". .env && forge test --gas-report"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ensdomains/ens-contracts": "^0.0.21",
|
||||
"@ensdomains/eth-ens-namehash": "^2.0.15",
|
||||
"@openzeppelin/contracts": "^4.9.0",
|
||||
"@openzeppelin/upgrades-core": "^1.26.2",
|
||||
"base58-solidity": "^1.0.2",
|
||||
"content-hash": "^2.5.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
11
remappings.txt
Normal file
11
remappings.txt
Normal file
@ -0,0 +1,11 @@
|
||||
@root/=src/
|
||||
@interfaces/=src/interfaces
|
||||
@proprietary/=src/proprietary
|
||||
@forge-std/=lib/forge-std/src/
|
||||
|
||||
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
|
||||
@openzeppelin/upgrades/=node_modules/@openzeppelin/upgrades-core/
|
||||
@ens/contracts/=node_modules/@ensdomains/ens-contracts/contracts/
|
||||
@gnosis/contracts/=node_modules/@gnosis.pm/safe-contracts/contracts/
|
||||
@gnosis/ido-contracts/=node_modules/@gnosis.pm/ido-contracts/contracts/
|
||||
@torn-token/=node_modules/torn-token/
|
35
scripts/calculateENSNodes.ts
Normal file
35
scripts/calculateENSNodes.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
// @ts-ignore
|
||||
import { hash } from "@ensdomains/eth-ens-namehash";
|
||||
import { keccak_256 } from "js-sha3";
|
||||
import { DeclCalculator } from "./utils";
|
||||
import { ensDomains } from "./constants";
|
||||
|
||||
const getLabelhashFromDomain = (ensDomain: string) => "0x" + keccak_256(ensDomain.split(".")[0]);
|
||||
|
||||
const solidityInContractPadding = " ".repeat(4);
|
||||
const { calculateDecl: calculateNodeDecl } = new DeclCalculator(
|
||||
"bytes32 internal constant",
|
||||
solidityInContractPadding,
|
||||
hash,
|
||||
(name: string) => name + "Node"
|
||||
);
|
||||
const { calculateDecl: calculateLabelDecl } = new DeclCalculator(
|
||||
"bytes32 internal constant",
|
||||
solidityInContractPadding,
|
||||
getLabelhashFromDomain,
|
||||
(name: string) => name + "Labelhash"
|
||||
);
|
||||
|
||||
const solidityCode =
|
||||
Object.entries(ensDomains)
|
||||
.map((e) => calculateNodeDecl(e))
|
||||
.join("") +
|
||||
"\n" +
|
||||
Object.entries(ensDomains)
|
||||
.map((e) => calculateLabelDecl(e))
|
||||
.join("");
|
||||
|
||||
fs.writeFileSync(path.join("data", "ensNodesDeclarations.txt"), solidityCode);
|
23
scripts/calculateIPFSContenthashes.ts
Normal file
23
scripts/calculateIPFSContenthashes.ts
Normal file
@ -0,0 +1,23 @@
|
||||
// @ts-ignore
|
||||
import contentHash from "content-hash";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
import { DeclCalculator } from "./utils";
|
||||
import { ipfsCids } from "./constants";
|
||||
|
||||
const contentHashToBytesMemory = (hash: string) => `hex"${hash}"`;
|
||||
const ipfsCidToBytesMemory = (cid: string) => contentHashToBytesMemory(contentHash.fromIpfs(cid));
|
||||
|
||||
const solidityDoublePadding = " ".repeat(8);
|
||||
const { calculateDecl: calculateContenthashDecl } = new DeclCalculator(
|
||||
"bytes memory",
|
||||
solidityDoublePadding,
|
||||
ipfsCidToBytesMemory,
|
||||
(name: string) => name + "Contenthash"
|
||||
);
|
||||
const solidityCode = Object.entries(ipfsCids)
|
||||
.map((e) => calculateContenthashDecl(e))
|
||||
.join("");
|
||||
|
||||
fs.writeFileSync(path.join("data", "ensDomainsIPFSContenthashes.txt"), solidityCode);
|
15
scripts/calculateIpfsV1Cids.ts
Normal file
15
scripts/calculateIpfsV1Cids.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import CID from "cids";
|
||||
|
||||
import { DeclCalculator } from "./utils";
|
||||
import { ipfsCids } from "./constants";
|
||||
|
||||
const convertCIDToV1 = (cidV0: string) => `"${new CID(cidV0).toV1().toString()}"`;
|
||||
|
||||
const { calculateDecl } = new DeclCalculator("const", "", convertCIDToV1, (name: string) => name + "IpfsCid");
|
||||
const typescriptCode = Object.entries(ipfsCids)
|
||||
.map((e) => calculateDecl(e))
|
||||
.join("");
|
||||
|
||||
fs.writeFileSync(path.join(".", "data", "ipfsV1CIDs.txt"), typescriptCode);
|
27
scripts/constants.ts
Normal file
27
scripts/constants.ts
Normal file
@ -0,0 +1,27 @@
|
||||
const rootTornadoDomain = "tornadocash.eth";
|
||||
const sourcesDomain = "sources." + rootTornadoDomain;
|
||||
|
||||
export const ensDomains = {
|
||||
rootTornadoDomain,
|
||||
sourcesDomain,
|
||||
docsDomain: "docs." + rootTornadoDomain,
|
||||
relayersUiSiteDomain: "relayers-ui." + rootTornadoDomain,
|
||||
relayersUiSiteOldDomain: "relayers-network." + rootTornadoDomain,
|
||||
downloadScriptSourceDomain: "download." + sourcesDomain,
|
||||
ipfsHostHelpScriptSourceDomain: "help." + sourcesDomain,
|
||||
docsSourceDomain: "docs." + sourcesDomain,
|
||||
relayersUISourceDomain: "relayers-ui." + sourcesDomain,
|
||||
relayerSoftwareSource: "relayer." + sourcesDomain,
|
||||
};
|
||||
|
||||
export const ipfsCids = {
|
||||
relayersUiSource: "QmW535jPAscFPqh5M38YjLcwJDJjBrT6ZRtqQqCPF19SzF",
|
||||
relayersUiSite: "QmTuGF7kKRjWRjmbxg5qMox622T2VftYiZWKjRpRvYkUN6",
|
||||
relayersUiOldSite: "QmTuGF7kKRjWRjmbxg5qMox622T2VftYiZWKjRpRvYkUN6",
|
||||
downloadScriptSource: "QmXzf2Lymv1YStHiiMaFrEDxkD4o4cN8cdS6N82voSaTpv",
|
||||
ipfsHostHelpScriptSource: "QmPBfNYr7hWtpUGNbTgYzaXa6wPp5HcEysZH7pNn9zyEqe",
|
||||
downloadInstructionsHtml: "QmQ8T782t6TDFKoZLeVeQaHabgaGjNnTGk86zKMPE4uHtx",
|
||||
tornadoRelayerSoftwareSource: "QmVLBoVZAkigrf7x1VHx4aeCHMX5HFwa9cmKGEcC1eUP9i",
|
||||
docsSource: "QmZ7tLxVF5nwmTNwq61MMf7gnUxh85t5Rs6ixxcwu1gRay",
|
||||
docsSite: "QmUtXxMHnLGxsG3Mqm3hhQ2rByFsehSqS57LiEKpEdEiHR",
|
||||
};
|
50
scripts/test/calculateENSNodes.ts
Normal file
50
scripts/test/calculateENSNodes.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
// @ts-ignore
|
||||
import { hash } from "@ensdomains/eth-ens-namehash";
|
||||
import { keccak_256 } from "js-sha3";
|
||||
import { DeclCalculator } from "../utils";
|
||||
|
||||
// Different domain for Goerli testing
|
||||
const rootTornadoDomain = "tornadotest.eth";
|
||||
const sourcesDomain = "sources." + rootTornadoDomain;
|
||||
const ensDomains = {
|
||||
rootTornadoDomain,
|
||||
sourcesDomain,
|
||||
docsDomain: "docs." + rootTornadoDomain,
|
||||
relayersUiSiteDomain: "relayers-ui." + rootTornadoDomain,
|
||||
relayersUiSiteOldDomain: "relayers-network." + rootTornadoDomain,
|
||||
downloadScriptSourceDomain: "download." + sourcesDomain,
|
||||
ipfsHostHelpScriptSourceDomain: "help." + sourcesDomain,
|
||||
docsSourceDomain: "docs." + sourcesDomain,
|
||||
relayersUISourceDomain: "relayers-ui." + sourcesDomain,
|
||||
relayerSoftwareSource: "relayer." + sourcesDomain,
|
||||
};
|
||||
|
||||
const getLabelhashFromDomain = (ensDomain: string) => "0x" + keccak_256(ensDomain.split(".")[0]);
|
||||
|
||||
const solidityInContractPadding = " ".repeat(4);
|
||||
const { calculateDecl: calculateNodeDecl } = new DeclCalculator(
|
||||
"bytes32 internal constant",
|
||||
solidityInContractPadding,
|
||||
hash,
|
||||
(name: string) => name + "Node"
|
||||
);
|
||||
const { calculateDecl: calculateLabelDecl } = new DeclCalculator(
|
||||
"bytes32 internal constant",
|
||||
solidityInContractPadding,
|
||||
getLabelhashFromDomain,
|
||||
(name: string) => name + "Labelhash"
|
||||
);
|
||||
|
||||
const solidityCode =
|
||||
Object.entries(ensDomains)
|
||||
.map((e) => calculateNodeDecl(e))
|
||||
.join("") +
|
||||
"\n" +
|
||||
Object.entries(ensDomains)
|
||||
.map((e) => calculateLabelDecl(e))
|
||||
.join("");
|
||||
|
||||
fs.writeFileSync(path.join("data", "test", "ensNodesDeclarations.txt"), solidityCode);
|
34
scripts/utils.ts
Normal file
34
scripts/utils.ts
Normal file
@ -0,0 +1,34 @@
|
||||
type NodeVarObject = { [key: string]: string };
|
||||
type NodeVarArray = [string, string];
|
||||
|
||||
const solidityCodePadding = " ".repeat(8);
|
||||
const pad = (decl: string, padding: string = solidityCodePadding) => padding + decl + "\n";
|
||||
|
||||
class DeclCalculator {
|
||||
public constructor(
|
||||
private declType: string,
|
||||
private padding: string = solidityCodePadding,
|
||||
private transformator: Function = (
|
||||
() => (x: any) =>
|
||||
x
|
||||
)(),
|
||||
private variableNameChanger: Function = (
|
||||
() => (x: any) =>
|
||||
x
|
||||
)()
|
||||
) {}
|
||||
|
||||
private displayVariableName(varObj: NodeVarObject) {
|
||||
return Object.keys(varObj)[0];
|
||||
}
|
||||
|
||||
public calculateDecl = (varInfo: NodeVarObject | NodeVarArray, type: string = "bytes32") => {
|
||||
const solidityVariableName = this.variableNameChanger(Array.isArray(varInfo) ? varInfo[0] : this.displayVariableName(varInfo));
|
||||
const solidityVariableValue = this.transformator(Array.isArray(varInfo) ? varInfo[1] : Object.values(varInfo)[0]);
|
||||
const solidityDeclaration = `${this.declType || type} ${solidityVariableName} = ${solidityVariableValue};`;
|
||||
|
||||
return pad(solidityDeclaration, this.padding);
|
||||
};
|
||||
}
|
||||
|
||||
export { DeclCalculator };
|
67
src/UpdateENSDataProposal.sol
Normal file
67
src/UpdateENSDataProposal.sol
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
import { ITorn } from "@interfaces/ITornToken.sol";
|
||||
import { IENSRegistry } from "@interfaces/IENSRegistry.sol";
|
||||
import { IENSResolver } from "@interfaces/IENSResolver.sol";
|
||||
|
||||
contract UpdateENSDataProposal {
|
||||
address constant usdtTokenAddress = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
|
||||
address constant tornTokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
|
||||
address constant governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
|
||||
address payable constant developerAddress = payable(0x9Ff3C1Bea9ffB56a78824FE29f457F066257DD58);
|
||||
|
||||
address constant ensResolverAddress = 0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41;
|
||||
address constant ensRegistryAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
|
||||
|
||||
IENSRegistry internal constant ensRegistry = IENSRegistry(ensRegistryAddress);
|
||||
IENSResolver internal constant ensResolver = IENSResolver(ensResolverAddress);
|
||||
|
||||
bytes32 internal constant rootTornadoDomainNode = 0xe6ae31d630cc7a8279c0f1c7cbe6e7064814c47d1785fa2703d9ae511ee2be0c;
|
||||
bytes32 internal constant sourcesDomainNode = 0x4e5775b58e8aeaa32fc2b429c9485da9de5a1c6fead70b8704ce0f970a6f127d;
|
||||
bytes32 internal constant docsDomainNode = 0xd7b8aac14a9b2507ab99b5fde3060197fddb9735afa9bf38b1f7e34923cb935e;
|
||||
bytes32 internal constant relayersUiSiteDomainNode = 0x5d1d6b09c964d7e0f4511d6dc896d8cc8899508fb73a202ecfa80a7f50ae3d8a;
|
||||
bytes32 internal constant relayersUiSiteOldDomainNode = 0x4e37047f2c961db41dfb7d38cf79ca745faf134a8392cfb834d3a93330b9108d;
|
||||
bytes32 internal constant downloadScriptSourceDomainNode = 0x4a6bb62eaa2524f194a206df4c15dcc8e9a93036119d40516dab5b7c021fa43b;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainNode = 0xb0406167f975c3168de8d385bb5a6c6bd572727ad505e37734e0a6ec54201a75;
|
||||
bytes32 internal constant docsSourceDomainNode = 0xdd158a78d03e8c953fe2b54edcf9f9919efaec1d782a6603b3f8f5871107672c;
|
||||
bytes32 internal constant relayersUISourceDomainNode = 0x0315c3730f5894b97933d148a24f1b29f823c6a64caadc4a55b5600b510234b2;
|
||||
bytes32 internal constant relayerSoftwareSourceNode = 0xedfb4f99b2a0b005fa627cfd899fabc4ca52f23df310c32597fa23c593220877;
|
||||
|
||||
bytes32 internal constant relayersUiSiteDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainLabelhash = 0x0825203969ee8c01895e26a522db220e9541acc7b27e3cb4a1a9317cb0c30bfb;
|
||||
bytes32 internal constant relayerSoftwareSourceLabelhash = 0x802cf867c2da464d4ff0ebc4dfcccdfbd65d75a8bc1c273fb02e80bf3446b516;
|
||||
|
||||
function executeProposal() public {
|
||||
// Register missing subnodes, set Governance as an owner
|
||||
ensRegistry.setSubnodeRecord(rootTornadoDomainNode, relayersUiSiteDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, relayerSoftwareSourceLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, ipfsHostHelpScriptSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
// From data/ensDomainsIPFSContenthashes.txt, calculated via scripts/calculateIPFSContenthashes.ts
|
||||
bytes memory relayersUiSourceContenthash = hex"e3010170122072dd7fe08bc98404c3a2e402dac817562b2533aa549c475e8e85b9a266bc507c";
|
||||
bytes memory relayersUiSiteContenthash = hex"e3010170122052a5331f2ff57ce75b2fb48870e2f1f0752d0da2a0d612104028ce5930976adb";
|
||||
bytes memory downloadScriptSourceContenthash = hex"e301017012208f759bcffb194cb59161916ee7f1f1d225016f03514b5430d3fb4c5fb254a3bb";
|
||||
bytes memory ipfsHostHelpScriptSourceContenthash = hex"e301017012200c8e358709e32756da156639a8aedbf6950090d4e73c2dc6e1c012fe5b78e4e9";
|
||||
bytes memory downloadInstructionsHtmlContenthash = hex"e301017012201a9748cd5f0f64c682d309f6af6354944e0d2e572e81c301ea8ce76c11dee1f5";
|
||||
bytes memory tornadoRelayerSoftwareSourceContenthash =
|
||||
hex"e3010170122067e3626e5999eccfbe9ad14db95a40bd1c32305f580f37eb3f2c9535026aa7d9";
|
||||
bytes memory docsSourceContenthash = hex"e30101701220a02b6c5846715cae70d0f7a7df09cbc929b5af97d38dd130ffd44aa0adf21daa";
|
||||
bytes memory docsSiteContenthash = hex"e30101701220615111f92c8087a46a397f77046d8c0eed57b27fbb9221e4d270307f0fb317a4";
|
||||
|
||||
// Set IPFS Cids in ENS subdomain contenthashes
|
||||
ensResolver.setContenthash(sourcesDomainNode, downloadInstructionsHtmlContenthash);
|
||||
ensResolver.setContenthash(downloadScriptSourceDomainNode, downloadScriptSourceContenthash);
|
||||
ensResolver.setContenthash(relayerSoftwareSourceNode, tornadoRelayerSoftwareSourceContenthash);
|
||||
ensResolver.setContenthash(docsSourceDomainNode, docsSourceContenthash);
|
||||
ensResolver.setContenthash(relayersUISourceDomainNode, relayersUiSourceContenthash);
|
||||
ensResolver.setContenthash(relayersUiSiteDomainNode, relayersUiSiteContenthash);
|
||||
ensResolver.setContenthash(relayersUiSiteOldDomainNode, relayersUiSiteContenthash);
|
||||
ensResolver.setContenthash(ipfsHostHelpScriptSourceDomainNode, ipfsHostHelpScriptSourceContenthash);
|
||||
ensResolver.setContenthash(docsDomainNode, docsSiteContenthash);
|
||||
|
||||
ITorn(tornTokenAddress).rescueTokens(usdtTokenAddress, developerAddress, 0);
|
||||
}
|
||||
}
|
17
src/interfaces/IENSRegistry.sol
Normal file
17
src/interfaces/IENSRegistry.sol
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
interface IENSRegistry {
|
||||
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external returns (bytes32);
|
||||
|
||||
function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external;
|
||||
|
||||
function resolver(bytes32 node) external view returns (address);
|
||||
|
||||
function setOwner(bytes32 node, address owner) external;
|
||||
|
||||
function owner(bytes32 node) external view returns (address);
|
||||
|
||||
function recordExists(bytes32 node) external view returns (bool);
|
||||
}
|
13
src/interfaces/IENSResolver.sol
Normal file
13
src/interfaces/IENSResolver.sol
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
interface IENSResolver {
|
||||
function setContenthash(bytes32 node, bytes memory hash) external;
|
||||
|
||||
function setAddr(bytes32 node, address a) external;
|
||||
|
||||
function addr(bytes32 node) external view returns (address);
|
||||
|
||||
function contenthash(bytes32 node) external returns (bytes memory);
|
||||
}
|
57
src/interfaces/IGovernance.sol
Normal file
57
src/interfaces/IGovernance.sol
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
enum ProposalState {
|
||||
Pending,
|
||||
Active,
|
||||
Defeated,
|
||||
Timelocked,
|
||||
AwaitingExecution,
|
||||
Executed,
|
||||
Expired
|
||||
}
|
||||
|
||||
struct Proposal {
|
||||
// Creator of the proposal
|
||||
address proposer;
|
||||
// target addresses for the call to be made
|
||||
address target;
|
||||
// The block at which voting begins
|
||||
uint256 startTime;
|
||||
// The block at which voting ends: votes must be cast prior to this block
|
||||
uint256 endTime;
|
||||
// Current number of votes in favor of this proposal
|
||||
uint256 forVotes;
|
||||
// Current number of votes in opposition to this proposal
|
||||
uint256 againstVotes;
|
||||
// Flag marking whether the proposal has been executed
|
||||
bool executed;
|
||||
// Flag marking whether the proposal voting time has been extended
|
||||
// Voting time can be extended once, if the proposal outcome has changed during CLOSING_PERIOD
|
||||
bool extended;
|
||||
}
|
||||
|
||||
interface IGovernance {
|
||||
function initialized() external view returns (bool);
|
||||
function initializing() external view returns (bool);
|
||||
function EXECUTION_DELAY() external view returns (uint256);
|
||||
function EXECUTION_EXPIRATION() external view returns (uint256);
|
||||
function QUORUM_VOTES() external view returns (uint256);
|
||||
function PROPOSAL_THRESHOLD() external view returns (uint256);
|
||||
function VOTING_DELAY() external view returns (uint256);
|
||||
function VOTING_PERIOD() external view returns (uint256);
|
||||
function CLOSING_PERIOD() external view returns (uint256);
|
||||
function VOTE_EXTEND_TIME() external view returns (uint256);
|
||||
function torn() external view returns (address);
|
||||
function proposals(uint256 index) external view returns (Proposal memory);
|
||||
function proposalCount() external view returns (uint256);
|
||||
function lockedBalance(address account) external view returns (uint256);
|
||||
function propose(address target, string memory description) external returns (uint256);
|
||||
function castVote(uint256 proposalId, bool support) external;
|
||||
function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
|
||||
function unlock(uint256 amount) external;
|
||||
function lockWithApproval(uint256 amount) external;
|
||||
function execute(uint256 proposalId) external payable;
|
||||
function state(uint256 proposalId) external view returns (ProposalState);
|
||||
}
|
7
src/interfaces/ITornToken.sol
Normal file
7
src/interfaces/ITornToken.sol
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
interface ITorn {
|
||||
function rescueTokens(address _token, address payable _to, uint256 _balance) external;
|
||||
}
|
14
src/proprietary/TornadoAddresses.sol
Normal file
14
src/proprietary/TornadoAddresses.sol
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract TornadoAddresses {
|
||||
address public constant ENSAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
|
||||
address public constant tornTokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
|
||||
address public constant multisigAddress = 0xb04E030140b30C27bcdfaafFFA98C57d80eDa7B4;
|
||||
address public constant governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
|
||||
address public constant stakingAddress = 0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29;
|
||||
address public constant relayerRegistryAddress = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
|
||||
address public constant feeManagerAddress = 0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7;
|
||||
address public constant governanceVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185;
|
||||
}
|
39
test/ENSNamehash.sol
Normal file
39
test/ENSNamehash.sol
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
/*
|
||||
* @dev Solidity implementation of the ENS namehash algorithm.
|
||||
*
|
||||
* Warning! Does not normalize or validate names before hashing.
|
||||
*/
|
||||
library ENSNamehash {
|
||||
function namehash(bytes memory domain) internal pure returns (bytes32) {
|
||||
return namehash(domain, 0);
|
||||
}
|
||||
|
||||
function namehash(bytes memory domain, uint256 i) internal pure returns (bytes32) {
|
||||
if (domain.length <= i) {
|
||||
return 0x0000000000000000000000000000000000000000000000000000000000000000;
|
||||
}
|
||||
|
||||
uint256 len = LabelLength(domain, i);
|
||||
|
||||
return keccak256(abi.encodePacked(namehash(domain, i + len + 1), keccak(domain, i, len)));
|
||||
}
|
||||
|
||||
function LabelLength(bytes memory domain, uint256 i) private pure returns (uint256) {
|
||||
uint256 len;
|
||||
while (i + len != domain.length && domain[i + len] != 0x2e) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
function keccak(bytes memory data, uint256 offset, uint256 len) private pure returns (bytes32 ret) {
|
||||
require(offset + len <= data.length);
|
||||
assembly {
|
||||
ret := keccak256(add(add(data, 32), offset), len)
|
||||
}
|
||||
}
|
||||
}
|
78
test/GoerliENSDomainOwner.sol
Normal file
78
test/GoerliENSDomainOwner.sol
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IENSResolver } from "@interfaces/IENSResolver.sol";
|
||||
import { IENSRegistry } from "@interfaces/IENSRegistry.sol";
|
||||
import { ENSNamehash } from "./ENSNamehash.sol";
|
||||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
|
||||
|
||||
contract GoerliDomainOwner is Ownable, ERC1155Holder {
|
||||
address internal ensRegistryAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
|
||||
|
||||
IENSRegistry ensRegistry = IENSRegistry(ensRegistryAddress);
|
||||
|
||||
function calculateDomainNode(string memory domain) private pure returns (bytes32) {
|
||||
return ENSNamehash.namehash(bytes(domain));
|
||||
}
|
||||
|
||||
function transferDomainOwnership(string memory domain, address to) public onlyOwner {
|
||||
_transferDomainOwnership(calculateDomainNode(domain), to);
|
||||
}
|
||||
|
||||
function transferSubdomainOwnership(string memory domain, string memory subdomainLabel, address to) public onlyOwner {
|
||||
_transferSubdomainOwnership(domain, subdomainLabel, to);
|
||||
}
|
||||
|
||||
function _transferSubdomainOwnership(string memory domain, string memory subdomainLabel, address to) private {
|
||||
bytes32 rootNode = calculateDomainNode(domain);
|
||||
bytes32 subdomainLabelhash = calculateSubdomainLabelhash(subdomainLabel);
|
||||
bytes32 subdomainNode = keccak256(abi.encodePacked(rootNode, subdomainLabelhash));
|
||||
require(ensRegistry.recordExists(subdomainNode), "Subdomain not registered");
|
||||
require(ensRegistry.owner(rootNode) == address(this), "This contract must be an owner of domain");
|
||||
|
||||
ensRegistry.setSubnodeOwner(rootNode, subdomainLabelhash, to);
|
||||
}
|
||||
|
||||
function _transferDomainOwnership(bytes32 domainNode, address to) private {
|
||||
require(ensRegistry.owner(domainNode) == address(this), "This test contract must be an owner of domain");
|
||||
ensRegistry.setOwner(domainNode, to);
|
||||
}
|
||||
|
||||
function calculateSubdomainLabelhash(string memory subdomainLabel) internal pure returns (bytes32) {
|
||||
return keccak256(bytes(subdomainLabel));
|
||||
}
|
||||
|
||||
function ownSubdomain(string memory domain, string memory subdomainLabel) public onlyOwner {
|
||||
_transferSubdomainOwnership(domain, subdomainLabel, address(this));
|
||||
}
|
||||
|
||||
function registerSubname(string memory domain, string memory subdomainLabel) public onlyOwner {
|
||||
bytes32 rootNode = calculateDomainNode(domain);
|
||||
address rootResolver = ensRegistry.resolver(rootNode);
|
||||
bytes32 subdomainLabelhash = calculateSubdomainLabelhash(subdomainLabel);
|
||||
|
||||
ensRegistry.setSubnodeRecord(rootNode, subdomainLabelhash, address(this), rootResolver, 0);
|
||||
}
|
||||
|
||||
function isContract(address _addr) private view returns (bool) {
|
||||
uint32 size;
|
||||
assembly {
|
||||
size := extcodesize(_addr)
|
||||
}
|
||||
return (size > 0);
|
||||
}
|
||||
|
||||
function execute(address proposal) public onlyOwner {
|
||||
require(isContract(proposal), "not a contract");
|
||||
(bool success, bytes memory data) = proposal.delegatecall(abi.encodeWithSignature("executeProposal()"));
|
||||
if (!success) {
|
||||
if (data.length > 0) {
|
||||
revert(string(data));
|
||||
} else {
|
||||
revert("Proposal execution failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
test/GoerliTestProposal.sol
Normal file
61
test/GoerliTestProposal.sol
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
import { IENSRegistry } from "@interfaces/IENSRegistry.sol";
|
||||
import { IENSResolver } from "@interfaces/IENSResolver.sol";
|
||||
|
||||
contract GoerliTestProposal {
|
||||
address constant governanceAddress = 0x810d00cb74aD4811265Ca3D2E5CE45031f872054;
|
||||
|
||||
address constant ensResolverAddress = 0xd7a4F6473f32aC2Af804B3686AE8F1932bC35750;
|
||||
address constant ensRegistryAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
|
||||
|
||||
IENSRegistry internal constant ensRegistry = IENSRegistry(ensRegistryAddress);
|
||||
IENSResolver internal constant ensResolver = IENSResolver(ensResolverAddress);
|
||||
|
||||
bytes32 internal constant rootTornadoDomainNode = 0xa8f2228d0331c20e8d36b0bf33b102b5b8d8d416db25502b04e5b854d7a5c556;
|
||||
bytes32 internal constant sourcesDomainNode = 0x857d0c409cbb3112c1b9a6a2c1fb1ac516630d9c263cb04bf3d5a32407b936d5;
|
||||
bytes32 internal constant docsDomainNode = 0x06e536502f65df80c0a9013069725d2b0e90c8bd0191f526734b520d495d0659;
|
||||
bytes32 internal constant relayersUiSiteDomainNode = 0x4df656d467b9ec37b486def2c97d7175ee02a0a48b475f847fb8203d0df526b3;
|
||||
bytes32 internal constant relayersUiSiteOldDomainNode = 0x63faf07f77e39e4343415ee019ba0502f3a9ec0374e8aa201ec72fddd8603eeb;
|
||||
bytes32 internal constant downloadScriptSourceDomainNode = 0x3ca990173243a16600a2c480447f5506291f48aaccc152c6ceb05ab13b26dd1a;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainNode = 0x1faa2f3d84c92ca774b5b6ac77b83f0789a7f3ff652bedac0806ef08cf335a22;
|
||||
bytes32 internal constant docsSourceDomainNode = 0x2c6d4d7c3f94987894b9893d813e5f15447b2e63534f423cbdf97490ceccd57c;
|
||||
bytes32 internal constant relayersUISourceDomainNode = 0x1e0e78434fb4ccd771715e5ef7cb66253591943a3d863d3d75f2be3418904dea;
|
||||
bytes32 internal constant relayerSoftwareSourceNode = 0x9ecada456dfbf930ac79577caae66a43d989d1c2960cf6cac116699707808bec;
|
||||
|
||||
bytes32 internal constant relayersUiSiteDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant ipfsHostHelpScriptSourceDomainLabelhash = 0x0825203969ee8c01895e26a522db220e9541acc7b27e3cb4a1a9317cb0c30bfb;
|
||||
bytes32 internal constant relayerSoftwareSourceLabelhash = 0x802cf867c2da464d4ff0ebc4dfcccdfbd65d75a8bc1c273fb02e80bf3446b516;
|
||||
|
||||
function executeProposal() public {
|
||||
// Register missing subnodes, set Governance as an owner
|
||||
ensRegistry.setSubnodeRecord(rootTornadoDomainNode, relayersUiSiteDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, relayerSoftwareSourceLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, ipfsHostHelpScriptSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
// From data/ensDomainsIPFSContenthashes.txt, calculated via scripts/calculateIPFSContenthashes.ts
|
||||
bytes memory relayersUiSourceContenthash = hex"e3010170122072dd7fe08bc98404c3a2e402dac817562b2533aa549c475e8e85b9a266bc507c";
|
||||
bytes memory relayersUiSiteContenthash = hex"e3010170122052a5331f2ff57ce75b2fb48870e2f1f0752d0da2a0d612104028ce5930976adb";
|
||||
bytes memory downloadScriptSourceContenthash = hex"e301017012208f759bcffb194cb59161916ee7f1f1d225016f03514b5430d3fb4c5fb254a3bb";
|
||||
bytes memory ipfsHostHelpScriptSourceContenthash = hex"e301017012200c8e358709e32756da156639a8aedbf6950090d4e73c2dc6e1c012fe5b78e4e9";
|
||||
bytes memory downloadInstructionsHtmlContenthash = hex"e301017012201a9748cd5f0f64c682d309f6af6354944e0d2e572e81c301ea8ce76c11dee1f5";
|
||||
bytes memory tornadoRelayerSoftwareSourceContenthash =
|
||||
hex"e3010170122067e3626e5999eccfbe9ad14db95a40bd1c32305f580f37eb3f2c9535026aa7d9";
|
||||
bytes memory docsSourceContenthash = hex"e30101701220a02b6c5846715cae70d0f7a7df09cbc929b5af97d38dd130ffd44aa0adf21daa";
|
||||
bytes memory docsSiteContenthash = hex"e30101701220615111f92c8087a46a397f77046d8c0eed57b27fbb9221e4d270307f0fb317a4";
|
||||
|
||||
// Set IPFS Cids in ENS subdomain contenthashes
|
||||
ensResolver.setContenthash(sourcesDomainNode, downloadInstructionsHtmlContenthash);
|
||||
ensResolver.setContenthash(downloadScriptSourceDomainNode, downloadScriptSourceContenthash);
|
||||
ensResolver.setContenthash(relayerSoftwareSourceNode, tornadoRelayerSoftwareSourceContenthash);
|
||||
ensResolver.setContenthash(docsSourceDomainNode, docsSourceContenthash);
|
||||
ensResolver.setContenthash(relayersUISourceDomainNode, relayersUiSourceContenthash);
|
||||
ensResolver.setContenthash(relayersUiSiteDomainNode, relayersUiSiteContenthash);
|
||||
ensResolver.setContenthash(relayersUiSiteOldDomainNode, relayersUiSiteContenthash);
|
||||
ensResolver.setContenthash(ipfsHostHelpScriptSourceDomainNode, ipfsHostHelpScriptSourceContenthash);
|
||||
ensResolver.setContenthash(docsDomainNode, docsSiteContenthash);
|
||||
}
|
||||
}
|
167
test/GoerliTestProposal30.sol
Normal file
167
test/GoerliTestProposal30.sol
Normal file
@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
import { IENSRegistry } from "@interfaces/IENSRegistry.sol";
|
||||
import { IENSResolver } from "@interfaces/IENSResolver.sol";
|
||||
|
||||
contract GoerliTestProposal30 {
|
||||
address constant governanceAddress = 0x810d00cb74aD4811265Ca3D2E5CE45031f872054;
|
||||
|
||||
address constant ensResolverAddress = 0xd7a4F6473f32aC2Af804B3686AE8F1932bC35750;
|
||||
address constant ensRegistryAddress = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
|
||||
|
||||
IENSRegistry internal constant ensRegistry = IENSRegistry(ensRegistryAddress);
|
||||
IENSResolver internal constant ensResolver = IENSResolver(ensResolverAddress);
|
||||
|
||||
bytes32 internal constant rootTornadoDomainNode = 0xa8f2228d0331c20e8d36b0bf33b102b5b8d8d416db25502b04e5b854d7a5c556;
|
||||
bytes32 internal constant sourcesDomainNode = 0x857d0c409cbb3112c1b9a6a2c1fb1ac516630d9c263cb04bf3d5a32407b936d5;
|
||||
bytes32 internal constant minifiedSourcesDomainNode = 0x0b7a6db16524d96c9c45252b05191330e5cd76af1a65e883f15a6b0df143ea72;
|
||||
bytes32 internal constant packagesDomainNode = 0xcc0d5182bef33b3ece771ca070bdff76ab80c3af59951aa41995e0ddd1a307f1;
|
||||
bytes32 internal constant downloadScriptSourceDomainNode = 0x3ca990173243a16600a2c480447f5506291f48aaccc152c6ceb05ab13b26dd1a;
|
||||
bytes32 internal constant classicUISourceDomainNode = 0x0b5e06d4c6e76faae426647aceda719067818b62a53350ad34f73792e8850254;
|
||||
bytes32 internal constant novaUISourceDomainNode = 0x38676e6f1e375cea26d79df47f589850623e84cf77426cdccd8e8e50c964dfdf;
|
||||
bytes32 internal constant docsSourceDomainNode = 0x2c6d4d7c3f94987894b9893d813e5f15447b2e63534f423cbdf97490ceccd57c;
|
||||
bytes32 internal constant relayersUISourceDomainNode = 0x1e0e78434fb4ccd771715e5ef7cb66253591943a3d863d3d75f2be3418904dea;
|
||||
bytes32 internal constant tornTokenSourceDomainNode = 0x3a17690a58fe5f6b5b33eef2d2998114a332b4feb3e8f06f818542f4d528e3eb;
|
||||
bytes32 internal constant classicRelayerSoftwareSourceDomainNode = 0x0e30230d2c81771372c21b8c82b957bf8a44cbb48a3a0396e3a7bc593577d72e;
|
||||
bytes32 internal constant novaRelayerSoftwareSourceDomainNode = 0x1c1bc2a95e6db3a336aca1f33ebaae0af0343c5a2b0ca9cb03f56fd8631557f0;
|
||||
bytes32 internal constant tornadoCliSourceDomainNode = 0x8fd0043a38548a5022a557c3e196e2aa9de038f2f6036ad565e842f43565af21;
|
||||
bytes32 internal constant infoPageSourceDomainNode = 0x51c628ee8a039a17cfc4509e671da25e2832ce9d496c0dce2525e67ab14c4b06;
|
||||
bytes32 internal constant classicUIMinifiedDomainNode = 0xbf189e20cf74064173ac3d9b572f36268de3a74416c0743b80f80a72e77c39c5;
|
||||
bytes32 internal constant novaMinifiedDomainNode = 0xaba43caec785b400d898195b430e1d67e9c242d0873b24c51e0988a7b7c4c3ec;
|
||||
bytes32 internal constant tornadoCliMinifiedDomainNode = 0xeb5a0c348b96ea0a86ffba4cc09329cafed4e7858a3b09b9e4951fc45b155051;
|
||||
bytes32 internal constant websnarkPackageDomainNode = 0xd5dc0d0f67049b9973792539efbc65c74f1ccfa34bcacc245d95fef528348f31;
|
||||
bytes32 internal constant circomlibPackageDomainNode = 0x5c0d325132700969f3a5d9cc29362934547c6b547d9f2de89667cf25976d4030;
|
||||
bytes32 internal constant snarkjsPackageDomainNode = 0x68d17fc00031d0a157958a4a4aac1f51431ebe1ad3b907649a746fad227934c1;
|
||||
bytes32 internal constant tornadoOraclesPackageDomainNode = 0xd1678f13f0fc6712edd4d8a8ccad982e75df07403c96e65ce1ef2e0df6ccd72c;
|
||||
bytes32 internal constant gasPriceOraclePackageDomainNode = 0xfbe0717768964b98ff37c4d89db1e305e42914fbebd8722bb5b113aa2e34a8b5;
|
||||
bytes32 internal constant tornadoConfigPackageDomainNode = 0xca98d0d3c988c445e30fa8a49981008d16a41f006cd5d1730a90790cf5a5f638;
|
||||
bytes32 internal constant anonymityMiningPackageDomainNode = 0x5627f29b5f86fea22182dd2a20d2a747be3ad0f204e7d8637e60ce2a8505a74f;
|
||||
bytes32 internal constant tornadoTreesPackageDomainNode = 0xb812eb01e6f49f624c16f227ce6680e639476057ad26fe4ec559b08f461a8a3d;
|
||||
bytes32 internal constant fixedMerkleTreePackageDomainNode = 0xea4f316afeb12220db9b9737341ca13329fa73557841cdf344fb895eefeaaecc;
|
||||
bytes32 internal constant txManagerPackageDomainNode = 0x91e6d11b11e5c0a98be4130f69446eb9460afeaae935dbfa6ef7b2361120c75d;
|
||||
bytes32 internal constant merkleRootUpdaterPackageDomainNode = 0xa9f9472a40c96dc4c30470e180df2fd94b75f19161fb5610bff0b4ef2ddf06ab;
|
||||
|
||||
bytes32 internal constant rootTornadoDomainLabelhash = 0x28d5131e4f60044a3e4d52eb398a7f8f08b6b7e01040696e895a1f81029fca83;
|
||||
bytes32 internal constant sourcesDomainLabelhash = 0x6ee89d35dcb4b9803f51dc5e513c1c1714149cf0821537078d8ad61616e49f2b;
|
||||
bytes32 internal constant minifiedSourcesDomainLabelhash = 0x26403be8dc5694ba56b8d49945b813cff19140637d1fa38a3187a07faf4ee073;
|
||||
bytes32 internal constant packagesDomainLabelhash = 0x89c4c51c9264344cbc2ab3aa255b085918a2841af8ffaa3133ceabee961afffd;
|
||||
bytes32 internal constant downloadScriptSourceDomainLabelhash = 0xedb311f245ef85f918a5790470448cf17c7d06961f4dfa42cc41616de7f8c2e1;
|
||||
bytes32 internal constant classicUISourceDomainLabelhash = 0x4e27b2a330e4a0d8d8521393df67e9a24fb2ab5f10f9e640c244d504874322bc;
|
||||
bytes32 internal constant novaUISourceDomainLabelhash = 0xc90e7e9184dce6e0d7fff2e19e72ffa35430aca54bd634ada091bef2d2bb0635;
|
||||
bytes32 internal constant docsSourceDomainLabelhash = 0x6bf9054545420e9e9f4aa4f353a32c7d0d52c11dbcdda56c53be8375cafeebb1;
|
||||
bytes32 internal constant relayersUISourceDomainLabelhash = 0xea7c97223b0629f1c3bea11a57dd6179a12e9cc4bbdf8f69fb999c4051c682cf;
|
||||
bytes32 internal constant tornTokenSourceDomainLabelhash = 0x5d8fec99a5792d7772f788343c7991bf1049b821dcd1b0b900f86e6b7fe7fb25;
|
||||
bytes32 internal constant classicRelayerSoftwareSourceDomainLabelhash =
|
||||
0x7bece1009df269e16c3552ea6ced49b1d66c22438cda5caf73f55ac74bcadea9;
|
||||
bytes32 internal constant novaRelayerSoftwareSourceDomainLabelhash = 0xe01bed58384f9ee9a9dccf26a4236eca42aa8b767efe27c5d191a51885118e5b;
|
||||
bytes32 internal constant tornadoCliSourceDomainLabelhash = 0x92c0fea2a18f1747f48f5503806e5f24d5ccb2c360ef56a462ce254707afa64a;
|
||||
bytes32 internal constant infoPageSourceDomainLabelhash = 0x41c8b7e0e9650ab5d1f55454c8ad68d9d4c6d42f1a8a14878b77e92e9794e610;
|
||||
bytes32 internal constant classicUIMinifiedDomainLabelhash = 0x4e27b2a330e4a0d8d8521393df67e9a24fb2ab5f10f9e640c244d504874322bc;
|
||||
bytes32 internal constant novaMinifiedDomainLabelhash = 0xc90e7e9184dce6e0d7fff2e19e72ffa35430aca54bd634ada091bef2d2bb0635;
|
||||
bytes32 internal constant tornadoCliMinifiedDomainLabelhash = 0x92c0fea2a18f1747f48f5503806e5f24d5ccb2c360ef56a462ce254707afa64a;
|
||||
bytes32 internal constant websnarkPackageDomainLabelhash = 0x50d1752a9b1f31ebf05378927a112194d33596cc02a04c06970477bd8a40c931;
|
||||
bytes32 internal constant circomlibPackageDomainLabelhash = 0x68dc231d08143bcf7cf261e63071bdcb7d606e41dec696e34482f6d1068c4afa;
|
||||
bytes32 internal constant snarkjsPackageDomainLabelhash = 0x31df71a9eb77699aba0f0e6d565af942889afef76e60ee8a9f80c27f2e946065;
|
||||
bytes32 internal constant tornadoOraclesPackageDomainLabelhash = 0xb7a48206cd37ed309fdcdf62fe4b65d6871298645d5e41942f0cd89c08a65cbf;
|
||||
bytes32 internal constant gasPriceOraclePackageDomainLabelhash = 0x05048648c60bebc220ad5a82188a966f910539a7e1947cc8a9ac0ec1cd99ca40;
|
||||
bytes32 internal constant tornadoConfigPackageDomainLabelhash = 0x0b49c88cd3d1ba3c99fdd9a41ced95ec8629bda85e80b6c506c15db62ab8f761;
|
||||
bytes32 internal constant anonymityMiningPackageDomainLabelhash = 0xc3520c36e06133299b24abf819a008b22bc3e9adfa39a38bbccd5cf829831d48;
|
||||
bytes32 internal constant tornadoTreesPackageDomainLabelhash = 0xef1496a9cbb93e123ce8e3a0868374bda8446faafa4c2eb7fce3c7a9465be8df;
|
||||
bytes32 internal constant fixedMerkleTreePackageDomainLabelhash = 0x37441881d8c14192cbe636eb3d4318346c6af80d92971e1357419a1a94e8a2e2;
|
||||
bytes32 internal constant txManagerPackageDomainLabelhash = 0x0d3be7866f858f24a43fd40d3844a410405b3d6abd2255102d8327fa242a4ff3;
|
||||
bytes32 internal constant merkleRootUpdaterPackageDomainLabelhash = 0x1b162702ef4549cb2e6522252d90c0d44fcce15b939897373cfa4f829488cab4;
|
||||
|
||||
function executeProposal() public {
|
||||
// Register all subnodes, set Governance as an owner
|
||||
ensRegistry.setSubnodeRecord(rootTornadoDomainNode, sourcesDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, minifiedSourcesDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, packagesDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, downloadScriptSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, classicUISourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, novaUISourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, docsSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, relayersUISourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, tornTokenSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, novaRelayerSoftwareSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(
|
||||
sourcesDomainNode, classicRelayerSoftwareSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0
|
||||
);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, tornadoCliSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(sourcesDomainNode, infoPageSourceDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
ensRegistry.setSubnodeRecord(minifiedSourcesDomainNode, classicUIMinifiedDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(minifiedSourcesDomainNode, novaMinifiedDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(minifiedSourcesDomainNode, tornadoCliMinifiedDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, websnarkPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, circomlibPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, snarkjsPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, tornadoOraclesPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, gasPriceOraclePackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, tornadoConfigPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, anonymityMiningPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, tornadoTreesPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, fixedMerkleTreePackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, txManagerPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
ensRegistry.setSubnodeRecord(packagesDomainNode, merkleRootUpdaterPackageDomainLabelhash, governanceAddress, ensResolverAddress, 0);
|
||||
|
||||
// From data/ensDomainsIPFSContenthashes.txt, calculated via scripts/calculateIPFSContenthashes.ts
|
||||
bytes memory downloadInstructionsHtmlContenthash = hex"e30101701220810e2b756845f89793b616c56a0b5ab9689da7f6e7fdf93280d05a0969a4902c";
|
||||
bytes memory downloadScriptSourceContenthash = hex"e301017012208d6f8f48d3c2bcb6eaafae3110ad59b5aa2137010d827996ea1b87f39266b4f5";
|
||||
bytes memory classicUiSourceContenthash = hex"e30101701220b674829af0777f2b89ed96020184ee6f04f6cfd2eb176ad2b653b1f2a5563d98";
|
||||
bytes memory classicRelayerSourceContenthash = hex"e301017012205ad0c59d5fcc60e4866ab37f063480ffa305eb84da143894be5baeff2bb8e931";
|
||||
bytes memory novaRelayerSourceContenthash = hex"e30101701220c9106227570ab16e639adb5f05ccde1b367b004f582e0700a00dfb54f914068c";
|
||||
bytes memory relayersUiSourceContenthash = hex"e3010170122046847feae11b2774438df322e014e04652fe029ba59b79df90fafba040ba6550";
|
||||
bytes memory novaUiSourceContenthash = hex"e30101701220b554eed2a9ba47011b6790ff6d23d0480419de78abf723ea7ada55e1664f5976";
|
||||
bytes memory docsSourceContenthash = hex"e30101701220a140c7c35f6f2cc72f77d69b73dbab14ac0ccd6ba611a394282ac29f05b89951";
|
||||
bytes memory tornadoCliSourceContenthash = hex"e30101701220cb1d7ca2be9c5d7ddba48d5c2b5bb027359ac4c0cf077327a14c9ffe1db057e6";
|
||||
bytes memory infoPageSourceContenthash = hex"e30101701220269c131010a479474d82d7926cc14394d01c41bfb4cda23c26aa3defd65ad4fe";
|
||||
bytes memory classicUiMinifiedContenthash = hex"e301017012201cbffa16ff8f8bd88f2600f1826648aead1ad513b2f3b1118ef873db9f2add59";
|
||||
bytes memory novaUiMinifiedContenthash = hex"e30101701220f1e9f532b9a96e8d808f983d4471da7c261daeacbd9d8e76f82d04875d5ad9fa";
|
||||
bytes memory tornadoCliMinifiedContenthash = hex"e3010170122057be20935fa635689427856a462b288fe353df7b588dcb30ff1b7e6cbffe0d9c";
|
||||
bytes memory tornTokenSourceContenthash = hex"e30101701220fdee0b6906de7f60179c44103dc0bfd4600233f3737c48eb2e7279850970fd92";
|
||||
bytes memory merkleRootUpdaterPackageContenthash = hex"e301017012204c9d433771e8e97cece783366a16c6cd4357b6fb94c6602a90d98e54c4179a3d";
|
||||
bytes memory gasPriceOraclePackageContenthash = hex"e3010170122073e0f65b60d455058aff4fd9b2d0ba2b87f62fb59069433439810dad2d54e615";
|
||||
bytes memory tornadoOraclesPackageContenthash = hex"e30101701220968d7fb0c0b8981bc8ec464e27ad2a90ef0dbcf67df5990498d94718fa9c6361";
|
||||
bytes memory snarkjsPackageContenthash = hex"e30101701220e5d69d83d296c8623aa1b1ff5f9ddc3242914df2bd5f20c1682f07ee095dc6d4";
|
||||
bytes memory websnarkPackageContenthash = hex"e3010170122033fa876a2752cc124fec5c61ebedaf623b42ac50ff348322f8f08183c5aabb8f";
|
||||
bytes memory circomlibPackageContenthash = hex"e30101701220663529c784c5702922344a1035884949317cd59a529160cfb4571709df9c7059";
|
||||
bytes memory txManagerPackageContenthash = hex"e30101701220952a5880f8b175e2206e7502b9891710876e2c970031616b7ede68ce994dea4b";
|
||||
bytes memory fixedMerkleTreePackageContenthash = hex"e30101701220615d9d0986e8fd6a233615d792a70cf5125e188aa82c7493816a5d83c384b924";
|
||||
bytes memory tornadoTreesPackageContenthash = hex"e30101701220b8ea77533cc9b2f434bac48d96d8bc48183cc335fd726b8c5edf11dfa36a78dc";
|
||||
bytes memory anonymityMiningPackageContenthash = hex"e301017012204f3d3a8f0a8a183261288f6012844f74605fd7813d9adc5200784125fb1f671c";
|
||||
bytes memory tornadoConfigPackageContenthash = hex"e301017012202d419e8834b28e8aafabe3dfe39e3d71f2c07c3911c856248a6e6587bfec195a";
|
||||
|
||||
// Set IPFS Cids in ENS subdomain contenthashes
|
||||
ensResolver.setContenthash(sourcesDomainNode, downloadInstructionsHtmlContenthash);
|
||||
ensResolver.setContenthash(downloadScriptSourceDomainNode, downloadScriptSourceContenthash);
|
||||
ensResolver.setContenthash(classicUISourceDomainNode, classicUiSourceContenthash);
|
||||
ensResolver.setContenthash(novaUISourceDomainNode, novaUiSourceContenthash);
|
||||
ensResolver.setContenthash(docsSourceDomainNode, docsSourceContenthash);
|
||||
ensResolver.setContenthash(relayersUISourceDomainNode, relayersUiSourceContenthash);
|
||||
ensResolver.setContenthash(tornTokenSourceDomainNode, tornTokenSourceContenthash);
|
||||
ensResolver.setContenthash(classicRelayerSoftwareSourceDomainNode, classicRelayerSourceContenthash);
|
||||
ensResolver.setContenthash(novaRelayerSoftwareSourceDomainNode, novaRelayerSourceContenthash);
|
||||
ensResolver.setContenthash(tornadoCliSourceDomainNode, tornadoCliSourceContenthash);
|
||||
ensResolver.setContenthash(infoPageSourceDomainNode, infoPageSourceContenthash);
|
||||
ensResolver.setContenthash(classicUIMinifiedDomainNode, classicUiMinifiedContenthash);
|
||||
ensResolver.setContenthash(tornadoCliMinifiedDomainNode, tornadoCliMinifiedContenthash);
|
||||
ensResolver.setContenthash(websnarkPackageDomainNode, websnarkPackageContenthash);
|
||||
ensResolver.setContenthash(circomlibPackageDomainNode, circomlibPackageContenthash);
|
||||
ensResolver.setContenthash(novaMinifiedDomainNode, novaUiMinifiedContenthash);
|
||||
ensResolver.setContenthash(snarkjsPackageDomainNode, snarkjsPackageContenthash);
|
||||
ensResolver.setContenthash(tornadoOraclesPackageDomainNode, tornadoOraclesPackageContenthash);
|
||||
ensResolver.setContenthash(gasPriceOraclePackageDomainNode, gasPriceOraclePackageContenthash);
|
||||
ensResolver.setContenthash(tornadoConfigPackageDomainNode, tornadoConfigPackageContenthash);
|
||||
ensResolver.setContenthash(anonymityMiningPackageDomainNode, anonymityMiningPackageContenthash);
|
||||
ensResolver.setContenthash(tornadoTreesPackageDomainNode, tornadoTreesPackageContenthash);
|
||||
ensResolver.setContenthash(fixedMerkleTreePackageDomainNode, fixedMerkleTreePackageContenthash);
|
||||
ensResolver.setContenthash(txManagerPackageDomainNode, txManagerPackageContenthash);
|
||||
ensResolver.setContenthash(merkleRootUpdaterPackageDomainNode, merkleRootUpdaterPackageContenthash);
|
||||
}
|
||||
}
|
116
test/UpdateENSDataProposal.t.sol
Normal file
116
test/UpdateENSDataProposal.t.sol
Normal file
@ -0,0 +1,116 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { ProposalUtils } from "./utils/ProposalUtils.sol";
|
||||
import { UpdateENSDataProposal } from "@root/UpdateENSDataProposal.sol";
|
||||
|
||||
import { console2 } from "@forge-std/console2.sol";
|
||||
import { IENSResolver } from "@interfaces/IENSResolver.sol";
|
||||
import { IENSRegistry } from "@interfaces/IENSRegistry.sol";
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import "node_modules/base58-solidity/contracts/Base58.sol";
|
||||
|
||||
import { ENSNamehash } from "./ENSNamehash.sol";
|
||||
|
||||
contract TestExampleProposal is ProposalUtils {
|
||||
using ENSNamehash for bytes;
|
||||
|
||||
IENSResolver internal ensResolver = IENSResolver(0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41);
|
||||
IENSRegistry ensRegistry = IENSRegistry(ENSAddress);
|
||||
|
||||
modifier executeCurrentProposalBefore() {
|
||||
createAndExecuteProposal();
|
||||
_;
|
||||
}
|
||||
|
||||
function calculateDomainNode(string memory domain) internal pure returns (bytes32) {
|
||||
return ENSNamehash.namehash(bytes(domain));
|
||||
}
|
||||
|
||||
function calculateIpfsContenthash(string memory ipfsCid) internal pure returns (bytes memory) {
|
||||
if (bytes(ipfsCid).length == 0) return bytes("");
|
||||
return bytes.concat(hex"e3010170", Base58.decodeFromString(ipfsCid));
|
||||
}
|
||||
|
||||
function createAndExecuteProposal() public {
|
||||
address proposalAddress = address(new UpdateENSDataProposal());
|
||||
|
||||
proposeAndExecute(proposalAddress);
|
||||
}
|
||||
|
||||
struct DomainInfo {
|
||||
string ensName;
|
||||
string ipfsCid;
|
||||
}
|
||||
|
||||
DomainInfo[] subdomains = [
|
||||
DomainInfo("sources.tornadocash.eth", "QmQ8T782t6TDFKoZLeVeQaHabgaGjNnTGk86zKMPE4uHtx"),
|
||||
DomainInfo("download.sources.tornadocash.eth", "QmXzf2Lymv1YStHiiMaFrEDxkD4o4cN8cdS6N82voSaTpv"),
|
||||
DomainInfo("help.sources.tornadocash.eth", "QmPBfNYr7hWtpUGNbTgYzaXa6wPp5HcEysZH7pNn9zyEqe"),
|
||||
DomainInfo("relayers-ui.tornadocash.eth", "QmTuGF7kKRjWRjmbxg5qMox622T2VftYiZWKjRpRvYkUN6"),
|
||||
DomainInfo("relayers-network.tornadocash.eth", "QmTuGF7kKRjWRjmbxg5qMox622T2VftYiZWKjRpRvYkUN6"),
|
||||
DomainInfo("relayers-ui.sources.tornadocash.eth", "QmW535jPAscFPqh5M38YjLcwJDJjBrT6ZRtqQqCPF19SzF"),
|
||||
DomainInfo("relayer.sources.tornadocash.eth", "QmVLBoVZAkigrf7x1VHx4aeCHMX5HFwa9cmKGEcC1eUP9i"),
|
||||
DomainInfo("docs.sources.tornadocash.eth", "QmZ7tLxVF5nwmTNwq61MMf7gnUxh85t5Rs6ixxcwu1gRay"),
|
||||
DomainInfo("docs.tornadocash.eth", "QmUtXxMHnLGxsG3Mqm3hhQ2rByFsehSqS57LiEKpEdEiHR")
|
||||
];
|
||||
|
||||
function testSubdomainsRegistered() public executeCurrentProposalBefore {
|
||||
for (uint256 i = 0; i < subdomains.length; i++) {
|
||||
bytes32 node = calculateDomainNode(subdomains[i].ensName);
|
||||
bool isRegistered = ensRegistry.recordExists(node);
|
||||
|
||||
if (isRegistered) {
|
||||
console2.log("Subdomain %s registered", subdomains[i].ensName);
|
||||
} else {
|
||||
console2.log("Subdomain %s isn't registered!", subdomains[i].ensName);
|
||||
}
|
||||
require(isRegistered, "subdomain not registered");
|
||||
}
|
||||
}
|
||||
|
||||
function testContenthashesOnSubdomainsAreCorrect() public executeCurrentProposalBefore {
|
||||
for (uint256 i = 0; i < subdomains.length; i++) {
|
||||
bytes32 node = calculateDomainNode(subdomains[i].ensName);
|
||||
bytes memory desiredIpfsContenthash = calculateIpfsContenthash(subdomains[i].ipfsCid);
|
||||
bytes memory realContenthash = ensResolver.contenthash(node);
|
||||
assertEq(desiredIpfsContenthash, realContenthash, "contenthash is wrong");
|
||||
}
|
||||
}
|
||||
|
||||
function testOwnerOfAllSubdomainsIsGovernance() public executeCurrentProposalBefore {
|
||||
for (uint256 i = 0; i < subdomains.length; i++) {
|
||||
bytes32 node = calculateDomainNode(subdomains[i].ensName);
|
||||
require(ensRegistry.owner(node) == governanceAddress, "owner is not governance");
|
||||
}
|
||||
}
|
||||
|
||||
function testUsdtTransferredToDeveloper() public {
|
||||
bytes32 tornadoDeveloperENSNode = calculateDomainNode("tornado-dev.eth");
|
||||
address tornadoDeveloperAddress = IENSResolver(ensRegistry.resolver(tornadoDeveloperENSNode)).addr(tornadoDeveloperENSNode);
|
||||
|
||||
address usdtTokenAddress = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
|
||||
uint256 usdtDecimals = 1e6;
|
||||
|
||||
IERC20 usdt = IERC20(usdtTokenAddress);
|
||||
uint256 developerBalanceBeforeProposal = usdt.balanceOf(tornadoDeveloperAddress);
|
||||
uint256 tornContractBalanceBeforeProposal = usdt.balanceOf(tornTokenAddress);
|
||||
|
||||
console2.log("Torn contract usdt balance before proposal execution: %s USDT", tornContractBalanceBeforeProposal / usdtDecimals);
|
||||
console2.log("Usdt balance on developer address before proposal execution: %s", developerBalanceBeforeProposal / usdtDecimals);
|
||||
require(developerBalanceBeforeProposal == 0 && tornContractBalanceBeforeProposal > 1500, "wrong usdt balance before proposal");
|
||||
|
||||
createAndExecuteProposal();
|
||||
|
||||
uint256 developerBalanceAfterProposal = usdt.balanceOf(tornadoDeveloperAddress);
|
||||
uint256 tornContractBalanceAfterProposal = usdt.balanceOf(tornTokenAddress);
|
||||
|
||||
console2.log("Torn contract usdt balance after proposal exectuion: %s USDT", tornContractBalanceAfterProposal / usdtDecimals);
|
||||
console2.log("Usdt balance on developer address after proposal execution: %s", developerBalanceAfterProposal / usdtDecimals);
|
||||
require(
|
||||
developerBalanceAfterProposal == tornContractBalanceBeforeProposal && tornContractBalanceAfterProposal == 0,
|
||||
"wrong usdt balance after proposal"
|
||||
);
|
||||
}
|
||||
}
|
18
test/utils/Mock.sol
Normal file
18
test/utils/Mock.sol
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
|
||||
contract Mock {
|
||||
// Developer address with 22 staked TORN
|
||||
address public constant TEST_REAL_ADDRESS_WITH_BALANCE = 0x9Ff3C1Bea9ffB56a78824FE29f457F066257DD58;
|
||||
address public constant TEST_RELAYER_ADDRESS = 0x30F96AEF199B399B722F8819c9b0723016CEAe6C; // moon-relayer.eth (just for testing)
|
||||
|
||||
// Address and private key to test staking, Governance lock and rewards accruals
|
||||
address public constant TEST_STAKER_ADDRESS = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
|
||||
uint256 public constant TEST_STAKER_PRIVATE_KEY = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;
|
||||
|
||||
// Test account to create proposal and vote for it
|
||||
address public constant TEST_ADDRESS_ONE = 0x118251976c65AFAf291f5255450ddb5b6A4d8B88;
|
||||
uint256 public constant TEST_PRIVATE_KEY_ONE = 0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0;
|
||||
}
|
37
test/utils/MockProposal.sol
Normal file
37
test/utils/MockProposal.sol
Normal file
@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
import { TornadoAddresses } from "@proprietary/TornadoAddresses.sol";
|
||||
|
||||
import { Test } from "@forge-std/Test.sol";
|
||||
import { console2 } from "@forge-std/console2.sol";
|
||||
|
||||
contract MockProposal is TornadoAddresses, Test {
|
||||
uint256 public PROPOSAL_VOTING_DURATION;
|
||||
uint256 public PROPOSAL_LOCKED_DURATION;
|
||||
uint256 public PROPOSAL_DURATION;
|
||||
uint256 public PROPOSAL_EXECUTION_MAX_DURATION;
|
||||
uint256 public PROPOSAL_QOURUM_THRESHOLD;
|
||||
uint256 public PROPOSAL_VOTE_EXTEND_TIME;
|
||||
string public constant PROPOSAL_DESCRIPTION = "{title:'Some proposal',description:''}";
|
||||
|
||||
function _fetchConfiguration() internal {
|
||||
IGovernance governance = IGovernance(governanceAddress);
|
||||
|
||||
PROPOSAL_LOCKED_DURATION = governance.EXECUTION_DELAY();
|
||||
PROPOSAL_EXECUTION_MAX_DURATION = governance.EXECUTION_EXPIRATION();
|
||||
PROPOSAL_QOURUM_THRESHOLD = governance.QUORUM_VOTES();
|
||||
PROPOSAL_VOTING_DURATION = governance.VOTING_PERIOD();
|
||||
PROPOSAL_VOTE_EXTEND_TIME = governance.VOTE_EXTEND_TIME();
|
||||
PROPOSAL_DURATION = PROPOSAL_VOTING_DURATION + PROPOSAL_LOCKED_DURATION;
|
||||
}
|
||||
|
||||
function setUp() public virtual {
|
||||
// If fork block number unitialized, then set latest
|
||||
if (block.number == 1) vm.createSelectFork(vm.rpcUrl("mainnet"));
|
||||
else vm.createSelectFork(vm.rpcUrl("mainnet"), block.number);
|
||||
|
||||
_fetchConfiguration();
|
||||
}
|
||||
}
|
79
test/utils/ProposalUtils.sol
Normal file
79
test/utils/ProposalUtils.sol
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import { Utils } from "./Utils.sol";
|
||||
import { Proposal, IGovernance } from "@interfaces/IGovernance.sol";
|
||||
|
||||
contract ProposalUtils is Utils {
|
||||
IGovernance internal governance = IGovernance(governanceAddress);
|
||||
|
||||
function getProposalExecutableTime(uint256 proposalId) internal view returns (uint256) {
|
||||
Proposal memory proposal = getProposal(proposalId);
|
||||
return proposal.endTime + PROPOSAL_LOCKED_DURATION + 1 seconds;
|
||||
}
|
||||
|
||||
function getProposal(uint256 proposalId) internal view returns (Proposal memory) {
|
||||
return governance.proposals(proposalId);
|
||||
}
|
||||
|
||||
function hasProposal(uint256 proposalId) internal view returns (bool) {
|
||||
return governance.proposalCount() >= proposalId;
|
||||
}
|
||||
|
||||
function waitUntilExecutable(uint256 proposalId) internal {
|
||||
uint256 proposalExecutableTime = getProposalExecutableTime(proposalId);
|
||||
require(block.timestamp < proposalExecutableTime + PROPOSAL_EXECUTION_MAX_DURATION, "Too late to execute proposal");
|
||||
|
||||
vm.warp(proposalExecutableTime);
|
||||
}
|
||||
|
||||
function proposeAndVote(address proposalAddress) public returns (uint256) {
|
||||
retrieveAndLockBalance(TEST_PRIVATE_KEY_ONE, TEST_ADDRESS_ONE, PROPOSAL_QOURUM_THRESHOLD + 1 ether);
|
||||
|
||||
/* ----------PROPOSE------------ */
|
||||
vm.startPrank(TEST_ADDRESS_ONE);
|
||||
|
||||
uint256 proposalId = governance.propose(proposalAddress, PROPOSAL_DESCRIPTION);
|
||||
|
||||
/* ------------------------------ */
|
||||
|
||||
// TIME-TRAVEL
|
||||
vm.warp(block.timestamp + 6 hours);
|
||||
|
||||
/* ------------VOTE-------------- */
|
||||
|
||||
governance.castVote(proposalId, true);
|
||||
|
||||
vm.stopPrank();
|
||||
/* ------------------------------ */
|
||||
|
||||
return proposalId;
|
||||
}
|
||||
|
||||
function proposeAndExecute(address proposalAddress) public {
|
||||
uint256 proposalId = proposeAndVote(proposalAddress);
|
||||
|
||||
waitUntilExecutable(proposalId);
|
||||
governance.execute(proposalId);
|
||||
|
||||
returnTokensToGovernanceAfterVoting(proposalId);
|
||||
}
|
||||
|
||||
function returnTokensToGovernanceAfterVoting(uint256 proposalId) public {
|
||||
uint256 retrievedAmount = PROPOSAL_QOURUM_THRESHOLD + 1 ether;
|
||||
|
||||
uint256 proposalExecutableTime = getProposalExecutableTime(proposalId);
|
||||
uint256 tokensUnlockTime = proposalExecutableTime + PROPOSAL_VOTE_EXTEND_TIME + PROPOSAL_EXECUTION_MAX_DURATION + 1 seconds;
|
||||
|
||||
if (block.timestamp < tokensUnlockTime) vm.warp(tokensUnlockTime);
|
||||
|
||||
vm.startPrank(TEST_ADDRESS_ONE);
|
||||
|
||||
governance.unlock(retrievedAmount);
|
||||
IERC20(tornTokenAddress).transfer(governanceAddress, retrievedAmount);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
57
test/utils/Utils.sol
Normal file
57
test/utils/Utils.sol
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
|
||||
import { Test } from "@forge-std/Test.sol";
|
||||
|
||||
import { TornadoAddresses } from "@proprietary/TornadoAddresses.sol";
|
||||
import { Mock } from "./Mock.sol";
|
||||
import { MockProposal } from "./MockProposal.sol";
|
||||
import { IGovernance } from "@interfaces/IGovernance.sol";
|
||||
|
||||
contract Utils is TornadoAddresses, Test, Mock, MockProposal {
|
||||
address public constant VERIFIER_ADDRESS = tornTokenAddress;
|
||||
|
||||
bytes32 public constant PERMIT_TYPEHASH =
|
||||
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
|
||||
|
||||
bytes32 public constant EIP712_DOMAIN = keccak256(
|
||||
abi.encode(
|
||||
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
|
||||
keccak256(bytes("TornadoCash")),
|
||||
keccak256(bytes("1")),
|
||||
1,
|
||||
VERIFIER_ADDRESS
|
||||
)
|
||||
);
|
||||
|
||||
uint16 public constant PERMIT_FUNC_SELECTOR = uint16(0x1901);
|
||||
|
||||
function retrieveAndLockBalance(uint256 privateKey, address voter, uint256 amount) public {
|
||||
uint256 lockTimestamp = block.timestamp + PROPOSAL_DURATION;
|
||||
uint256 accountNonce = ERC20Permit(tornTokenAddress).nonces(voter);
|
||||
|
||||
bytes32 messageHash = keccak256(
|
||||
abi.encodePacked(
|
||||
PERMIT_FUNC_SELECTOR,
|
||||
EIP712_DOMAIN,
|
||||
keccak256(abi.encode(PERMIT_TYPEHASH, voter, governanceAddress, amount, accountNonce, lockTimestamp))
|
||||
)
|
||||
);
|
||||
|
||||
/* ----------GOVERNANCE------- */
|
||||
vm.startPrank(governanceAddress);
|
||||
IERC20(tornTokenAddress).transfer(voter, amount);
|
||||
vm.stopPrank();
|
||||
/* ----------------------------*/
|
||||
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, messageHash);
|
||||
|
||||
/* ----------VOTER------------ */
|
||||
vm.startPrank(voter);
|
||||
IGovernance(governanceAddress).lock(voter, amount, lockTimestamp, v, r, s);
|
||||
vm.stopPrank();
|
||||
/* ----------------------------*/
|
||||
}
|
||||
}
|
109
tsconfig.json
Normal file
109
tsconfig.json
Normal file
@ -0,0 +1,109 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "ES2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "CommonJS" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
"resolveJsonModule": true /* Enable importing .json files. */,
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
"allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user