Skip to content

Commit

Permalink
Merge pull request #99 from mysteriumnetwork/feature/versioned-registry
Browse files Browse the repository at this point in the history
Parent registry support
  • Loading branch information
chompomonim authored Jun 18, 2020
2 parents e84e0a8 + cd7edd0 commit d36f728
Show file tree
Hide file tree
Showing 17 changed files with 240 additions and 19 deletions.
34 changes: 30 additions & 4 deletions contracts/Registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ interface HermesContract {
function getStatus() external view returns (Status);
}

interface ParentRegistry {
function isRegistered(address _identityHash) external view returns (bool);
function isAccountant(address _hermesId) external view returns (bool);
function isActiveAccountant(address _hermesId) external view returns (bool);
}

contract Registry is FundsRecovery {
using ECDSA for bytes32;
using SafeMath for uint256;
Expand All @@ -29,6 +35,7 @@ contract Registry is FundsRecovery {
uint256 public minimalHermesStake;
address internal channelImplementationAddress;
address internal hermesImplementationAddress;
ParentRegistry internal parentRegistry;

struct Hermes {
address operator;
Expand All @@ -42,7 +49,7 @@ contract Registry is FundsRecovery {
event RegisteredHermes(address indexed hermesId, address hermesOperator);
event ConsumerChannelCreated(address indexed identityHash, address indexed hermesId, address channelAddress);

constructor (address _tokenAddress, address _dexAddress, uint256 _regFee, uint256 _minimalHermesStake, address _channelImplementation, address _hermesImplementation) public {
constructor (address _tokenAddress, address _dexAddress, uint256 _regFee, uint256 _minimalHermesStake, address _channelImplementation, address _hermesImplementation, address _parentAddress) public {
registrationFee = _regFee;
minimalHermesStake = _minimalHermesStake;

Expand All @@ -54,9 +61,11 @@ contract Registry is FundsRecovery {

channelImplementationAddress = _channelImplementation;
hermesImplementationAddress = _hermesImplementation;

parentRegistry = ParentRegistry(_parentAddress);
}

// Reject any ethers send to this smart-contract
// Reject any ethers sent to this smart-contract
receive() external payable {
revert("Rejecting tx with ethers sent");
}
Expand Down Expand Up @@ -181,11 +190,24 @@ contract Registry is FundsRecovery {

// ------------------------------------------------------------------------

function isRegistered(address _identityHash) public view returns (bool) {
return identities[_identityHash];
// Returns true when parent registry is set
function hasParentRegistry(address _parentAddress) public view returns (bool) {
return _parentAddress != address(0x0);
}

function isRegistered(address _identity) public view returns (bool) {
if (hasParentRegistry(address(parentRegistry)) && parentRegistry.isRegistered(_identity)) {
return true;
}

return identities[_identity];
}

function isHermes(address _hermesId) public view returns (bool) {
if (hasParentRegistry(address(parentRegistry)) && parentRegistry.isAccountant(_hermesId)) {
return true;
}

address hermesOperator = hermeses[_hermesId].operator;
address _addr = getHermesAddress(hermesOperator);
uint _codeLength;
Expand All @@ -198,6 +220,10 @@ contract Registry is FundsRecovery {
}

function isActiveHermes(address _hermesId) internal view returns (bool) {
if (hasParentRegistry(address(parentRegistry)) && parentRegistry.isActiveAccountant(_hermesId)) {
return true;
}

// If stake is 0, then it's either incactive or unregistered hermes
HermesContract.Status status = HermesContract(_hermesId).getStatus();
return status == HermesContract.Status.Active;
Expand Down
4 changes: 3 additions & 1 deletion migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const DEXProxy = artifacts.require("DEXProxy")
const MystToken = artifacts.require("MystToken")
const SafeMathLib = artifacts.require("SafeMathLib")

const zeroAddress = '0x0000000000000000000000000000000000000000'

module.exports = async function (deployer, network, accounts) {
// We do have MYSTT and Config deployed on Görli already
if (network === 'goerli') {
Expand All @@ -24,6 +26,6 @@ module.exports = async function (deployer, network, accounts) {
await deployer.deploy(DEXImplementation)
await deployer.deploy(ChannelImplementation)
await deployer.deploy(HermesImplementation)
await deployer.deploy(Registry, MystToken.address, DEXImplementation.address, 0, 0, ChannelImplementation.address, HermesImplementation.address)
await deployer.deploy(Registry, MystToken.address, DEXImplementation.address, 0, 0, ChannelImplementation.address, HermesImplementation.address, zeroAddress)
}
};
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "payments-smart-contracts",
"version": "0.9.1",
"version": "0.9.3",
"description": "Smart contracts for Mysterium Network payments flow",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -37,4 +37,4 @@
"truffle": "^5.1.29",
"truffle-flattener": "^1.4.4"
}
}
}
3 changes: 2 additions & 1 deletion test/beneficiary.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")
const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const OneEther = web3.utils.toWei(new BN(1), 'ether')
const Zero = new BN(0)
const zeroAddress = '0x0000000000000000000000000000000000000000'

// const operatorPrivKey = Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')
const operator = wallet.generateAccount(Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')) // Generate hermes operator wallet
Expand All @@ -37,7 +38,7 @@ contract("Setting beneficiary tests", ([txMaker, operatorAddress, beneficiaryA,
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, operator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address, zeroAddress)

// Give some ethers for gas for operator
await topUpEthers(txMaker, operator.address, OneEther)
Expand Down
93 changes: 93 additions & 0 deletions test/contracts/TestOldRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.7.0;

import { ECDSA } from "@openzeppelin/contracts/cryptography/ECDSA.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { FundsRecovery } from "../../contracts/FundsRecovery.sol";

interface AccountantContract {
enum Status { Active, Paused, Punishment, Closed }
function initialize(address _token, address _operator, uint16 _hermesFee, uint256 _minStake, uint256 _maxStake) external;
function openChannel(address _party, address _beneficiary, uint256 _amountToLend) external;
function getStake() external view returns (uint256);
function getStatus() external view returns (Status);
}

contract TestOldRegistry is FundsRecovery {
using ECDSA for bytes32;
using SafeMath for uint256;

string constant REGISTER_PREFIX="Register prefix:";

struct Accountant {
address operator;
}
mapping(address => Accountant) public accountants;
mapping(address => bool) private identities;

event RegisteredIdentity(address indexed identityHash, address indexed accId);
event RegisteredAccountant(address indexed accId, address accountantOperator);

constructor (address _tokenAddress) public {
require(_tokenAddress != address(0));
token = IERC20(_tokenAddress);
}

// Reject any ethers sent to this smart-contract
receive() external payable {
revert("Rejecting tx with ethers sent");
}

function registerIdentity(address _accId, uint256 _stakeAmount, uint256 _transactorFee, address _beneficiary, bytes memory _signature) public {
// Check if given signature is valid
address _identityHash = keccak256(abi.encodePacked(address(this), _accId, _stakeAmount, _transactorFee, _beneficiary)).recover(_signature);
require(_identityHash != address(0), "wrong signature");

if (!isRegistered(_identityHash)) {
identities[_identityHash] = true;
emit RegisteredIdentity(_identityHash, _accId);
}
}

function registerAccountant(address _accountantOperator) public {
address _accId = getAccountantAddress(_accountantOperator);
require(!isAccountant(_accId), "accountant already registered");

accountants[_accId] = Accountant(_accountantOperator);

emit RegisteredAccountant(_accId, _accountantOperator);
}

function isRegistered(address _identity) public view returns (bool) {
return identities[_identity];
}

function isAccountant(address _accId) public view returns (bool) {
return accountants[_accId].operator != address(0);
}

function isActiveAccountant(address _accId) public view returns (bool) {
AccountantContract.Status status = AccountantContract(_accId).getStatus();
return status == AccountantContract.Status.Active;
}

function getAccountantAddress(address _accountantOperator) public view returns (address) {
bytes32 _code = keccak256(getProxyCode());
return getCreate2Address(bytes32(uint256(_accountantOperator)), _code);
}

function getCreate2Address(bytes32 _salt, bytes32 _code) internal view returns (address) {
return address(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
bytes32(_salt),
bytes32(_code)
))));
}

function getProxyCode() public pure returns (bytes memory) {
bytes memory _code = hex"3d602d80600a3d3981f3363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3";
return _code;
}
}
2 changes: 1 addition & 1 deletion test/fundsRecovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ contract('Registry funds recovery', ([_, txMaker, identity, account, fundsDestin

// Deploy registry smart contract
const nativeToken = await Token.new() // Native token is used as main unit of value in channels. We're recovering any other tokens but not this.
registry = await Registry.new(nativeToken.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address, { from: txMaker })
registry = await Registry.new(nativeToken.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address, ZeroAddress, { from: txMaker })
expect(registry.address.toLowerCase()).to.be.equal(registryAddress.toLowerCase())

// Set funds destination
Expand Down
2 changes: 1 addition & 1 deletion test/fundsRecoveryByCheque.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract('Full path (in channel using cheque) test for funds recovery', ([txMake
const dex = await MystDex.new()
const channelImplementation = await ChannelImplementation.new()
const hermesImplementation = await HermesImplementation.new()
registry = await Registry.new(nativeToken.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(nativeToken.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address, ZeroAddress)

hermesId = await registry.getHermesAddress(hermesOperator)
expectedAddress = await genCreate2Address(identityHash, hermesId, registry, channelImplementation.address)
Expand Down
3 changes: 2 additions & 1 deletion test/greenpaths.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")
const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const OneEther = web3.utils.toWei(new BN(1), 'ether')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

let token, hermes, registry;
const identities = generateIdentities(5) // Generates array of identities
Expand All @@ -51,7 +52,7 @@ contract('Green path tests', ([txMaker, ...beneficiaries]) => {
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new()
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Give some ethers for gas for operator
await topUpEthers(txMaker, operator.address, OneEther)
Expand Down
3 changes: 2 additions & 1 deletion test/hermes.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")
const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const OneEther = web3.utils.toWei(new BN(1), 'ether')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const operatorPrivKey = Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')

Expand All @@ -43,7 +44,7 @@ contract('Hermes Contract Implementation tests', ([txMaker, operatorAddress, ben
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, operator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, 0, 1, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Give some ethers for gas for operator
await topUpEthers(txMaker, operator.address, OneEther)
Expand Down
3 changes: 2 additions & 1 deletion test/hermesChannelSettlement.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const Registry = artifacts.require("Registry")
const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const OneEther = web3.utils.toWei(new BN(1), 'ether')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const operator = wallet.generateAccount(Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')) // Generate hermes operator wallet
const providerA = wallet.generateAccount()
Expand All @@ -40,7 +41,7 @@ contract("Channel openinig via settlement tests", ([txMaker, beneficiaryA, benef
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, operator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, 0, 100, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, 0, 100, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Give some ethers for gas for operator
await topUpEthers(txMaker, operator.address, OneEther)
Expand Down
3 changes: 2 additions & 1 deletion test/hermesClosing.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")

const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const operatorPrivKey = Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')
const hermesOperator = wallet.generateAccount(operatorPrivKey)
Expand All @@ -33,7 +34,7 @@ contract('Hermes closing', ([txMaker, operatorAddress, ...beneficiaries]) => {
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, hermesOperator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Topup some tokens into txMaker address so it could register hermes
await topUpTokens(token, txMaker, OneToken)
Expand Down
3 changes: 2 additions & 1 deletion test/hermesFee.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")

const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const provider = wallet.generateAccount()
const operatorPrivKey = Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')
Expand All @@ -30,7 +31,7 @@ contract('Hermes fee', ([txMaker, operatorAddress, ...beneficiaries]) => {
dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, hermesOperator.address, 0, OneToken)
channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, 0, 0, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Topup some tokens into txMaker address so it could register hermes
await topUpTokens(token, txMaker, 1000)
Expand Down
3 changes: 2 additions & 1 deletion test/hermesPunishment.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")

const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const provider = wallet.generateAccount()
const operatorPrivKey = Buffer.from('d6dd47ec61ae1e85224cec41885eec757aa77d518f8c26933e5d9f0cda92f3c3', 'hex')
Expand All @@ -35,7 +36,7 @@ contract('Hermes punishment', ([txMaker, operatorAddress, ...beneficiaries]) =>
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, hermesOperator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Topup some tokens into txMaker address so it could register hermes
await topUpTokens(token, txMaker, OneToken)
Expand Down
3 changes: 2 additions & 1 deletion test/hermesStake.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ChannelImplementation = artifacts.require("ChannelImplementation")

const OneToken = web3.utils.toWei(new BN('100000000'), 'wei')
const Zero = new BN(0)
const ZeroAddress = '0x0000000000000000000000000000000000000000'

const provider = wallet.generateAccount()
const hermesOperator = wallet.generateAccount()
Expand All @@ -33,7 +34,7 @@ contract('Hermes stake management', ([txMaker, operatorAddress, ...beneficiaries
const dex = await MystDex.new()
const hermesImplementation = await HermesImplementation.new(token.address, hermesOperator.address, 0, OneToken)
const channelImplementation = await ChannelImplementation.new()
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address)
registry = await Registry.new(token.address, dex.address, Zero, stake, channelImplementation.address, hermesImplementation.address, ZeroAddress)

// Topup some tokens into txMaker address so it could register hermes
await topUpTokens(token, txMaker, OneToken)
Expand Down
Loading

0 comments on commit d36f728

Please sign in to comment.