This commit is contained in:
ButterflyEffect 2023-10-23 13:48:36 +00:00
parent a31dd618f3
commit 9392027851
14 changed files with 240 additions and 54 deletions

@ -3,7 +3,7 @@
{ {
"files": "*.sol", "files": "*.sol",
"options": { "options": {
"printWidth": 80, "printWidth": 120,
"tabWidth": 4, "tabWidth": 4,
"useTabs": false, "useTabs": false,
"singleQuote": false, "singleQuote": false,

@ -4,16 +4,34 @@ pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import { IRelayerRegistryProxy } from "./interfaces/RelayerRegistryProxy.sol"; import { IRelayerRegistryProxy } from "./interfaces/RelayerRegistryProxy.sol";
import { IRelayerRegistry } from "./interfaces/RelayerRegistry.sol";
import { ENSNamehash } from "./libraries/EnsNamehash.sol";
import { EnsResolve } from "torn-token/contracts/ENS.sol";
contract Proposal is EnsResolve {
using ENSNamehash for bytes;
contract Proposal {
address immutable newRelayerRegistry; address immutable newRelayerRegistry;
address constant relayerRegistryProxyAddr = 0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2;
constructor(address _newRelayerRegistry) public { constructor(address _newRelayerRegistry) public {
newRelayerRegistry = _newRelayerRegistry; newRelayerRegistry = _newRelayerRegistry;
} }
function executeProposal() public { function executeProposal() public {
IRelayerRegistryProxy relayerRegistryProxy = IRelayerRegistryProxy(0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2); IRelayerRegistryProxy relayerRegistryProxy = IRelayerRegistryProxy(relayerRegistryProxyAddr);
relayerRegistryProxy.upgradeTo(newRelayerRegistry); relayerRegistryProxy.upgradeTo(newRelayerRegistry);
string[5] memory cheatingRelayers = [
"available-reliable-relayer.eth",
"0xtornadocash.eth",
"0xtorn365.eth",
"tornrelayers.eth",
"moon-relayer.eth"
];
for (uint i = 0; i < cheatingRelayers.length; i++) {
address cheatingRelayer = resolve(bytes(cheatingRelayers[i]).namehash());
IRelayerRegistry(relayerRegistryProxyAddr).unregisterRelayer(cheatingRelayer);
}
} }
} }

@ -58,12 +58,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
event StakeBurned(address relayer, uint256 amountBurned); event StakeBurned(address relayer, uint256 amountBurned);
event MinimumStakeAmount(uint256 minStakeAmount); event MinimumStakeAmount(uint256 minStakeAmount);
event RouterRegistered(address tornadoRouter); event RouterRegistered(address tornadoRouter);
event RelayerRegistered( event RelayerRegistered(bytes32 relayer, string ensName, address relayerAddress, uint256 stakedAmount);
bytes32 relayer,
string ensName,
address relayerAddress,
uint256 stakedAmount
);
event RelayerUnregistered(address relayer); event RelayerUnregistered(address relayer);
modifier onlyGovernance() { modifier onlyGovernance() {
@ -81,13 +76,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
_; _;
} }
constructor( constructor(address _torn, address _governance, address _ens, address _staking, address _feeManager) public {
address _torn,
address _governance,
address _ens,
address _staking,
address _feeManager
) public {
torn = TORN(_torn); torn = TORN(_torn);
governance = _governance; governance = _governance;
ens = IENS(_ens); ens = IENS(_ens);
@ -112,11 +101,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param stake the initial amount of stake in TORN the relayer is depositing * @param stake the initial amount of stake in TORN the relayer is depositing
* *
*/ */
function register( function register(string calldata ensName, uint256 stake, address[] calldata workersToRegister) external {
string calldata ensName,
uint256 stake,
address[] calldata workersToRegister
) external {
_register(msg.sender, ensName, stake, workersToRegister); _register(msg.sender, ensName, stake, workersToRegister);
} }
@ -173,10 +158,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param worker Address to register * @param worker Address to register
* *
*/ */
function registerWorker( function registerWorker(address relayer, address worker) external onlyRelayer(msg.sender, relayer) {
address relayer,
address worker
) external onlyRelayer(msg.sender, relayer) {
_registerWorker(relayer, worker); _registerWorker(relayer, worker);
} }
@ -195,8 +177,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* *
*/ */
function unregisterWorker(address worker) external { function unregisterWorker(address worker) external {
if (worker != msg.sender) if (worker != msg.sender) require(workers[worker] == msg.sender, "only owner of worker");
require(workers[worker] == msg.sender, "only owner of worker");
require(workers[worker] != worker, "cant unregister master"); require(workers[worker] != worker, "cant unregister master");
emit WorkerUnregistered(workers[worker], worker); emit WorkerUnregistered(workers[worker], worker);
workers[worker] = address(0); workers[worker] = address(0);
@ -242,11 +223,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
_stakeToRelayer(staker, relayer, stake); _stakeToRelayer(staker, relayer, stake);
} }
function _stakeToRelayer( function _stakeToRelayer(address staker, address relayer, uint256 stake) internal {
address staker,
address relayer,
uint256 stake
) internal {
require(workers[relayer] == relayer, "!registered"); require(workers[relayer] == relayer, "!registered");
torn.safeTransferFrom(staker, address(staking), stake); torn.safeTransferFrom(staker, address(staking), stake);
relayers[relayer].balance = stake.add(relayers[relayer].balance); relayers[relayer].balance = stake.add(relayers[relayer].balance);
@ -265,11 +242,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param pool instance to get fee for * @param pool instance to get fee for
* *
*/ */
function burn( function burn(address sender, address relayer, ITornadoInstance pool) external onlyTornadoRouter {
address sender,
address relayer,
ITornadoInstance pool
) external onlyTornadoRouter {
address masterAddress = workers[sender]; address masterAddress = workers[sender];
if (masterAddress == address(0)) { if (masterAddress == address(0)) {
require(workers[relayer] == address(0), "Only custom relayer"); require(workers[relayer] == address(0), "Only custom relayer");
@ -298,9 +271,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @param tornadoRouterAddress address of the new proxy * @param tornadoRouterAddress address of the new proxy
* *
*/ */
function setTornadoRouter( function setTornadoRouter(address tornadoRouterAddress) external onlyGovernance {
address tornadoRouterAddress
) external onlyGovernance {
tornadoRouter = tornadoRouterAddress; tornadoRouter = tornadoRouterAddress;
emit RouterRegistered(tornadoRouterAddress); emit RouterRegistered(tornadoRouterAddress);
} }
@ -337,10 +308,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @return true if registered * @return true if registered
* *
*/ */
function isRelayerRegistered( function isRelayerRegistered(address relayer, address toResolve) external view returns (bool) {
address relayer,
address toResolve
) external view returns (bool) {
return workers[toResolve] == relayer; return workers[toResolve] == relayer;
} }
@ -350,9 +318,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @return relayer's ensHash * @return relayer's ensHash
* *
*/ */
function getRelayerEnsHash( function getRelayerEnsHash(address relayer) external view returns (bytes32) {
address relayer
) external view returns (bytes32) {
return relayers[workers[relayer]].ensHash; return relayers[workers[relayer]].ensHash;
} }
@ -362,9 +328,7 @@ contract RelayerRegistry is Initializable, EnsResolve {
* @return relayer's balance * @return relayer's balance
* *
*/ */
function getRelayerBalance( function getRelayerBalance(address relayer) external view returns (uint256) {
address relayer
) external view returns (uint256) {
return relayers[workers[relayer]].balance; return relayers[workers[relayer]].balance;
} }
} }

@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface IRelayerRegistry {
function unregisterRelayer(address relayer) external;
}

@ -16,8 +16,9 @@ module.exports = {
forking: { forking: {
url: "https://eth.llamarpc.com", url: "https://eth.llamarpc.com",
enabled: true, enabled: true,
blockNumber: 18391425 blockNumber: 18391425,
} },
chainId: 1
} }
}, },
etherscan: { etherscan: {

13
package-lock.json generated

@ -24,6 +24,7 @@
"@types/chai": "^4.3.9", "@types/chai": "^4.3.9",
"@types/mocha": "^10.0.2", "@types/mocha": "^10.0.2",
"chai": "^4.3.10", "chai": "^4.3.10",
"chai-things": "^0.2.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"ethers": "^6.8.0", "ethers": "^6.8.0",
"hardhat": "^2.18.1", "hardhat": "^2.18.1",
@ -2796,6 +2797,12 @@
"chai": ">= 2.1.2 < 5" "chai": ">= 2.1.2 < 5"
} }
}, },
"node_modules/chai-things": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chai-things/-/chai-things-0.2.0.tgz",
"integrity": "sha512-6ns0SU21xdRCoEXVKH3HGbwnsgfVMXQ+sU5V8PI9rfxaITos8lss1vUxbF1FAcJKjfqmmmLVlr/z3sLes00w+A==",
"dev": true
},
"node_modules/chalk": { "node_modules/chalk": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@ -12272,6 +12279,12 @@
"check-error": "^1.0.2" "check-error": "^1.0.2"
} }
}, },
"chai-things": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chai-things/-/chai-things-0.2.0.tgz",
"integrity": "sha512-6ns0SU21xdRCoEXVKH3HGbwnsgfVMXQ+sU5V8PI9rfxaITos8lss1vUxbF1FAcJKjfqmmmLVlr/z3sLes00w+A==",
"dev": true
},
"chalk": { "chalk": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",

@ -7,7 +7,8 @@
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "npx hardhat test",
"deploy": "npx hardhat run script/deploy.js"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -22,6 +23,7 @@
"@types/chai": "^4.3.9", "@types/chai": "^4.3.9",
"@types/mocha": "^10.0.2", "@types/mocha": "^10.0.2",
"chai": "^4.3.10", "chai": "^4.3.10",
"chai-things": "^0.2.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"ethers": "^6.8.0", "ethers": "^6.8.0",
"hardhat": "^2.18.1", "hardhat": "^2.18.1",

175
test/RelayerRegistry.js Normal file

@ -0,0 +1,175 @@
const { time, loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { expect, assert } = require("chai");
const { ethers, network } = require("hardhat");
const { relayerRegistry } = require("torn-token");
describe("Registry update", function () {
async function deployAndExecuteFixture() {
const RelayerRegistryFactory = await ethers.getContractFactory("RelayerRegistry");
const constructorArgs = [
"0x77777FeDdddFfC19Ff86DB637967013e6C6A116C",
"0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce",
"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
"0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29",
"0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7",
];
const relayerRegistry = await RelayerRegistryFactory.deploy(...constructorArgs);
const deployedRegistryAddr = await relayerRegistry.getAddress();
const proposalFactory = await ethers.getContractFactory("Proposal");
const proposal = await proposalFactory.deploy(deployedRegistryAddr);
const deployedProposalAddr = await proposal.getAddress();
const bigStakerAddr = "0xE4143f6377AEcd7193b9731d1C28815b57C4f5Ab";
await network.provider.send("hardhat_setBalance", [
bigStakerAddr,
"0x116663015358483537"
]);
const stakerSigner = await ethers.getImpersonatedSigner(bigStakerAddr);
const governanceAddr = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
const governanceContract = await ethers.getContractAt(require("./abi/governance.abi.json"), governanceAddr, stakerSigner);
await governanceContract.propose(deployedProposalAddr, "");
const proposalId = await governanceContract.proposalCount();
await time.increase(60 * 60);
await governanceContract.castVote(proposalId, true);
await time.increase(60 * 60 * 24 * 7 + 60);
await governanceContract.execute(proposalId);
const governanceSigner = await ethers.getImpersonatedSigner(governanceAddr);
const relayerRegistryProxyAddr = "0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2";
const relayerRegistryContract = await ethers.getContractAt("RelayerRegistry", relayerRegistryProxyAddr, governanceSigner);
return { relayerRegistryProxyAddr, deployedRegistryAddr, relayerRegistryContract, governanceSigner };
}
async function unregisterRelayer(ensNameOrAddress){
const { relayerRegistryContract } = await loadFixture(deployAndExecuteFixture);
const relayerAddr = ethers.isAddress(ensNameOrAddress) ? ensNameOrAddress : resolveAddr(ensNameOrAddress);
await relayerRegistryContract.unregisterRelayer(relayerAddr);
}
async function resolveAddr(ensName){
const ensNode = ethers.namehash(ensName);
const ensAddr = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
const registryContract = await ethers.getContractAt(require("./abi/ensRegistry.abi.json"), ensAddr);
const resolverAddr = await registryContract.resolver(ensNode);
const resolverContract = await ethers.getContractAt(require("./abi/ensResolver.abi.json"), resolverAddr);
return await resolverContract.addr(ensNode);
}
async function getOldRelayerRegistryContractFixture(){
const relayerRegistryProxyAddr = "0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2";
return await ethers.getContractAt(require("./abi/relayerRegistryOld.abi.json"), relayerRegistryProxyAddr);
}
it("Implementation address should be updated", async function () {
await loadFixture(getOldRelayerRegistryContractFixture);
const { relayerRegistryProxyAddr, deployedRegistryAddr } = await loadFixture(deployAndExecuteFixture);
const implementation = await ethers.provider.getStorage(relayerRegistryProxyAddr, "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
const [implementationAddr] = new ethers.AbiCoder().decode(["address"], implementation);
expect(implementationAddr).to.equal(deployedRegistryAddr)
});
describe("Unregister relayer", function(){
it("Uregister relayer function should work", async function(){
const testRelayerAddr = await resolveAddr("first-relayer.eth");
const relayerRegistryOldContract = await loadFixture(getOldRelayerRegistryContractFixture);
let isRelayer = await relayerRegistryOldContract.isRelayer(testRelayerAddr);
let isRelayerRegistered = await relayerRegistryOldContract.isRelayerRegistered(testRelayerAddr, testRelayerAddr);
expect(isRelayer).to.equal(true);
expect(isRelayerRegistered).to.equal(true);
const { relayerRegistryContract } = await loadFixture(deployAndExecuteFixture);
await unregisterRelayer(testRelayerAddr);
isRelayer = await relayerRegistryContract.isRelayer(testRelayerAddr);
isRelayerRegistered = await relayerRegistryContract.isRelayerRegistered(testRelayerAddr, testRelayerAddr);
expect(isRelayer).to.equal(false);
expect(isRelayerRegistered).to.equal(false);
})
it("Unregistered relayer should have zero balance", async function(){
const testRelayerAddr = await resolveAddr("first-relayer.eth");
const { relayerRegistryContract } = await loadFixture(deployAndExecuteFixture);
await unregisterRelayer(testRelayerAddr);
const relayerBalance = await relayerRegistryContract.getRelayerBalance(testRelayerAddr);
expect(relayerBalance).to.equal(0);
})
it("Tornado router address should be valid", async function(){
const relayerRegistryOldContract = await loadFixture(getOldRelayerRegistryContractFixture);
const oldRegistryRouterAddress = await relayerRegistryOldContract.tornadoRouter();
const { relayerRegistryContract } = await loadFixture(deployAndExecuteFixture);
expect(await relayerRegistryContract.tornadoRouter()).to.equal(oldRegistryRouterAddress);
})
it("Aggregator contract data for unregistered relayers should be valid", async function(){
const aggregatorAddr = "0xE8F47A78A6D52D317D0D2FFFac56739fE14D1b49";
const aggregatorContract = await ethers.getContractAt(require("./abi/aggregator.abi.json"), aggregatorAddr);
const notRelayer = "🦋️-effect.eth";
const testRelayer = "first-relayer.eth";
const callAggr = async () => await aggregatorContract.relayersData([notRelayer, testRelayer].map(ethers.namehash), ["mainnet-tornado", "bsc-tornado"]);
const oldData = await callAggr();
await loadFixture(deployAndExecuteFixture);
await unregisterRelayer(testRelayer);
const newData = await callAggr();
assert.deepEqual(oldData[0], newData[0]);
expect(oldData[1][1]).to.greaterThan(500n * 10n ** 18n);
expect(newData[1][1]).to.equal(0);
expect(oldData[1][2]).to.equal(true);
expect(newData[1][2]).to.equal(false);
})
it("Cheating relayers should be unregistered", async function(){
const cheatingRelayers = await Promise.all([
"available-reliable-relayer.eth",
"0xtornadocash.eth",
"0xtorn365.eth",
"tornrelayers.eth",
"moon-relayer.eth"
].map(resolveAddr));
const relayerRegistryOldContract = await loadFixture(getOldRelayerRegistryContractFixture);
let areRegistered = await Promise.all(cheatingRelayers.map(r => relayerRegistryOldContract.isRelayer(r)));
let balances = await Promise.all(cheatingRelayers.map(r => relayerRegistryOldContract.getRelayerBalance(r)));
expect(areRegistered).satisfy(v => v.every(v => v === true));
expect(balances).satisfy(v => v.every(v => v >= 0n));
const { relayerRegistryContract } = await loadFixture(deployAndExecuteFixture);
areRegistered = await Promise.all(cheatingRelayers.map(r => relayerRegistryContract.isRelayer(r)));
balances = await Promise.all(cheatingRelayers.map(r => relayerRegistryContract.getRelayerBalance(r)));
expect(areRegistered).satisfy(v => v.every(v => v === false));
expect(balances).satisfy(v => v.every(v => v === 0n));
})
})
it("Unregistered relayers can register again", async function(){
const { relayerRegistryContract, governanceSigner } = await loadFixture(deployAndExecuteFixture);
const relayerEns = "moon-relayer.eth";
const unregisteredRelayer = await resolveAddr(relayerEns);
const tornContract = await ethers.getContractAt(require("./abi/torn.abi.json"), "0x77777FeDdddFfC19Ff86DB637967013e6C6A116C", governanceSigner);
const toStake = 2000n * 10n ** 18n;
await tornContract.transfer(unregisteredRelayer, toStake);
const relayerSigner = await ethers.getImpersonatedSigner(unregisteredRelayer);
await relayerRegistryContract.connect(relayerSigner).register(relayerEns, toStake, []);
const isRelayerRegistered = await relayerRegistryContract.isRelayerRegistered(unregisteredRelayer, unregisteredRelayer);
const relayerBalance = await relayerRegistryContract.getRelayerBalance(unregisteredRelayer);
expect(isRelayerRegistered).to.be.equal(true);
expect(relayerBalance).to.be.equal(toStake);
})
});

@ -0,0 +1 @@
[{"inputs":[],"name":"ensRegistry","outputs":[{"internalType":"contract ENSRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Governance","name":"governance","type":"address"}],"name":"getAllProposals","outputs":[{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"forVotes","type":"uint256"},{"internalType":"uint256","name":"againstVotes","type":"uint256"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"extended","type":"bool"},{"internalType":"enum Governance.ProposalState","name":"state","type":"uint8"}],"internalType":"struct GovernanceAggregator.Proposal[]","name":"proposals","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Governance","name":"governance","type":"address"},{"internalType":"address[]","name":"accs","type":"address[]"}],"name":"getGovernanceBalances","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Governance","name":"governance","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"getUserData","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"latestProposalId","type":"uint256"},{"internalType":"uint256","name":"latestProposalIdState","type":"uint256"},{"internalType":"uint256","name":"timelock","type":"uint256"},{"internalType":"address","name":"delegatee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relayerRegistry","outputs":[{"internalType":"contract RelayerRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_relayers","type":"bytes32[]"},{"internalType":"string[]","name":"_subdomains","type":"string[]"}],"name":"relayersData","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"bool","name":"isRegistered","type":"bool"},{"internalType":"string[20]","name":"records","type":"string[20]"}],"internalType":"struct Relayer[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}]

@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract ENS","name":"_old","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"old","outputs":[{"internalType":"contract ENS","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"recordExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setSubnodeRecord","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
test/abi/torn.abi.json Normal file

File diff suppressed because one or more lines are too long