2023-10-18 18:11:34 +03:00
|
|
|
// 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"),
|
2023-10-18 21:05:19 +03:00
|
|
|
DomainInfo("relayer.sources.tornadocash.eth", "QmUcvz2A6WbLpQJ3AoGvW8auAPn2PKbfgBZAz2htfKEVLn"),
|
2023-10-18 18:11:34 +03:00
|
|
|
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"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|