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
config/production/password
config/livenet/password
embarkArtifacts/
embark_demo/
# egg-related
viper.egg-info/
@ -36,7 +38,6 @@ coverage.json
# node
node_modules/
npm-debug.log
package-lock.json
# other
.vs/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,62 +1,46 @@
module.exports = {
development: {
default: {
enabled: true,
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
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.
client: "geth"
},
development: {
client: 'ganache-cli',
clientConfig: {
miningMode: 'dev'
}
},
testnet: {
enabled: true,
networkType: "testnet",
syncMode: "light",
rpcHost: "localhost",
rpcPort: 8545,
rpcCorsDomain: "http://localhost:8000",
account: {
password: "config/testnet/password"
}
accounts: [
{
nodeAccounts: true,
password: "config/testnet/password"
}
]
},
livenet: {
enabled: true,
networkType: "livenet",
syncMode: "light",
rpcHost: "localhost",
rpcPort: 8545,
rpcCorsDomain: "http://localhost:8000",
account: {
password: "config/livenet/password"
}
accounts: [
{
nodeAccounts: true,
password: "config/livenet/password"
}
]
},
privatenet: {
enabled: true,
networkType: "custom",
rpcHost: "localhost",
rpcPort: 8545,
rpcCorsDomain: "http://localhost:8000",
datadir: "yourdatadir",
networkId: "123",
bootnodes: ""
rinkeby: {
networkType: "rinkeby",
syncMode: "light",
accounts: [
{
nodeAccounts: true,
password: "config/rinkeby/password"
}
]
}
};

View File

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

View File

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

View File

@ -1,5 +1,6 @@
module.exports = {
default: {
enabled: false,
available_providers: ["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: {
enabled: true,
ipfs_bin: "ipfs",
provider: "ipfs",
available_providers: ["ipfs"],
upload: {
provider: "ipfs",
host: "localhost",
port: 5001
},
@ -16,20 +16,23 @@ module.exports = {
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: {
enabled: true,
provider: "ipfs",
upload: {
provider: "ipfs",
host: "localhost",
port: 5001,
getUrl: "http://localhost:8080/ipfs/"
}
}
},
testnet: {
},
livenet: {
},
rinkeby: {
},
};

View File

@ -1,5 +1,6 @@
module.exports = {
enabled: true,
host: "localhost",
openBrowser: true,
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 {
/// @notice The address of the controller is the only address that can call
/// a function with this modifier
modifier onlyController {
require(msg.sender == controller);
_;
modifier onlyController {
require(msg.sender == controller, "Unauthorized");
_;
}
address public controller;
address payable public controller;
constructor() internal {
controller = msg.sender;
constructor() internal {
controller = msg.sender;
}
/// @notice Changes the 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;
}
}

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
*/
function verifyProof(
bytes32[] _proof,
bytes32[] memory _proof,
bytes32 _root,
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
*/
contract MessageSigned {
constructor() internal {
}
constructor() internal {}
/**
* @notice recovers address who signed the message
@ -15,12 +15,12 @@ contract MessageSigned {
* @param _messageSignature message `_signHash` signature
*/
function recoverAddress(
bytes32 _signHash,
bytes _messageSignature
bytes32 _signHash,
bytes memory _messageSignature
)
internal
pure
returns(address)
returns(address)
{
uint8 v;
bytes32 r;
@ -42,21 +42,22 @@ contract MessageSigned {
function getSignHash(
bytes32 _hash
)
pure
internal
pure
returns (bytes32 signHash)
{
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)
pure
function signatureSplit(bytes memory _signature)
internal
pure
returns (uint8 v, bytes32 r, bytes32 s)
{
require(_signature.length == 65, "Bad signature length");
// The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
@ -70,8 +71,10 @@ contract MessageSigned {
// use the second best option, 'and'
v := and(mload(add(_signature, 65)), 0xff)
}
require(v == 27 || v == 28);
if (v < 27) {
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
/// later changed
@ -7,23 +9,23 @@ contract Owned {
/// @dev `owner` is the only address that can call a function with this
/// modifier
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`
constructor() internal {
owner = msg.sender;
}
address public newOwner;
address payable public newOwner;
/// @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
/// an unowned neutral vault, however that cannot be undone
function changeOwner(address _newOwner) public onlyOwner {
function changeOwner(address payable _newOwner) public onlyOwner {
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

View File

@ -1,26 +1,35 @@
pragma solidity ^0.4.24;
// SPDX-License-Identifier: BSD-2-Clause
pragma solidity 0.5.11;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when the TTL of a node changes
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 setResolver(bytes32 node, address resolver) public;
function setOwner(bytes32 node, address owner) public;
function setTTL(bytes32 node, uint64 ttl) public;
function owner(bytes32 node) public view returns (address);
function resolver(bytes32 node) public view returns (address);
function ttl(bytes32 node) public view returns (uint64);
}
function setRecord(bytes32 _node, address _owner, address _resolver, uint64 _ttl) external;
function setSubnodeRecord(bytes32 _node, bytes32 _label, address _owner, address _resolver, uint64 _ttl) external;
function setSubnodeOwner(bytes32 _node, bytes32 _label, address _owner) external returns(bytes32);
function setResolver(bytes32 _node, address _resolver) external;
function setOwner(bytes32 _node, address _owner) external;
function setTTL(bytes32 _node, uint64 _ttl) external;
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";
@ -6,6 +8,7 @@ import "./ENS.sol";
* The ENS registry contract.
*/
contract ENSRegistry is ENS {
struct Record {
address owner;
address resolver;
@ -13,10 +16,12 @@ contract ENSRegistry is ENS {
}
mapping (bytes32 => Record) records;
mapping (address => mapping(address => bool)) operators;
// Permits modifications only by the owner of the specified node.
modifier only_owner(bytes32 node) {
require(records[node].owner == msg.sender);
// Permits modifications only by the _owner of the specified _node.
modifier authorised(bytes32 _node) {
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.
* @param node The node to transfer ownership of.
* @param owner The address of the new owner.
* @dev Sets the record for a _node.
* @param _node The _node to update.
* @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) {
emit Transfer(node, owner);
records[node].owner = owner;
function setRecord(bytes32 _node, address _owner, address _resolver, uint64 _ttl) external {
setOwner(_node, _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.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
* @dev Sets the record for a subnode.
* @param _node The parent _node.
* @param _label The hash of the _label specifying the subnode.
* @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) {
bytes32 subnode = keccak256(abi.encodePacked(node, label));
emit NewOwner(node, label, owner);
records[subnode].owner = owner;
function setSubnodeRecord(bytes32 _node, bytes32 _label, address _owner, address _resolver, uint64 _ttl) external {
bytes32 subnode = setSubnodeOwner(_node, _label, _owner);
_setResolverAndTTL(subnode, _resolver, _ttl);
}
/**
* @dev Sets the resolver address for the specified node.
* @param node The node to update.
* @param resolver The address of the resolver.
* @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 transfer ownership of.
* @param _owner The address of the new _owner.
*/
function setResolver(bytes32 node, address resolver) public only_owner(node) {
emit NewResolver(node, resolver);
records[node].resolver = resolver;
function setOwner(bytes32 _node, address _owner) public authorised(_node) {
_setOwner(_node, _owner);
emit Transfer(_node, _owner);
}
/**
* @dev Sets the TTL for the specified node.
* @param node The node to update.
* @param ttl The TTL in seconds.
* @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 parent _node.
* @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) {
emit NewTTL(node, ttl);
records[node].ttl = ttl;
function setSubnodeOwner(bytes32 _node, bytes32 _label, address _owner) public authorised(_node) returns(bytes32) {
bytes32 subnode = keccak256(abi.encodePacked(_node, _label));
_setOwner(subnode, _owner);
emit NewOwner(_node, _label, _owner);
return subnode;
}
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
* @dev Sets the _resolver address for the specified _node.
* @param _node The _node to update.
* @param _resolver The address of the _resolver.
*/
function owner(bytes32 node) public view returns (address) {
return records[node].owner;
function setResolver(bytes32 _node, address _resolver) public authorised(_node) {
emit NewResolver(_node, _resolver);
records[_node].resolver = _resolver;
}
/**
* @dev Returns the address of the resolver for the specified node.
* @param node The specified node.
* @return address of the resolver.
* @dev Sets the TTL for the specified _node.
* @param _node The _node to update.
* @param _ttl The TTL in seconds.
*/
function resolver(bytes32 node) public view returns (address) {
return records[node].resolver;
function setTTL(bytes32 _node, uint64 _ttl) public authorised(_node) {
emit NewTTL(_node, _ttl);
records[_node].ttl = _ttl;
}
/**
* @dev Returns the TTL of a node, and any records associated with it.
* @param node The specified node.
* @return ttl of the node.
* @dev Enable or disable approval for a third party ("_operator") to manage
* all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
* @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) {
return records[node].ttl;
function setApprovalForAll(address _operator, bool _approved) external {
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";
@ -10,20 +12,20 @@ contract PublicResolver {
bytes4 constant INTERFACE_META_ID = 0x01ffc9a7;
bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5;
bytes4 constant NAME_INTERFACE_ID = 0x691f3431;
bytes4 constant ABI_INTERFACE_ID = 0x2203ab56;
bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233;
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 ContentChanged(bytes32 indexed node, bytes32 hash);
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 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 {
bytes32 x;
@ -32,19 +34,19 @@ contract PublicResolver {
struct Record {
address addr;
bytes32 content;
string name;
PublicKey pubkey;
mapping(string=>string) text;
mapping(uint256=>bytes) abis;
bytes multihash;
bytes contenthash;
mapping(bytes4=>address) interfaces;
}
ENS ens;
mapping (bytes32 => Record) records;
modifier only_owner(bytes32 node) {
modifier onlyOwner(bytes32 node) {
require(ens.owner(node) == msg.sender);
_;
}
@ -63,42 +65,29 @@ contract PublicResolver {
* @param node The node to update.
* @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;
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.
* 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 hash The content hash to set
* @param hash The contenthash to set
*/
function setContent(bytes32 node, bytes32 hash) public only_owner(node) {
records[node].content = hash;
emit ContentChanged(node, hash);
function setContenthash(bytes32 node, bytes calldata hash) external onlyOwner(node) {
records[node].contenthash = 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.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @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;
emit NameChanged(node, name);
}
@ -111,21 +100,21 @@ contract PublicResolver {
* @param contentType The content type of the ABI
* @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
require(((contentType - 1) & contentType) == 0);
records[node].abis[contentType] = data;
emit ABIChanged(node, contentType);
}
/**
* Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query
* @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.
*/
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);
emit PubkeyChanged(node, x, y);
}
@ -137,18 +126,30 @@ contract PublicResolver {
* @param key The key 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;
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.
* @param node The ENS node to query.
* @param key The text data key to query.
* @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];
}
@ -156,9 +157,10 @@ contract PublicResolver {
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @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);
}
@ -170,15 +172,17 @@ contract PublicResolver {
* @return contentType The content type of the return value
* @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];
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
data = record.abis[contentType];
return;
return (contentType, record.abis[contentType]);
}
}
contentType = 0;
bytes memory empty;
return (0, empty);
}
/**
@ -187,30 +191,10 @@ contract PublicResolver {
* @param node The ENS node to query.
* @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;
}
/**
* 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.
* @param node The ENS node to query.
@ -220,19 +204,64 @@ contract PublicResolver {
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.
* @param interfaceID The ID of the interface to check for.
* @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 ||
interfaceID == CONTENT_INTERFACE_ID ||
interfaceID == NAME_INTERFACE_ID ||
interfaceID == ABI_INTERFACE_ID ||
interfaceID == PUBKEY_INTERFACE_ID ||
interfaceID == TEXT_INTERFACE_ID ||
interfaceID == MULTIHASH_INTERFACE_ID ||
interfaceID == CONTENTHASH_INTERFACE_ID ||
interfaceID == INTERFACE_INTERFACE_ID ||
interfaceID == INTERFACE_META_ID;
}
}
}

View File

@ -1,10 +1,46 @@
pragma solidity ^0.4.24;
// SPDX-License-Identifier: BSD-2-Clause
contract ResolverInterface {
function PublicResolver(address ensAddr) public;
function setAddr(bytes32 node, address addr) public;
function setHash(bytes32 node, bytes32 hash) public;
function addr(bytes32 node) public view returns (address);
function hash(bytes32 node) public view returns (bytes32);
function supportsInterface(bytes4 interfaceID) public pure returns (bool);
pragma solidity 0.5.11;
pragma experimental ABIEncoderV2;
/**
* A generic resolver interface which includes all the functions including the ones deprecated
*/
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 "../token/ERC20Token.sol";
import "../token/ApproveAndCallFallBack.sol";
import "../ens/ENS.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`
*/
contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ERC20Token public token;
ENS public ensRegistry;
PublicResolver public resolver;
@ -20,11 +21,9 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
uint256 public constant releaseDelay = 365 days;
mapping (bytes32 => Account) public accounts;
mapping (bytes32 => SlashReserve) reservedSlashers;
//Slashing conditions
uint256 public usernameMinLength;
bytes32 public reservedUsernamesMerkleRoot;
uint256 public lastUpdate;
address public slashMechanism;
event RegistryState(RegistrarState state);
event RegistryPrice(uint256 price);
@ -43,10 +42,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address owner;
}
struct SlashReserve {
address reserver;
uint256 blockNumber;
}
/**
* @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`.
* Other updates require a new contract and migration of domain.
* @param _token ERC20 token with optional `approveAndCall(address,uint256,bytes)` for locking fee.
* @param _ensRegistry Ethereum Name Service root contract address.
* @param _resolver Public Resolver for resolving usernames.
* @param _ensNode ENS node (domain) being used for usernames subnodes (subdomain)
* @param _usernameMinLength Minimum length of usernames
* @param _reservedUsernamesMerkleRoot Merkle root of reserved usernames
* @param _slashMechanism Slashing mechanism address
* @param _parentRegistry Address of old registry (if any) for optional account migration.
*/
constructor(
@ -73,11 +68,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ENS _ensRegistry,
PublicResolver _resolver,
bytes32 _ensNode,
uint256 _usernameMinLength,
bytes32 _reservedUsernamesMerkleRoot,
address _slashMechanism,
address _parentRegistry
)
public
)
public
{
require(address(_token) != address(0), "No ERC20Token address defined.");
require(address(_ensRegistry) != address(0), "No ENS address defined.");
@ -87,8 +81,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ensRegistry = _ensRegistry;
resolver = _resolver;
ensNode = _ensNode;
usernameMinLength = _usernameMinLength;
reservedUsernamesMerkleRoot = _reservedUsernamesMerkleRoot;
slashMechanism = _slashMechanism;
lastUpdate = block.timestamp;
parentRegistry = _parentRegistry;
setState(RegistrarState.Inactive);
}
@ -101,9 +95,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
* - User deposits are completely protected. The contract controller cannot access them.
* - 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.
* - Usernames registered with less then `usernameMinLength` characters can be slashed.
* - Usernames contained in the merkle tree of root `reservedUsernamesMerkleRoot` can be slashed.
* - Usernames starting with `0x` and bigger then 12 characters can be slashed.
* - Usernames registered can be slashed if offending the `slashMechanism` contract rules.
* - 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 _account Optional address to set at public resolver.
@ -115,30 +107,30 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _account,
bytes32 _pubkeyA,
bytes32 _pubkeyB
)
external
returns(bytes32 namehash)
)
external
returns(bytes32 namehash)
{
return registerUser(msg.sender, _label, _account, _pubkeyA, _pubkeyB);
}
/**
* @notice Release username and retrieve locked fee, needs to be called
* after `releasePeriod` from creation time by ENS registry owner of domain
/**
* @notice Release username and retrieve locked fee, needs to be called
* after `releasePeriod` from creation time by ENS registry owner of domain
* or anytime by account owner when domain migrated to a new registry.
* @param _label Username hash.
*/
function release(
bytes32 _label
)
external
external
{
bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label));
Account memory account = accounts[_label];
require(account.creationTime > 0, "Username not registered.");
if (state == RegistrarState.Active) {
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 {
require(msg.sender == account.owner, "Not the former account owner.");
}
@ -153,28 +145,28 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
ensRegistry.setOwner(namehash, address(0));
} else {
address newOwner = ensRegistry.owner(ensNode);
//Low level call, case dropUsername not implemented or failing, proceed release.
//Invert (!) to supress warning, return of this call have no use.
!newOwner.call.gas(80000)(
abi.encodeWithSignature(
"dropUsername(bytes32)",
//Low level call, case dropUsername not implemented or failing, proceed release.
//Return of this call have no use.
newOwner.call.gas(80000)(
abi.encodeWithSelector(
this.dropUsername.selector,
_label
)
);
}
emit UsernameOwner(namehash, address(0));
emit UsernameOwner(namehash, address(0));
}
/**
* @notice update account owner, should be called by new ens node owner
* to update this contract registry, otherwise former owner can release
* if domain is moved to a new registry.
/**
* @notice update account owner, should be called by new ens node owner
* to update this contract registry, otherwise former owner can release
* if domain is moved to a new registry.
* @param _label Username hash.
**/
function updateAccountOwner(
bytes32 _label
)
external
)
external
{
bytes32 namehash = keccak256(abi.encodePacked(ensNode, _label));
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.");
accounts[_label].owner = 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.
* @param _labels Sequence to erase.
*/
function eraseNode(
bytes32[] _labels
)
external
bytes32[] calldata _labels
)
external
{
uint len = _labels.length;
require(len != 0, "Nothing to erase");
@ -292,8 +195,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
if(len > 1) {
eraseNodeHierarchy(len - 2, _labels, subnode);
}
ensRegistry.setResolver(subnode, 0);
ensRegistry.setOwner(subnode, 0);
ensRegistry.setResolver(subnode, address(0));
ensRegistry.setOwner(subnode, address(0));
}
/**
@ -303,8 +206,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
function moveAccount(
bytes32 _label,
UsernameRegistrar _newRegistry
)
external
)
external
{
require(state == RegistrarState.Moved, "Wrong contract state");
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];
delete accounts[_label];
token.approve(_newRegistry, account.balance);
token.approve(address(_newRegistry), account.balance);
_newRegistry.migrateUsername(
_label,
account.balance,
@ -321,13 +224,13 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
);
}
/**
/**
* @notice Activate registration.
* @param _price The price of registration.
*/
function activate(
uint256 _price
)
)
external
onlyController
{
@ -338,26 +241,41 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
emit RegistryPrice(_price);
}
/**
/**
* @notice Updates Public Resolver for resolving users.
* @param _resolver New PublicResolver.
*/
function setResolver(
address _resolver
)
)
external
onlyController
{
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.
* @param _price New registration price.
*/
function updateRegistryPrice(
uint256 _price
)
)
external
onlyController
{
@ -365,7 +283,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
price = _price;
emit RegistryPrice(_price);
}
/**
* @notice Transfer ownership of ensNode to `_newRegistry`.
* 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);
}
/**
/**
* @notice Opt-out migration of username from `parentRegistry()`.
* Clear ENS resolver and subnode owner.
* @param _label Username hash.
*/
function dropUsername(
bytes32 _label
)
external
)
external
onlyParentRegistry
{
require(accounts[_label].creationTime == 0, "Already migrated");
@ -403,10 +321,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
**/
function withdrawExcessBalance(
address _token,
address _beneficiary
address payable _beneficiary
)
external
onlyController
external
onlyController
{
require(_beneficiary != address(0), "Cannot burn token");
if (_token == address(0)) {
@ -432,72 +350,72 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
function withdrawWrongNode(
bytes32 _domainHash,
address _beneficiary
)
)
external
onlyController
{
require(_beneficiary != address(0), "Cannot burn node");
require(_domainHash != ensNode, "Cannot withdraw main node");
require(ensRegistry.owner(_domainHash) == address(this), "Not owner of this node");
require(_domainHash != ensNode, "Cannot withdraw main node");
require(ensRegistry.owner(_domainHash) == address(this), "Not owner of this node");
ensRegistry.setOwner(_domainHash, _beneficiary);
}
/**
* @notice Gets registration price.
* @return Registration price.
* @return registryPrice Registration price.
**/
function getPrice()
external
view
returns(uint256 registryPrice)
function getPrice()
external
view
returns(uint256 registryPrice)
{
return price;
}
/**
* @notice reads amount tokens locked in username
* @notice reads amount tokens locked in username
* @param _label Username hash.
* @return Locked username balance.
* @return accountBalance Locked username balance.
**/
function getAccountBalance(bytes32 _label)
external
view
returns(uint256 accountBalance)
returns(uint256 accountBalance)
{
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.
* @param _label Username hash.
* @return Username account owner.
* @return owner Username account owner.
**/
function getAccountOwner(bytes32 _label)
external
view
returns(address owner)
returns(address owner)
{
owner = accounts[_label].owner;
}
/**
* @notice reads when the account was registered
* @notice reads when the account was registered
* @param _label Username hash.
* @return Registration time.
* @return creationTime Registration time.
**/
function getCreationTime(bytes32 _label)
external
view
returns(uint256 creationTime)
returns(uint256 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.
* @return Exact time when username can be released.
* @return releaseTime Exact time when username can be released.
**/
function getExpirationTime(bytes32 _label)
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.
* @return Part of reward
* @return partReward Part of reward
**/
function getSlashRewardPart(bytes32 _label)
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 _amount Amount being approved, need to be equal `getPrice()`.
* @param _token Token being approved, need to be equal `token()`.
@ -537,8 +455,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _from,
uint256 _amount,
address _token,
bytes _data
)
bytes memory _data
)
public
{
require(_amount == price, "Wrong value");
@ -552,17 +470,17 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
bytes32 pubkeyB;
(sig, label, account, pubkeyA, pubkeyB) = abiDecodeRegister(_data);
require(
sig == bytes4(0xb82fedbb), //bytes4(keccak256("register(bytes32,address,bytes32,bytes32)"))
sig == this.register.selector,
"Wrong method selector"
);
registerUser(_from, label, account, pubkeyA, pubkeyB);
}
/**
* @notice Continues migration of username to new registry.
* @param _label Username hash.
* @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.
**/
function migrateUsername(
@ -580,7 +498,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
parentRegistry,
address(this),
_tokenBalance
),
),
"Error moving funds from old registar."
);
reserveAmount += _tokenBalance;
@ -595,7 +513,7 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
**/
function migrateRegistry(
uint256 _price
)
)
external
onlyParentRegistry
{
@ -620,8 +538,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
address _account,
bytes32 _pubkeyA,
bytes32 _pubkeyB
)
internal
)
internal
returns(bytes32 namehash)
{
require(state == RegistrarState.Active, "Registry not active.");
@ -640,14 +558,14 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
"Transfer failed"
);
reserveAmount += price;
}
}
bool resolvePubkey = _pubkeyA != 0 || _pubkeyB != 0;
bool resolveAccount = _account != address(0);
if (resolvePubkey || resolveAccount) {
//set to self the ownership to setup initial resolver
ensRegistry.setSubnodeOwner(ensNode, _label, address(this));
ensRegistry.setResolver(namehash, resolver); //default resolver
ensRegistry.setResolver(namehash, address(resolver)); //default resolver
if (resolveAccount) {
resolver.setAddr(namehash, _account);
}
@ -661,22 +579,24 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
}
emit UsernameOwner(namehash, _owner);
}
/**
* @dev Removes account hash of `_username` and send account.balance to msg.sender.
* @param _username Username being slashed.
*/
function slashUsername(
bytes _username,
uint256 _reserveSecret
string calldata _username,
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));
uint256 amountToTransfer = 0;
uint256 creationTime = accounts[label].creationTime;
address owner = ensRegistry.owner(namehash);
address beneficiary = _reserver;
if(creationTime == 0) {
require(
owner != address(0) ||
@ -686,24 +606,22 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
} else {
assert(creationTime != block.timestamp);
amountToTransfer = accounts[label].balance;
if(lastUpdate > creationTime) {
beneficiary = accounts[label].owner;
}
delete accounts[label];
}
ensRegistry.setSubnodeOwner(ensNode, label, address(this));
ensRegistry.setResolver(namehash, address(0));
ensRegistry.setOwner(namehash, address(0));
if (amountToTransfer > 0) {
reserveAmount -= amountToTransfer;
uint256 partialDeposit = amountToTransfer / 3;
amountToTransfer = partialDeposit * 2; // reserve 1/3 to network (controller)
bytes32 secret = keccak256(abi.encodePacked(namehash, creationTime, _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];
require(token.transfer(reserve.reserver, amountToTransfer), "Error in transfer.");
if(lastUpdate < creationTime) {
amountToTransfer = (amountToTransfer * 2) / 3; // reserve 1/3 to network (controller)
}
require(token.transfer(beneficiary, amountToTransfer), "Error in transfer.");
}
emit UsernameOwner(namehash, address(0));
}
@ -721,10 +639,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
*/
function eraseNodeHierarchy(
uint _idx,
bytes32[] _labels,
bytes32[] memory _labels,
bytes32 _subnode
)
private
)
private
{
// Take ownership of the node
ensRegistry.setSubnodeOwner(_subnode, _labels[_idx], address(this));
@ -736,8 +654,8 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
}
// Erase the resolver and owner records
ensRegistry.setResolver(subnode, 0);
ensRegistry.setOwner(subnode, 0);
ensRegistry.setResolver(subnode, address(0));
ensRegistry.setOwner(subnode, address(0));
}
/**
@ -746,10 +664,10 @@ contract UsernameRegistrar is Controlled, ApproveAndCallFallBack {
* @return Decoded registry call.
*/
function abiDecodeRegister(
bytes _data
)
private
pure
bytes memory _data
)
private
pure
returns(
bytes4 sig,
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 {
function verifyProof(
bytes32[] _proof,
bytes32[] memory _proof,
bytes32 _root,
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 {
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";
@ -43,7 +45,7 @@ contract ERC20Receiver {
)
external
{
require(_token.allowance(msg.sender, address(this)) >= _amount);
require(_token.allowance(msg.sender, address(this)) >= _amount, "Bad argument");
_depositToken(msg.sender, _token, _amount);
}
@ -65,7 +67,7 @@ contract ERC20Receiver {
)
private
{
require(_amount > 0);
require(_amount > 0, "Bad argument");
if (_token.transferFrom(_from, address(this), _amount)) {
tokenBalances[address(_token)][_from] += _amount;
emit TokenDeposited(address(_token), _from, _amount);
@ -79,10 +81,10 @@ contract ERC20Receiver {
)
private
{
require(_amount > 0);
require(tokenBalances[address(_token)][_from] >= _amount);
require(_amount > 0, "Bad argument");
require(tokenBalances[address(_token)][_from] >= _amount, "Insufficient funds");
tokenBalances[address(_token)][_from] -= _amount;
require(_token.transfer(_from, _amount));
require(_token.transfer(_from, _amount), "Transfer fail");
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
// https://github.com/ethereum/EIPs/issues/20
@ -9,7 +11,7 @@ interface ERC20Token {
* @notice send `_value` token to `_to` from `msg.sender`
* @param _to The address of the recipient
* @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);
@ -17,7 +19,7 @@ interface ERC20Token {
* @notice `msg.sender` approves `_spender` to spend `_value` tokens
* @param _spender The address of the account able to transfer the tokens
* @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);
@ -26,25 +28,26 @@ interface ERC20Token {
* @param _from The address of the sender
* @param _to The address of the recipient
* @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);
/**
* @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);
/**
* @param _owner The address of the account owning 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);
/**
* @notice return total supply of tokens
* @return supply Total supply of the token.
*/
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";
contract StandardToken is ERC20Token {
uint256 private supply;
uint256 private totalTokens;
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
@ -67,11 +69,11 @@ contract StandardToken is ERC20Token {
function totalSupply()
external
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.
* @param _from The address that is approving the spend
@ -98,8 +100,8 @@ contract StandardToken is ERC20Token {
internal
{
balances[_to] += _amount;
supply += _amount;
emit Transfer(0x0, _to, _amount);
totalTokens += _amount;
emit Transfer(address(0x0), _to, _amount);
}
function transfer(
@ -113,7 +115,7 @@ contract StandardToken is ERC20Token {
if (balances[_from] >= _value && _value > 0) {
balances[_from] -= _value;
if(_to == address(0)) {
supply -= _value;
totalTokens -= _value;
} else {
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 "./ApproveAndCallFallBack.sol";
@ -18,12 +20,13 @@ contract TestToken is StandardToken {
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)
{
approve(msg.sender, _spender, _value);
ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _value, this, _extraData);
ApproveAndCallFallBack(_spender).receiveApproval(msg.sender, _value, address(this), _extraData);
return true;
}

View File

@ -9,9 +9,23 @@
"buildDir": "dist/",
"config": "config/",
"versions": {
"web3": "1.0.0-beta.34",
"solc": "0.4.24",
"ipfs-api": "17.2.4"
"solc": "0.5.11"
},
"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"
},
"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-decorators": "^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-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-syntax-import-meta": "^7.0.0",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.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 = {
contracts : {
"ERC20Receiver": {
}
}
exports.contracts = {
"ERC20Receiver": {}
}
exports.Test = (ERC20Token) => {
@ -26,14 +23,14 @@ exports.Test = (ERC20Token) => {
let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call();
let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call();
assert.equal(result0, +initialBalance0-1, "account 0 balance unexpected");
assert.equal(result1, +initialBalance1+1, "account 1 balance unexpected");
assert.equal(+result0, +initialBalance0-1, "account 0 balance unexpected");
assert.equal(+result1, +initialBalance1+1, "account 1 balance unexpected");
});
it("should set approved amount", async function() {
await ERC20Token.methods.approve(accounts[2],10000000).send({from: accounts[0]});
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() {
@ -41,7 +38,7 @@ exports.Test = (ERC20Token) => {
await ERC20Token.methods.transferFrom(accounts[0], accounts[0],1).send({from: accounts[2]});
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() {
@ -51,15 +48,15 @@ exports.Test = (ERC20Token) => {
let result0 = await ERC20Token.methods.balanceOf(accounts[0]).call();
let result1 = await ERC20Token.methods.balanceOf(accounts[1]).call();
assert.equal(result0, +initialBalance0-1);
assert.equal(result1, +initialBalance1+1);
assert.equal(+result0, +initialBalance0-1);
assert.equal(+result1, +initialBalance1+1);
});
it("should unset approved amount", async function() {
await ERC20Token.methods.approve(accounts[2],0).send({from: accounts[0]});
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() {
@ -68,14 +65,14 @@ exports.Test = (ERC20Token) => {
await ERC20Token.methods.approve(ERC20Receiver.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();
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() {
let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accounts[0]).call();
await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accounts[0]});
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

View File

@ -1,11 +1,11 @@
const utils = require('../utils/testUtils.js');
const ENSRegistry = require('Embark/contracts/ENSRegistry');
const ENSRegistry = artifacts.require('ENSRegistry');
const web3Utils = require('web3-utils');
const namehash = require('eth-ens-namehash');
config({
contracts: {
"ENSRegistry": { },
deploy: {"ENSRegistry": { }}
}
});
@ -57,10 +57,10 @@ contract('ENS', function () {
it('should allow setting the TTL', async () => {
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;
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 () => {

View File

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

View File

@ -1,12 +1,14 @@
const Utils = require('../utils/testUtils');
const TestToken = require('Embark/contracts/TestToken');
const TestToken = artifacts.require('TestToken');
const ERC20TokenSpec = require('./abstract/erc20tokenspec');
config({
contracts: {
"TestToken": {
},
...ERC20TokenSpec.config.contracts
deploy: {
"TestToken": {
},
...ERC20TokenSpec.contracts
}
}
});
@ -24,28 +26,28 @@ contract("TestToken", function() {
let initialSupply = await TestToken.methods.totalSupply().call();
await TestToken.methods.mint(100).send();
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() {
let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call();
await TestToken.methods.mint(100).send({from: accounts[0]});
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() {
let initialBalance = await TestToken.methods.balanceOf(accounts[0]).call();
await TestToken.methods.transfer(Utils.zeroAddress, initialBalance).send({from: accounts[0]});
assert.equal(await TestToken.methods.totalSupply().call(), 0);
assert.equal(await TestToken.methods.balanceOf(accounts[0]).call(), 0);
assert.equal(+await TestToken.methods.totalSupply().call(), 0);
assert.equal(+await TestToken.methods.balanceOf(accounts[0]).call(), 0);
})
it("should mint balances for ERC20TokenSpec", async function() {
let initialBalance = 7 * 10 ^ 18;
for(i=0;i<accounts.length;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',
label: web3Utils.sha3('stateofus'),
namehash: namehash.hash('stateofus.eth'),
price: 100000000
price: 1000
}
const dummyRegistry = {
@ -19,7 +19,7 @@ const dummyRegistry = {
registry: 'dummyreg.eth',
label: web3Utils.sha3('dummyreg'),
namehash: namehash.hash('dummyreg.eth'),
price: 100000000
price: 1000
}
@ -28,7 +28,7 @@ const dummy2Registry = {
registry: 'dummy2reg.eth',
label: web3Utils.sha3('dummy2reg'),
namehash: namehash.hash('dummy2reg.eth'),
price: 100000000
price: 1000
}
// TODO: load file of reserved names and balance array lenght to be even
@ -39,97 +39,100 @@ let accountsArr;
config(
{
contracts: {
"TestToken": { },
"ENSRegistry": {
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()"
]
},
"PublicResolver": {
"args": [
"$ENSRegistry"
]
},
"UsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
registry.namehash,
"3",
merkleRoot,
"0x0"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+registry.label+"', UsernameRegistrar.address).send()",
]
},
"UpdatedUsernameRegistrar": {
"instanceOf" : "UsernameRegistrar",
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
registry.namehash,
"3",
merkleRoot,
"$UsernameRegistrar"
]
},
"DummyUsernameRegistrar": {
"instanceOf" : "UsernameRegistrar",
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummyRegistry.namehash,
"3",
merkleRoot,
"0x0"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummyRegistry.label+"', DummyUsernameRegistrar.address).send()",
]
},
"UpdatedDummyUsernameRegistrar": {
"instanceOf" : "UsernameRegistrar",
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummyRegistry.namehash,
"3",
merkleRoot,
"$DummyUsernameRegistrar"
]
},
"Dummy2UsernameRegistrar": {
"instanceOf" : "UsernameRegistrar",
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummy2Registry.namehash,
"3",
utils.zeroBytes32,
"0x0"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummy2Registry.label+"', Dummy2UsernameRegistrar.address).send()",
"await Dummy2UsernameRegistrar.methods.activate("+dummy2Registry.price+").send()"
]
},
"UpdatedDummy2UsernameRegistrar": {
"instanceOf" : "UsernameRegistrar",
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummy2Registry.namehash,
"3",
merkleRoot,
"$Dummy2UsernameRegistrar"
]
deploy: {
"TestToken": { },
"ENSRegistry": {
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x0000000000000000000000000000000000000000000000000000000000000000', '0x4f5b812789fc606be1b3b16908db13fc7a9adf7ca72641f84d75b47069d3d7f0', web3.eth.defaultAccount).send()"
]
},
"PublicResolver": {
"args": [
"$ENSRegistry"
]
},
"SlashMechanism": {
"args": [
"3",
merkleRoot
],
}
,"UsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
registry.namehash,
"$SlashMechanism",
"0x0000000000000000000000000000000000000000"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+registry.label+"', UsernameRegistrar.address).send()",
]
},
"UpdatedUsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
registry.namehash,
"$SlashMechanism",
"$UsernameRegistrar"
]
},
"DummyUsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummyRegistry.namehash,
"$SlashMechanism",
"0x0000000000000000000000000000000000000000"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummyRegistry.label+"', DummyUsernameRegistrar.address).send()",
]
},
"UpdatedDummyUsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummyRegistry.namehash,
"$SlashMechanism",
"$DummyUsernameRegistrar"
]
},
"Dummy2SlashMechanism": {
"args": [
"3",
utils.zeroBytes32
],
},
"Dummy2UsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummy2Registry.namehash,
"$Dummy2SlashMechanism",
"0x0000000000000000000000000000000000000000"
],
"onDeploy": [
"await ENSRegistry.methods.setSubnodeOwner('0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae', '"+dummy2Registry.label+"', Dummy2UsernameRegistrar.address).send()",
"await Dummy2UsernameRegistrar.methods.activate("+dummy2Registry.price+").send()"
]
},
"UpdatedDummy2UsernameRegistrar": {
"args": [
"$TestToken",
"$ENSRegistry",
"$PublicResolver",
dummy2Registry.namehash,
"$SlashMechanism",
"$Dummy2UsernameRegistrar"
]
}
}
}
}, (_err, web3_accounts) => {
@ -137,15 +140,17 @@ config(
}
);
const TestToken = require('Embark/contracts/TestToken');
const ENSRegistry = require('Embark/contracts/ENSRegistry');
const PublicResolver = require('Embark/contracts/PublicResolver');
const UsernameRegistrar = require('Embark/contracts/UsernameRegistrar');
const UpdatedUsernameRegistrar = require('Embark/contracts/UpdatedUsernameRegistrar');
const DummyUsernameRegistrar = require('Embark/contracts/DummyUsernameRegistrar');
const UpdatedDummyUsernameRegistrar = require('Embark/contracts/UpdatedDummyUsernameRegistrar');
const Dummy2UsernameRegistrar = require('Embark/contracts/Dummy2UsernameRegistrar');
const UpdatedDummy2UsernameRegistrar = require('Embark/contracts/UpdatedDummy2UsernameRegistrar');
const TestToken = artifacts.require('TestToken');
const ENSRegistry = artifacts.require('ENSRegistry');
const PublicResolver = artifacts.require('PublicResolver');
const UsernameRegistrar = artifacts.require('UsernameRegistrar');
const UpdatedUsernameRegistrar = artifacts.require('UpdatedUsernameRegistrar');
const DummyUsernameRegistrar = artifacts.require('DummyUsernameRegistrar');
const UpdatedDummyUsernameRegistrar = artifacts.require('UpdatedDummyUsernameRegistrar');
const Dummy2UsernameRegistrar = artifacts.require('Dummy2UsernameRegistrar');
const UpdatedDummy2UsernameRegistrar = artifacts.require('UpdatedDummy2UsernameRegistrar');
const SlashMechanism = artifacts.require('SlashMechanism');
const Dummy2SlashMechanism = artifacts.require('Dummy2SlashMechanism');
contract('UsernameRegistrar', function () {
@ -155,9 +160,9 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(1000)
const initialPrice = 100
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(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state")
assert.equal(await UsernameRegistrar.methods.price().call(), initialPrice, "Wrong registry 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.price().call(), initialPrice, "Wrong registry price")
});
});
@ -165,9 +170,9 @@ contract('UsernameRegistrar', function () {
it('should change registry price', async () => {
const newPrice = registry.price;
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(await UsernameRegistrar.methods.state().call(), 1, "Wrong registry state")
assert.equal(await UsernameRegistrar.methods.price().call(), newPrice, "Wrong registry 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.price().call(), newPrice, "Wrong registry price")
});
});
@ -177,10 +182,10 @@ contract('UsernameRegistrar', function () {
const username = 'erin';
const usernameHash = namehash.hash(username + '.' + registry.registry);
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});
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await TestToken.methods.approve(UsernameRegistrar.address, registry.price).send({from: registrant});
const resultRegister = await UsernameRegistrar.methods.register(
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(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(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[1], registry.namehash, "Wrong Node");
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(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 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 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(registrant).call(), +initialRegistrantBalance-registryPrice, "User 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 () => {
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(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(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[1], registry.namehash, "Wrong Node");
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(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 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 PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
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(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(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[1], registry.namehash, "Wrong Node");
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(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 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 PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set");
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(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(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[1], registry.namehash, "Wrong Node");
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(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 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 PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -344,10 +349,10 @@ contract('UsernameRegistrar', function () {
const username = 'erinauto';
const usernameHash = namehash.hash(username + '.' + registry.registry);
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});
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const registerCall = UsernameRegistrar.methods.register(
web3Utils.sha3(username),
@ -359,10 +364,10 @@ contract('UsernameRegistrar', function () {
// TODO: check events
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 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 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(registrant).call(), +initialRegistrantBalance-registryPrice, "User 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 () => {
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.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 PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -410,7 +415,7 @@ contract('UsernameRegistrar', function () {
// TODO: check events
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 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 PublicResolver.methods.addr(usernameHash).call(), utils.zeroAddress, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -436,7 +441,7 @@ contract('UsernameRegistrar', function () {
// TODO: check events
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 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 PublicResolver.methods.addr(usernameHash).call(), registrant, "Resolved address not set");
const resolverPubKey = await PublicResolver.methods.pubkey(usernameHash).call();
@ -480,21 +485,21 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32,
utils.zeroBytes32
).send({from: registrant});
const releaseDelay = await UsernameRegistrar.methods.releaseDelay().call();
const releaseDelay = +await UsernameRegistrar.methods.releaseDelay().call();
await utils.increaseTime(releaseDelay)
await utils.increaseTime(1000)
const initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialAccountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await utils.increaseTime(1000)
const resultRelease = await UsernameRegistrar.methods.release(
web3Utils.sha3(username),
).send({from: registrant});
//TODO: check events
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(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
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(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
});
it('should release transfered username', async () => {
let registrant = accountsArr[7];
@ -511,20 +516,20 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).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(1000)
let initialAccountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call();
let initialRegistrantBalance = await TestToken.methods.balanceOf(newOwner).call();
let initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
let initialAccountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call();
let initialRegistrantBalance = +await TestToken.methods.balanceOf(newOwner).call();
let initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
await utils.increaseTime(1000)
let resultRelease = await UsernameRegistrar.methods.release(
label
).send({from: newOwner});
//TODO: check events
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(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
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(UsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
});
it('should release moved username account balance by owner', async () => {
const registrant = accountsArr[5];
@ -541,9 +546,9 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32,
utils.zeroBytes32
).send({from: registrant});
let initialAccountBalance = await DummyUsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call();
let initialAccountBalance = +await DummyUsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = +await TestToken.methods.balanceOf(DummyUsernameRegistrar.address).call();
await DummyUsernameRegistrar.methods.moveRegistry(UpdatedDummyUsernameRegistrar.address).send();
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant, "ENSRegistry owner mismatch");
@ -554,8 +559,8 @@ contract('UsernameRegistrar', function () {
label
).send({from: registrant});
//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(DummyUsernameRegistrar.address).call(), (+initialRegistryBalance)-(+initialAccountBalance), "Registry token balance didnt decrease")
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 ENSRegistry.methods.resolver(usernameHash).call(), utils.zeroAddress, "Resolver not undefined");
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.
@ -605,14 +610,13 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
assert.notEqual(await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
assert.notEqual(+await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send()
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
await SlashMechanism.methods.slashInvalidUsername(username, 4, reserveSecret).send()
//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);
});
it('should not slash valid username', async () => {
@ -628,13 +632,12 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).send({from: registrant});
await utils.increaseTime(20000)
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
try{
await UsernameRegistrar.methods.slashInvalidUsername(username, 4, reserveSecret).send()
await SlashMechanism.methods.slashInvalidUsername(username, 4, reserveSecret).send()
failed = false;
} catch(e){
failed = true;
@ -658,13 +661,12 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
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;
} catch(e){
failed = true;
@ -685,13 +687,12 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
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;
} catch(e){
failed = true;
@ -712,11 +713,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
result = await UsernameRegistrar.methods.slashReservedUsername(username, merkleTree.getHexProof(username), reserveSecret).send()
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
await SlashMechanism.methods.slashReservedUsername(username, merkleTree.getHexProof(username), reserveSecret).send()
//TODO: check events
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
});
@ -736,13 +736,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).send({from: registrant});
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 secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
try{
await UsernameRegistrar.methods.slashSmallUsername(username).send()
await SlashMechanism.methods.slashSmallUsername(username).send()
failed = false;
} catch(e){
failed = true;
@ -764,11 +764,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(web3Utils.sha3(username)).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
result = await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send()
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
result = await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send()
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), utils.zeroAddress);
});
});
@ -789,11 +788,10 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(1000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const creationTime = await UsernameRegistrar.methods.getCreationTime(userlabelHash).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send()
const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
result = await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
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 () => {
@ -810,13 +808,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).send({from: registrant});
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 secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
try{
result = await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send()
await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false;
} catch(e){
failed = true;
@ -837,13 +835,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).send({from: registrant});
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 secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
try{
await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send()
await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false;
} catch(e){
failed = true;
@ -864,13 +862,13 @@ contract('UsernameRegistrar', function () {
utils.zeroBytes32
).send({from: registrant});
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 secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send();
const secret = web3Utils.soliditySha3({value: username, type: "string"}, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send();
let failed;
try{
await UsernameRegistrar.methods.slashAddressLikeUsername(username, reserveSecret).send()
await SlashMechanism.methods.slashAddressLikeUsername(username, reserveSecret).send()
failed = false;
} catch(e){
failed = true;
@ -896,18 +894,17 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(20000)
const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call();
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const initialSlasherBalance = await TestToken.methods.balanceOf(slasher).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const initialSlasherBalance = +await TestToken.methods.balanceOf(slasher).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: slasher});
await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slasher})
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send({from: slasher});
await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send({from: slasher})
//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);
});
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 notRegistrant = accountsArr[6];
@ -925,20 +922,19 @@ contract('UsernameRegistrar', function () {
).send({from: registrant});
await utils.increaseTime(20000)
let initialAccountBalance = await Dummy2UsernameRegistrar.methods.getAccountBalance(label).call();
const initialRegistrantBalance = await TestToken.methods.balanceOf(registrant).call();
const initialRegistryBalance = await TestToken.methods.balanceOf(Dummy2UsernameRegistrar.address).call();
const initialRegistrantBalance = +await TestToken.methods.balanceOf(registrant).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.resolver(usernameHash).call(), PublicResolver.address, "Resolver wrongly defined");
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 secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: notRegistrant});
const resultRelease = await UpdatedDummy2UsernameRegistrar.methods.slashReservedUsername(
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(Dummy2UsernameRegistrar.address, secret).send({from: notRegistrant});
await SlashMechanism.methods.slashReservedUsername(
username,
merkleTree.getHexProof(username),
reserveSecret
@ -970,14 +966,13 @@ contract('UsernameRegistrar', function () {
await utils.increaseTime(20000)
assert.equal(await ENSRegistry.methods.owner(usernameHash).call(), registrant);
const partReward = await UsernameRegistrar.methods.getSlashRewardPart(label).call();
const initialSlashReserverBalance = await TestToken.methods.balanceOf(slashReserverCaller).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const initialSlashReserverBalance = +await TestToken.methods.balanceOf(slashReserverCaller).call();
const reserveSecret = 1337;
const secret = web3Utils.soliditySha3(usernameHash, creationTime, reserveSecret);
await UsernameRegistrar.methods.reserveSlash(secret).send({from: slashReserverCaller});
await UsernameRegistrar.methods.slashSmallUsername(username, reserveSecret).send({from: slashReserverCaller})
const secret = web3Utils.soliditySha3(username, reserveSecret);
await SlashMechanism.methods.reserveSlash(UsernameRegistrar.address, secret).send({from: slashReserverCaller});
await SlashMechanism.methods.slashSmallUsername(username, reserveSecret).send({from: slashReserverCaller})
//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);
});
});
@ -1012,7 +1007,7 @@ describe('eraseNode(bytes32[])', function() {
utils.zeroBytes32
).send({from: 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(1000)
await utils.increaseTime(1000)
@ -1055,7 +1050,7 @@ describe('eraseNode(bytes32[])', function() {
const result = await UsernameRegistrar.methods.moveRegistry(UpdatedUsernameRegistrar.address).send();
//TODO: check events
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 label = web3Utils.sha3(username);
const accountBalance = await UsernameRegistrar.methods.getAccountBalance(label).call()
const accountBalance = +await UsernameRegistrar.methods.getAccountBalance(label).call()
assert.notEqual(accountBalance, 0);
const initialRegistryBalance = await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialUpdatedRegistryBalance = await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call();
const creationTime = await UsernameRegistrar.methods.getCreationTime(label).call();
const initialRegistryBalance = +await TestToken.methods.balanceOf(UsernameRegistrar.address).call();
const initialUpdatedRegistryBalance = +await TestToken.methods.balanceOf(UpdatedUsernameRegistrar.address).call();
const creationTime = +await UsernameRegistrar.methods.getCreationTime(label).call();
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});
assert.equal(await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
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(UpdatedUsernameRegistrar.address).call(), (+initialUpdatedRegistryBalance)+(+accountBalance))
assert.equal(+await UsernameRegistrar.methods.getCreationTime(label).call(), 0);
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(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');
}
exports.increaseTime = async (amount) => {
return new Promise(function(resolve, reject) {
web3.currentProvider.sendAsync(
{
exports.increaseTime = async (addSeconds) => {
const id = Date.now();
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',
method: 'evm_increaseTime',
params: [+amount],
id: new Date().getSeconds()
},
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();
}
)
}
)
method: 'evm_mine',
id: id + 1,
}, (err2, res) => (err2 ? reject(err2) : resolve(res)));
});
});
}
}
exports.generateXY = pub => {
const stripped = pub.slice(2);