merge develop

This commit is contained in:
Ricardo Guilherme Schmidt 2020-09-18 08:56:18 -03:00
commit b0e75e853b
No known key found for this signature in database
GPG Key ID: 1FD1630B93893608
56 changed files with 27482 additions and 877 deletions

3
.gitignore vendored
View File

@ -8,6 +8,8 @@ __pycache__/
chains.json chains.json
config/production/password config/production/password
config/livenet/password config/livenet/password
embarkArtifacts/
embark_demo/
# egg-related # egg-related
viper.egg-info/ viper.egg-info/
@ -36,7 +38,6 @@ coverage.json
# node # node
node_modules/ node_modules/
npm-debug.log npm-debug.log
package-lock.json
# other # other
.vs/ .vs/

View File

@ -1,6 +1,6 @@
import ERC20Token from 'Embark/contracts/ERC20Token' import ERC20Token from '../../embarkArtifacts/contracts/ERC20Token'
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar' import UsernameRegistrar from '../../embarkArtifacts/contracts/UsernameRegistrar'
import TestToken from 'Embark/contracts/TestToken' import TestToken from '../../embarkArtifacts/contracts/TestToken'
import { getDefaultAccount } from '../utils/web3Helpers' import { getDefaultAccount } from '../utils/web3Helpers'
import { actions as accountActions } from '../reducers/accounts' import { actions as accountActions } from '../reducers/accounts'

View File

@ -1,4 +1,3 @@
import web3 from 'Embark/web3'
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Nav, MenuItem, NavDropdown } from 'react-bootstrap'; import { Nav, MenuItem, NavDropdown } from 'react-bootstrap';

View File

@ -1,7 +1,7 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import web3 from 'web3';
import ENSRegistry from 'Embark/contracts/ENSRegistry'; import ENSRegistry from '../../../embarkArtifacts/contracts/ENSRegistry';
import React from 'react'; import React from 'react';
import { Button } from 'react-bootstrap'; import { Button } from 'react-bootstrap';
import FieldGroup from '../standard/FieldGroup'; import FieldGroup from '../standard/FieldGroup';

View File

@ -1,6 +1,6 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import web3 from 'web3';
import React from 'react'; import React from 'react';
import { Button } from 'react-bootstrap'; import { Button } from 'react-bootstrap';
import FieldGroup from '../standard/FieldGroup'; import FieldGroup from '../standard/FieldGroup';

View File

@ -1,6 +1,6 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import React, { Fragment, PureComponent } from 'react'; import React, { Fragment, PureComponent } from 'react';
import web3 from 'web3';
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { actions as accountActions, getDefaultAccount } from '../../reducers/accounts'; import { actions as accountActions, getDefaultAccount } from '../../reducers/accounts';
@ -8,8 +8,8 @@ import { hash } from 'eth-ens-namehash';
import { isNil } from 'lodash'; import { isNil } from 'lodash';
import Hidden from '@material-ui/core/Hidden'; import Hidden from '@material-ui/core/Hidden';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import ENSRegistry from 'Embark/contracts/ENSRegistry'; import ENSRegistry from '../../../embarkArtifacts/contracts/ENSRegistry';
import { Button, Field, TextInput, MobileSearch, MobileButton, Card, Info, Text } from '../../ui/components' import { Button, Field, TextInput, MobileSearch, MobileButton, Card, Info, Text } from '../../ui/components'
import { IconCheck } from '../../ui/icons' import { IconCheck } from '../../ui/icons'
import { keyFromXY } from '../../utils/ecdsa'; import { keyFromXY } from '../../utils/ecdsa';
@ -17,7 +17,7 @@ import EditOptions from './EditOptions';
import ReleaseDomainAlert from './ReleaseDomain'; import ReleaseDomainAlert from './ReleaseDomain';
import theme from '../../ui/theme' import theme from '../../ui/theme'
import { withFormik } from 'formik'; import { withFormik } from 'formik';
import PublicResolver from 'Embark/contracts/PublicResolver'; import PublicResolver from '../../../embarkArtifacts/contracts/PublicResolver';
import { CopyToClipboard } from 'react-copy-to-clipboard'; import { CopyToClipboard } from 'react-copy-to-clipboard';
import RegisterSubDomain from '../ens/registerSubDomain'; import RegisterSubDomain from '../ens/registerSubDomain';
import StatusLogo from '../../ui/icons/components/StatusLogo' import StatusLogo from '../../ui/icons/components/StatusLogo'

View File

@ -1,7 +1,7 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import web3 from "Embark/web3"
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import TestToken from 'Embark/contracts/TestToken'; import TestToken from '../../../embarkArtifacts/contracts/TestToken';
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import Hidden from '@material-ui/core/Hidden'; import Hidden from '@material-ui/core/Hidden';

View File

@ -1,7 +1,7 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { Button } from 'react-bootstrap'; import { Button } from 'react-bootstrap';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import web3Utils from 'web3-utils' import web3Utils from 'web3-utils'
import { hash } from 'eth-ens-namehash' import { hash } from 'eth-ens-namehash'

View File

@ -1,6 +1,6 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../../embarkArtifacts/contracts/UsernameRegistrar';
import web3 from 'web3';
import React from 'react'; import React from 'react';
import { Button } from 'react-bootstrap'; import { Button } from 'react-bootstrap';
import FieldGroup from '../standard/FieldGroup'; import FieldGroup from '../standard/FieldGroup';

View File

@ -1,7 +1,7 @@
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import web3 from "Embark/web3"; ;
import ENSRegistry from 'Embark/contracts/ENSRegistry'; import ENSRegistry from '../../../../embarkArtifacts/contracts/ENSRegistry';
import PublicResolver from 'Embark/contracts/PublicResolver'; import PublicResolver from '../../../../embarkArtifacts/contracts/PublicResolver';
const { methods: { owner, resolver } } = ENSRegistry; const { methods: { owner, resolver } } = ENSRegistry;

View File

@ -1,7 +1,7 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import ENSRegistry from 'Embark/contracts/ENSRegistry'; import ENSRegistry from '../../embarkArtifacts/contracts/ENSRegistry';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../../embarkArtifacts/contracts/UsernameRegistrar';
import TestToken from 'Embark/contracts/TestToken'; import TestToken from '../../embarkArtifacts/contracts/TestToken';
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import AddDomain from './ens/addDomain'; import AddDomain from './ens/addDomain';
import MoveDomain from './ens/moveDomain'; import MoveDomain from './ens/moveDomain';

View File

@ -1,6 +1,6 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import ERC20Token from 'Embark/contracts/ERC20Token'; import ERC20Token from '../../embarkArtifacts/contracts/ERC20Token';
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap'; import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';

View File

@ -1,6 +1,6 @@
import React, { Fragment, PureComponent } from 'react'; import React, { Fragment, PureComponent } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import web3 from "Embark/web3"
import Toggle from 'react-toggle'; import Toggle from 'react-toggle';
import { BigNumber } from './utils' import { BigNumber } from './utils'
import "react-toggle/style.css"; import "react-toggle/style.css";

View File

@ -1,10 +1,10 @@
import lang from 'i18n-js'; import lang from 'i18n-js';
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import TestToken from 'Embark/contracts/TestToken'; import TestToken from '../../embarkArtifacts/contracts/TestToken';
import React from 'react'; import React from 'react';
import { Form, FormGroup, FormControl, Button } from 'react-bootstrap'; import { Form, FormGroup, FormControl, Button } from 'react-bootstrap';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import web3 from 'web3';
import ERC20TokenUI from './erc20token'; import ERC20TokenUI from './erc20token';
import { actions as accountActions } from '../reducers/accounts'; import { actions as accountActions } from '../reducers/accounts';

View File

@ -2,13 +2,12 @@ import React from 'react';
import 'typeface-roboto' import 'typeface-roboto'
import Toggle from 'react-toggle'; import Toggle from 'react-toggle';
import EmbarkJS from 'Embark/EmbarkJS'; import EmbarkJS from 'Embark/EmbarkJS';
import TestToken from 'Embark/contracts/TestToken'; import TestToken from '../embarkArtifacts/contracts/TestToken';
import { startCase } from 'lodash'; import { startCase } from 'lodash';
import UsernameRegistrar from 'Embark/contracts/UsernameRegistrar'; import UsernameRegistrar from '../embarkArtifacts/contracts/UsernameRegistrar';
import NameLookup from './components/ens/nameLookup'; import NameLookup from './components/ens/nameLookup';
import AdminMode from './components/AdminMode'; import AdminMode from './components/AdminMode';
import TokenPermissions from './components/standard/TokenPermissionConnect'; import TokenPermissions from './components/standard/TokenPermissionConnect';
import web3 from "Embark/web3";
import Welcome from './components/ens/welcome'; import Welcome from './components/ens/welcome';
import Hidden from '@material-ui/core/Hidden'; import Hidden from '@material-ui/core/Hidden';
import Web3Render from './components/standard/Web3Render'; import Web3Render from './components/standard/Web3Render';
@ -30,6 +29,8 @@ const isReady = (network, environment) => {
if (environment === 'livenet') return true if (environment === 'livenet') return true
} else if(formattedNetwork.includes('ropsten')) { } else if(formattedNetwork.includes('ropsten')) {
if (environment === 'testnet') return true if (environment === 'testnet') return true
}else if(formattedNetwork.includes('private')) {
if (environment === 'private') return true
} }
return formattedNetwork.includes(environment.toLowerCase()); return formattedNetwork.includes(environment.toLowerCase());
} }
@ -70,7 +71,7 @@ class App extends React.Component {
componentDidMount(){ componentDidMount(){
EmbarkJS.onReady((err) => { EmbarkJS.onReady((err) => {
getNetworkType().then(network => { getNetworkType().then(network => {
const { environment } = EmbarkJS const environment = network;
this.setState({ network, environment }) this.setState({ network, environment })
}); });
}); });

View File

@ -1,4 +1,4 @@
import web3 from "Embark/web3"
import EmbarkJS from 'Embark/EmbarkJS' import EmbarkJS from 'Embark/EmbarkJS'
import store from './configureStore' import store from './configureStore'
import { fetchAndDispatchSNTAllowance, fetchAndDispatchAccountsWithBalances } from '../actions/accounts' import { fetchAndDispatchSNTAllowance, fetchAndDispatchAccountsWithBalances } from '../actions/accounts'

View File

@ -1,4 +1,4 @@
import web3 from "Embark/web3"
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
// By default BigNumber's `toString` method converts to exponential notation if the value has // By default BigNumber's `toString` method converts to exponential notation if the value has

View File

@ -1,62 +1,46 @@
module.exports = { module.exports = {
development: { default: {
enabled: true, enabled: true,
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId client: "geth"
networkId: "1337", // Network id used when networkType is custom
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
genesisBlock: "config/development/genesis.json", // Genesis block to initiate on first creation of a development node
datadir: ".embark/development/datadir", // Data directory for the databases and keystore
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost")
rpcPort: 8545, // HTTP-RPC server listening port (default: 8545)
rpcCorsDomain: "auto", // Comma separated list of domains from which to accept cross origin requests (browser enforced)
// When set to "auto", Embark will automatically set the cors to the address of the webserver
proxy: true, // Proxy is used to present meaningful information about transactions
account: {
// "address": "", // When specified, uses that address instead of the default one for the network
password: "config/development/password" // Password to unlock the account
},
targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine
wsRPC: true, // Enable the WS-RPC server
wsOrigins: "auto", // Origins from which to accept websockets requests
// When set to "auto", Embark will automatically set the cors to the address of the webserver
wsHost: "localhost", // WS-RPC server listening interface (default: "localhost")
wsPort: 8546, // WS-RPC server listening port (default: 8546)
simulatorMnemonic: "example exile argue silk regular smile grass bomb merge arm assist farm", // Mnemonic used by the simulator to generate a wallet
simulatorBlocktime: 0 // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining.
}, },
development: {
client: 'ganache-cli',
clientConfig: {
miningMode: 'dev'
}
},
testnet: { testnet: {
enabled: true,
networkType: "testnet", networkType: "testnet",
syncMode: "light", syncMode: "light",
rpcHost: "localhost", accounts: [
rpcPort: 8545, {
rpcCorsDomain: "http://localhost:8000", nodeAccounts: true,
account: { password: "config/testnet/password"
password: "config/testnet/password" }
} ]
}, },
livenet: { livenet: {
enabled: true,
networkType: "livenet", networkType: "livenet",
syncMode: "light", syncMode: "light",
rpcHost: "localhost", accounts: [
rpcPort: 8545, {
rpcCorsDomain: "http://localhost:8000", nodeAccounts: true,
account: { password: "config/livenet/password"
password: "config/livenet/password" }
} ]
}, },
privatenet: {
enabled: true, rinkeby: {
networkType: "custom", networkType: "rinkeby",
rpcHost: "localhost", syncMode: "light",
rpcPort: 8545, accounts: [
rpcCorsDomain: "http://localhost:8000", {
datadir: "yourdatadir", nodeAccounts: true,
networkId: "123", password: "config/rinkeby/password"
bootnodes: "" }
]
} }
}; };

View File

@ -1,12 +1,8 @@
module.exports = { module.exports = {
default: { default: {
enabled: true, enabled: false,
provider: "whisper", // Communication provider. Currently, Embark only supports whisper provider: "whisper",
available_providers: ["whisper"], // Array of available providers available_providers: ["whisper"],
connection: { client: "geth"
host: "localhost", // Host of the blockchain node
port: 8546, // Port of the blockchain node
type: "ws" // Type of connection (ws or rpc)
}
} }
}; };

View File

@ -4,31 +4,30 @@ const { ReservedUsernames } = require('./ens-usernames/reservedNames.js');
const merkleTree = new MerkleTree(ReservedUsernames); const merkleTree = new MerkleTree(ReservedUsernames);
module.exports = { module.exports = {
"default": { default: {
"deployment": { library: 'embarkjs',
"host": "localhost", dappConnection: [
"port": 8545, "$EMBARK",
"type": "rpc" "$WEB3", // uses pre existing web3 object if available (e.g in Mist)
}, "ws://localhost:8546",
"dappConnection": [
"$WEB3",
"http://localhost:8545" "http://localhost:8545"
], ],
"gas": "auto", gas: "auto",
"contracts": { strategy: "explicit",
"TestToken": {}, deploy: {
"MerkleProofWrapper": { TestToken: {},
"deploy": false MerkleProofWrapper: {
deploy: false
}, },
"ERC20Receiver": { ERC20Receiver: {
"deploy": false deploy: false
}, },
"ENSRegistry": {}, ENSRegistry: {},
"PublicResolver": { PublicResolver: {
"args": ["$ENSRegistry"] args: ["$ENSRegistry"]
}, },
"UsernameRegistrar": { UsernameRegistrar: {
"args": [ args: [
"$TestToken", "$TestToken",
"$ENSRegistry", "$ENSRegistry",
"$PublicResolver", "$PublicResolver",
@ -40,87 +39,87 @@ module.exports = {
} }
} }
}, },
"development": { development: {
"contracts": { deploy: {
"TestToken": { TestToken: {
"deploy": true deploy: true
}, },
"ENSRegistry": { ENSRegistry: {
"deploy": true, deploy: true,
"onDeploy": [ onDeploy: [
"ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()" "ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()"
] ]
}, },
"PublicResolver": { PublicResolver: {
"deploy": true, deploy: true,
"args": [ args: [
"$ENSRegistry" "$ENSRegistry"
] ]
}, },
"UsernameRegistrar": { UsernameRegistrar: {
"onDeploy": [ onDeploy: [
"ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '0xbd99f8d5e7f81d2d7c1da34b67a2bb3a94dd8c9b0ab40ddc077621b98405983b', UsernameRegistrar.address).send()" "ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '0xbd99f8d5e7f81d2d7c1da34b67a2bb3a94dd8c9b0ab40ddc077621b98405983b', UsernameRegistrar.address).send()"
] ]
} }
} }
}, },
"livenet":{ livenet:{
"contracts": { deploy: {
"ENSRegistry": { ENSRegistry: {
"address": "0x314159265dd8dbb310642f98f50c066173c1259b" address: "0x314159265dd8dbb310642f98f50c066173c1259b"
}, },
"PublicResolver": { PublicResolver: {
"address": "0x5FfC014343cd971B7eb70732021E26C35B744cc4" address: "0x5FfC014343cd971B7eb70732021E26C35B744cc4"
}, },
"TestToken": { TestToken: {
"address": "0x744d70fdbe2ba4cf95131626614a1763df805b9e" address: "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
}, },
"UsernameRegistrar": { UsernameRegistrar: {
"address": "0xDB5ac1a559b02E12F29fC0eC0e37Be8E046DEF49" address: "0xDB5ac1a559b02E12F29fC0eC0e37Be8E046DEF49"
}, },
"MerkleProof": { MerkleProof: {
"address": "0x713ED9846463235df08D92B886938651105D3940" address: "0x713ED9846463235df08D92B886938651105D3940"
}, },
"MerkleProofWrapper": { MerkleProofWrapper: {
"address": "0x76E55E13C5891a90f7fCA2e1238a6B3463F564e2" address: "0x76E55E13C5891a90f7fCA2e1238a6B3463F564e2"
}, },
"SafeMath": { SafeMath: {
"address": "0xA115a57952D3337e2a1aB3Cb82bA376EEcDDc469" address: "0xA115a57952D3337e2a1aB3Cb82bA376EEcDDc469"
} }
} }
}, },
"testnet":{ testnet:{
"contracts": { deploy: {
"ENSRegistry": { ENSRegistry: {
"address": "0x112234455c3a32fd11230c42e7bccd4a84e02010" address: "0x112234455c3a32fd11230c42e7bccd4a84e02010"
}, },
"PublicResolver": { PublicResolver: {
"address": "0x29754bADB2640b98F6deF0f52D41418b0d2e0C51" address: "0x29754bADB2640b98F6deF0f52D41418b0d2e0C51"
}, },
"TestToken": { TestToken: {
"address": "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162" address: "0xc55cF4B03948D7EBc8b9E8BAD92643703811d162"
}, },
"SafeMath": { SafeMath: {
"address": "0x0F9992f7737f9ba3aceD170D4D1259cb2CEcc050" address: "0x0F9992f7737f9ba3aceD170D4D1259cb2CEcc050"
}, },
"MerkleProof": { MerkleProof: {
"address": "0x5df00E70AD165D50228DB6d8285fB6EAAc630FD7" address: "0x5df00E70AD165D50228DB6d8285fB6EAAc630FD7"
}, },
"MerkleProofWrapper": { MerkleProofWrapper: {
"address": "0x58E01078d14142E0370526dFdAE44E4f508c844B" address: "0x58E01078d14142E0370526dFdAE44E4f508c844B"
}, },
"UsernameRegistrar": { UsernameRegistrar: {
"address": "0x11d9F481effd20D76cEE832559bd9Aca25405841" address: "0x11d9F481effd20D76cEE832559bd9Aca25405841"
} }
} }
}, },
"rinkeby":{ rinkeby:{
"contracts": { deploy: {
"ENSRegistry": { ENSRegistry: {
"address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A" address: "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
}, },
"PublicResolver": { PublicResolver: {
"address": "0x5d20cf83cb385e06d2f2a892f9322cd4933eacdc" address: "0x5d20cf83cb385e06d2f2a892f9322cd4933eacdc"
} }
} }
} }

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
default: { default: {
enabled: false,
available_providers: ["ens"], available_providers: ["ens"],
provider: "ens" provider: "ens"
} }

4
config/pipeline.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
typescript: false,
enabled: true
};

View File

@ -2,9 +2,9 @@ module.exports = {
default: { default: {
enabled: true, enabled: true,
ipfs_bin: "ipfs", ipfs_bin: "ipfs",
provider: "ipfs",
available_providers: ["ipfs"], available_providers: ["ipfs"],
upload: { upload: {
provider: "ipfs",
host: "localhost", host: "localhost",
port: 5001 port: 5001
}, },
@ -16,20 +16,23 @@ module.exports = {
getUrl: "http://localhost:8080/ipfs/" getUrl: "http://localhost:8080/ipfs/"
} }
] ]
// Configuration to start Swarm in the same terminal as `embark run`
/*,account: {
address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm
password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account
},
swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/
}, },
development: { development: {
enabled: true,
provider: "ipfs",
upload: { upload: {
provider: "ipfs",
host: "localhost", host: "localhost",
port: 5001, port: 5001,
getUrl: "http://localhost:8080/ipfs/" getUrl: "http://localhost:8080/ipfs/"
} }
} },
testnet: {
},
livenet: {
},
rinkeby: {
},
}; };

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
enabled: true, enabled: true,
host: "localhost", host: "localhost",
openBrowser: true,
port: 8000 port: 8000
}; };

View File

@ -1,22 +1,24 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
contract Controlled { contract Controlled {
/// @notice The address of the controller is the only address that can call /// @notice The address of the controller is the only address that can call
/// a function with this modifier /// a function with this modifier
modifier onlyController { modifier onlyController {
require(msg.sender == controller); require(msg.sender == controller, "Unauthorized");
_; _;
} }
address public controller; address payable public controller;
constructor() internal { constructor() internal {
controller = msg.sender; controller = msg.sender;
} }
/// @notice Changes the controller of the contract /// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract /// @param _newController The new controller of the contract
function changeController(address _newController) public onlyController { function changeController(address payable _newController) public onlyController {
controller = _newController; controller = _newController;
} }
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: MIT
pragma solidity 0.5.11;
/** /**
@ -15,7 +17,7 @@ library MerkleProof {
* @param _leaf Leaf of Merkle tree * @param _leaf Leaf of Merkle tree
*/ */
function verifyProof( function verifyProof(
bytes32[] _proof, bytes32[] memory _proof,
bytes32 _root, bytes32 _root,
bytes32 _leaf bytes32 _leaf
) )

View File

@ -1,13 +1,13 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
/** pragma solidity 0.5.11;
/**
* @notice Uses ethereum signed messages * @notice Uses ethereum signed messages
*/ */
contract MessageSigned { contract MessageSigned {
constructor() internal {
} constructor() internal {}
/** /**
* @notice recovers address who signed the message * @notice recovers address who signed the message
@ -15,12 +15,12 @@ contract MessageSigned {
* @param _messageSignature message `_signHash` signature * @param _messageSignature message `_signHash` signature
*/ */
function recoverAddress( function recoverAddress(
bytes32 _signHash, bytes32 _signHash,
bytes _messageSignature bytes memory _messageSignature
) )
internal internal
pure pure
returns(address) returns(address)
{ {
uint8 v; uint8 v;
bytes32 r; bytes32 r;
@ -42,21 +42,22 @@ contract MessageSigned {
function getSignHash( function getSignHash(
bytes32 _hash bytes32 _hash
) )
pure
internal internal
pure
returns (bytes32 signHash) returns (bytes32 signHash)
{ {
signHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)); signHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
} }
/** /**
* @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s` * @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`
*/ */
function signatureSplit(bytes _signature) function signatureSplit(bytes memory _signature)
pure
internal internal
pure
returns (uint8 v, bytes32 r, bytes32 s) returns (uint8 v, bytes32 r, bytes32 s)
{ {
require(_signature.length == 65, "Bad signature length");
// The signature format is a compact form of: // The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v} // {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes. // Compact means, uint8 is not padded to 32 bytes.
@ -70,8 +71,10 @@ contract MessageSigned {
// use the second best option, 'and' // use the second best option, 'and'
v := and(mload(add(_signature, 65)), 0xff) v := and(mload(add(_signature, 65)), 0xff)
} }
if (v < 27) {
require(v == 27 || v == 28); v += 27;
}
require(v == 27 || v == 28, "Bad signature version");
} }
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
/// @dev `Owned` is a base level contract that assigns an `owner` that can be /// @dev `Owned` is a base level contract that assigns an `owner` that can be
/// later changed /// later changed
@ -7,23 +9,23 @@ contract Owned {
/// @dev `owner` is the only address that can call a function with this /// @dev `owner` is the only address that can call a function with this
/// modifier /// modifier
modifier onlyOwner() { modifier onlyOwner() {
require(msg.sender == owner); require(msg.sender == owner, "Unauthorized");
_; _;
} }
address public owner; address payable public owner;
/// @notice The Constructor assigns the message sender to be `owner` /// @notice The Constructor assigns the message sender to be `owner`
constructor() internal { constructor() internal {
owner = msg.sender; owner = msg.sender;
} }
address public newOwner; address payable public newOwner;
/// @notice `owner` can step down and assign some other address to this role /// @notice `owner` can step down and assign some other address to this role
/// @param _newOwner The address of the new owner. 0x0 can be used to create /// @param _newOwner The address of the new owner. 0x0 can be used to create
/// an unowned neutral vault, however that cannot be undone /// an unowned neutral vault, however that cannot be undone
function changeOwner(address _newOwner) public onlyOwner { function changeOwner(address payable _newOwner) public onlyOwner {
newOwner = _newOwner; newOwner = _newOwner;
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: MIT
pragma solidity 0.5.11;
/** /**
* Math operations with safety checks * Math operations with safety checks

View File

@ -1,26 +1,35 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: BSD-2-Clause
pragma solidity 0.5.11;
interface ENS { interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode. // Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account. // Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner); event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes. // Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver); event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes // Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl); event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when an operator is added or removed.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public; function setRecord(bytes32 _node, address _owner, address _resolver, uint64 _ttl) external;
function setResolver(bytes32 node, address resolver) public; function setSubnodeRecord(bytes32 _node, bytes32 _label, address _owner, address _resolver, uint64 _ttl) external;
function setOwner(bytes32 node, address owner) public; function setSubnodeOwner(bytes32 _node, bytes32 _label, address _owner) external returns(bytes32);
function setTTL(bytes32 node, uint64 ttl) public; function setResolver(bytes32 _node, address _resolver) external;
function owner(bytes32 node) public view returns (address); function setOwner(bytes32 _node, address _owner) external;
function resolver(bytes32 node) public view returns (address); function setTTL(bytes32 _node, uint64 _ttl) external;
function ttl(bytes32 node) public view returns (uint64); function setApprovalForAll(address _operator, bool _approved) external;
function owner(bytes32 _node) external view returns (address);
} function resolver(bytes32 _node) external view returns (address);
function ttl(bytes32 _node) external view returns (uint64);
function recordExists(bytes32 _node) external view returns (bool);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: BSD-2-Clause
pragma solidity 0.5.11;
import "./ENS.sol"; import "./ENS.sol";
@ -6,6 +8,7 @@ import "./ENS.sol";
* The ENS registry contract. * The ENS registry contract.
*/ */
contract ENSRegistry is ENS { contract ENSRegistry is ENS {
struct Record { struct Record {
address owner; address owner;
address resolver; address resolver;
@ -13,10 +16,12 @@ contract ENSRegistry is ENS {
} }
mapping (bytes32 => Record) records; mapping (bytes32 => Record) records;
mapping (address => mapping(address => bool)) operators;
// Permits modifications only by the owner of the specified node. // Permits modifications only by the _owner of the specified _node.
modifier only_owner(bytes32 node) { modifier authorised(bytes32 _node) {
require(records[node].owner == msg.sender); address _owner = records[_node].owner;
require(_owner == msg.sender || operators[_owner][msg.sender], "ENS: Not Authorized");
_; _;
} }
@ -28,72 +33,148 @@ contract ENSRegistry is ENS {
} }
/** /**
* @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node. * @dev Sets the record for a _node.
* @param node The node to transfer ownership of. * @param _node The _node to update.
* @param owner The address of the new owner. * @param _owner The address of the new _owner.
* @param _resolver The address of the _resolver.
* @param _ttl The TTL in seconds.
*/ */
function setOwner(bytes32 node, address owner) public only_owner(node) { function setRecord(bytes32 _node, address _owner, address _resolver, uint64 _ttl) external {
emit Transfer(node, owner); setOwner(_node, _owner);
records[node].owner = owner; _setResolverAndTTL(_node, _resolver, _ttl);
} }
/** /**
* @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node. * @dev Sets the record for a subnode.
* @param node The parent node. * @param _node The parent _node.
* @param label The hash of the label specifying the subnode. * @param _label The hash of the _label specifying the subnode.
* @param owner The address of the new owner. * @param _owner The address of the new _owner.
* @param _resolver The address of the _resolver.
* @param _ttl The TTL in seconds.
*/ */
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) { function setSubnodeRecord(bytes32 _node, bytes32 _label, address _owner, address _resolver, uint64 _ttl) external {
bytes32 subnode = keccak256(abi.encodePacked(node, label)); bytes32 subnode = setSubnodeOwner(_node, _label, _owner);
emit NewOwner(node, label, owner); _setResolverAndTTL(subnode, _resolver, _ttl);
records[subnode].owner = owner;
} }
/** /**
* @dev Sets the resolver address for the specified node. * @dev Transfers ownership of a _node to a new address. May only be called by the current _owner of the _node.
* @param node The node to update. * @param _node The _node to transfer ownership of.
* @param resolver The address of the resolver. * @param _owner The address of the new _owner.
*/ */
function setResolver(bytes32 node, address resolver) public only_owner(node) { function setOwner(bytes32 _node, address _owner) public authorised(_node) {
emit NewResolver(node, resolver); _setOwner(_node, _owner);
records[node].resolver = resolver; emit Transfer(_node, _owner);
} }
/** /**
* @dev Sets the TTL for the specified node. * @dev Transfers ownership of a subnode keccak256(_node, _label) to a new address. May only be called by the _owner of the parent _node.
* @param node The node to update. * @param _node The parent _node.
* @param ttl The TTL in seconds. * @param _label The hash of the _label specifying the subnode.
* @param _owner The address of the new _owner.
*/ */
function setTTL(bytes32 node, uint64 ttl) public only_owner(node) { function setSubnodeOwner(bytes32 _node, bytes32 _label, address _owner) public authorised(_node) returns(bytes32) {
emit NewTTL(node, ttl); bytes32 subnode = keccak256(abi.encodePacked(_node, _label));
records[node].ttl = ttl; _setOwner(subnode, _owner);
emit NewOwner(_node, _label, _owner);
return subnode;
} }
/** /**
* @dev Returns the address that owns the specified node. * @dev Sets the _resolver address for the specified _node.
* @param node The specified node. * @param _node The _node to update.
* @return address of the owner. * @param _resolver The address of the _resolver.
*/ */
function owner(bytes32 node) public view returns (address) { function setResolver(bytes32 _node, address _resolver) public authorised(_node) {
return records[node].owner; emit NewResolver(_node, _resolver);
records[_node].resolver = _resolver;
} }
/** /**
* @dev Returns the address of the resolver for the specified node. * @dev Sets the TTL for the specified _node.
* @param node The specified node. * @param _node The _node to update.
* @return address of the resolver. * @param _ttl The TTL in seconds.
*/ */
function resolver(bytes32 node) public view returns (address) { function setTTL(bytes32 _node, uint64 _ttl) public authorised(_node) {
return records[node].resolver; emit NewTTL(_node, _ttl);
records[_node].ttl = _ttl;
} }
/** /**
* @dev Returns the TTL of a node, and any records associated with it. * @dev Enable or disable approval for a third party ("_operator") to manage
* @param node The specified node. * all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
* @return ttl of the node. * @param _operator Address to add to the set of authorized operators.
* @param _approved True if the _operator is _approved, false to revoke approval.
*/ */
function ttl(bytes32 node) public view returns (uint64) { function setApprovalForAll(address _operator, bool _approved) external {
return records[node].ttl; operators[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
} }
/**
* @dev Returns the address that owns the specified _node.
* @param _node The specified _node.
* @return address of the _owner.
*/
function owner(bytes32 _node) public view returns (address) {
address addr = records[_node].owner;
if (addr == address(this)) {
return address(0x0);
}
return addr;
}
/**
* @dev Returns the address of the _resolver for the specified _node.
* @param _node The specified _node.
* @return address of the _resolver.
*/
function resolver(bytes32 _node) public view returns (address) {
return records[_node].resolver;
}
/**
* @dev Returns the TTL of a _node, and any records associated with it.
* @param _node The specified _node.
* @return _ttl of the _node.
*/
function ttl(bytes32 _node) public view returns (uint64) {
return records[_node].ttl;
}
/**
* @dev Returns whether a record has been imported to the registry.
* @param _node The specified _node.
* @return Bool if record exists
*/
function recordExists(bytes32 _node) public view returns (bool) {
return records[_node].owner != address(0x0);
}
/**
* @dev Query if an address is an authorized _operator for another address.
* @param _owner The address that owns the records.
* @param _operator The address that acts on behalf of the _owner.
* @return True if `_operator` is an _approved _operator for `_owner`, false otherwise.
*/
function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
return operators[_owner][_operator];
}
function _setOwner(bytes32 _node, address _owner) internal {
records[_node].owner = _owner;
}
function _setResolverAndTTL(bytes32 _node, address _resolver, uint64 _ttl) internal {
if(_resolver != records[_node].resolver) {
records[_node].resolver = _resolver;
emit NewResolver(_node, _resolver);
}
if(_ttl != records[_node].ttl) {
records[_node].ttl = _ttl;
emit NewTTL(_node, _ttl);
}
}
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: BSD-2-Clause
pragma solidity 0.5.11;
import "./ENS.sol"; import "./ENS.sol";
@ -10,20 +12,20 @@ contract PublicResolver {
bytes4 constant INTERFACE_META_ID = 0x01ffc9a7; bytes4 constant INTERFACE_META_ID = 0x01ffc9a7;
bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de; bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5;
bytes4 constant NAME_INTERFACE_ID = 0x691f3431; bytes4 constant NAME_INTERFACE_ID = 0x691f3431;
bytes4 constant ABI_INTERFACE_ID = 0x2203ab56; bytes4 constant ABI_INTERFACE_ID = 0x2203ab56;
bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233; bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233;
bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c; bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c;
bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1; bytes4 constant CONTENTHASH_INTERFACE_ID = 0xbc1c58d1;
bytes4 constant INTERFACE_INTERFACE_ID = bytes4(keccak256("interfaceImplementer(bytes32,bytes4)"));
event AddrChanged(bytes32 indexed node, address a); event AddrChanged(bytes32 indexed node, address a);
event ContentChanged(bytes32 indexed node, bytes32 hash);
event NameChanged(bytes32 indexed node, string name); event NameChanged(bytes32 indexed node, string name);
event ABIChanged(bytes32 indexed node, uint256 indexed contentType); event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y); event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
event TextChanged(bytes32 indexed node, string indexedKey, string key); event TextChanged(bytes32 indexed node, string indexedKey, string key);
event MultihashChanged(bytes32 indexed node, bytes hash); event ContenthashChanged(bytes32 indexed node, bytes hash);
event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);
struct PublicKey { struct PublicKey {
bytes32 x; bytes32 x;
@ -32,19 +34,19 @@ contract PublicResolver {
struct Record { struct Record {
address addr; address addr;
bytes32 content;
string name; string name;
PublicKey pubkey; PublicKey pubkey;
mapping(string=>string) text; mapping(string=>string) text;
mapping(uint256=>bytes) abis; mapping(uint256=>bytes) abis;
bytes multihash; bytes contenthash;
mapping(bytes4=>address) interfaces;
} }
ENS ens; ENS ens;
mapping (bytes32 => Record) records; mapping (bytes32 => Record) records;
modifier only_owner(bytes32 node) { modifier onlyOwner(bytes32 node) {
require(ens.owner(node) == msg.sender); require(ens.owner(node) == msg.sender);
_; _;
} }
@ -63,42 +65,29 @@ contract PublicResolver {
* @param node The node to update. * @param node The node to update.
* @param addr The address to set. * @param addr The address to set.
*/ */
function setAddr(bytes32 node, address addr) public only_owner(node) { function setAddr(bytes32 node, address addr) external onlyOwner(node) {
records[node].addr = addr; records[node].addr = addr;
emit AddrChanged(node, addr); emit AddrChanged(node, addr);
} }
/** /**
* Sets the content hash associated with an ENS node. * Sets the contenthash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry. * May only be called by the owner of that node in the ENS registry.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The node to update. * @param node The node to update.
* @param hash The content hash to set * @param hash The contenthash to set
*/ */
function setContent(bytes32 node, bytes32 hash) public only_owner(node) { function setContenthash(bytes32 node, bytes calldata hash) external onlyOwner(node) {
records[node].content = hash; records[node].contenthash = hash;
emit ContentChanged(node, hash); emit ContenthashChanged(node, hash);
} }
/**
* Sets the multihash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The multihash to set
*/
function setMultihash(bytes32 node, bytes hash) public only_owner(node) {
records[node].multihash = hash;
emit MultihashChanged(node, hash);
}
/** /**
* Sets the name associated with an ENS node, for reverse records. * Sets the name associated with an ENS node, for reverse records.
* May only be called by the owner of that node in the ENS registry. * May only be called by the owner of that node in the ENS registry.
* @param node The node to update. * @param node The node to update.
* @param name The name to set. * @param name The name to set.
*/ */
function setName(bytes32 node, string name) public only_owner(node) { function setName(bytes32 node, string calldata name) external onlyOwner(node) {
records[node].name = name; records[node].name = name;
emit NameChanged(node, name); emit NameChanged(node, name);
} }
@ -111,21 +100,21 @@ contract PublicResolver {
* @param contentType The content type of the ABI * @param contentType The content type of the ABI
* @param data The ABI data. * @param data The ABI data.
*/ */
function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) { function setABI(bytes32 node, uint256 contentType, bytes calldata data) external onlyOwner(node) {
// Content types must be powers of 2 // Content types must be powers of 2
require(((contentType - 1) & contentType) == 0); require(((contentType - 1) & contentType) == 0);
records[node].abis[contentType] = data; records[node].abis[contentType] = data;
emit ABIChanged(node, contentType); emit ABIChanged(node, contentType);
} }
/** /**
* Sets the SECP256k1 public key associated with an ENS node. * Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query * @param node The ENS node to query
* @param x the X coordinate of the curve point for the public key. * @param x the X coordinate of the curve point for the public key.
* @param y the Y coordinate of the curve point for the public key. * @param y the Y coordinate of the curve point for the public key.
*/ */
function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) { function setPubkey(bytes32 node, bytes32 x, bytes32 y) external onlyOwner(node) {
records[node].pubkey = PublicKey(x, y); records[node].pubkey = PublicKey(x, y);
emit PubkeyChanged(node, x, y); emit PubkeyChanged(node, x, y);
} }
@ -137,18 +126,30 @@ contract PublicResolver {
* @param key The key to set. * @param key The key to set.
* @param value The text data value to set. * @param value The text data value to set.
*/ */
function setText(bytes32 node, string key, string value) public only_owner(node) { function setText(bytes32 node, string calldata key, string calldata value) external onlyOwner(node) {
records[node].text[key] = value; records[node].text[key] = value;
emit TextChanged(node, key, key); emit TextChanged(node, key, key);
} }
/**
* Sets an interface associated with a name.
* Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
* @param node The node to update.
* @param interfaceID The EIP 168 interface ID.
* @param implementer The address of a contract that implements this interface for this node.
*/
function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external onlyOwner(node) {
records[node].interfaces[interfaceID] = implementer;
emit InterfaceChanged(node, interfaceID, implementer);
}
/** /**
* Returns the text data associated with an ENS node and key. * Returns the text data associated with an ENS node and key.
* @param node The ENS node to query. * @param node The ENS node to query.
* @param key The text data key to query. * @param key The text data key to query.
* @return The associated text data. * @return The associated text data.
*/ */
function text(bytes32 node, string key) public view returns (string) { function text(bytes32 node, string calldata key) external view returns (string memory) {
return records[node].text[key]; return records[node].text[key];
} }
@ -156,9 +157,10 @@ contract PublicResolver {
* Returns the SECP256k1 public key associated with an ENS node. * Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619. * Defined in EIP 619.
* @param node The ENS node to query * @param node The ENS node to query
* @return x, y the X and Y coordinates of the curve point for the public key. * @return x Pubkey x point
* @return y Pubkey y point
*/ */
function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) { function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {
return (records[node].pubkey.x, records[node].pubkey.y); return (records[node].pubkey.x, records[node].pubkey.y);
} }
@ -170,15 +172,17 @@ contract PublicResolver {
* @return contentType The content type of the return value * @return contentType The content type of the return value
* @return data The ABI data * @return data The ABI data
*/ */
function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) { function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {
Record storage record = records[node]; Record storage record = records[node];
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) { if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
data = record.abis[contentType]; return (contentType, record.abis[contentType]);
return;
} }
} }
contentType = 0;
bytes memory empty;
return (0, empty);
} }
/** /**
@ -187,30 +191,10 @@ contract PublicResolver {
* @param node The ENS node to query. * @param node The ENS node to query.
* @return The associated name. * @return The associated name.
*/ */
function name(bytes32 node) public view returns (string) { function name(bytes32 node) external view returns (string memory) {
return records[node].name; return records[node].name;
} }
/**
* Returns the content hash associated with an ENS node.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The ENS node to query.
* @return The associated content hash.
*/
function content(bytes32 node) public view returns (bytes32) {
return records[node].content;
}
/**
* Returns the multihash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated multihash.
*/
function multihash(bytes32 node) public view returns (bytes) {
return records[node].multihash;
}
/** /**
* Returns the address associated with an ENS node. * Returns the address associated with an ENS node.
* @param node The ENS node to query. * @param node The ENS node to query.
@ -220,19 +204,64 @@ contract PublicResolver {
return records[node].addr; return records[node].addr;
} }
/**
* Returns the contenthash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function contenthash(bytes32 node) external view returns (bytes memory) {
return records[node].contenthash;
}
/**
* Returns the address of a contract that implements the specified interface for this name.
* If an implementer has not been set for this interfaceID and name, the resolver will query
* the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
* contract implements EIP168 and returns `true` for the specified interfaceID, its address
* will be returned.
* @param node The ENS node to query.
* @param interfaceID The EIP 168 interface ID to check for.
* @return The address that implements this interface, or 0 if the interface is unsupported.
*/
function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {
address implementer = records[node].interfaces[interfaceID];
if(implementer != address(0)) {
return implementer;
}
address a = addr(node);
if(a == address(0)) {
return address(0);
}
(bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", INTERFACE_META_ID));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// EIP 168 not supported by target
return address(0);
}
(success, returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// Specified interface not supported by target
return address(0);
}
return a;
}
/** /**
* Returns true if the resolver implements the interface specified by the provided hash. * Returns true if the resolver implements the interface specified by the provided hash.
* @param interfaceID The ID of the interface to check for. * @param interfaceID The ID of the interface to check for.
* @return True if the contract implements the requested interface. * @return True if the contract implements the requested interface.
*/ */
function supportsInterface(bytes4 interfaceID) public pure returns (bool) { function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
return interfaceID == ADDR_INTERFACE_ID || return interfaceID == ADDR_INTERFACE_ID ||
interfaceID == CONTENT_INTERFACE_ID ||
interfaceID == NAME_INTERFACE_ID || interfaceID == NAME_INTERFACE_ID ||
interfaceID == ABI_INTERFACE_ID || interfaceID == ABI_INTERFACE_ID ||
interfaceID == PUBKEY_INTERFACE_ID || interfaceID == PUBKEY_INTERFACE_ID ||
interfaceID == TEXT_INTERFACE_ID || interfaceID == TEXT_INTERFACE_ID ||
interfaceID == MULTIHASH_INTERFACE_ID || interfaceID == CONTENTHASH_INTERFACE_ID ||
interfaceID == INTERFACE_INTERFACE_ID ||
interfaceID == INTERFACE_META_ID; interfaceID == INTERFACE_META_ID;
} }
} }

View File

@ -1,10 +1,46 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: BSD-2-Clause
contract ResolverInterface { pragma solidity 0.5.11;
function PublicResolver(address ensAddr) public; pragma experimental ABIEncoderV2;
function setAddr(bytes32 node, address addr) public;
function setHash(bytes32 node, bytes32 hash) public; /**
function addr(bytes32 node) public view returns (address); * A generic resolver interface which includes all the functions including the ones deprecated
function hash(bytes32 node) public view returns (bytes32); */
function supportsInterface(bytes4 interfaceID) public pure returns (bool); interface Resolver{
event AddrChanged(bytes32 indexed node, address a);
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
event NameChanged(bytes32 indexed node, string name);
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
event ContenthashChanged(bytes32 indexed node, bytes hash);
/* Deprecated events */
event ContentChanged(bytes32 indexed node, bytes32 hash);
function ABI(bytes32 _node, uint256 _contentTypes) external view returns (uint256, bytes memory);
function addr(bytes32 _node) external view returns (address);
function addr(bytes32 _node, uint _coinType) external view returns(bytes memory);
function contenthash(bytes32 _node) external view returns (bytes memory);
function dnsrr(bytes32 _node) external view returns (bytes memory);
function name(bytes32 _node) external view returns (string memory);
function pubkey(bytes32 _node) external view returns (bytes32 x, bytes32 y);
function text(bytes32 _node, string calldata _key) external view returns (string memory);
function interfaceImplementer(bytes32 _node, bytes4 _interfaceID) external view returns (address);
function setABI(bytes32 _node, uint256 _contentType, bytes calldata _data) external;
function setAddr(bytes32 _node, address _addr) external;
function setAddr(bytes32 _node, uint _coinType, bytes calldata _a) external;
function setContenthash(bytes32 _node, bytes calldata _hash) external;
function setDnsrr(bytes32 _node, bytes calldata _data) external;
function setName(bytes32 _node, string calldata _name) external;
function setPubkey(bytes32 _node, bytes32 _x, bytes32 _y) external;
function setText(bytes32 _node, string calldata _key, string calldata _value) external;
function setInterface(bytes32 _node, bytes4 _interfaceID, address _implementer) external;
function supportsInterface(bytes4 _interfaceID) external pure returns (bool);
function multicall(bytes[] calldata _data) external returns(bytes[] memory results);
/* Deprecated functions */
function content(bytes32 _node) external view returns (bytes32);
function multihash(bytes32 _node) external view returns (bytes memory);
function setContent(bytes32 _node, bytes32 hash) external;
function setMultihash(bytes32 _node, bytes calldata _hash) external;
} }

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "../registry/SlashMechanism.sol";
contract Dummy2SlashMechanism is SlashMechanism {
constructor(
uint256 _usernameMinLength,
bytes32 _reservedUsernamesMerkleRoot
)
public
SlashMechanism(
_usernameMinLength,
_reservedUsernamesMerkleRoot
)
{
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "../registry/UsernameRegistrar.sol";
contract Dummy2UsernameRegistrar is UsernameRegistrar {
constructor(
ERC20Token _token,
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
address _slashMechanism,
address _parentRegistry
)
public
UsernameRegistrar(
_token,
_ensRegistry,
_resolver,
_ensNode,
_slashMechanism,
_parentRegistry
)
{
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "../registry/UsernameRegistrar.sol";
contract DummyUsernameRegistrar is UsernameRegistrar {
constructor(
ERC20Token _token,
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
address _slashMechanism,
address _parentRegistry
)
public
UsernameRegistrar(
_token,
_ensRegistry,
_resolver,
_ensNode,
_slashMechanism,
_parentRegistry
)
{
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./Dummy2UsernameRegistrar.sol";
contract UpdatedDummy2UsernameRegistrar is Dummy2UsernameRegistrar {
constructor(
ERC20Token _token,
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
address _slashMechanism,
address _parentRegistry
)
public
Dummy2UsernameRegistrar(
_token,
_ensRegistry,
_resolver,
_ensNode,
_slashMechanism,
_parentRegistry
)
{
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./DummyUsernameRegistrar.sol";
contract UpdatedDummyUsernameRegistrar is DummyUsernameRegistrar {
constructor(
ERC20Token _token,
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
address _slashMechanism,
address _parentRegistry
)
public
DummyUsernameRegistrar(
_token,
_ensRegistry,
_resolver,
_ensNode,
_slashMechanism,
_parentRegistry
)
{
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "../registry/UsernameRegistrar.sol";
contract UpdatedUsernameRegistrar is UsernameRegistrar {
constructor(
ERC20Token _token,
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
address _slashMechanism,
address _parentRegistry
)
public
UsernameRegistrar(
_token,
_ensRegistry,
_resolver,
_ensNode,
_slashMechanism,
_parentRegistry
)
{
}
}

View File

@ -0,0 +1,141 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./UsernameRegistrar.sol";
import "../common/MerkleProof.sol";
/**
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @notice Defines static rules for slashing usernames
*/
contract SlashMechanism {
struct SlashReserve {
address reserver;
uint256 blockNumber;
UsernameRegistrar registrar;
}
mapping (bytes32 => SlashReserve) public reservedSlashers;
//Slashing conditions
uint256 public usernameMinLength;
bytes32 public reservedUsernamesMerkleRoot;
constructor(
uint256 _usernameMinLength,
bytes32 _reservedUsernamesMerkleRoot
) public {
usernameMinLength = _usernameMinLength;
reservedUsernamesMerkleRoot = _reservedUsernamesMerkleRoot;
}
/**
* @notice secretly reserve the slashing reward to `msg.sender`
* @param _registrar address of the registrar with the offending name
* @param _secret keccak256(abi.encodePacked(label, reserveSecret)), label being the username label and reserveSecret a random number.
*/
function reserveSlash(UsernameRegistrar _registrar, bytes32 _secret) external {
require(reservedSlashers[_secret].blockNumber == 0, "Already Reserved");
reservedSlashers[_secret] = SlashReserve(msg.sender, block.number, _registrar);
}
/**
* @notice Slash username smaller then `usernameMinLength`.
* @param _username Raw value of offending username.
* @param _reserveSecret number used in reserve secret generation.
*/
function slashSmallUsername(
string calldata _username,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length < usernameMinLength, "Not a small username.");
slashUsername(_username, _reserveSecret);
}
/**
* @notice Slash username starting with "0x" and with length greater than 12.
* @param _username Raw value of offending username.
* @param _reserveSecret number used in reserve secret generation.
*/
function slashAddressLikeUsername(
string calldata _username,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length > 12, "Too small to look like an address.");
require(username[0] == byte("0"), "First character need to be 0");
require(username[1] == byte("x"), "Second character need to be x");
for(uint i = 2; i < 7; i++){
uint8 b = uint8(username[i]);
require((b >= 48 && b <= 57) || (b >= 97 && b <= 102), "Does not look like an address");
}
slashUsername(_username, _reserveSecret);
}
/**
* @notice Slash username that is exactly a reserved name.
* @param _username Raw value of offending username.
* @param _proof Merkle proof that name is listed on merkle tree.
* @param _reserveSecret number used in reserve secret generation.
*/
function slashReservedUsername(
string calldata _username,
bytes32[] calldata _proof,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(
MerkleProof.verifyProof(
_proof,
reservedUsernamesMerkleRoot,
keccak256(username)
),
"Invalid Proof."
);
slashUsername(_username, _reserveSecret);
}
/**
* @notice Slash username that contains a non alphanumeric character.
* @param _username Raw value of offending username.
* @param _offendingPos Position of non alphanumeric character.
* @param _reserveSecret number used in reserve secret generation.
*/
function slashInvalidUsername(
string calldata _username,
uint256 _offendingPos,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length > _offendingPos, "Invalid position.");
uint8 b = uint8(username[_offendingPos]);
require(!((b >= 48 && b <= 57) || (b >= 97 && b <= 122)), "Not invalid character.");
slashUsername(_username, _reserveSecret);
}
/**
* @dev Checks for reservation and requests username slashing in the selected registrar.
* @param _username Raw value of offending username.
* @param _reserveSecret number used in reserve secret generation.
*/
function slashUsername(string memory _username, uint256 _reserveSecret) internal{
bytes32 secret = keccak256(abi.encodePacked(_username, _reserveSecret));
SlashReserve memory reserve = reservedSlashers[secret];
require(reserve.reserver != address(0), "Not reserved.");
require(reserve.blockNumber < block.number, "Cannot reveal in same block");
delete reservedSlashers[secret];
reserve.registrar.slashUsername(_username, reserve.reserver);
}
}

View File

@ -1,18 +1,19 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "../common/MerkleProof.sol";
import "../common/Controlled.sol"; import "../common/Controlled.sol";
import "../token/ERC20Token.sol"; import "../token/ERC20Token.sol";
import "../token/ApproveAndCallFallBack.sol"; import "../token/ApproveAndCallFallBack.sol";
import "../ens/ENS.sol"; import "../ens/ENS.sol";
import "../ens/PublicResolver.sol"; import "../ens/PublicResolver.sol";
/** /**
* @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
* @notice Registers usernames as ENS subnodes of the domain `ensNode` * @notice Registers usernames as ENS subnodes of the domain `ensNode`
*/ */
contract UsernameRegistrar is Controlled, ApproveAndCallFallBack { contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ERC20Token public token; ERC20Token public token;
ENS public ensRegistry; ENS public ensRegistry;
PublicResolver public resolver; PublicResolver public resolver;
@ -20,11 +21,9 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
uint256 public constant releaseDelay = 365 days; uint256 public constant releaseDelay = 365 days;
mapping (bytes32 => Account) public accounts; mapping (bytes32 => Account) public accounts;
mapping (bytes32 => SlashReserve) reservedSlashers;
//Slashing conditions uint256 public lastUpdate;
uint256 public usernameMinLength; address public slashMechanism;
bytes32 public reservedUsernamesMerkleRoot;
event RegistryState(RegistrarState state); event RegistryState(RegistrarState state);
event RegistryPrice(uint256 price); event RegistryPrice(uint256 price);
@ -43,10 +42,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address owner; address owner;
} }
struct SlashReserve {
address reserver;
uint256 blockNumber;
}
/** /**
* @notice Callable only by `parentRegistry()` to continue migration of ENSSubdomainRegistry. * @notice Callable only by `parentRegistry()` to continue migration of ENSSubdomainRegistry.
@ -56,16 +52,15 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
_; _;
} }
/** /**
* @notice Initializes UsernameRegistrar contract. * @notice Initializes UsernameRegistrar contract.
* The only parameter from this list that can be changed later is `_resolver`. * The only parameter from this list that can be changed later is `_resolver`.
* Other updates require a new contract and migration of domain. * Other updates require a new contract and migration of domain.
* @param _token ERC20 token with optional `approveAndCall(address,uint256,bytes)` for locking fee. * @param _token ERC20 token with optional `approveAndCall(address,uint256,bytes)` for locking fee.
* @param _ensRegistry Ethereum Name Service root contract address. * @param _ensRegistry Ethereum Name Service root contract address.
* @param _resolver Public Resolver for resolving usernames. * @param _resolver Public Resolver for resolving usernames.
* @param _ensNode ENS node (domain) being used for usernames subnodes (subdomain) * @param _ensNode ENS node (domain) being used for usernames subnodes (subdomain)
* @param _usernameMinLength Minimum length of usernames * @param _slashMechanism Slashing mechanism address
* @param _reservedUsernamesMerkleRoot Merkle root of reserved usernames
* @param _parentRegistry Address of old registry (if any) for optional account migration. * @param _parentRegistry Address of old registry (if any) for optional account migration.
*/ */
constructor( constructor(
@ -73,11 +68,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ENS _ensRegistry, ENS _ensRegistry,
PublicResolver _resolver, PublicResolver _resolver,
bytes32 _ensNode, bytes32 _ensNode,
uint256 _usernameMinLength, address _slashMechanism,
bytes32 _reservedUsernamesMerkleRoot,
address _parentRegistry address _parentRegistry
) )
public public
{ {
require(address(_token) != address(0), "No ERC20Token address defined."); require(address(_token) != address(0), "No ERC20Token address defined.");
require(address(_ensRegistry) != address(0), "No ENS address defined."); require(address(_ensRegistry) != address(0), "No ENS address defined.");
@ -87,8 +81,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ensRegistry = _ensRegistry; ensRegistry = _ensRegistry;
resolver = _resolver; resolver = _resolver;
ensNode = _ensNode; ensNode = _ensNode;
usernameMinLength = _usernameMinLength; slashMechanism = _slashMechanism;
reservedUsernamesMerkleRoot = _reservedUsernamesMerkleRoot; lastUpdate = block.timestamp;
parentRegistry = _parentRegistry; parentRegistry = _parentRegistry;
setState(RegistrarState.Inactive); setState(RegistrarState.Inactive);
} }
@ -101,9 +95,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
* - User deposits are completely protected. The contract controller cannot access them. * - User deposits are completely protected. The contract controller cannot access them.
* - User's address(es) will be publicly associated with the ENS name. * - User's address(es) will be publicly associated with the ENS name.
* - User must authorise the contract to transfer `price` `token.name()` on their behalf. * - User must authorise the contract to transfer `price` `token.name()` on their behalf.
* - Usernames registered with less then `usernameMinLength` characters can be slashed. * - Usernames registered can be slashed if offending the `slashMechanism` contract rules.
* - Usernames contained in the merkle tree of root `reservedUsernamesMerkleRoot` can be slashed.
* - Usernames starting with `0x` and bigger then 12 characters can be slashed.
* - If terms of the contract changee.g. Status makes contract upgradesthe user has the right to release the username and get their deposit back. * - If terms of the contract changee.g. Status makes contract upgradesthe user has the right to release the username and get their deposit back.
* @param _label Choosen unowned username hash. * @param _label Choosen unowned username hash.
* @param _account Optional address to set at public resolver. * @param _account Optional address to set at public resolver.
@ -115,30 +107,30 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _account, address _account,
bytes32 _pubkeyA, bytes32 _pubkeyA,
bytes32 _pubkeyB bytes32 _pubkeyB
) )
external external
returns(bytes32 namehash) returns(bytes32 namehash)
{ {
return registerUser(msg.sender, _label, _account, _pubkeyA, _pubkeyB); return registerUser(msg.sender, _label, _account, _pubkeyA, _pubkeyB);
} }
/** /**
* @notice Release username and retrieve locked fee, needs to be called * @notice Release username and retrieve locked fee, needs to be called
* after `releasePeriod` from creation time by ENS registry owner of domain * after `releasePeriod` from creation time by ENS registry owner of domain
* or anytime by account owner when domain migrated to a new registry. * or anytime by account owner when domain migrated to a new registry.
* @param _label Username hash. * @param _label Username hash.
*/ */
function release( function release(
bytes32 _label bytes32 _label
) )
external external
{ {
bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label)); bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label));
Account memory account = accounts[_label]; Account memory account = accounts[_label];
require(account.creationTime > 0, "Username not registered."); require(account.creationTime > 0, "Username not registered.");
if (state == RegistrarState.Active) { if (state == RegistrarState.Active) {
require(msg.sender == ensRegistry.owner(namehash), "Not owner of ENS node."); require(msg.sender == ensRegistry.owner(namehash), "Not owner of ENS node.");
require(block.timestamp > account.creationTime + releaseDelay, "Release period not reached."); require(block.timestamp > account.creationTime + releaseDelay || lastUpdate > account.creationTime, "Release period not reached.");
} else { } else {
require(msg.sender == account.owner, "Not the former account owner."); require(msg.sender == account.owner, "Not the former account owner.");
} }
@ -153,28 +145,28 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ensRegistry.setOwner(namehash, address(0)); ensRegistry.setOwner(namehash, address(0));
} else { } else {
address newOwner = ensRegistry.owner(ensNode); address newOwner = ensRegistry.owner(ensNode);
//Low level call, case dropUsername not implemented or failing, proceed release. //Low level call, case dropUsername not implemented or failing, proceed release.
//Invert (!) to supress warning, return of this call have no use. //Return of this call have no use.
!newOwner.call.gas(80000)( newOwner.call.gas(80000)(
abi.encodeWithSignature( abi.encodeWithSelector(
"dropUsername(bytes32)", this.dropUsername.selector,
_label _label
) )
); );
} }
emit UsernameOwner(namehash, address(0)); emit UsernameOwner(namehash, address(0));
} }
/** /**
* @notice update account owner, should be called by new ens node owner * @notice update account owner, should be called by new ens node owner
* to update this contract registry, otherwise former owner can release * to update this contract registry, otherwise former owner can release
* if domain is moved to a new registry. * if domain is moved to a new registry.
* @param _label Username hash. * @param _label Username hash.
**/ **/
function updateAccountOwner( function updateAccountOwner(
bytes32 _label bytes32 _label
) )
external external
{ {
bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label)); bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label));
require(msg.sender == ensRegistry.owner(namehash), "Caller not owner of ENS node."); require(msg.sender == ensRegistry.owner(namehash), "Caller not owner of ENS node.");
@ -182,106 +174,17 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
require(ensRegistry.owner(ensNode) == address(this), "Registry not owner of registry."); require(ensRegistry.owner(ensNode) == address(this), "Registry not owner of registry.");
accounts[_label].owner = msg.sender; accounts[_label].owner = msg.sender;
emit UsernameOwner(namehash, msg.sender); emit UsernameOwner(namehash, msg.sender);
}
/**
* @notice secretly reserve the slashing reward to `msg.sender`
* @param _secret keccak256(abi.encodePacked(namehash, creationTime, reserveSecret))
*/
function reserveSlash(bytes32 _secret) external {
require(reservedSlashers[_secret].blockNumber == 0, "Already Reserved");
reservedSlashers[_secret] = SlashReserve(msg.sender, block.number);
} }
/**
* @notice Slash username smaller then `usernameMinLength`.
* @param _username Raw value of offending username.
*/
function slashSmallUsername(
string _username,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length < usernameMinLength, "Not a small username.");
slashUsername(username, _reserveSecret);
}
/**
* @notice Slash username starting with "0x" and with length greater than 12.
* @param _username Raw value of offending username.
*/
function slashAddressLikeUsername(
string _username,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length > 12, "Too small to look like an address.");
require(username[0] == byte("0"), "First character need to be 0");
require(username[1] == byte("x"), "Second character need to be x");
for(uint i = 2; i < 7; i++){
byte b = username[i];
require((b >= 48 && b <= 57) || (b >= 97 && b <= 102), "Does not look like an address");
}
slashUsername(username, _reserveSecret);
}
/**
* @notice Slash username that is exactly a reserved name.
* @param _username Raw value of offending username.
* @param _proof Merkle proof that name is listed on merkle tree.
*/
function slashReservedUsername(
string _username,
bytes32[] _proof,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(
MerkleProof.verifyProof(
_proof,
reservedUsernamesMerkleRoot,
keccak256(username)
),
"Invalid Proof."
);
slashUsername(username, _reserveSecret);
}
/**
* @notice Slash username that contains a non alphanumeric character.
* @param _username Raw value of offending username.
* @param _offendingPos Position of non alphanumeric character.
*/
function slashInvalidUsername(
string _username,
uint256 _offendingPos,
uint256 _reserveSecret
)
external
{
bytes memory username = bytes(_username);
require(username.length > _offendingPos, "Invalid position.");
byte b = username[_offendingPos];
require(!((b >= 48 && b <= 57) || (b >= 97 && b <= 122)), "Not invalid character.");
slashUsername(username, _reserveSecret);
}
/** /**
* @notice Clear resolver and ownership of unowned subdomians. * @notice Clear resolver and ownership of unowned subdomians.
* @param _labels Sequence to erase. * @param _labels Sequence to erase.
*/ */
function eraseNode( function eraseNode(
bytes32[] _labels bytes32[] calldata _labels
) )
external external
{ {
uint len = _labels.length; uint len = _labels.length;
require(len != 0, "Nothing to erase"); require(len != 0, "Nothing to erase");
@ -292,8 +195,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
if(len > 1) { if(len > 1) {
eraseNodeHierarchy(len - 2, _labels, subnode); eraseNodeHierarchy(len - 2, _labels, subnode);
} }
ensRegistry.setResolver(subnode, 0); ensRegistry.setResolver(subnode, address(0));
ensRegistry.setOwner(subnode, 0); ensRegistry.setOwner(subnode, address(0));
} }
/** /**
@ -303,8 +206,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
function moveAccount( function moveAccount(
bytes32 _label, bytes32 _label,
UsernameRegistrar _newRegistry UsernameRegistrar _newRegistry
) )
external external
{ {
require(state == RegistrarState.Moved, "Wrong contract state"); require(state == RegistrarState.Moved, "Wrong contract state");
require(msg.sender == accounts[_label].owner, "Callable only by account owner."); require(msg.sender == accounts[_label].owner, "Callable only by account owner.");
@ -312,7 +215,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
Account memory account = accounts[_label]; Account memory account = accounts[_label];
delete accounts[_label]; delete accounts[_label];
token.approve(_newRegistry, account.balance); token.approve(address(_newRegistry), account.balance);
_newRegistry.migrateUsername( _newRegistry.migrateUsername(
_label, _label,
account.balance, account.balance,
@ -321,13 +224,13 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
); );
} }
/** /**
* @notice Activate registration. * @notice Activate registration.
* @param _price The price of registration. * @param _price The price of registration.
*/ */
function activate( function activate(
uint256 _price uint256 _price
) )
external external
onlyController onlyController
{ {
@ -338,26 +241,41 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
emit RegistryPrice(_price); emit RegistryPrice(_price);
} }
/** /**
* @notice Updates Public Resolver for resolving users. * @notice Updates Public Resolver for resolving users.
* @param _resolver New PublicResolver. * @param _resolver New PublicResolver.
*/ */
function setResolver( function setResolver(
address _resolver address _resolver
) )
external external
onlyController onlyController
{ {
resolver = PublicResolver(_resolver); resolver = PublicResolver(_resolver);
} }
/**
* @notice Updates slash mechanism.
* @param _slashMechanism New Slash Mechanism
*/
function setSlashMechanism(
address _slashMechanism
)
external
onlyController
{
lastUpdate = block.timestamp;
require(_slashMechanism != address(0), "Zero address for _slashMechanism");
slashMechanism = _slashMechanism;
}
/** /**
* @notice Updates registration price. * @notice Updates registration price.
* @param _price New registration price. * @param _price New registration price.
*/ */
function updateRegistryPrice( function updateRegistryPrice(
uint256 _price uint256 _price
) )
external external
onlyController onlyController
{ {
@ -365,7 +283,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
price = _price; price = _price;
emit RegistryPrice(_price); emit RegistryPrice(_price);
} }
/** /**
* @notice Transfer ownership of ensNode to `_newRegistry`. * @notice Transfer ownership of ensNode to `_newRegistry`.
* Usernames registered are not affected, but they would be able to instantly release. * Usernames registered are not affected, but they would be able to instantly release.
@ -378,15 +296,15 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
emit RegistryMoved(_newRegistry); emit RegistryMoved(_newRegistry);
} }
/** /**
* @notice Opt-out migration of username from `parentRegistry()`. * @notice Opt-out migration of username from `parentRegistry()`.
* Clear ENS resolver and subnode owner. * Clear ENS resolver and subnode owner.
* @param _label Username hash. * @param _label Username hash.
*/ */
function dropUsername( function dropUsername(
bytes32 _label bytes32 _label
) )
external external
onlyParentRegistry onlyParentRegistry
{ {
require(accounts[_label].creationTime == 0, "Already migrated"); require(accounts[_label].creationTime == 0, "Already migrated");
@ -403,10 +321,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
**/ **/
function withdrawExcessBalance( function withdrawExcessBalance(
address _token, address _token,
address _beneficiary address payable _beneficiary
) )
external external
onlyController onlyController
{ {
require(_beneficiary != address(0), "Cannot burn token"); require(_beneficiary != address(0), "Cannot burn token");
if (_token == address(0)) { if (_token == address(0)) {
@ -432,72 +350,72 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
function withdrawWrongNode( function withdrawWrongNode(
bytes32 _domainHash, bytes32 _domainHash,
address _beneficiary address _beneficiary
) )
external external
onlyController onlyController
{ {
require(_beneficiary != address(0), "Cannot burn node"); require(_beneficiary != address(0), "Cannot burn node");
require(_domainHash != ensNode, "Cannot withdraw main node"); require(_domainHash != ensNode, "Cannot withdraw main node");
require(ensRegistry.owner(_domainHash) == address(this), "Not owner of this node"); require(ensRegistry.owner(_domainHash) == address(this), "Not owner of this node");
ensRegistry.setOwner(_domainHash, _beneficiary); ensRegistry.setOwner(_domainHash, _beneficiary);
} }
/** /**
* @notice Gets registration price. * @notice Gets registration price.
* @return Registration price. * @return registryPrice Registration price.
**/ **/
function getPrice() function getPrice()
external external
view view
returns(uint256 registryPrice) returns(uint256 registryPrice)
{ {
return price; return price;
} }
/** /**
* @notice reads amount tokens locked in username * @notice reads amount tokens locked in username
* @param _label Username hash. * @param _label Username hash.
* @return Locked username balance. * @return accountBalance Locked username balance.
**/ **/
function getAccountBalance(bytes32 _label) function getAccountBalance(bytes32 _label)
external external
view view
returns(uint256 accountBalance) returns(uint256 accountBalance)
{ {
accountBalance = accounts[_label].balance; accountBalance = accounts[_label].balance;
} }
/** /**
* @notice reads username account owner at this contract, * @notice reads username account owner at this contract,
* which can release or migrate in case of upgrade. * which can release or migrate in case of upgrade.
* @param _label Username hash. * @param _label Username hash.
* @return Username account owner. * @return owner Username account owner.
**/ **/
function getAccountOwner(bytes32 _label) function getAccountOwner(bytes32 _label)
external external
view view
returns(address owner) returns(address owner)
{ {
owner = accounts[_label].owner; owner = accounts[_label].owner;
} }
/** /**
* @notice reads when the account was registered * @notice reads when the account was registered
* @param _label Username hash. * @param _label Username hash.
* @return Registration time. * @return creationTime Registration time.
**/ **/
function getCreationTime(bytes32 _label) function getCreationTime(bytes32 _label)
external external
view view
returns(uint256 creationTime) returns(uint256 creationTime)
{ {
creationTime = accounts[_label].creationTime; creationTime = accounts[_label].creationTime;
} }
/** /**
* @notice calculate time where username can be released * @notice calculate time where username can be released
* @param _label Username hash. * @param _label Username hash.
* @return Exact time when username can be released. * @return releaseTime Exact time when username can be released.
**/ **/
function getExpirationTime(bytes32 _label) function getExpirationTime(bytes32 _label)
external external
@ -511,9 +429,9 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} }
/** /**
* @notice calculate reward part an account could payout on slash * @notice calculate reward part an account could payout on slash
* @param _label Username hash. * @param _label Username hash.
* @return Part of reward * @return partReward Part of reward
**/ **/
function getSlashRewardPart(bytes32 _label) function getSlashRewardPart(bytes32 _label)
external external
@ -527,7 +445,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} }
/** /**
* @notice Support for "approveAndCall". Callable only by `token()`. * @notice Support for "approveAndCall". Callable only by `token()`.
* @param _from Who approved. * @param _from Who approved.
* @param _amount Amount being approved, need to be equal `getPrice()`. * @param _amount Amount being approved, need to be equal `getPrice()`.
* @param _token Token being approved, need to be equal `token()`. * @param _token Token being approved, need to be equal `token()`.
@ -537,8 +455,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _from, address _from,
uint256 _amount, uint256 _amount,
address _token, address _token,
bytes _data bytes memory _data
) )
public public
{ {
require(_amount == price, "Wrong value"); require(_amount == price, "Wrong value");
@ -552,17 +470,17 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
bytes32 pubkeyB; bytes32 pubkeyB;
(sig, label, account, pubkeyA, pubkeyB) = abiDecodeRegister(_data); (sig, label, account, pubkeyA, pubkeyB) = abiDecodeRegister(_data);
require( require(
sig == bytes4(0xb82fedbb), //bytes4(keccak256("register(bytes32,address,bytes32,bytes32)")) sig == this.register.selector,
"Wrong method selector" "Wrong method selector"
); );
registerUser(_from, label, account, pubkeyA, pubkeyB); registerUser(_from, label, account, pubkeyA, pubkeyB);
} }
/** /**
* @notice Continues migration of username to new registry. * @notice Continues migration of username to new registry.
* @param _label Username hash. * @param _label Username hash.
* @param _tokenBalance Amount being transfered from `parentRegistry()`. * @param _tokenBalance Amount being transfered from `parentRegistry()`.
* @param _creationTime Time user registrated in `parentRegistry()` is preserved. * @param _creationTime Time user registrated in `parentRegistry()` is preserved.
* @param _accountOwner Account owner which migrated the account. * @param _accountOwner Account owner which migrated the account.
**/ **/
function migrateUsername( function migrateUsername(
@ -580,7 +498,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
parentRegistry, parentRegistry,
address(this), address(this),
_tokenBalance _tokenBalance
), ),
"Error moving funds from old registar." "Error moving funds from old registar."
); );
reserveAmount += _tokenBalance; reserveAmount += _tokenBalance;
@ -595,7 +513,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
**/ **/
function migrateRegistry( function migrateRegistry(
uint256 _price uint256 _price
) )
external external
onlyParentRegistry onlyParentRegistry
{ {
@ -620,8 +538,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _account, address _account,
bytes32 _pubkeyA, bytes32 _pubkeyA,
bytes32 _pubkeyB bytes32 _pubkeyB
) )
internal internal
returns(bytes32 namehash) returns(bytes32 namehash)
{ {
require(state == RegistrarState.Active, "Registry not active."); require(state == RegistrarState.Active, "Registry not active.");
@ -640,14 +558,14 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
"Transfer failed" "Transfer failed"
); );
reserveAmount += price; reserveAmount += price;
} }
bool resolvePubkey = _pubkeyA != 0 || _pubkeyB != 0; bool resolvePubkey = _pubkeyA != 0 || _pubkeyB != 0;
bool resolveAccount = _account != address(0); bool resolveAccount = _account != address(0);
if (resolvePubkey || resolveAccount) { if (resolvePubkey || resolveAccount) {
//set to self the ownership to setup initial resolver //set to self the ownership to setup initial resolver
ensRegistry.setSubnodeOwner(ensNode, _label, address(this)); ensRegistry.setSubnodeOwner(ensNode, _label, address(this));
ensRegistry.setResolver(namehash, resolver); //default resolver ensRegistry.setResolver(namehash, address(resolver)); //default resolver
if (resolveAccount) { if (resolveAccount) {
resolver.setAddr(namehash, _account); resolver.setAddr(namehash, _account);
} }
@ -661,22 +579,24 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} }
emit UsernameOwner(namehash, _owner); emit UsernameOwner(namehash, _owner);
} }
/** /**
* @dev Removes account hash of `_username` and send account.balance to msg.sender. * @dev Removes account hash of `_username` and send account.balance to msg.sender.
* @param _username Username being slashed. * @param _username Username being slashed.
*/ */
function slashUsername( function slashUsername(
bytes _username, string calldata _username,
uint256 _reserveSecret address _reserver
) )
internal external
{ {
bytes32 label = keccak256(_username); require(msg.sender == slashMechanism, "Unauthorized");
bytes32 label = keccak256(bytes(_username));
bytes32 namehash = keccak256(abi.encodePacked(ensNode, label)); bytes32 namehash = keccak256(abi.encodePacked(ensNode, label));
uint256 amountToTransfer = 0; uint256 amountToTransfer = 0;
uint256 creationTime = accounts[label].creationTime; uint256 creationTime = accounts[label].creationTime;
address owner = ensRegistry.owner(namehash); address owner = ensRegistry.owner(namehash);
address beneficiary = _reserver;
if(creationTime == 0) { if(creationTime == 0) {
require( require(
owner != address(0) || owner != address(0) ||
@ -686,24 +606,22 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} else { } else {
assert(creationTime != block.timestamp); assert(creationTime != block.timestamp);
amountToTransfer = accounts[label].balance; amountToTransfer = accounts[label].balance;
if(lastUpdate > creationTime) {
beneficiary = accounts[label].owner;
}
delete accounts[label]; delete accounts[label];
} }
ensRegistry.setSubnodeOwner(ensNode, label, address(this)); ensRegistry.setSubnodeOwner(ensNode, label, address(this));
ensRegistry.setResolver(namehash, address(0)); ensRegistry.setResolver(namehash, address(0));
ensRegistry.setOwner(namehash, address(0)); ensRegistry.setOwner(namehash, address(0));
if (amountToTransfer > 0) { if (amountToTransfer > 0) {
reserveAmount -= amountToTransfer; reserveAmount -= amountToTransfer;
uint256 partialDeposit = amountToTransfer / 3; if(lastUpdate < creationTime) {
amountToTransfer = partialDeposit * 2; // reserve 1/3 to network (controller) amountToTransfer = (amountToTransfer * 2) / 3; // reserve 1/3 to network (controller)
bytes32 secret = keccak256(abi.encodePacked(namehash, creationTime, _reserveSecret)); }
SlashReserve memory reserve = reservedSlashers[secret]; require(token.transfer(beneficiary, amountToTransfer), "Error in transfer.");
require(reserve.reserver != address(0), "Not reserved.");
require(reserve.blockNumber < block.number, "Cannot reveal in same block");
delete reservedSlashers[secret];
require(token.transfer(reserve.reserver, amountToTransfer), "Error in transfer.");
} }
emit UsernameOwner(namehash, address(0)); emit UsernameOwner(namehash, address(0));
} }
@ -721,10 +639,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
*/ */
function eraseNodeHierarchy( function eraseNodeHierarchy(
uint _idx, uint _idx,
bytes32[] _labels, bytes32[] memory _labels,
bytes32 _subnode bytes32 _subnode
) )
private private
{ {
// Take ownership of the node // Take ownership of the node
ensRegistry.setSubnodeOwner(_subnode, _labels[_idx], address(this)); ensRegistry.setSubnodeOwner(_subnode, _labels[_idx], address(this));
@ -736,8 +654,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} }
// Erase the resolver and owner records // Erase the resolver and owner records
ensRegistry.setResolver(subnode, 0); ensRegistry.setResolver(subnode, address(0));
ensRegistry.setOwner(subnode, 0); ensRegistry.setOwner(subnode, address(0));
} }
/** /**
@ -746,10 +664,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
* @return Decoded registry call. * @return Decoded registry call.
*/ */
function abiDecodeRegister( function abiDecodeRegister(
bytes _data bytes memory _data
) )
private private
pure pure
returns( returns(
bytes4 sig, bytes4 sig,
bytes32 label, bytes32 label,

View File

@ -1,12 +1,14 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
import { MerkleProof } from "../common/MerkleProof.sol"; pragma solidity 0.5.11;
import "../common/MerkleProof.sol";
contract MerkleProofWrapper { contract MerkleProofWrapper {
function verifyProof( function verifyProof(
bytes32[] _proof, bytes32[] memory _proof,
bytes32 _root, bytes32 _root,
bytes32 _leaf bytes32 _leaf
) )

View File

@ -1,5 +1,7 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.5.11;
contract ApproveAndCallFallBack { contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public; function receiveApproval(address from, uint256 _amount, address _token, bytes memory _data) public;
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./ERC20Token.sol"; import "./ERC20Token.sol";
@ -43,7 +45,7 @@ contract ERC20Receiver {
) )
external external
{ {
require(_token.allowance(msg.sender, address(this)) >= _amount); require(_token.allowance(msg.sender, address(this)) >= _amount, "Bad argument");
_depositToken(msg.sender, _token, _amount); _depositToken(msg.sender, _token, _amount);
} }
@ -65,7 +67,7 @@ contract ERC20Receiver {
) )
private private
{ {
require(_amount > 0); require(_amount > 0, "Bad argument");
if (_token.transferFrom(_from, address(this), _amount)) { if (_token.transferFrom(_from, address(this), _amount)) {
tokenBalances[address(_token)][_from] += _amount; tokenBalances[address(_token)][_from] += _amount;
emit TokenDeposited(address(_token), _from, _amount); emit TokenDeposited(address(_token), _from, _amount);
@ -79,10 +81,10 @@ contract ERC20Receiver {
) )
private private
{ {
require(_amount > 0); require(_amount > 0, "Bad argument");
require(tokenBalances[address(_token)][_from] >= _amount); require(tokenBalances[address(_token)][_from] >= _amount, "Insufficient funds");
tokenBalances[address(_token)][_from] -= _amount; tokenBalances[address(_token)][_from] -= _amount;
require(_token.transfer(_from, _amount)); require(_token.transfer(_from, _amount), "Transfer fail");
emit TokenWithdrawn(address(_token), _from, _amount); emit TokenWithdrawn(address(_token), _from, _amount);
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
// Abstract contract for the full ERC 20 Token standard // Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20 // https://github.com/ethereum/EIPs/issues/20
@ -9,7 +11,7 @@ interface ERC20Token {
* @notice send `_value` token to `_to` from `msg.sender` * @notice send `_value` token to `_to` from `msg.sender`
* @param _to The address of the recipient * @param _to The address of the recipient
* @param _value The amount of token to be transferred * @param _value The amount of token to be transferred
* @return Whether the transfer was successful or not * @return success Whether the transfer was successful or not
*/ */
function transfer(address _to, uint256 _value) external returns (bool success); function transfer(address _to, uint256 _value) external returns (bool success);
@ -17,7 +19,7 @@ interface ERC20Token {
* @notice `msg.sender` approves `_spender` to spend `_value` tokens * @notice `msg.sender` approves `_spender` to spend `_value` tokens
* @param _spender The address of the account able to transfer the tokens * @param _spender The address of the account able to transfer the tokens
* @param _value The amount of tokens to be approved for transfer * @param _value The amount of tokens to be approved for transfer
* @return Whether the approval was successful or not * @return success Whether the approval was successful or not
*/ */
function approve(address _spender, uint256 _value) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success);
@ -26,25 +28,26 @@ interface ERC20Token {
* @param _from The address of the sender * @param _from The address of the sender
* @param _to The address of the recipient * @param _to The address of the recipient
* @param _value The amount of token to be transferred * @param _value The amount of token to be transferred
* @return Whether the transfer was successful or not * @return success Whether the transfer was successful or not
*/ */
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
/** /**
* @param _owner The address from which the balance will be retrieved * @param _owner The address from which the balance will be retrieved
* @return The balance * @return balance The balance
*/ */
function balanceOf(address _owner) external view returns (uint256 balance); function balanceOf(address _owner) external view returns (uint256 balance);
/** /**
* @param _owner The address of the account owning tokens * @param _owner The address of the account owning tokens
* @param _spender The address of the account able to transfer the tokens * @param _spender The address of the account able to transfer the tokens
* @return Amount of remaining tokens allowed to spent * @return remaining Amount of remaining tokens allowed to spent
*/ */
function allowance(address _owner, address _spender) external view returns (uint256 remaining); function allowance(address _owner, address _spender) external view returns (uint256 remaining);
/** /**
* @notice return total supply of tokens * @notice return total supply of tokens
* @return supply Total supply of the token.
*/ */
function totalSupply() external view returns (uint256 supply); function totalSupply() external view returns (uint256 supply);

View File

@ -1,10 +1,12 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./ERC20Token.sol"; import "./ERC20Token.sol";
contract StandardToken is ERC20Token { contract StandardToken is ERC20Token {
uint256 private supply; uint256 private totalTokens;
mapping (address => uint256) balances; mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed; mapping (address => mapping (address => uint256)) allowed;
@ -67,11 +69,11 @@ contract StandardToken is ERC20Token {
function totalSupply() function totalSupply()
external external
view view
returns(uint256 currentTotalSupply) returns(uint256 supply)
{ {
return supply; return totalTokens;
} }
/** /**
* @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender. * @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _from The address that is approving the spend * @param _from The address that is approving the spend
@ -98,8 +100,8 @@ contract StandardToken is ERC20Token {
internal internal
{ {
balances[_to] += _amount; balances[_to] += _amount;
supply += _amount; totalTokens += _amount;
emit Transfer(0x0, _to, _amount); emit Transfer(address(0x0), _to, _amount);
} }
function transfer( function transfer(
@ -113,7 +115,7 @@ contract StandardToken is ERC20Token {
if (balances[_from] >= _value && _value > 0) { if (balances[_from] >= _value && _value > 0) {
balances[_from] -= _value; balances[_from] -= _value;
if(_to == address(0)) { if(_to == address(0)) {
supply -= _value; totalTokens -= _value;
} else { } else {
balances[_to] += _value; balances[_to] += _value;
} }

View File

@ -1,4 +1,6 @@
pragma solidity ^0.4.24; // SPDX-License-Identifier: CC0-1.0
pragma solidity 0.5.11;
import "./StandardToken.sol"; import "./StandardToken.sol";
import "./ApproveAndCallFallBack.sol"; import "./ApproveAndCallFallBack.sol";
@ -18,12 +20,13 @@ contract TestToken is StandardToken {
mint(msg.sender, _amount); mint(msg.sender, _amount);
} }
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
external function approveAndCall(address _spender, uint256 _value, bytes calldata _extraData)
external
returns (bool success) returns (bool success)
{ {
approve(msg.sender, _spender, _value); approve(msg.sender, _spender, _value);
ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _value, this, _extraData); ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _value, address(this), _extraData);
return true; return true;
} }

View File

@ -9,9 +9,23 @@
"buildDir": "dist/", "buildDir": "dist/",
"config": "config/", "config": "config/",
"versions": { "versions": {
"web3": "1.0.0-beta.34", "solc": "0.5.11"
"solc": "0.4.24",
"ipfs-api": "17.2.4"
}, },
"plugins": {} "plugins": {
} "embark-ipfs": {},
"embark-swarm": {},
"embark-whisper-geth": {},
"embark-geth": {},
"embark-parity": {},
"embark-profiler": {},
"embark-graph": {},
"embark-basic-pipeline": {}
},
"options": {
"solc": {
"optimize": true,
"optimize-runs": 200
}
},
"generationDir": "embarkArtifacts"
}

26191
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,21 @@
"web3-utils": "^1.0.0-beta.34" "web3-utils": "^1.0.0-beta.34"
}, },
"devDependencies": { "devDependencies": {
"embark": "^6.0.0",
"embark-basic-pipeline": "^6.0.0",
"embark-geth": "^6.0.0",
"embark-graph": "^6.0.0",
"embark-ipfs": "^6.0.0",
"embark-parity": "^6.0.0",
"embark-profiler": "^6.0.0",
"embark-swarm": "^6.0.0",
"embark-whisper-geth": "^6.0.0",
"embarkjs": "^6.0.0",
"embarkjs-ens": "^6.0.0",
"embarkjs-ipfs": "^6.0.0",
"embarkjs-swarm": "^6.0.0",
"embarkjs-web3": "^6.0.0",
"embarkjs-whisper": "^6.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-decorators": "^7.0.0", "@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/plugin-proposal-export-namespace-from": "^7.0.0", "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
@ -58,6 +73,7 @@
"@babel/plugin-proposal-throw-expressions": "^7.0.0", "@babel/plugin-proposal-throw-expressions": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-syntax-import-meta": "^7.0.0", "@babel/plugin-syntax-import-meta": "^7.0.0",
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0", "eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.12.0", "eslint-plugin-import": "^2.12.0",

View File

@ -1,11 +1,8 @@
const ERC20Receiver = require('Embark/contracts/ERC20Receiver'); const ERC20Receiver = artifacts.require('ERC20Receiver');
exports.config = { exports.contracts = {
contracts : { "ERC20Receiver": {}
"ERC20Receiver": {
}
}
} }
exports.Test = (ERC20Token) => { exports.Test = (ERC20Token) => {
@ -26,14 +23,14 @@ exports.Test = (ERC20Token) => {
let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call();
let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call();
assert.equal(result0, +initialBalance0-1, "account 0 balance unexpected"); assert.equal(+result0, +initialBalance0-1, "account 0 balance unexpected");
assert.equal(result1, +initialBalance1+1, "account 1 balance unexpected"); assert.equal(+result1, +initialBalance1+1, "account 1 balance unexpected");
}); });
it("should set approved amount", async function() { it("should set approved amount", async function() {
await ERC20Token.methods.approve(accounts[2],10000000).send({from: accounts[0]}); await ERC20Token.methods.approve(accounts[2],10000000).send({from: accounts[0]});
let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call();
assert.equal(result, 10000000); assert.equal(+result, 10000000);
}); });
it("should consume allowance amount", async function() { it("should consume allowance amount", async function() {
@ -41,7 +38,7 @@ exports.Test = (ERC20Token) => {
await ERC20Token.methods.transferFrom(accounts[0], accounts[0],1).send({from: accounts[2]}); await ERC20Token.methods.transferFrom(accounts[0], accounts[0],1).send({from: accounts[2]});
let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call();
assert.equal(result, +initialAllowance-1); assert.equal(+result, +initialAllowance-1);
}); });
it("should transfer approved amount", async function() { it("should transfer approved amount", async function() {
@ -51,15 +48,15 @@ exports.Test = (ERC20Token) => {
let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call(); let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call();
let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call(); let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call();
assert.equal(result0, +initialBalance0-1); assert.equal(+result0, +initialBalance0-1);
assert.equal(result1, +initialBalance1+1); assert.equal(+result1, +initialBalance1+1);
}); });
it("should unset approved amount", async function() { it("should unset approved amount", async function() {
await ERC20Token.methods.approve(accounts[2],0).send({from: accounts[0]}); await ERC20Token.methods.approve(accounts[2],0).send({from: accounts[0]});
let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call(); let result = await ERC20Token.methods.allowance(accounts[0], accounts[2]).call();
assert.equal(result, 0); assert.equal(+result, 0);
}); });
it("should deposit approved amount to contract ERC20Receiver", async function() { it("should deposit approved amount to contract ERC20Receiver", async function() {
@ -68,14 +65,14 @@ exports.Test = (ERC20Token) => {
await ERC20Token.methods.approve(ERC20Receiver.address, 10).send({from: accounts[0]}); await ERC20Token.methods.approve(ERC20Receiver.address, 10).send({from: accounts[0]});
await ERC20Receiver.methods.depositToken(ERC20Token.address, 10).send({from: accounts[0]}); await ERC20Receiver.methods.depositToken(ERC20Token.address, 10).send({from: accounts[0]});
let result = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); let result = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call();
assert.equal(result, 10, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong"); assert.equal(+result, 10, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong");
}); });
it("should witdraw approved amount from contract ERC20Receiver", async function() { it("should witdraw approved amount from contract ERC20Receiver", async function() {
let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call();
await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accounts[0]}); await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accounts[0]});
tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call(); tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call();
assert.equal(tokenBalance, 0, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong"); assert.equal(+tokenBalance, 0, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accounts[0]+") wrong");
}); });
//TODO: include checks for expected events fired //TODO: include checks for expected events fired

View File

@ -1,11 +1,11 @@
const utils = require('../utils/testUtils.js'); const utils = require('../utils/testUtils.js');
const ENSRegistry = require('Embark/contracts/ENSRegistry'); const ENSRegistry = artifacts.require('ENSRegistry');
const web3Utils = require('web3-utils'); const web3Utils = require('web3-utils');
const namehash = require('eth-ens-namehash'); const namehash = require('eth-ens-namehash');
config({ config({
contracts: { contracts: {
"ENSRegistry": { }, deploy: {"ENSRegistry": { }}
} }
}); });
@ -57,10 +57,10 @@ contract('ENS', function () {
it('should allow setting the TTL', async () => { it('should allow setting the TTL', async () => {
let result = await ENSRegistry.methods.setTTL(utils.zeroBytes32, 3600).send({from: accountsArr[1]}); let result = await ENSRegistry.methods.setTTL(utils.zeroBytes32, 3600).send({from: accountsArr[1]});
assert.equal(await ENSRegistry.methods.ttl(utils.zeroBytes32).call(), 3600); assert.equal(+await ENSRegistry.methods.ttl(utils.zeroBytes32).call(), 3600);
let args = result.events.NewTTL.returnValues; let args = result.events.NewTTL.returnValues;
assert.equal(args.node, utils.zeroBytes32); assert.equal(args.node, utils.zeroBytes32);
assert.equal(args.ttl, 3600); assert.equal(+args.ttl, 3600);
}); });
it('should prevent setting the TTL by non-owners', async () => { it('should prevent setting the TTL by non-owners', async () => {

View File

@ -1,7 +1,7 @@
const { MerkleTree } = require('../utils/merkleTree.js'); const { MerkleTree } = require('../utils/merkleTree.js');
const { sha3, bufferToHex } = require('ethereumjs-util'); const { sha3, bufferToHex } = require('ethereumjs-util');
const MerkleProofWrapper = require('Embark/contracts/MerkleProofWrapper'); const MerkleProofWrapper = artifacts.require('MerkleProofWrapper');
var contractsConfig = { var contractsConfig = {
"MerkleProofWrapper": { "MerkleProofWrapper": {
@ -9,7 +9,7 @@ var contractsConfig = {
} }
}; };
config({ contracts: contractsConfig }); config({ contracts: { deploy: contractsConfig }});
contract('MerkleProof', function () { contract('MerkleProof', function () {

View File

@ -1,12 +1,14 @@
const Utils = require('../utils/testUtils'); const Utils = require('../utils/testUtils');
const TestToken = require('Embark/contracts/TestToken'); const TestToken = artifacts.require('TestToken');
const ERC20TokenSpec = require('./abstract/erc20tokenspec'); const ERC20TokenSpec = require('./abstract/erc20tokenspec');
config({ config({
contracts: { contracts: {
"TestToken": { deploy: {
}, "TestToken": {
...ERC20TokenSpec.config.contracts },
...ERC20TokenSpec.contracts
}
} }
}); });
@ -24,28 +26,28 @@ contract("TestToken", function() {
let initialSupply = await TestToken.methods.totalSupply().call(); let initialSupply = await TestToken.methods.totalSupply().call();
await TestToken.methods.mint(100).send(); await TestToken.methods.mint(100).send();
let result = await TestToken.methods.totalSupply().call(); let result = await TestToken.methods.totalSupply().call();
assert.equal(result, +initialSupply+100); assert.equal(+result, +initialSupply+100);
}); });
it("should increase accountBalance in mint", async function() { it("should increase accountBalance in mint", async function() {
let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call(); let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call();
await TestToken.methods.mint(100).send({from: accounts[0]}); await TestToken.methods.mint(100).send({from: accounts[0]});
let result = await TestToken.methods.balanceOf(accounts[0]).call(); let result = await TestToken.methods.balanceOf(accounts[0]).call();
assert.equal(result, +initialBalance+100); assert.equal(+result, +initialBalance+100);
}); });
it("should burn account supply", async function() { it("should burn account supply", async function() {
let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call(); let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call();
await TestToken.methods.transfer(Utils.zeroAddress, initialBalance).send({from: accounts[0]}); await TestToken.methods.transfer(Utils.zeroAddress, initialBalance).send({from: accounts[0]});
assert.equal(await TestToken.methods.totalSupply().call(), 0); assert.equal(+await TestToken.methods.totalSupply().call(), 0);
assert.equal(await TestToken.methods.balanceOf(accounts[0]).call(), 0); assert.equal(+await TestToken.methods.balanceOf(accounts[0]).call(), 0);
}) })
it("should mint balances for ERC20TokenSpec", async function() { it("should mint balances for ERC20TokenSpec", async function() {
let initialBalance = 7 * 10 ^ 18; let initialBalance = 7 * 10 ^ 18;
for(i=0;i<accounts.length;i++){ for(i=0;i<accounts.length;i++){
await TestToken.methods.mint(initialBalance).send({from: accounts[i]}) await TestToken.methods.mint(initialBalance).send({from: accounts[i]})
assert.equal(await TestToken.methods.balanceOf(accounts[i]).call(), initialBalance); assert.equal(+await TestToken.methods.balanceOf(accounts[i]).call(), initialBalance);
} }
}) })

View File

@ -11,7 +11,7 @@ const registry = {
registry: 'stateofus.eth', registry: 'stateofus.eth',
label: web3Utils.sha3('stateofus'), label: web3Utils.sha3('stateofus'),
namehash: namehash.hash('stateofus.eth'), namehash: namehash.hash('stateofus.eth'),
price: 100000000 price: 1000
} }
const dummyRegistry = { const dummyRegistry = {
@ -19,7 +19,7 @@ const dummyRegistry = {
registry: 'dummyreg.eth', registry: 'dummyreg.eth',
label: web3Utils.sha3('dummyreg'), label: web3Utils.sha3('dummyreg'),
namehash: namehash.hash('dummyreg.eth'), namehash: namehash.hash('dummyreg.eth'),
price: 100000000 price: 1000
} }
@ -28,7 +28,7 @@ const dummy2Registry = {
registry: 'dummy2reg.eth', registry: 'dummy2reg.eth',
label: web3Utils.sha3('dummy2reg'), label: web3Utils.sha3('dummy2reg'),
namehash: namehash.hash('dummy2reg.eth'), namehash: namehash.hash('dummy2reg.eth'),
price: 100000000 price: 1000
} }
// TODO: load file of reserved names and balance array lenght to be even // TODO: load file of reserved names and balance array lenght to be even
@ -39,97 +39,100 @@ let accountsArr;
config( config(
{ {
contracts: { contracts: {
"TestToken": { }, deploy: {
"ENSRegistry": { "TestToken": { },
"onDeploy": [ "ENSRegistry": {
"await ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()" "onDeploy": [
] "await ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()"
}, ]
"PublicResolver": { },
"args": [ "PublicResolver": {
"$ENSRegistry" "args": [
] "$ENSRegistry"
}, ]
"UsernameRegistrar": { },
"args": [ "SlashMechanism": {
"$TestToken", "args": [
"$ENSRegistry", "3",
"$PublicResolver", merkleRoot
registry.namehash, ],
"3", }
merkleRoot, ,"UsernameRegistrar": {
"0x0" "args": [
], "$TestToken",
"onDeploy": [ "$ENSRegistry",
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+registry.label+"', UsernameRegistrar.address).send()", "$PublicResolver",
] registry.namehash,
}, "$SlashMechanism",
"UpdatedUsernameRegistrar": { "0x0000000000000000000000000000000000000000"
"instanceOf" : "UsernameRegistrar", ],
"args": [ "onDeploy": [
"$TestToken", "await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+registry.label+"', UsernameRegistrar.address).send()",
"$ENSRegistry", ]
"$PublicResolver", },
registry.namehash, "UpdatedUsernameRegistrar": {
"3", "args": [
merkleRoot, "$TestToken",
"$UsernameRegistrar" "$ENSRegistry",
] "$PublicResolver",
}, registry.namehash,
"DummyUsernameRegistrar": { "$SlashMechanism",
"instanceOf" : "UsernameRegistrar", "$UsernameRegistrar"
"args": [ ]
"$TestToken", },
"$ENSRegistry", "DummyUsernameRegistrar": {
"$PublicResolver", "args": [
dummyRegistry.namehash, "$TestToken",
"3", "$ENSRegistry",
merkleRoot, "$PublicResolver",
"0x0" dummyRegistry.namehash,
], "$SlashMechanism",
"onDeploy": [ "0x0000000000000000000000000000000000000000"
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummyRegistry.label+"', DummyUsernameRegistrar.address).send()", ],
] "onDeploy": [
}, "await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummyRegistry.label+"', DummyUsernameRegistrar.address).send()",
"UpdatedDummyUsernameRegistrar": { ]
"instanceOf" : "UsernameRegistrar", },
"args": [ "UpdatedDummyUsernameRegistrar": {
"$TestToken", "args": [
"$ENSRegistry", "$TestToken",
"$PublicResolver", "$ENSRegistry",
dummyRegistry.namehash, "$PublicResolver",
"3", dummyRegistry.namehash,
merkleRoot, "$SlashMechanism",
"$DummyUsernameRegistrar" "$DummyUsernameRegistrar"
] ]
}, },
"Dummy2UsernameRegistrar": { "Dummy2SlashMechanism": {
"instanceOf" : "UsernameRegistrar", "args": [
"args": [ "3",
"$TestToken", utils.zeroBytes32
"$ENSRegistry", ],
"$PublicResolver", },
dummy2Registry.namehash, "Dummy2UsernameRegistrar": {
"3", "args": [
utils.zeroBytes32, "$TestToken",
"0x0" "$ENSRegistry",
], "$PublicResolver",
"onDeploy": [ dummy2Registry.namehash,
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummy2Registry.label+"', Dummy2UsernameRegistrar.address).send()", "$Dummy2SlashMechanism",
"await Dummy2UsernameRegistrar.methods.activate("+dummy2Registry.price+").send()" "0x0000000000000000000000000000000000000000"
] ],
}, "onDeploy": [
"UpdatedDummy2UsernameRegistrar": { "await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummy2Registry.label+"', Dummy2UsernameRegistrar.address).send()",
"instanceOf" : "UsernameRegistrar", "await Dummy2UsernameRegistrar.methods.activate("+dummy2Registry.price+").send()"
"args": [ ]
"$TestToken", },
"$ENSRegistry", "UpdatedDummy2UsernameRegistrar": {
"$PublicResolver", "args": [
dummy2Registry.namehash, "$TestToken",
"3", "$ENSRegistry",
merkleRoot, "$PublicResolver",
"$Dummy2UsernameRegistrar" dummy2Registry.namehash,
] "$SlashMechanism",
"$Dummy2UsernameRegistrar"
]
}
} }
} }
}, (_err, web3_accounts) => { }, (_err, web3_accounts) => {
@ -137,15 +140,17 @@ config(
} }
); );
const TestToken = require('Embark/contracts/TestToken'); const TestToken = artifacts.require('TestToken');
const ENSRegistry = require('Embark/contracts/ENSRegistry'); const ENSRegistry = artifacts.require('ENSRegistry');
const PublicResolver = require('Embark/contracts/PublicResolver'); const PublicResolver = artifacts.require('PublicResolver');
const UsernameRegistrar = require('Embark/contracts/UsernameRegistrar'); const UsernameRegistrar = artifacts.require('UsernameRegistrar');
const UpdatedUsernameRegistrar = require('Embark/contracts/UpdatedUsernameRegistrar'); const UpdatedUsernameRegistrar = artifacts.require('UpdatedUsernameRegistrar');
const DummyUsernameRegistrar = require('Embark/contracts/DummyUsernameRegistrar'); const DummyUsernameRegistrar = artifacts.require('DummyUsernameRegistrar');
const UpdatedDummyUsernameRegistrar = require('Embark/contracts/UpdatedDummyUsernameRegistrar'); const UpdatedDummyUsernameRegistrar = artifacts.require('UpdatedDummyUsernameRegistrar');
const Dummy2UsernameRegistrar = require('Embark/contracts/Dummy2UsernameRegistrar'); const Dummy2UsernameRegistrar = artifacts.require('Dummy2UsernameRegistrar');
const UpdatedDummy2UsernameRegistrar = require('Embark/contracts/UpdatedDummy2UsernameRegistrar'); const UpdatedDummy2UsernameRegistrar = artifacts.require('UpdatedDummy2UsernameRegistrar');
const SlashMechanism = artifacts.require('SlashMechanism');
const Dummy2SlashMechanism = artifacts.require('Dummy2SlashMechanism');
contract('UsernameRegistrar', function () { contract('UsernameRegistrar', function () {
@ -155,9 +160,9 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(1000) await utils.increaseTime(1000)
const initialPrice = 100 const initialPrice = 100
const resultSetRegistryPrice = await UsernameRegistrar.methods.activate(initialPrice).send({from: accountsArr[0]}); const resultSetRegistryPrice = await UsernameRegistrar.methods.activate(initialPrice).send({from: accountsArr[0]});
assert.equal(resultSetRegistryPrice.events.RegistryPrice.returnValues.price, initialPrice, "event RegistryPrice wrong price"); assert.equal(+resultSetRegistryPrice.events.RegistryPrice.returnValues.price, initialPrice, "event RegistryPrice wrong price");
assert.equal(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state") assert.equal(+await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state")
assert.equal(await UsernameRegistrar.methods.price().call(), initialPrice, "Wrong registry price") assert.equal(+await UsernameRegistrar.methods.price().call(), initialPrice, "Wrong registry price")
}); });
}); });
@ -165,9 +170,9 @@ contract('UsernameRegistrar', function () {
it('should change registry price', async () => { it('should change registry price', async () => {
const newPrice = registry.price; const newPrice = registry.price;
const resultUpdateRegistryPrice = await UsernameRegistrar.methods.updateRegistryPrice(newPrice).send({from: accountsArr[0]}); const resultUpdateRegistryPrice = await UsernameRegistrar.methods.updateRegistryPrice(newPrice).send({from: accountsArr[0]});
assert.equal(resultUpdateRegistryPrice.events.RegistryPrice.returnValues.price, registry.price, "event RegistryPrice wrong price"); assert.equal(+resultUpdateRegistryPrice.events.RegistryPrice.returnValues.price, registry.price, "event RegistryPrice wrong price");
assert.equal(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state") assert.equal(+await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state")
assert.equal(await UsernameRegistrar.methods.price().call(), newPrice, "Wrong registry price") assert.equal(+await UsernameRegistrar.methods.price().call(), newPrice, "Wrong registry price")
}); });
}); });
@ -177,10 +182,10 @@ contract('UsernameRegistrar', function () {
const username = 'erin'; const username = 'erin';
const usernameHash = namehash.hash(username + '.' + registry.registry); const usernameHash = namehash.hash(username + '.' + registry.registry);
const label = web3Utils.sha3(username); const label = web3Utils.sha3(username);
const registryPrice = await UsernameRegistrar.methods.getPrice().call() const registryPrice = +await UsernameRegistrar.methods.getPrice().call()
await TestToken.methods.mint(registry.price).send({from: registrant}); await TestToken.methods.mint(registry.price).send({from: registrant});
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant}); await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant});
const resultRegister = await UsernameRegistrar.methods.register( const resultRegister = await UsernameRegistrar.methods.register(
web3Utils.sha3(username), web3Utils.sha3(username),
@ -191,7 +196,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to");
assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); assert.equal(+resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value");
assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event");
assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node");
assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label");
@ -200,10 +205,10 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch");
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong") assert.equal(+await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong")
assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong") assert.equal(+await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong")
}); });
it('should register username only resolveing address ', async () => { it('should register username only resolveing address ', async () => {
const registrant = accountsArr[2]; const registrant = accountsArr[2];
@ -222,7 +227,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to");
assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); assert.equal(+resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value");
assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event");
assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node");
assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label");
@ -240,7 +245,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch");
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -265,7 +270,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to");
assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); assert.equal(+resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value");
assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event");
assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node");
assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label");
@ -283,7 +288,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch");
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -308,7 +313,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event"); assert.equal(resultRegister.events['0'].raw.topics[0], web3Utils.sha3("Transfer(address,address,uint256)"), "Wrong Event");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[1]), registrant, "Wrong Transfer from");
assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to"); assert.equal(utils.eventAddress(resultRegister.events['0'].raw.topics[2]), UsernameRegistrar.address, "Wrong transfer to");
assert.equal(resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value"); assert.equal(+resultRegister.events['0'].raw.data, registry.price, "Wrong transfer value");
assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event"); assert.equal(resultRegister.events['1'].raw.topics[0], web3Utils.sha3("NewOwner(bytes32,bytes32,address)"), "Wrong Event");
assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node"); assert.equal(resultRegister.events['1'].raw.topics[1], registry.namehash, "Wrong Node");
assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label"); assert.equal(resultRegister.events['1'].raw.topics[2], label, "Wrong Label");
@ -329,7 +334,7 @@ contract('UsernameRegistrar', function () {
assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch"); assert.equal(resultRegister.events.UsernameOwner.returnValues.nameHash, usernameHash, "event UsernameOwner usernameHash mismatch");
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -344,10 +349,10 @@ contract('UsernameRegistrar', function () {
const username = 'erinauto'; const username = 'erinauto';
const usernameHash = namehash.hash(username + '.' + registry.registry); const usernameHash = namehash.hash(username + '.' + registry.registry);
const label = web3Utils.sha3(username); const label = web3Utils.sha3(username);
const registryPrice = await UsernameRegistrar.methods.getPrice().call() const registryPrice = +await UsernameRegistrar.methods.getPrice().call()
await TestToken.methods.mint(registry.price).send({from: registrant}); await TestToken.methods.mint(registry.price).send({from: registrant});
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const registerCall = UsernameRegistrar.methods.register( const registerCall = UsernameRegistrar.methods.register(
web3Utils.sha3(username), web3Utils.sha3(username),
@ -359,10 +364,10 @@ contract('UsernameRegistrar', function () {
// TODO: check events // TODO: check events
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registryPrice, "Registry username account balance wrong");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong") assert.equal(+await TestToken.methods.balanceOf(registrant).call(), +initialRegistrantBalance-registryPrice, "User final balance wrong")
assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong") assert.equal(+await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)+(+registry.price), "Registry final balance wrong")
}); });
it('should register username only resolving address ', async () => { it('should register username only resolving address ', async () => {
const registrant = accountsArr[2]; const registrant = accountsArr[2];
@ -383,7 +388,7 @@ contract('UsernameRegistrar', function () {
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -410,7 +415,7 @@ contract('UsernameRegistrar', function () {
// TODO: check events // TODO: check events
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -436,7 +441,7 @@ contract('UsernameRegistrar', function () {
// TODO: check events // TODO: check events
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), registry.price, "Wrong account balance");
assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch"); assert.equal(await UsernameRegistrar.methods.getAccountOwner(label).call(), registrant, "Account owner mismatch");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call(); const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -480,21 +485,21 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32, utils.zeroBytes32,
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); const releaseDelay = +await UsernameRegistrar.methods.releaseDelay().call();
await utils.increaseTime(releaseDelay) await utils.increaseTime(releaseDelay)
await utils.increaseTime(1000) await utils.increaseTime(1000)
const initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call(); const initialAccountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await utils.increaseTime(1000) await utils.increaseTime(1000)
const resultRelease = await UsernameRegistrar.methods.release( const resultRelease = await UsernameRegistrar.methods.release(
web3Utils.sha3(username), web3Utils.sha3(username),
).send({from: registrant}); ).send({from: registrant});
//TODO: check events //TODO: check events
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed");
assert.equal(await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "Releaser token balance didnt increase") assert.equal(+await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "Releaser token balance didnt increase")
assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") assert.equal(+await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
}); });
it('should release transfered username', async () => { it('should release transfered username', async () => {
let registrant = accountsArr[7]; let registrant = accountsArr[7];
@ -511,20 +516,20 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await ENSRegistry.methods.setOwner(usernameHash, newOwner).send({from: registrant}); await ENSRegistry.methods.setOwner(usernameHash, newOwner).send({from: registrant});
let releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); let releaseDelay = +await UsernameRegistrar.methods.releaseDelay().call();
await utils.increaseTime(releaseDelay) await utils.increaseTime(releaseDelay)
await utils.increaseTime(1000) await utils.increaseTime(1000)
let initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call(); let initialAccountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call();
let initialRegistrantBalance = await TestToken.methods.balanceOf(newOwner).call(); let initialRegistrantBalance = +await TestToken.methods.balanceOf(newOwner).call();
let initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); let initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await utils.increaseTime(1000) await utils.increaseTime(1000)
let resultRelease = await UsernameRegistrar.methods.release( let resultRelease = await UsernameRegistrar.methods.release(
label label
).send({from: newOwner}); ).send({from: newOwner});
//TODO: check events //TODO: check events
assert.equal(await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed"); assert.equal(+await UsernameRegistrar.methods.getAccountBalance(label).call(), 0, "Final balance didnt zeroed");
assert.equal(await TestToken.methods.balanceOf(newOwner).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase") assert.equal(+await TestToken.methods.balanceOf(newOwner).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase")
assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") assert.equal(+await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
}); });
it('should release moved username account balance by owner', async () => { it('should release moved username account balance by owner', async () => {
const registrant = accountsArr[5]; const registrant = accountsArr[5];
@ -541,9 +546,9 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32, utils.zeroBytes32,
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
let initialAccountBalance = await DummyUsernameRegistrar.methods.getAccountBalance(label).call(); let initialAccountBalance = +await DummyUsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call();
await DummyUsernameRegistrar.methods.moveRegistry(UpdatedDummyUsernameRegistrar.address).send(); await DummyUsernameRegistrar.methods.moveRegistry(UpdatedDummyUsernameRegistrar.address).send();
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
@ -554,8 +559,8 @@ contract('UsernameRegistrar', function () {
label label
).send({from: registrant}); ).send({from: registrant});
//TODO: verify events //TODO: verify events
assert.equal(await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase") assert.equal(+await TestToken.methods.balanceOf(registrant).call(), (+initialRegistrantBalance)+(+initialAccountBalance), "New owner token balance didnt increase")
assert.equal(await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease") assert.equal(+await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver not undefined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver not undefined");
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress, "Owner not removed"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress, "Owner not removed");
//We are not cleaning PublicResolver or any resolver, so the value should remain the same. //We are not cleaning PublicResolver or any resolver, so the value should remain the same.
@ -605,14 +610,13 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
assert.notEqual(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); assert.notEqual(+await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send() await SlashMechanism.methods.slashInvalidUsername(username, 4, reserveSecret).send()
//TODO: check events //TODO: check events
assert.equal(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); assert.equal(+await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
it('should not slash valid username', async () => { it('should not slash valid username', async () => {
@ -628,13 +632,12 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send() await SlashMechanism.methods.slashInvalidUsername(username, 4, reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -658,13 +661,12 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[0]), reserveSecret).send() await SlashMechanism.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[0]), reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -685,13 +687,12 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[1]), reserveSecret).send() await SlashMechanism.methods.slashReservedUsername(username, merkleTree.getHexProof(ReservedUsernames[1]), reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -712,11 +713,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
result = await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(username), reserveSecret).send() await SlashMechanism.methods.slashReservedUsername(username, merkleTree.getHexProof(username), reserveSecret).send()
//TODO: check events //TODO: check events
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
@ -736,13 +736,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(1000) await utils.increaseTime(1000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call(); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashSmallUsername(username).send() await SlashMechanism.methods.slashSmallUsername(username).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -764,11 +764,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
result = await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send() result = await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send()
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
}); });
@ -789,11 +788,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(1000) await utils.increaseTime(1000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() result = await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
it('should not slash username that starts with 0x but is smaller then 12', async () => { it('should not slash username that starts with 0x but is smaller then 12', async () => {
@ -810,13 +808,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -837,13 +835,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -864,13 +862,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call(); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send(); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed; let failed;
try{ try{
await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send() await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false; failed = false;
} catch(e){ } catch(e){
failed = true; failed = true;
@ -896,18 +894,17 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(20000) await utils.increaseTime(20000)
const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call(); const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call();
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const initialSlasherBalance = await TestToken.methods.balanceOf(slasher).call(); const initialSlasherBalance = +await TestToken.methods.balanceOf(slasher).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: slasher}); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send({from: slasher});
await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slasher}) await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send({from: slasher})
//TODO: check events //TODO: check events
assert.equal(await TestToken.methods.balanceOf(slasher).call(), (+initialSlasherBalance)+((+partReward)*2)); assert.equal(+await TestToken.methods.balanceOf(slasher).call(), (+initialSlasherBalance)+((+partReward)*2));
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
it('should slash a username of a not migrated subnode that became unallowed', async () => { it('should return funds of slashing when changed rules', async () => {
const registrant = accountsArr[5]; const registrant = accountsArr[5];
const notRegistrant = accountsArr[6]; const notRegistrant = accountsArr[6];
@ -925,20 +922,19 @@ contract('UsernameRegistrar', function () {
).send({from: registrant}); ).send({from: registrant});
await utils.increaseTime(20000) await utils.increaseTime(20000)
let initialAccountBalance = await Dummy2UsernameRegistrar.methods.getAccountBalance(label).call(); let initialAccountBalance = await Dummy2UsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call(); const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(Dummy2UsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(Dummy2UsernameRegistrar.address).call();
await Dummy2UsernameRegistrar.methods.moveRegistry(UpdatedDummy2UsernameRegistrar.address).send(); await Dummy2UsernameRegistrar.methods.setSlashMechanism(SlashMechanism.address).send();
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch"); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined"); assert.equal(await ENSRegistry.methods.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set"); assert.equal(await PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: notRegistrant}); await SlashMechanism.methods.reserveSlash(Dummy2UsernameRegistrar.address, secret).send({from: notRegistrant});
const resultRelease = await UpdatedDummy2UsernameRegistrar.methods.slashReservedUsername( await SlashMechanism.methods.slashReservedUsername(
username, username,
merkleTree.getHexProof(username), merkleTree.getHexProof(username),
reserveSecret reserveSecret
@ -970,14 +966,13 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(20000) await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call(); const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call();
const initialSlashReserverBalance = await TestToken.methods.balanceOf(slashReserverCaller).call(); const initialSlashReserverBalance = +await TestToken.methods.balanceOf(slashReserverCaller).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const reserveSecret = 1337; const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret); const secret = web3Utils.soliditySha3(username, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: slashReserverCaller}); await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send({from: slashReserverCaller});
await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slashReserverCaller}) await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send({from: slashReserverCaller})
//TODO: check events //TODO: check events
assert.equal(await TestToken.methods.balanceOf(slashReserverCaller).call(), (+initialSlashReserverBalance)+(+partReward*2)); assert.equal(+await TestToken.methods.balanceOf(slashReserverCaller).call(), (+initialSlashReserverBalance)+(+partReward*2));
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
}); });
}); });
@ -1012,7 +1007,7 @@ describe('eraseNode(bytes32[])', function() {
utils.zeroBytes32 utils.zeroBytes32
).send({from: registrant}); ).send({from: registrant});
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant); assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call(); const releaseDelay = +await UsernameRegistrar.methods.releaseDelay().call();
await utils.increaseTime(releaseDelay) await utils.increaseTime(releaseDelay)
await utils.increaseTime(1000) await utils.increaseTime(1000)
await utils.increaseTime(1000) await utils.increaseTime(1000)
@ -1055,7 +1050,7 @@ describe('eraseNode(bytes32[])', function() {
const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send(); const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send();
//TODO: check events //TODO: check events
assert.equal(await ENSRegistry.methods.owner(registry.namehash).call(), UpdatedUsernameRegistrar.address, "registry ownership not moved correctly") assert.equal(await ENSRegistry.methods.owner(registry.namehash).call(), UpdatedUsernameRegistrar.address, "registry ownership not moved correctly")
assert.equal(await UpdatedUsernameRegistrar.methods.getPrice().call(), registry.price, "updated registry didnt migrated price") assert.equal(+await UpdatedUsernameRegistrar.methods.getPrice().call(), registry.price, "updated registry didnt migrated price")
}); });
}); });
@ -1066,18 +1061,18 @@ describe('eraseNode(bytes32[])', function() {
const usernameHash = namehash.hash(username + '.' + registry.registry); const usernameHash = namehash.hash(username + '.' + registry.registry);
const label = web3Utils.sha3(username); const label = web3Utils.sha3(username);
const accountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call() const accountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call()
assert.notEqual(accountBalance, 0); assert.notEqual(accountBalance, 0);
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call(); const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialUpdatedRegistryBalance = await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call(); const initialUpdatedRegistryBalance = +await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call(); const creationTime = +await UsernameRegistrar.methods.getCreationTime(label).call();
assert.notEqual(creationTime, 0); assert.notEqual(creationTime, 0);
assert.equal(await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), 0); assert.equal(+await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), 0);
const result = await UsernameRegistrar.methods.moveAccount(label, UpdatedUsernameRegistrar.address).send({from: registrant}); const result = await UsernameRegistrar.methods.moveAccount(label, UpdatedUsernameRegistrar.address).send({from: registrant});
assert.equal(await UsernameRegistrar.methods.getCreationTime(label).call(), 0); assert.equal(+await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
assert.equal(await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), creationTime); assert.equal(+await UpdatedUsernameRegistrar.methods.getCreationTime(label).call(), creationTime);
assert.equal(await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+accountBalance)) assert.equal(+await TestToken.methods.balanceOf(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+accountBalance))
assert.equal(await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call(), (+initialUpdatedRegistryBalance)+(+accountBalance)) assert.equal(+await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call(), (+initialUpdatedRegistryBalance)+(+accountBalance))
}); });
}); });

View File

@ -212,38 +212,28 @@ function isException(error) {
return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert'); return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
} }
exports.increaseTime = async (amount) => { exports.increaseTime = async (addSeconds) => {
return new Promise(function(resolve, reject) { const id = Date.now();
web3.currentProvider.sendAsync(
{ return new Promise((resolve, reject) => {
web3.currentProvider.send({
jsonrpc: '2.0',
method: 'evm_increaseTime',
params: [addSeconds],
id,
}, (err1) => {
if (err1) return reject(err1);
web3.currentProvider.send({
jsonrpc: '2.0', jsonrpc: '2.0',
method: 'evm_increaseTime', method: 'evm_mine',
params: [+amount], id: id + 1,
id: new Date().getSeconds() }, (err2, res) => (err2 ? reject(err2) : resolve(res)));
}, });
async (error) => {
if (error) {
console.log(error);
return reject(err);
}
await web3.currentProvider.sendAsync(
{
jsonrpc: '2.0',
method: 'evm_mine',
params: [],
id: new Date().getSeconds()
}, (error) => {
if (error) {
console.log(error);
return reject(err);
}
resolve();
}
)
}
)
}); });
} }
exports.generateXY = pub => { exports.generateXY = pub => {
const stripped = pub.slice(2); const stripped = pub.slice(2);