From 878095ffb05b15148088b24f10f94f16e80a06c5 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 14:21:13 +0300 Subject: [PATCH 01/10] remove custody, custody-factory and nitro-protocol --- .../custody-factory/ISimpleVaultFactory.sol | 39 - contracts/custody-factory/SimpleERC20.sol | 62 -- .../custody-factory/SimpleVaultFactory.sol | 340 ------- .../test/SimpleFaultFactoryTest.sol | 8 - contracts/custody/IVault.sol | 45 - contracts/custody/SimpleVault.sol | 266 ------ contracts/custody/test/TestERC20.sol | 33 - contracts/nitro-protocol/CountingApp.sol | 47 - contracts/nitro-protocol/ForceMove.sol | 827 ------------------ contracts/nitro-protocol/MultiAssetHolder.sol | 648 -------------- contracts/nitro-protocol/NitroAdjudicator.sol | 142 --- contracts/nitro-protocol/StatusManager.sol | 90 -- contracts/nitro-protocol/Token.sol | 16 - contracts/nitro-protocol/TrivialApp.sol | 24 - .../examples/EmbeddedApplication.sol | 432 --------- .../examples/HashLockedSwap.sol | 79 -- .../examples/SingleAssetPayments.sol | 86 -- .../nitro-protocol/interfaces/IForceMove.sol | 149 ---- .../interfaces/IForceMoveApp.sol | 29 - .../interfaces/IMultiAssetHolder.sol | 95 -- .../interfaces/IStatusManager.sol | 13 - .../nitro-protocol/libraries/ECRecovery.sol | 28 - .../nitro-protocol/test/TESTForceMove.sol | 127 --- .../test/TESTNitroAdjudicator.sol | 41 - data/erc20-tokens.json | 324 ------- deployments/addresses.json | 88 -- hardhat-deploy/00-nitro-adjudicator.ts | 21 - hardhat-deploy/01-simple-vault-factory.ts | 30 - hardhat-deploy/02-simple-erc20s.ts | 60 -- .../custody-factory/deploy-factory-erc20.ts | 87 -- scripts/custody/deploy-local.ts | 113 --- scripts/custody/deploy-simple-vault.ts | 19 - scripts/custody/deploy-test-token.ts | 16 - scripts/custody/deposit-withdraw.ts | 114 --- scripts/custody/mint-test-token.ts | 21 - scripts/nitro-protocol/postdeploy.ts | 18 - test/custody-factory/SimpleERC20.spec.ts | 75 -- .../SimpleVaultFactory.spec.ts | 348 -------- test/custody/SimpleVault.spec.ts | 417 --------- test/custody/common.ts | 90 -- 40 files changed, 5507 deletions(-) delete mode 100644 contracts/custody-factory/ISimpleVaultFactory.sol delete mode 100644 contracts/custody-factory/SimpleERC20.sol delete mode 100644 contracts/custody-factory/SimpleVaultFactory.sol delete mode 100644 contracts/custody-factory/test/SimpleFaultFactoryTest.sol delete mode 100644 contracts/custody/IVault.sol delete mode 100644 contracts/custody/SimpleVault.sol delete mode 100644 contracts/custody/test/TestERC20.sol delete mode 100644 contracts/nitro-protocol/CountingApp.sol delete mode 100644 contracts/nitro-protocol/ForceMove.sol delete mode 100644 contracts/nitro-protocol/MultiAssetHolder.sol delete mode 100644 contracts/nitro-protocol/NitroAdjudicator.sol delete mode 100644 contracts/nitro-protocol/StatusManager.sol delete mode 100644 contracts/nitro-protocol/Token.sol delete mode 100644 contracts/nitro-protocol/TrivialApp.sol delete mode 100644 contracts/nitro-protocol/examples/EmbeddedApplication.sol delete mode 100644 contracts/nitro-protocol/examples/HashLockedSwap.sol delete mode 100644 contracts/nitro-protocol/examples/SingleAssetPayments.sol delete mode 100644 contracts/nitro-protocol/interfaces/IForceMove.sol delete mode 100644 contracts/nitro-protocol/interfaces/IForceMoveApp.sol delete mode 100644 contracts/nitro-protocol/interfaces/IMultiAssetHolder.sol delete mode 100644 contracts/nitro-protocol/interfaces/IStatusManager.sol delete mode 100644 contracts/nitro-protocol/libraries/ECRecovery.sol delete mode 100644 contracts/nitro-protocol/test/TESTForceMove.sol delete mode 100644 contracts/nitro-protocol/test/TESTNitroAdjudicator.sol delete mode 100644 data/erc20-tokens.json delete mode 100644 deployments/addresses.json delete mode 100644 hardhat-deploy/00-nitro-adjudicator.ts delete mode 100644 hardhat-deploy/01-simple-vault-factory.ts delete mode 100644 hardhat-deploy/02-simple-erc20s.ts delete mode 100644 scripts/custody-factory/deploy-factory-erc20.ts delete mode 100644 scripts/custody/deploy-local.ts delete mode 100644 scripts/custody/deploy-simple-vault.ts delete mode 100644 scripts/custody/deploy-test-token.ts delete mode 100644 scripts/custody/deposit-withdraw.ts delete mode 100644 scripts/custody/mint-test-token.ts delete mode 100644 scripts/nitro-protocol/postdeploy.ts delete mode 100644 test/custody-factory/SimpleERC20.spec.ts delete mode 100644 test/custody-factory/SimpleVaultFactory.spec.ts delete mode 100644 test/custody/SimpleVault.spec.ts delete mode 100644 test/custody/common.ts diff --git a/contracts/custody-factory/ISimpleVaultFactory.sol b/contracts/custody-factory/ISimpleVaultFactory.sol deleted file mode 100644 index 4fd01c6..0000000 --- a/contracts/custody-factory/ISimpleVaultFactory.sol +++ /dev/null @@ -1,39 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import '../custody/SimpleVault.sol'; -import './SimpleERC20.sol'; - -/** - * @notice Interface descibing structures and events used in SimpleFaultFactory contract - */ -contract ISimpleVaultFactory { - // broker to deployed vault - struct BrokerAndVault { - address broker; - SimpleVault vault; - } - - // added tokens to mint amount per deployment - struct TokenAndMint { - SimpleERC20 token; - uint256 mint_per_deployment; //solhint-disable-line var-name-mixedcase - } - - /** - * Vault Deployed event - * @param vaultAddress Address of deployed SimpleVault - * @param name Name of deployed SimpleVault - * @param broker Broker of deployed SimpleVault - */ - event VaultDeployed(address vaultAddress, string name, address broker); - - /** - * SimpleToken Deployed event - * @param tokenAddress Address of deployed SimpleToken - * @param name Name of deployed SimpleToken - * @param symbol Symbol of deployed SimpleToken - * @param decimals Decimal representation of deployed SimpleToken - */ - event TokenDeployed(address tokenAddress, string name, string symbol, uint256 decimals); -} diff --git a/contracts/custody-factory/SimpleERC20.sol b/contracts/custody-factory/SimpleERC20.sol deleted file mode 100644 index 5f6a879..0000000 --- a/contracts/custody-factory/SimpleERC20.sol +++ /dev/null @@ -1,62 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; -import '@openzeppelin/contracts/access/AccessControl.sol'; - -/** - * @notice SimpleERC20 is an ERC20 token modified for usage in OpenDAX v4 testing. - */ -contract SimpleERC20 is ERC20, AccessControl { - bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE'); - bytes32 public constant BURNER_ROLE = keccak256('BURNER_ROLE'); - - uint8 private _decimals; - - /** - * @notice Grant default admin, minter and burner roles to msg.sender; specify decimals token representation. - * @dev Grant default admin, minter and burner roles to msg.sender; specify token decimals representation. - * @param name_ Name of the token. - * @param symbol_ Symbol of the token. - * @param decimals_ Token decimal representation override. - */ - constructor( - string memory name_, - string memory symbol_, - uint8 decimals_ - ) ERC20(name_, symbol_) { - _decimals = decimals_; - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _grantRole(MINTER_ROLE, msg.sender); - _grantRole(BURNER_ROLE, msg.sender); - } - - /** - * @notice ERC20 decimals() override, providing ability to change decimal representation of the token. - * @dev ERC20 decimals() override, providing ability to change decimal representation of the token. - * @return uint8 Overriden token decimal representation. - */ - function decimals() public view virtual override returns (uint8) { - return _decimals; - } - - /** - * @notice Public _mint implementation. - * @dev MINTER_ROLE rights required. - * @param to Address to mint tokens to. - * @param amount Amount of tokens to mint to. - */ - function mintTo(address to, uint256 amount) public virtual onlyRole(MINTER_ROLE) { - _mint(to, amount); - } - - /** - * @notice Public _burn implementation. - * @dev BURNER_ROLE rights required. - * @param from Address to burn tokens from. - * @param amount Amount of tokens to burn. - */ - function burnFrom(address from, uint256 amount) public virtual onlyRole(BURNER_ROLE) { - _burn(from, amount); - } -} diff --git a/contracts/custody-factory/SimpleVaultFactory.sol b/contracts/custody-factory/SimpleVaultFactory.sol deleted file mode 100644 index 636446a..0000000 --- a/contracts/custody-factory/SimpleVaultFactory.sol +++ /dev/null @@ -1,340 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import './ISimpleVaultFactory.sol'; -import '../custody/SimpleVault.sol'; -import './SimpleERC20.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; - -/** - * SimpleVaultFactory provides bonding functionality between ERC20 tokens and SimpleVault in OpenDAX v4 testing. - */ -contract SimpleVaultFactory is AccessControlUpgradeable, ISimpleVaultFactory { - // NOTE: no support of EnumerableMap as of @openzeppelin/contracts@4.5.0 - // EnumerableMap(address => address) public vaultOf; - - // order is not preserved between add/remove operations - BrokerAndVault[] public brokerAndVaultArr; - - // TODO: replace with EnumerableMap from @openzeppelin/contracts@4.6.0 when released - // EnumerableMap(address => uint256) public tokens; - - // order is not preserved between add/remove operations - TokenAndMint[] public tokenAndMintArr; - - /** - * @notice Grant default admin role to msg.sender. - * @dev Grant default admin role to msg.sender. - */ - function initialize() public initializer { - __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - } - - /** - * @notice Grant DEFAULT_ADMIN_ROLE to account. - * @dev DEFAULT_ADMIN_ROLE rights required. - * @param account Address to grant role to. - */ - function addAdmin(address account) public onlyRole(DEFAULT_ADMIN_ROLE) { - _grantRole(DEFAULT_ADMIN_ROLE, account); - } - - /** - * @notice Deploy a new SimpleVault and add it to list of vaults for future usage. Grants DEFAULT_ADMIN_ROLE of deployed SimpleVault to msg.sender. - * @dev Deploy a new SimpleVault and add it to list of vaults for future usage. Grants DEFAULT_ADMIN_ROLE of deployed SimpleVault to msg.sender. - * @param name_ Name of the vault to create. - * @param broker_ Broker address of the vault to create. - * @return address Deployed SimpleVault address. - */ - function deployVault(string memory name_, address broker_) public returns (SimpleVault) { - SimpleVault vault = new SimpleVault(name_, broker_); - vault.grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _addVault(vault, broker_); - _mintAllTokensToVault(vault); - - emit VaultDeployed(address(vault), name_, broker_); - return vault; - } - - /** - * @notice Redeploy SimpleVault: remove old vault and deploy a new one with the same name and broker. - * @dev Vault must be already present in the list. msg.sender must have DEFAULT_ADMIN_ROLE of SimpleVault. - * @param vault SimpleVault address to redeploy. - * @return address Redeployed SimpleVault address. - */ - function redeployVault(SimpleVault vault) public returns (SimpleVault) { - _requireVaultIsPresent(vault); - _requireIsVaultAdmin(vault, msg.sender); - - // remove old vault, return BrokerAndVault struct - address broker_ = removeVault(vault).broker; - string memory name_ = vault.name(); - SimpleVault newVault = new SimpleVault(name_, broker_); - - newVault.grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _addVault(newVault, broker_); - _mintAllTokensToVault(newVault); - - emit VaultDeployed(address(newVault), name_, broker_); - return newVault; - } - - /** - * @notice Remove SimpleVault from the list and burn all tokens from it. - * @dev DEFAULT_ADMIN_ROLE required on the Vault. - * @param vault SimpleVault to remove. - * @return BrokerAndVault Structure contraining SimpleVault and broker addresses. - */ - function removeVault(SimpleVault vault) public returns (BrokerAndVault memory) { - _requireVaultIsPresent(vault); - _requireIsVaultAdmin(vault, msg.sender); - - _burnAllTokensFromVault(vault); - return _removeVaultAtIndex(uint256(_getVaultIndex(vault))); - } - - /** - * @notice Add deployed token to list of tokens and mint it to all vaults. SimpleVaultFactory is required to have MINTER_ROLE and BURNER_ROLE of token being added. - * @dev DEFAULT_ADMIN_ROLE rights required. Token must not be already present in the list. - * @param token SimpleERC20 token address. - * @param mint_per_deployment Initial amount of tokens to mint to vaults. - */ - function addToken( - SimpleERC20 token, - uint256 mint_per_deployment //solhint-disable-line var-name-mixedcase - ) public onlyRole(DEFAULT_ADMIN_ROLE) { - _requireTokenIsNotPresent(token); - _requireFactoryIsMinterBurner(token); - - _addToken(token, mint_per_deployment); - _mintTokenForAllVaults(token, mint_per_deployment); - } - - /** - * @notice Deploy SimpleERC20 token, add it to list of tokens and mint it to all vaults. Grants DEFAULT_ADMIN_ROLE of deployed SimpleERC20 to msg.sender. - * @dev DEFAULT_ADMIN_ROLE required. - * @param name Token name. - * @param symbol Token symbol. - * @param decimals Token decimal representation. - * @param mint_per_deployment Initial amount of tokens to mint to vaults. - * @return SimpleERC20 Deployed token address. - */ - function deployAndAddToken( - string memory name, - string memory symbol, - uint8 decimals, - uint256 mint_per_deployment //solhint-disable-line var-name-mixedcase - ) public onlyRole(DEFAULT_ADMIN_ROLE) returns (SimpleERC20) { - SimpleERC20 token = new SimpleERC20(name, symbol, decimals); - token.grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _addToken(token, mint_per_deployment); - _mintTokenForAllVaults(token, mint_per_deployment); - - emit TokenDeployed(address(token), name, symbol, decimals); - return token; - } - - /** - * @notice Remove token from the list and burn it from vaults. - * @dev DEFAULT_ADMIN_ROLE required. Token must be present in the list. - * @param token SimpleERC20 token to add. - */ - function removeToken(SimpleERC20 token) public onlyRole(DEFAULT_ADMIN_ROLE) { - _requireTokenIsPresent(token); - - _removeTokenAtIndex(uint256(_getTokenIndex(token))); - _burnTokenFromAllVaults(token); - } - - /** - * @notice Check if Factory has Minter and Burner roles for specified token. - * @dev Check if Factory has Minter and Burner roles for specified token. - * @param token SimpleERC20 to check roles of. - */ - function _requireFactoryIsMinterBurner(SimpleERC20 token) internal view { - require(token.hasRole(keccak256('MINTER_ROLE'), address(this)), 'factory is not minter'); - require(token.hasRole(keccak256('BURNER_ROLE'), address(this)), 'factory is not burner'); - } - - /** - * @notice Check if vault is present in the list. - * @dev Check if vault is present in the list. - * @param vault SimpleVault to check. - */ - function _requireVaultIsPresent(SimpleVault vault) internal view { - require(_getVaultIndex(vault) != -1, 'vault is not present'); - } - - /** - * @notice Find the index of the vault in the list. Return -1 if not found. - * @dev Find the index of the vault in the list. Return -1 if not found. - * @param vault SimpleVault to find. - * @return int256 Index of the SimpleVault in the list or -1 if not present. - */ - function _getVaultIndex(SimpleVault vault) internal view returns (int256) { - for (uint256 i = 0; i < brokerAndVaultArr.length; i++) { - if (brokerAndVaultArr[i].vault == vault) { - return int256(i); - } - } - return -1; - } - - /** - * @notice Check if account has DEFAULT_ADMIN_ROLE in vault. - * @dev Check if account has DEFAULT_ADMIN_ROLE in vault. - * @param vault SimpleVault to check admin role in. - * @param account Address to check admin role of. - */ - function _requireIsVaultAdmin(SimpleVault vault, address account) internal view { - require(vault.hasRole(DEFAULT_ADMIN_ROLE, account), 'account is not vault admin'); - } - - /** - * @notice Check if token is not present in the list. - * @dev Check if token is not present in the list. - * @param token Address of the SimpleERC20 to check. - */ - function _requireTokenIsNotPresent(SimpleERC20 token) internal view { - require(_getTokenIndex(token) == -1, 'token is already present'); - } - - /** - * @notice Check if token is present in the list. - * @dev Check if token is present in the list. - * @param token Address of the SimpleERC20 to check. - */ - function _requireTokenIsPresent(SimpleERC20 token) internal view { - require(_getTokenIndex(token) != -1, 'token is not present'); - } - - /** - * @notice Add SimpleVault to the list. Internal method. - * @dev Add SimpleVault to the list. Internal method. - * @param vault SimpleVault address to add. - * @param broker Broker address corresponding to the SimpleVault. - */ - function _addVault(SimpleVault vault, address broker) internal { - brokerAndVaultArr.push(BrokerAndVault(broker, vault)); - } - - /** - * @notice Remove vault form the list. - * @dev Swap the last element with element at index and pops the last one. - * @param index Index of the element to remove. - * @return brokerAndVault Structure containing removed SimpleVault and broker addresses. - */ - function _removeVaultAtIndex(uint256 index) - internal - returns (BrokerAndVault memory brokerAndVault) - { - brokerAndVault = brokerAndVaultArr[index]; - brokerAndVaultArr[index] = brokerAndVaultArr[brokerAndVaultArr.length - 1]; - brokerAndVaultArr.pop(); - } - - /** - * @notice Burn all tokens from the vault. - * @dev Burn all tokens from the vault. - * @param vault Vault to burn tokens from. - */ - function _burnAllTokensFromVault(SimpleVault vault) internal { - for (uint256 i = 0; i < tokenAndMintArr.length; i++) { - SimpleERC20 token = tokenAndMintArr[i].token; - token.burnFrom(address(vault), token.balanceOf(address(vault))); - } - } - - /** - * @notice Mint mint_per_deployment amount of each token to vault specified. - * @dev Mint mint_per_deployment amount of each token to vault specified. - * @param vault SimpleVault address to mint tokens to. - */ - function _mintAllTokensToVault(SimpleVault vault) internal { - for (uint256 i = 0; i < tokenAndMintArr.length; i++) { - SimpleERC20 token = tokenAndMintArr[i].token; - token.mintTo( - address(vault), - tokenAndMintArr[i].mint_per_deployment * 10**token.decimals() - ); - } - } - - /** - * @notice Add SimpleERC20 token to the list. Internal method. - * @dev Add SimpleERC20 token to the list. Internal method. - * @param token SimpleERC20 token address to add. - * @param mint_per_deployment Initial amount of tokens to mint to vault. - */ - //solhint-disable-next-line var-name-mixedcase - function _addToken(SimpleERC20 token, uint256 mint_per_deployment) internal { - tokenAndMintArr.push(TokenAndMint(token, mint_per_deployment)); - } - - /** - * @notice Mint mint_per_deployment amount of SimpleERC20 token to all vaults from the list. - * @dev Mint mint_per_deployment amount of SimpleERC20 token to all vaults from the list. - * @param token SimpleERC20 token address. - * @param mint_per_deployment Initial amount of tokens to mint to vaults. - */ - //solhint-disable-next-line var-name-mixedcase - function _mintTokenForAllVaults(SimpleERC20 token, uint256 mint_per_deployment) internal { - for (uint256 i = 0; i < brokerAndVaultArr.length; i++) { - token.mintTo( - address(brokerAndVaultArr[i].vault), - mint_per_deployment * 10**token.decimals() - ); - } - } - - /** - * @notice Remove token form the list. - * @dev Swap the last element with element at index and pops the last one. - * @param index Index of the element to remove. - */ - function _removeTokenAtIndex(uint256 index) internal { - tokenAndMintArr[index] = tokenAndMintArr[tokenAndMintArr.length - 1]; - tokenAndMintArr.pop(); - } - - /** - * @notice Find the index of the SimpleERC20 token in the list. Return -1 if not found. - * @dev Find the index of the SimpleERC20 token in the list. Return -1 if not found. - * @param token Address of the token find. - * @return int256 Index of the token in the list or -1 if not present. - */ - function _getTokenIndex(SimpleERC20 token) internal view returns (int256) { - for (uint256 i = 0; i < tokenAndMintArr.length; i++) { - if (tokenAndMintArr[i].token == token) { - return int256(i); - } - } - return -1; - } - - /** - * @notice Burn all SimpleERC20 tokens from all vaults from the list. - * @dev Burn all SimpleERC20 tokens from all vaults from the list. - * @param token SimpleERC20 token address. - */ - function _burnTokenFromAllVaults(SimpleERC20 token) internal { - for (uint256 i = 0; i < brokerAndVaultArr.length; i++) { - token.burnFrom( - address(brokerAndVaultArr[i].vault), - token.balanceOf(address(brokerAndVaultArr[i].vault)) - ); - } - } - - /** - * @notice Check strings for equality. - * @dev Check strings for equality. - * @param s1 First string. - * @param s2 Second string. - * @return bool If s1 equals s2. - */ - function _stringsEqual(string memory s1, string memory s2) internal pure returns (bool) { - return keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)); - } -} diff --git a/contracts/custody-factory/test/SimpleFaultFactoryTest.sol b/contracts/custody-factory/test/SimpleFaultFactoryTest.sol deleted file mode 100644 index 41bab2d..0000000 --- a/contracts/custody-factory/test/SimpleFaultFactoryTest.sol +++ /dev/null @@ -1,8 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import '../SimpleVaultFactory.sol'; - -contract SimpleVaultFactoryTest is SimpleVaultFactory { - bool public constant AVAILABLE_AFTER_UPGRADE = true; -} diff --git a/contracts/custody/IVault.sol b/contracts/custody/IVault.sol deleted file mode 100644 index 68f59f1..0000000 --- a/contracts/custody/IVault.sol +++ /dev/null @@ -1,45 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -/** - * @notice IVault is the interface to implement custody - */ -interface IVault { - /** - * Deposited event - * @param id Ledger id - * @param account Account address - * @param asset Asset address to deposit - * @param amount Quantity of assets to be deposited - * @param rid Request id from broker - */ - event Deposited( - uint256 indexed id, - address indexed account, - address indexed asset, - uint256 amount, - bytes32 rid - ); - - /** - * Withdrawn event - * @param id Ledger id - * @param account Account address - * @param asset Asset address to deposit - * @param amount Quantity of assets to be deposited - * @param rid Request id from broker - */ - event Withdrawn( - uint256 indexed id, - address indexed account, - address indexed asset, - uint256 amount, - bytes32 rid - ); - - /** - * Get last ledger id (deposits and withdrawals id). - * @return uint256 Ledger id. - */ - function getLastId() external view returns (uint256); -} diff --git a/contracts/custody/SimpleVault.sol b/contracts/custody/SimpleVault.sol deleted file mode 100644 index afa9c13..0000000 --- a/contracts/custody/SimpleVault.sol +++ /dev/null @@ -1,266 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import '@openzeppelin/contracts/access/AccessControl.sol'; -import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; -import '@openzeppelin/contracts/utils/Counters.sol'; -import './IVault.sol'; - -/** - * @notice Custody smart contracts aim to provide a secure trading environment by holding - * the assets on the erc20 chain so that the user and broker can freely trade off-chain. - */ -contract SimpleVault is AccessControl, IVault { - using Counters for Counters.Counter; - - /** - * Broker role identifier value - */ - bytes32 public constant BROKER_ROLE = keccak256('CUSTODY_BROKER_ROLE'); - - /** - * Deposit type identifier value - */ - bytes32 public constant DEPOSIT_TYPE = keccak256('CUSTODY_DEPOSIT_TYPE'); - - /** - * Withdrawal type identifier value - */ - bytes32 public constant WITHDRAW_TYPE = keccak256('CUSTODY_WITHDRAW_TYPE'); - - struct Asset { - address asset; - uint256 amount; - } - - string private _name; - address private _broker; - Counters.Counter private _ledgerId; - - // Keep track of used signatures to prevent reuse before expiration. - mapping(address => mapping(bytes32 => bool)) private _sigUsage; - - /** - * Modifier to check information required for deposits and withdrawals. - * @param account Account address to check - * @param action Action type. One of DEPOSIT_TYPE and WITHDRAW_TYPE - * @param payload Payload consists of rid (unique identifier id), expire, destination, and the assets list with amount - * @param signature Broker signature - */ - modifier onlyValidSignature( - address account, - bytes32 action, - bytes calldata payload, - bytes memory signature - ) { - require(account != address(0), 'Vault: account is zero address'); - require(action != 0, 'Vault: action is required'); - { - bytes32 digest = ECDSA.toEthSignedMessageHash( - keccak256(abi.encodePacked(action, payload)) - ); - address recovered = ECDSA.recover(digest, signature); - require(recovered == _broker, 'Vault: invalid signature'); - } - require(hasRole(BROKER_ROLE, _broker), 'Vault: invalid broker'); - _; - } - - /** - * The constructor function sets the contract name and broker's address. - * @param name_ Contract name - * @param broker_ Broker name - */ - constructor(string memory name_, address broker_) { - _name = name_; - _broker = broker_; - _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); - _grantRole(BROKER_ROLE, _broker); - } - - /** - * Get contract name. - * @return string Contract name - */ - function name() public view virtual returns (string memory) { - return _name; - } - - /** - * Change broker address who signed the withdrawal signature. - * @param newBroker Broker address - */ - function changeBroker(address newBroker) external onlyRole(DEFAULT_ADMIN_ROLE) { - revokeRole(BROKER_ROLE, _broker); - _grantRole(BROKER_ROLE, newBroker); - _broker = newBroker; - } - - /** - * Get last ledger id (deposits and withdrawals id). - * @return uint256 Ledger id. - */ - function getLastId() external view override returns (uint256) { - return _ledgerId.current(); - } - - /** - * Deposit the assets with given payload from the caller - * @param payload Deposit payload consists of rid (unique identifier id), expire, destination, and the list of deposit asset and amount - * @param signature Broker signature - * @return bool Return 'true' when deposited - */ - function deposit(bytes calldata payload, bytes memory signature) public payable returns (bool) { - return _deposit(msg.sender, payload, signature); - } - - /** - * Internal deposit process and increment ledger id - * @param account Account address - * @param payload Deposit payload consists of rid (unique identifier id), expire, destination, and the list of deposit asset and amount - * @param signature Broker signature - * @return bool Return 'true' when deposited - */ - function _deposit( - address account, - bytes calldata payload, - bytes memory signature - ) internal onlyValidSignature(account, DEPOSIT_TYPE, payload, signature) returns (bool) { - bytes32 sigHash = keccak256(signature); - (bytes32 rid, , , Asset[] memory assets) = _extractPayload(account, sigHash, payload); - - _sigUsage[account][sigHash] = true; - - for (uint256 i = 0; i < assets.length; i++) { - _transferAssetFrom(assets[i].asset, account, assets[i].amount); - _ledgerId.increment(); - emit Deposited(_ledgerId.current(), account, assets[i].asset, assets[i].amount, rid); - } - - return true; - } - - /** - * Withdraw the assets with given payload to the caller - * @param payload Withdrawal payload consists of rid (unique identifier id), expire, destination, and the list of withdrawal asset and amount - * @param signature Broker signature - * @return bool Return 'true' when withdrawn - */ - function withdraw(bytes calldata payload, bytes memory signature) - public - payable - returns (bool) - { - return _withdraw(msg.sender, payload, signature); - } - - /** - * Internal withdraw process and increment ledger id - * @param account Account address - * @param payload Withdrawal payload consists of rid (unique identifier id), expire, destination, and the list of withdrawal asset and amount - * @param signature Broker signature - * @return bool Return 'true' when withdrawn - */ - function _withdraw( - address account, - bytes calldata payload, - bytes memory signature - ) internal onlyValidSignature(account, WITHDRAW_TYPE, payload, signature) returns (bool) { - bytes32 sigHash = keccak256(signature); - (bytes32 rid, , , Asset[] memory assets) = _extractPayload(account, sigHash, payload); - - _sigUsage[account][sigHash] = true; - - for (uint256 i = 0; i < assets.length; i++) { - _transferAssetTo(assets[i].asset, account, assets[i].amount); - _ledgerId.increment(); - emit Withdrawn(_ledgerId.current(), account, assets[i].asset, assets[i].amount, rid); - } - - return true; - } - - /** - * Internal function to extract payload data - * @param account Account address - * @param sigHash Broker signature keccak256 hash - * @param payload Payload consists of rid (unique identifier id), expire, destination, and the assets list with amount - * @return bytes32 rid - * @return uint64 expire - * @return address destination - * @return Asset Array of assets - */ - function _extractPayload( - address account, - bytes32 sigHash, - bytes calldata payload - ) - internal - view - returns ( - bytes32, - uint64, - address, - Asset[] memory - ) - { - (bytes32 rid, uint64 expire, address destination, Asset[] memory assets) = abi.decode( - payload, - (bytes32, uint64, address, Asset[]) - ); - - require(expire > block.timestamp, 'Vault: request is expired'); //solhint-disable-line not-rely-on-time - require(account == destination, 'Vault: invalid request'); - require(!_sigUsage[account][sigHash], 'Vault: signature has been used'); - - for (uint256 i = 0; i < assets.length; i++) { - require(assets[i].amount > 0, 'Vault: amount is zero'); - } - - return (rid, expire, destination, assets); - } - - /** - * Transfers the given amount of this AssetHolders's asset type from a supplied ethereum address. - * @param asset Asset address to transfer - * @param from Ethereum address to be credited - * @param amount Quantity of assets to be transferred - */ - function _transferAssetFrom( - address asset, - address from, - uint256 amount - ) internal { - require(from != address(0), 'Vault: transfer is zero address'); - if (asset == address(0)) { - require(msg.value == amount, 'Vault: Incorrect msg.value'); - } else { - // require successful deposit before updating holdings (protect against reentrancy) - require( - IERC20(asset).transferFrom(from, address(this), amount), - 'Vault: Could not deposit ERC20' - ); - } - } - - /** - * Transfers the given amount of this AssetHolders's asset type to a supplied ethereum address. - * @param asset Asset address to transfer - * @param destination Ethereum address to be credited - * @param amount Quantity of assets to be transferred - */ - function _transferAssetTo( - address asset, - address destination, - uint256 amount - ) internal { - require(destination != address(0), 'Vault: transfer is zero address'); - if (asset == address(0)) { - (bool success, ) = destination.call{value: amount}(''); //solhint-disable-line avoid-low-level-calls - require(success, 'Vault: Could not transfer ETH'); - } else { - IERC20(asset).transfer(destination, amount); - } - } -} diff --git a/contracts/custody/test/TestERC20.sol b/contracts/custody/test/TestERC20.sol deleted file mode 100644 index 538a0a5..0000000 --- a/contracts/custody/test/TestERC20.sol +++ /dev/null @@ -1,33 +0,0 @@ -//SPDX-License-Identifier: Unlicense -pragma solidity ^0.8.0; - -import 'hardhat/console.sol'; -import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; -import '@openzeppelin/contracts/access/Ownable.sol'; - -contract TestERC20 is ERC20, Ownable { - constructor( - string memory name_, - string memory symbol_, - uint256 amountToMint - ) ERC20(name_, symbol_) { - _setBalance(msg.sender, amountToMint); - } - - function setBalance(uint256 amount) public { - _setBalance(msg.sender, amount); - } - - function setUserBalance(address to, uint256 amount) public onlyOwner { - _setBalance(to, amount); - } - - function _setBalance(address to, uint256 amount) internal { - uint256 old = balanceOf(to); - if (old < amount) { - _mint(to, amount - old); - } else if (old > amount) { - _burn(to, old - amount); - } - } -} diff --git a/contracts/nitro-protocol/CountingApp.sol b/contracts/nitro-protocol/CountingApp.sol deleted file mode 100644 index c7b6b0c..0000000 --- a/contracts/nitro-protocol/CountingApp.sol +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import './interfaces/IForceMoveApp.sol'; - -/** - * @dev The CountingApp contracts complies with the ForceMoveApp interface and allows only for a simple counter to be incremented. Used for testing purposes. - */ -contract CountingApp is IForceMoveApp { - struct CountingAppData { - uint256 counter; - } - - /** - * @notice Decodes the appData. - * @dev Decodes the appData. - * @param appDataBytes The abi.encode of a CountingAppData struct describing the application-specific data. - * @return A CountingAppData struct containing the application-specific data. - */ - function appData(bytes memory appDataBytes) internal pure returns (CountingAppData memory) { - bytes memory decodedAppData = abi.decode(appDataBytes, (bytes)); - return abi.decode(decodedAppData, (CountingAppData)); - } - - /** - * @notice Encodes the CountingApp rules. - * @dev Encodes the CountingApp rules. - * @param a State being transitioned from. - * @param b State being transitioned to. - * @return true if the transition conforms to the rules, false otherwise. - */ - function validTransition( - VariablePart memory a, - VariablePart memory b, - uint48, // turnNumB, unused - uint256 // nParticipants, unused - ) public override pure returns (bool) { - require( - appData(b.appData).counter == appData(a.appData).counter + 1, - 'Counter must be incremented' - ); - // Note this is gas inefficient, and inferior to _bytesEqual in use elsewhere - require(keccak256(b.outcome) == keccak256(a.outcome), 'Outcome must not change'); - return true; - } -} diff --git a/contracts/nitro-protocol/ForceMove.sol b/contracts/nitro-protocol/ForceMove.sol deleted file mode 100644 index da8c3e6..0000000 --- a/contracts/nitro-protocol/ForceMove.sol +++ /dev/null @@ -1,827 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import { ExitFormat as Outcome } from '@statechannels/exit-format/contracts/ExitFormat.sol'; -import { ECRecovery } from './libraries/ECRecovery.sol'; -import './interfaces/IForceMove.sol'; -import './interfaces/IForceMoveApp.sol'; -import './StatusManager.sol'; - -/** - * @dev An implementation of ForceMove protocol, which allows state channels to be adjudicated and finalized. - */ -contract ForceMove is IForceMove, StatusManager { - // ***************** - // External methods: - // ***************** - - /** - * @notice Unpacks turnNumRecord, finalizesAt and fingerprint from the status of a particular channel. - * @dev Unpacks turnNumRecord, finalizesAt and fingerprint from the status of a particular channel. - * @param channelId Unique identifier for a state channel. - * @return turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant. - * @return finalizesAt The unix timestamp when `channelId` will finalize. - * @return fingerprint The last 160 bits of kecca256(stateHash, outcomeHash) - */ - function unpackStatus(bytes32 channelId) - external - view - returns ( - uint48 turnNumRecord, - uint48 finalizesAt, - uint160 fingerprint - ) - { - (turnNumRecord, finalizesAt, fingerprint) = _unpackStatus(channelId); - } - - /** - * @notice Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time. - * @dev Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. Length is from 1 to the number of participants (inclusive). - * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final. - * @param sigs An array of signatures that support the state with the `largestTurnNum`. There must be one for each participant, e.g.: [sig-from-p0, sig-from-p1, ...] - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param challengerSig The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove'). - */ - function challenge( - FixedPart memory fixedPart, - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] memory variableParts, - uint8 isFinalCount, // how many of the states are final - Signature[] memory sigs, - uint8[] memory whoSignedWhat, - Signature memory challengerSig - ) external override { - // input type validation - requireValidInput( - fixedPart.participants.length, - variableParts.length, - sigs.length, - whoSignedWhat.length - ); - - bytes32 channelId = _getChannelId(fixedPart); - - if (_mode(channelId) == ChannelMode.Open) { - _requireNonDecreasedTurnNumber(channelId, largestTurnNum); - } else if (_mode(channelId) == ChannelMode.Challenge) { - _requireIncreasedTurnNumber(channelId, largestTurnNum); - } else { - // This should revert. - _requireChannelNotFinalized(channelId); - } - bytes32 supportedStateHash = _requireStateSupportedBy( - largestTurnNum, - variableParts, - isFinalCount, - channelId, - fixedPart, - sigs, - whoSignedWhat - ); - - _requireChallengerIsParticipant(supportedStateHash, fixedPart.participants, challengerSig); - - // effects - - emit ChallengeRegistered( - channelId, - largestTurnNum, - uint48(block.timestamp) + fixedPart.challengeDuration, //solhint-disable-line not-rely-on-time - // This could overflow, so don't join a channel with a huge challengeDuration - isFinalCount > 0, - fixedPart, - variableParts, - sigs, - whoSignedWhat - ); - - statusOf[channelId] = _generateStatus( - ChannelData( - largestTurnNum, - uint48(block.timestamp) + fixedPart.challengeDuration, //solhint-disable-line not-rely-on-time - supportedStateHash, - keccak256(variableParts[variableParts.length - 1].outcome) - ) - ); - } - - /** - * @notice Repsonds to an ongoing challenge registered against a state channel. - * @dev Repsonds to an ongoing challenge registered against a state channel. - * @param isFinalAB An pair of booleans describing if the challenge state and/or the response state have the `isFinal` property set to `true`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param variablePartAB An pair of structs, each decribing the properties of the state channel that may change with each state update (for the challenge state and for the response state). - * @param sig The responder's signature on the `responseStateHash`. - */ - function respond( - bool[2] memory isFinalAB, - FixedPart memory fixedPart, - IForceMoveApp.VariablePart[2] memory variablePartAB, - // variablePartAB[0] = challengeVariablePart - // variablePartAB[1] = responseVariablePart - Signature memory sig - ) external override { - // No need to validate fixedPart.participants.length here, as that validation would have happened during challenge - - bytes32 channelId = _getChannelId(fixedPart); - (uint48 turnNumRecord, uint48 finalizesAt, ) = _unpackStatus(channelId); - - bytes32 challengeStateHash = _hashState( - channelId, - variablePartAB[0].appData, - variablePartAB[0].outcome, - turnNumRecord, - isFinalAB[0] - ); - - bytes32 responseStateHash = _hashState( - channelId, - variablePartAB[1].appData, - variablePartAB[1].outcome, - turnNumRecord + 1, - isFinalAB[1] - ); - - // checks - - bytes32 challengeOutcomeHash = keccak256(variablePartAB[0].outcome); - - _requireSpecificChallenge( - ChannelData(turnNumRecord, finalizesAt, challengeStateHash, challengeOutcomeHash), - channelId - ); - - require( - _recoverSigner(responseStateHash, sig) == - fixedPart.participants[(turnNumRecord + 1) % fixedPart.participants.length], - 'Signer not authorized mover' - ); - - _requireValidTransition( - fixedPart.participants.length, - isFinalAB, - variablePartAB, - turnNumRecord + 1, - fixedPart.appDefinition - ); - - // effects - _clearChallenge(channelId, turnNumRecord + 1); - } - - /** - * @notice Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant. - * @dev Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. - * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final. - * @param sigs An array of signatures that support the state with the `largestTurnNum`: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - */ - function checkpoint( - FixedPart memory fixedPart, - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] memory variableParts, - uint8 isFinalCount, // how many of the states are final - Signature[] memory sigs, - uint8[] memory whoSignedWhat - ) external override { - // input type validation - requireValidInput( - fixedPart.participants.length, - variableParts.length, - sigs.length, - whoSignedWhat.length - ); - - bytes32 channelId = _getChannelId(fixedPart); - - // checks - _requireChannelNotFinalized(channelId); - _requireIncreasedTurnNumber(channelId, largestTurnNum); - _requireStateSupportedBy( - largestTurnNum, - variableParts, - isFinalCount, - channelId, - fixedPart, - sigs, - whoSignedWhat - ); - - // effects - _clearChallenge(channelId, largestTurnNum); - } - - /** - * @notice Finalizes a channel by providing a finalization proof. External wrapper for _conclude. - * @dev Finalizes a channel by providing a finalization proof. External wrapper for _conclude. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param appData Application specific data. - * @param outcome Encoded outcome structure. Applies to all states in the finalization proof. Will be decoded to hash the State. - * @param numStates The number of states in the finalization proof. - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param sigs An array of signatures that support the state with the `largestTurnNum`: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - */ - function conclude( - uint48 largestTurnNum, - FixedPart memory fixedPart, - bytes memory appData, - bytes memory outcome, - uint8 numStates, - uint8[] memory whoSignedWhat, - Signature[] memory sigs - ) external override { - _conclude( - largestTurnNum, - fixedPart, - appData, - outcome, - numStates, - whoSignedWhat, - sigs - ); - } - - /** - * @notice Finalizes a channel by providing a finalization proof. Internal method. - * @dev Finalizes a channel by providing a finalization proof. Internal method. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param appData Application specific data. - * @param outcome Encoded outcome structure. Applies to all states in the finalization proof. Will be decoded to hash the State. - * @param numStates The number of states in the finalization proof. - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param sigs An array of signatures that support the state with the `largestTurnNum`:: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - */ - function _conclude( - uint48 largestTurnNum, - FixedPart memory fixedPart, - bytes memory appData, - bytes memory outcome, - uint8 numStates, - uint8[] memory whoSignedWhat, - Signature[] memory sigs - ) internal returns (bytes32 channelId) { - channelId = _getChannelId(fixedPart); - _requireChannelNotFinalized(channelId); - - // input type validation - requireValidInput( - fixedPart.participants.length, - numStates, - sigs.length, - whoSignedWhat.length - ); - - require(largestTurnNum + 1 >= numStates, 'largestTurnNum too low'); - // ^^ SW-C101: prevent underflow - - // By construction, the following states form a valid transition - bytes32[] memory stateHashes = new bytes32[](numStates); - for (uint48 i = 0; i < numStates; i++) { - stateHashes[i] = _hashState( - channelId, - appData, - outcome, - largestTurnNum + (i + 1) - numStates, // turnNum - // ^^ SW-C101: It is not easy to use SafeMath here, since we are not using uint256s - // Instead, we are protected by the require statement above - true // isFinal - ); - } - - // checks - require( - _validSignatures( - largestTurnNum, - fixedPart.participants, - stateHashes, - sigs, - whoSignedWhat - ), - 'Invalid signatures / !isFinal' - ); - - bytes32 outcomeHash = keccak256(outcome); - - // effects - statusOf[channelId] = _generateStatus( - ChannelData(0, uint48(block.timestamp), bytes32(0), outcomeHash) //solhint-disable-line not-rely-on-time - ); - emit Concluded(channelId, uint48(block.timestamp)); //solhint-disable-line not-rely-on-time - } - - function getChainID() public pure returns (uint256) { - uint256 id; - /* solhint-disable no-inline-assembly */ - assembly { - id := chainid() - } - /* solhint-disable no-inline-assembly */ - return id; - } - - /** - * @notice Validates input for several external methods. - * @dev Validates input for several external methods. - * @param numParticipants Length of the participants array - * @param numStates Number of states submitted - * @param numSigs Number of signatures submitted - * @param numWhoSignedWhats whoSignedWhat.length - */ - function requireValidInput( - uint256 numParticipants, - uint256 numStates, - uint256 numSigs, - uint256 numWhoSignedWhats - ) public pure returns (bool) { - require((numParticipants >= numStates) && (numStates > 0), 'Insufficient or excess states'); - require( - (numSigs == numParticipants) && (numWhoSignedWhats == numParticipants), - 'Bad |signatures|v|whoSignedWhat|' - ); - require(numParticipants <= type(uint8).max, 'Too many participants!'); // type(uint8).max = 2**8 - 1 = 255 - // no more than 255 participants - // max index for participants is 254 - return true; - } - - // ***************** - // Internal methods: - // ***************** - - /** - * @notice Checks that the challengerSignature was created by one of the supplied participants. - * @dev Checks that the challengerSignature was created by one of the supplied participants. - * @param supportedStateHash Forms part of the digest to be signed, along with the string 'forceMove'. - * @param participants A list of addresses representing the participants of a channel. - * @param challengerSignature The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove'). - */ - function _requireChallengerIsParticipant( - bytes32 supportedStateHash, - address[] memory participants, - Signature memory challengerSignature - ) internal pure { - address challenger = _recoverSigner( - keccak256(abi.encode(supportedStateHash, 'forceMove')), - challengerSignature - ); - require(_isAddressInArray(challenger, participants), 'Challenger is not a participant'); - } - - /** - * @notice Tests whether a given address is in a given array of addresses. - * @dev Tests whether a given address is in a given array of addresses. - * @param suspect A single address of interest. - * @param addresses A line-up of possible perpetrators. - * @return true if the address is in the array, false otherwise - */ - function _isAddressInArray(address suspect, address[] memory addresses) - internal - pure - returns (bool) - { - for (uint256 i = 0; i < addresses.length; i++) { - if (suspect == addresses[i]) { - return true; - } - } - return false; - } - - /** - * @notice Given an array of state hashes, checks the validity of the supplied signatures. Valid means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @dev Given an array of state hashes, checks the validity of the supplied signatures. Valid means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param participants A list of addresses representing the participants of a channel. - * @param stateHashes Array of keccak256(State) submitted in support of a state, - * @param sigs Array of Signatures, one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]] - * @return true if the signatures are valid, false otherwise - */ - function _validSignatures( - uint48 largestTurnNum, - address[] memory participants, - bytes32[] memory stateHashes, - Signature[] memory sigs, - uint8[] memory whoSignedWhat // whoSignedWhat[i] is the index of the state in stateHashes that was signed by participants[i] - ) internal pure returns (bool) { - uint256 nParticipants = participants.length; - uint256 nStates = stateHashes.length; - - require( - _acceptableWhoSignedWhat(whoSignedWhat, largestTurnNum, nParticipants, nStates), - 'Unacceptable whoSignedWhat array' - ); - for (uint256 i = 0; i < nParticipants; i++) { - address signer = _recoverSigner(stateHashes[whoSignedWhat[i]], sigs[i]); - if (signer != participants[i]) { - return false; - } - } - return true; - } - - /** - * @notice Given a declaration of which state in the support proof was signed by which participant, check if this declaration is acceptable. Acceptable means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @dev Given a declaration of which state in the support proof was signed by which participant, check if this declaration is acceptable. Acceptable means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]] - * @param largestTurnNum Largest turnNum of the support proof - * @param nParticipants Number of participants in the channel - * @param nStates Number of states in the support proof - * @return true if whoSignedWhat is acceptable, false otherwise - */ - function _acceptableWhoSignedWhat( - uint8[] memory whoSignedWhat, - uint48 largestTurnNum, - uint256 nParticipants, - uint256 nStates - ) internal pure returns (bool) { - require(whoSignedWhat.length == nParticipants, '|whoSignedWhat|!=nParticipants'); - for (uint256 i = 0; i < nParticipants; i++) { - uint256 offset = (nParticipants + largestTurnNum - i) % nParticipants; - // offset is the difference between the index of participant[i] and the index of the participant who owns the largesTurnNum state - // the additional nParticipants in the dividend ensures offset always positive - if (whoSignedWhat[i] + offset + 1 < nStates) { - return false; - } - } - return true; - } - - /** - * @notice Given a digest and ethereum digital signature, recover the signer - * @dev Given a digest and digital signature, recover the signer - * @param _d message digest - * @param sig ethereum digital signature - * @return signer - */ - function _recoverSigner(bytes32 _d, Signature memory sig) internal pure returns (address) { - bytes32 prefixedHash = keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n32', _d)); - address a = ECRecovery.recover(prefixedHash, sig.v, sig.r, sig.s); - require(a != address(0), 'Invalid signature'); - return (a); - } - - /** - * @notice Check that the submitted data constitute a support proof. - * @dev Check that the submitted data constitute a support proof. - * @param largestTurnNum Largest turnNum of the support proof - * @param variableParts Variable parts of the states in the support proof - * @param isFinalCount How many of the states are final? The final isFinalCount states are implied final, the remainder are implied not final. - * @param channelId Unique identifier for a channel. - * @param fixedPart Fixed Part of the states in the support proof - * @param sigs A signature from each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]] - * @return The hash of the latest state in the proof, if supported, else reverts. - */ - function _requireStateSupportedBy( - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] memory variableParts, - uint8 isFinalCount, - bytes32 channelId, - FixedPart memory fixedPart, - Signature[] memory sigs, - uint8[] memory whoSignedWhat - ) internal pure returns (bytes32) { - bytes32[] memory stateHashes = _requireValidTransitionChain( - largestTurnNum, - variableParts, - isFinalCount, - channelId, - fixedPart - ); - - require( - _validSignatures( - largestTurnNum, - fixedPart.participants, - stateHashes, - sigs, - whoSignedWhat - ), - 'Invalid signatures' - ); - - return stateHashes[stateHashes.length - 1]; - } - - /** - * @notice Check that the submitted states form a chain of valid transitions - * @dev Check that the submitted states form a chain of valid transitions - * @param largestTurnNum Largest turnNum of the support proof - * @param variableParts Variable parts of the states in the support proof - * @param isFinalCount How many of the states are final? The final isFinalCount states are implied final, the remainder are implied not final. - * @param channelId Unique identifier for a channel. - * @param fixedPart Fixed Part of the states in the support proof - * @return true if every state is a validTransition from its predecessor, false otherwise. - */ - function _requireValidTransitionChain( - // returns stateHashes array if valid - // else, reverts - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] memory variableParts, - uint8 isFinalCount, - bytes32 channelId, - FixedPart memory fixedPart - ) internal pure returns (bytes32[] memory) { - bytes32[] memory stateHashes = new bytes32[](variableParts.length); - uint48 firstFinalTurnNum = largestTurnNum - isFinalCount + 1; - uint48 turnNum; - - for (uint48 i = 0; i < variableParts.length; i++) { - turnNum = largestTurnNum - uint48(variableParts.length) + 1 + i; - stateHashes[i] = _hashState( - channelId, - variableParts[i].appData, - variableParts[i].outcome, - turnNum, - turnNum >= firstFinalTurnNum - ); - if (turnNum < largestTurnNum) { - _requireValidTransition( - fixedPart.participants.length, - [turnNum >= firstFinalTurnNum, turnNum + 1 >= firstFinalTurnNum], - [variableParts[i], variableParts[i + 1]], - turnNum + 1, - fixedPart.appDefinition - ); - } - } - return stateHashes; - } - - enum IsValidTransition {True, NeedToCheckApp} - - /** - * @notice Check that the submitted pair of states form a valid transition - * @dev Check that the submitted pair of states form a valid transition - * @param nParticipants Number of participants in the channel. - transition - * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final. - * @param ab Variable parts of each of the pair of states - * @param turnNumB turnNum of the later state of the pair - * @return true if the later state is a validTransition from its predecessor, false otherwise. - */ - function _requireValidProtocolTransition( - uint256 nParticipants, - bool[2] memory isFinalAB, // [a.isFinal, b.isFinal] - IForceMoveApp.VariablePart[2] memory ab, // [a,b] - uint48 turnNumB - ) internal pure returns (IsValidTransition) { - // a separate check on the signatures for the submitted states implies that the following fields are equal for a and b: - // chainId, participants, channelNonce, appDefinition, challengeDuration - // and that the b.turnNum = a.turnNum + 1 - if (isFinalAB[1]) { - require(_bytesEqual(ab[1].outcome, ab[0].outcome), 'Outcome change verboten'); - } else { - require(!isFinalAB[0], 'isFinal retrograde'); - if (turnNumB < 2 * nParticipants) { - require(_bytesEqual(ab[1].outcome, ab[0].outcome), 'Outcome change forbidden'); - require(_bytesEqual(ab[1].appData, ab[0].appData), 'appData change forbidden'); - } else { - return IsValidTransition.NeedToCheckApp; - } - } - return IsValidTransition.True; - } - - /** - * @notice Check that the submitted pair of states form a valid transition - * @dev Check that the submitted pair of states form a valid transition - * @param nParticipants Number of participants in the channel. - transition - * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final. - * @param ab Variable parts of each of the pair of states - * @param turnNumB turnNum of the later state of the pair. - * @param appDefinition Address of deployed contract containing application-specific validTransition function. - * @return true if the later state is a validTransition from its predecessor, false otherwise. - */ - function _requireValidTransition( - uint256 nParticipants, - bool[2] memory isFinalAB, // [a.isFinal, b.isFinal] - IForceMoveApp.VariablePart[2] memory ab, // [a,b] - uint48 turnNumB, - address appDefinition - ) internal pure returns (bool) { - IsValidTransition isValidProtocolTransition = _requireValidProtocolTransition( - nParticipants, - isFinalAB, // [a.isFinal, b.isFinal] - ab, // [a,b] - turnNumB - ); - - if (isValidProtocolTransition == IsValidTransition.NeedToCheckApp) { - require( - IForceMoveApp(appDefinition).validTransition(ab[0], ab[1], turnNumB, nParticipants), - 'Invalid ForceMoveApp Transition' - ); - } - - return true; - } - - /** - * @notice Check for equality of two byte strings - * @dev Check for equality of two byte strings - * @param _preBytes One bytes string - * @param _postBytes The other bytes string - * @return true if the bytes are identical, false otherwise. - */ - function _bytesEqual(bytes memory _preBytes, bytes memory _postBytes) - internal - pure - returns (bool) - { - // copied from https://www.npmjs.com/package/solidity-bytes-utils/v/0.1.1 - bool success = true; - - /* solhint-disable no-inline-assembly */ - assembly { - let length := mload(_preBytes) - - // if lengths don't match the arrays are not equal - switch eq(length, mload(_postBytes)) - case 1 { - // cb is a circuit breaker in the for loop since there's - // no said feature for inline assembly loops - // cb = 1 - don't breaker - // cb = 0 - break - let cb := 1 - - let mc := add(_preBytes, 0x20) - let end := add(mc, length) - - for { - let cc := add(_postBytes, 0x20) - // the next line is the loop condition: - // while(uint256(mc < end) + cb == 2) - } eq(add(lt(mc, end), cb), 2) { - mc := add(mc, 0x20) - cc := add(cc, 0x20) - } { - // if any of these checks fails then arrays are not equal - if iszero(eq(mload(mc), mload(cc))) { - // unsuccess: - success := 0 - cb := 0 - } - } - } - default { - // unsuccess: - success := 0 - } - } - /* solhint-disable no-inline-assembly */ - - return success; - } - - /** - * @notice Clears a challenge by updating the turnNumRecord and resetting the remaining channel storage fields, and emits a ChallengeCleared event. - * @dev Clears a challenge by updating the turnNumRecord and resetting the remaining channel storage fields, and emits a ChallengeCleared event. - * @param channelId Unique identifier for a channel. - * @param newTurnNumRecord New turnNumRecord to overwrite existing value - */ - function _clearChallenge(bytes32 channelId, uint48 newTurnNumRecord) internal { - statusOf[channelId] = _generateStatus( - ChannelData(newTurnNumRecord, 0, bytes32(0), bytes32(0)) - ); - emit ChallengeCleared(channelId, newTurnNumRecord); - } - - /** - * @notice Checks that the submitted turnNumRecord is strictly greater than the turnNumRecord stored on chain. - * @dev Checks that the submitted turnNumRecord is strictly greater than the turnNumRecord stored on chain. - * @param channelId Unique identifier for a channel. - * @param newTurnNumRecord New turnNumRecord intended to overwrite existing value - */ - function _requireIncreasedTurnNumber(bytes32 channelId, uint48 newTurnNumRecord) internal view { - (uint48 turnNumRecord, , ) = _unpackStatus(channelId); - require(newTurnNumRecord > turnNumRecord, 'turnNumRecord not increased.'); - } - - /** - * @notice Checks that the submitted turnNumRecord is greater than or equal to the turnNumRecord stored on chain. - * @dev Checks that the submitted turnNumRecord is greater than or equal to the turnNumRecord stored on chain. - * @param channelId Unique identifier for a channel. - * @param newTurnNumRecord New turnNumRecord intended to overwrite existing value - */ - function _requireNonDecreasedTurnNumber(bytes32 channelId, uint48 newTurnNumRecord) - internal - view - { - (uint48 turnNumRecord, , ) = _unpackStatus(channelId); - require(newTurnNumRecord >= turnNumRecord, 'turnNumRecord decreased.'); - } - - /** - * @notice Checks that a given ChannelData struct matches the challenge stored on chain, and that the channel is in Challenge mode. - * @dev Checks that a given ChannelData struct matches the challenge stored on chain, and that the channel is in Challenge mode. - * @param data A given ChannelData data structure. - * @param channelId Unique identifier for a channel. - */ - function _requireSpecificChallenge(ChannelData memory data, bytes32 channelId) internal view { - _requireMatchingStorage(data, channelId); - _requireOngoingChallenge(channelId); - } - - /** - * @notice Checks that a given channel is in the Challenge mode. - * @dev Checks that a given channel is in the Challenge mode. - * @param channelId Unique identifier for a channel. - */ - function _requireOngoingChallenge(bytes32 channelId) internal view { - require(_mode(channelId) == ChannelMode.Challenge, 'No ongoing challenge.'); - } - - /** - * @notice Checks that a given channel is NOT in the Finalized mode. - * @dev Checks that a given channel is in the Challenge mode. - * @param channelId Unique identifier for a channel. - */ - function _requireChannelNotFinalized(bytes32 channelId) internal view { - require(_mode(channelId) != ChannelMode.Finalized, 'Channel finalized.'); - } - - /** - * @notice Checks that a given channel is in the Open mode. - * @dev Checks that a given channel is in the Challenge mode. - * @param channelId Unique identifier for a channel. - */ - function _requireChannelOpen(bytes32 channelId) internal view { - require(_mode(channelId) == ChannelMode.Open, 'Channel not open.'); - } - - /** - * @notice Checks that a given ChannelData struct matches the challenge stored on chain. - * @dev Checks that a given ChannelData struct matches the challenge stored on chain. - * @param data A given ChannelData data structure. - * @param channelId Unique identifier for a channel. - */ - function _requireMatchingStorage(ChannelData memory data, bytes32 channelId) internal view { - require(_matchesStatus(data, statusOf[channelId]), 'status(ChannelData)!=storage'); - } - - /** - * @notice Checks that a given ChannelData struct matches a supplied bytes32 when formatted for storage. - * @dev Checks that a given ChannelData struct matches a supplied bytes32 when formatted for storage. - * @param data A given ChannelData data structure. - * @param s Some data in on-chain storage format. - */ - function _matchesStatus(ChannelData memory data, bytes32 s) internal pure returns (bool) { - return _generateStatus(data) == s; - } - - /** - * @notice Computes the hash of the state corresponding to the input data. - * @dev Computes the hash of the state corresponding to the input data. - * @param turnNum Turn number - * @param isFinal Is the state final? - * @param channelId Unique identifier for the channel - * @param appData Application specific date - * @param outcome Outcome bytes. Will be decoded to hash State properly - * @return The stateHash - */ - function _hashState( - bytes32 channelId, - bytes memory appData, - bytes memory outcome, - uint48 turnNum, - bool isFinal - ) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - channelId, - appData, - // Decoding to get an Outcome struct, since it is the one used in go-nitro State hashing - Outcome.decodeExit(outcome), - turnNum, - isFinal - ) - ); - } - - /** - * @notice Computes the unique id of a channel. - * @dev Computes the unique id of a channel. - * @param fixedPart Part of the state that does not change - * @return channelId - */ - function _getChannelId(FixedPart memory fixedPart) internal pure returns (bytes32 channelId) { - require(fixedPart.chainId == getChainID(), 'Incorrect chainId'); - channelId = keccak256( - abi.encode(getChainID(), fixedPart.participants, fixedPart.channelNonce, fixedPart.appDefinition, fixedPart.challengeDuration) - ); - } -} diff --git a/contracts/nitro-protocol/MultiAssetHolder.sol b/contracts/nitro-protocol/MultiAssetHolder.sol deleted file mode 100644 index be62d47..0000000 --- a/contracts/nitro-protocol/MultiAssetHolder.sol +++ /dev/null @@ -1,648 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; -import './ForceMove.sol'; -import '@openzeppelin/contracts-3.4.2/math/SafeMath.sol'; -import '@openzeppelin/contracts-3.4.2/token/ERC20/IERC20.sol'; -import './interfaces/IMultiAssetHolder.sol'; - -/** -@dev An implementation of the IMultiAssetHolder interface. The AssetHolder contract escrows ETH or tokens against state channels. It allows assets to be internally accounted for, and ultimately prepared for transfer from one channel to other channels and/or external destinations, as well as for guarantees to be claimed. - */ -contract MultiAssetHolder is IMultiAssetHolder, StatusManager { - using SafeMath for uint256; - - // ******* - // Storage - // ******* - - /** - * holdings[asset][channelId] is the amount of asset held against channel channelId. 0 address implies ETH - */ - mapping(address => mapping(bytes32 => uint256)) public holdings; - - // ************** - // External methods - // ************** - - /** - * @notice Deposit ETH or erc20 tokens against a given channelId. - * @dev Deposit ETH or erc20 tokens against a given channelId. - * @param asset erc20 token address, or zero address to indicate ETH - * @param channelId ChannelId to be credited. - * @param expectedHeld The number of wei/tokens the depositor believes are _already_ escrowed against the channelId. - * @param amount The intended number of wei/tokens to be deposited. - */ - function deposit( - address asset, - bytes32 channelId, - uint256 expectedHeld, - uint256 amount - ) external override payable { - require(!_isExternalDestination(channelId), 'Deposit to external destination'); - uint256 amountDeposited; - // this allows participants to reduce the wait between deposits, while protecting them from losing funds by depositing too early. Specifically it protects against the scenario: - // 1. Participant A deposits - // 2. Participant B sees A's deposit, which means it is now safe for them to deposit - // 3. Participant B submits their deposit - // 4. The chain re-orgs, leaving B's deposit in the chain but not A's - uint256 held = holdings[asset][channelId]; - require(held >= expectedHeld, 'holdings < expectedHeld'); - require(held < expectedHeld.add(amount), 'holdings already sufficient'); - - // The depositor wishes to increase the holdings against channelId to amount + expectedHeld - // The depositor need only deposit (at most) amount + (expectedHeld - holdings) (the term in parentheses is non-positive) - - amountDeposited = expectedHeld.add(amount).sub(held); // strictly positive - // require successful deposit before updating holdings (protect against reentrancy) - if (asset == address(0)) { - require(msg.value == amount, 'Incorrect msg.value for deposit'); - } else { - // require successful deposit before updating holdings (protect against reentrancy) - require( - IERC20(asset).transferFrom(msg.sender, address(this), amountDeposited), - 'Could not deposit ERC20s' - ); - } - - uint256 nowHeld = held.add(amountDeposited); - holdings[asset][channelId] = nowHeld; - emit Deposited(channelId, asset, amountDeposited, nowHeld); - - if (asset == address(0)) { - // refund whatever wasn't deposited. - uint256 refund = amount.sub(amountDeposited); - (bool success, ) = msg.sender.call{value: refund}(''); //solhint-disable-line avoid-low-level-calls - require(success, 'Could not refund excess funds'); - } - } - - /** - * @notice Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. - * @dev Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. - * @param assetIndex Will be used to slice the outcome into a single asset outcome. - * @param fromChannelId Unique identifier for state channel to transfer funds *from*. - * @param outcomeBytes The encoded Outcome of this state channel - * @param stateHash The hash of the state stored when the channel finalized. - * @param indices Array with each entry denoting the index of a destination to transfer funds to. An empty array indicates "all". - */ - function transfer( - uint256 assetIndex, // TODO consider a uint48? - bytes32 fromChannelId, - bytes memory outcomeBytes, - bytes32 stateHash, - uint256[] memory indices - ) external override { - ( - Outcome.SingleAssetExit[] memory outcome, - address asset, - uint256 initialAssetHoldings - ) = _apply_transfer_checks(assetIndex, indices, fromChannelId, stateHash, outcomeBytes); // view - - ( - Outcome.Allocation[] memory newAllocations, - , - Outcome.Allocation[] memory exitAllocations, - uint256 totalPayouts - ) = compute_transfer_effects_and_interactions( - initialAssetHoldings, - outcome[assetIndex].allocations, - indices - ); // pure, also performs checks - - _apply_transfer_effects( - assetIndex, - asset, - fromChannelId, - stateHash, - outcome, - newAllocations, - initialAssetHoldings, - totalPayouts - ); - _apply_transfer_interactions(outcome[assetIndex], exitAllocations); - } - - function _apply_transfer_checks( - uint256 assetIndex, - uint256[] memory indices, - bytes32 channelId, - bytes32 stateHash, - bytes memory outcomeBytes - ) - internal - view - returns ( - Outcome.SingleAssetExit[] memory outcome, - address asset, - uint256 initialAssetHoldings - ) - { - _requireIncreasingIndices(indices); // This assumption is relied on by compute_transfer_effects_and_interactions - _requireChannelFinalized(channelId); - _requireMatchingFingerprint(stateHash, keccak256(outcomeBytes), channelId); - - outcome = Outcome.decodeExit(outcomeBytes); - asset = outcome[assetIndex].asset; - initialAssetHoldings = holdings[asset][channelId]; - } - - function compute_transfer_effects_and_interactions( - uint256 initialHoldings, - Outcome.Allocation[] memory allocations, - uint256[] memory indices - ) - public - pure - returns ( - Outcome.Allocation[] memory newAllocations, - bool allocatesOnlyZeros, - Outcome.Allocation[] memory exitAllocations, - uint256 totalPayouts - ) - { - // `indices == []` means "pay out to all" - // Note: by initializing exitAllocations to be an array of fixed length, its entries are initialized to be `0` - exitAllocations = new Outcome.Allocation[]( - indices.length > 0 ? indices.length : allocations.length - ); - totalPayouts = 0; - newAllocations = new Outcome.Allocation[](allocations.length); - allocatesOnlyZeros = true; // switched to false if there is an item remaining with amount > 0 - uint256 surplus = initialHoldings; // tracks funds available during calculation - uint256 k = 0; // indexes the `indices` array - - // loop over allocations and decrease surplus - for (uint256 i = 0; i < allocations.length; i++) { - // copy destination, allocationType and metadata parts - newAllocations[i].destination = allocations[i].destination; - newAllocations[i].allocationType = allocations[i].allocationType; - newAllocations[i].metadata = allocations[i].metadata; - // compute new amount part - uint256 affordsForDestination = min(allocations[i].amount, surplus); - if ((indices.length == 0) || ((k < indices.length) && (indices[k] == i))) { - if (allocations[k].allocationType == uint8(Outcome.AllocationType.guarantee)) - revert('cannot transfer a guarantee'); - // found a match - // reduce the current allocationItem.amount - newAllocations[i].amount = allocations[i].amount - affordsForDestination; - // increase the relevant exit allocation - exitAllocations[k] = Outcome.Allocation( - allocations[i].destination, - affordsForDestination, - allocations[i].allocationType, - allocations[i].metadata - ); - totalPayouts += affordsForDestination; - // move on to the next supplied index - ++k; - } else { - newAllocations[i].amount = allocations[i].amount; - } - if (newAllocations[i].amount != 0) allocatesOnlyZeros = false; - // decrease surplus by the current amount if possible, else surplus goes to zero - surplus -= affordsForDestination; - } - } - - function _apply_transfer_effects( - uint256 assetIndex, - address asset, - bytes32 channelId, - bytes32 stateHash, - Outcome.SingleAssetExit[] memory outcome, - Outcome.Allocation[] memory newAllocations, - uint256 initialHoldings, - uint256 totalPayouts - ) internal { - // update holdings - holdings[asset][channelId] -= totalPayouts; - - // store fingerprint of modified outcome - outcome[assetIndex].allocations = newAllocations; - _updateFingerprint(channelId, stateHash, keccak256(abi.encode(outcome))); - - // emit the information needed to compute the new outcome stored in the fingerprint - emit AllocationUpdated(channelId, assetIndex, initialHoldings); - } - - function _apply_transfer_interactions( - Outcome.SingleAssetExit memory singleAssetExit, - Outcome.Allocation[] memory exitAllocations - ) internal { - // create a new tuple to avoid mutating singleAssetExit - _executeSingleAssetExit( - Outcome.SingleAssetExit( - singleAssetExit.asset, - singleAssetExit.metadata, - exitAllocations - ) - ); - } - - /** - * @notice Transfers as many funds escrowed against `sourceChannelId` as can be afforded for the destinations specified by targetAllocationIndicesToPayout in the beneficiaries of the __target__ of the channel at indexOfTargetInSource. - * @dev Transfers as many funds escrowed against `sourceChannelId` as can be afforded for the destinations specified by targetAllocationIndicesToPayout in the beneficiaries of the __target__ of the channel at indexOfTargetInSource. - * @param claimArgs arguments used in the claim function. Used to avoid stack too deep error. - */ - function claim(ClaimArgs memory claimArgs) external override { - ( - Outcome.SingleAssetExit[] memory sourceOutcome, - Outcome.SingleAssetExit[] memory targetOutcome, - address asset, - uint256 initialAssetHoldings - ) = _apply_claim_checks(claimArgs); // view - - Outcome.Allocation[] memory newSourceAllocations; - Outcome.Allocation[] memory newTargetAllocations; - Outcome.Allocation[] memory exitAllocations; - uint256 totalPayouts; - { - Outcome.Allocation[] memory sourceAllocations = sourceOutcome[claimArgs - .sourceAssetIndex] - .allocations; - Outcome.Allocation[] memory targetAllocations = targetOutcome[claimArgs - .targetAssetIndex] - .allocations; - ( - newSourceAllocations, - newTargetAllocations, - exitAllocations, - totalPayouts - ) = compute_claim_effects_and_interactions( - initialAssetHoldings, - sourceAllocations, - targetAllocations, - claimArgs.indexOfTargetInSource, - claimArgs.targetAllocationIndicesToPayout - ); // pure - } - - _apply_claim_effects( - claimArgs, - asset, - sourceOutcome, - newSourceAllocations, - sourceOutcome[claimArgs.sourceAssetIndex].allocations[claimArgs.indexOfTargetInSource] - .destination, // targetChannelId - targetOutcome, - newTargetAllocations, - initialAssetHoldings, - totalPayouts - ); - - _apply_claim_interactions(targetOutcome[claimArgs.targetAssetIndex], exitAllocations); - } - - /** - * @dev Checks that targetAllocationIndicesToPayout are increasing; that the source and target channels are finalized; that the supplied outcomes match the stored fingerprints; that the asset is identical in source and target. Computes and returns: the decoded outcomes, the asset being targetted; the number of assets held against the guarantor. - */ - function _apply_claim_checks(ClaimArgs memory claimArgs) - internal - view - returns ( - Outcome.SingleAssetExit[] memory sourceOutcome, - Outcome.SingleAssetExit[] memory targetOutcome, - address asset, - uint256 initialAssetHoldings - ) - { - ( - bytes32 sourceChannelId, - bytes memory sourceOutcomeBytes, - uint256 sourceAssetIndex, - bytes memory targetOutcomeBytes, - uint256 targetAssetIndex - ) = ( - claimArgs.sourceChannelId, - claimArgs.sourceOutcomeBytes, - claimArgs.sourceAssetIndex, - claimArgs.targetOutcomeBytes, - claimArgs.targetAssetIndex - ); - - _requireIncreasingIndices(claimArgs.targetAllocationIndicesToPayout); // This assumption is relied on by compute_transfer_effects_and_interactions - - // source checks - _requireChannelFinalized(sourceChannelId); - _requireMatchingFingerprint( - claimArgs.sourceStateHash, - keccak256(sourceOutcomeBytes), - sourceChannelId - ); - - sourceOutcome = Outcome.decodeExit(sourceOutcomeBytes); - targetOutcome = Outcome.decodeExit(targetOutcomeBytes); - asset = sourceOutcome[sourceAssetIndex].asset; - require( - sourceOutcome[sourceAssetIndex].allocations[targetAssetIndex].allocationType == - uint8(Outcome.AllocationType.guarantee), - 'not a guarantee allocation' - ); - - initialAssetHoldings = holdings[asset][sourceChannelId]; - bytes32 targetChannelId = sourceOutcome[sourceAssetIndex].allocations[claimArgs - .indexOfTargetInSource] - .destination; - - // target checks - require(targetOutcome[targetAssetIndex].asset == asset, 'targetAsset != guaranteeAsset'); - _requireChannelFinalized(targetChannelId); - _requireMatchingFingerprint( - claimArgs.targetStateHash, - keccak256(targetOutcomeBytes), - targetChannelId - ); - } - - /** - * @dev Computes side effects for the claim function. First, computes the amount the source channel can afford for the target. Then, computes and returns updated allocations for the source and for the target, as well as exit allocations (to be paid out). It does this by walking the target allocations, testing against the guarantee in the source, and conditionally siphoning money out. See the Nitro paper. - */ - function compute_claim_effects_and_interactions( - uint256 initialHoldings, - Outcome.Allocation[] memory sourceAllocations, - Outcome.Allocation[] memory targetAllocations, - uint256 indexOfTargetInSource, - uint256[] memory targetAllocationIndicesToPayout - ) - public - pure - returns ( - Outcome.Allocation[] memory newSourceAllocations, - Outcome.Allocation[] memory newTargetAllocations, - Outcome.Allocation[] memory exitAllocations, - uint256 totalPayouts - ) - { - // `targetAllocationIndicesToPayout == []` means "pay out to all" - - totalPayouts = 0; - uint256 k = 0; // indexes the `targetAllocationIndicesToPayout` array - // We rely on the assumption that the targetAllocationIndicesToPayout are strictly increasing. - // This allows us to iterate over the destinations in order once, continuing until we hit the first index, then the second etc. - // If the targetAllocationIndicesToPayout were to decrease, we would have to start from the beginning: doing a full search for each index. - - // copy allocations - newSourceAllocations = new Outcome.Allocation[](sourceAllocations.length); - newTargetAllocations = new Outcome.Allocation[](targetAllocations.length); - exitAllocations = new Outcome.Allocation[](targetAllocations.length); - for (uint256 i = 0; i < sourceAllocations.length; i++) { - newSourceAllocations[i].destination = sourceAllocations[i].destination; - newSourceAllocations[i].amount = sourceAllocations[i].amount; - newSourceAllocations[i].metadata = sourceAllocations[i].metadata; - newSourceAllocations[i].allocationType = sourceAllocations[i].allocationType; - } - for (uint256 i = 0; i < targetAllocations.length; i++) { - newTargetAllocations[i].destination = targetAllocations[i].destination; - newTargetAllocations[i].amount = targetAllocations[i].amount; - newTargetAllocations[i].metadata = targetAllocations[i].metadata; - newTargetAllocations[i].allocationType = targetAllocations[i].allocationType; - exitAllocations[i].destination = targetAllocations[i].destination; - exitAllocations[i].amount = 0; // default to zero - exitAllocations[i].metadata = targetAllocations[i].metadata; - exitAllocations[i].allocationType = targetAllocations[i].allocationType; - } - - // compute how much the source can afford for the target - uint256 sourceSurplus = initialHoldings; - for ( - uint256 sourceAllocationIndex; - sourceAllocationIndex < indexOfTargetInSource; - sourceAllocationIndex++ - ) { - if (sourceSurplus == 0) break; - uint256 affordsForDestination = min( - sourceAllocations[sourceAllocationIndex].amount, - sourceSurplus - ); - sourceSurplus -= affordsForDestination; - } - - uint256 targetSurplus = min(sourceSurplus, sourceAllocations[indexOfTargetInSource].amount); - - bytes32[] memory guaranteeDestinations = decodeGuaranteeData( - sourceAllocations[indexOfTargetInSource].metadata - ); - - for (uint256 j = 0; j < guaranteeDestinations.length; j++) { - if (targetSurplus == 0) break; - for (uint256 i = 0; i < newTargetAllocations.length; i++) { - if (targetSurplus == 0) break; - // search for it in the allocation - if (guaranteeDestinations[j] == newTargetAllocations[i].destination) { - // if we find it, compute new amount - uint256 affordsForDestination = min(targetAllocations[i].amount, targetSurplus); - // decrease surplus by the current amount regardless of hitting a specified index - targetSurplus -= affordsForDestination; - if ( - (targetAllocationIndicesToPayout.length == 0) || - ((k < targetAllocationIndicesToPayout.length) && - (targetAllocationIndicesToPayout[k] == i)) - ) { - // only if specified in supplied targetAllocationIndicesToPayout, or we if we are doing "all" - // reduce the new allocationItem.amount in target and source - newTargetAllocations[i].amount -= affordsForDestination; - newSourceAllocations[indexOfTargetInSource].amount -= affordsForDestination; - // increase the relevant exit allocation - exitAllocations[i].amount = affordsForDestination; - totalPayouts += affordsForDestination; - // move on to the next supplied index - ++k; - } - break; // start again with the next guarantee destination - } - } - } - } - - /** - * @dev Applies precomputed side effects for claim. Updates the holdings of the source channel. Updates the fingerprint of the outcome for the source and the target channel. Emits an event for each channel. - */ - function _apply_claim_effects( - ClaimArgs memory claimArgs, - address asset, - Outcome.SingleAssetExit[] memory sourceOutcome, - Outcome.Allocation[] memory newSourceAllocations, - bytes32 targetChannelId, - Outcome.SingleAssetExit[] memory targetOutcome, - Outcome.Allocation[] memory newTargetAllocations, - uint256 initialHoldings, - uint256 totalPayouts - ) internal { - (bytes32 sourceChannelId, uint256 sourceAssetIndex, uint256 targetAssetIndex) = ( - claimArgs.sourceChannelId, - claimArgs.sourceAssetIndex, - claimArgs.targetAssetIndex - ); - - // update holdings - holdings[asset][sourceChannelId] -= totalPayouts; - - // store fingerprint of modified source outcome - sourceOutcome[sourceAssetIndex].allocations = newSourceAllocations; - _updateFingerprint( - sourceChannelId, - claimArgs.sourceStateHash, - keccak256(abi.encode(sourceOutcome)) - ); - - // store fingerprint of modified target outcome - targetOutcome[targetAssetIndex].allocations = newTargetAllocations; - _updateFingerprint( - targetChannelId, - claimArgs.targetStateHash, - keccak256(abi.encode(targetOutcome)) - ); - - // emit the information needed to compute the new source outcome stored in the fingerprint - emit AllocationUpdated(sourceChannelId, sourceAssetIndex, initialHoldings); - - // emit the information needed to compute the new target outcome stored in the fingerprint - emit AllocationUpdated(targetChannelId, targetAssetIndex, initialHoldings); - } - - /** - * @dev Applies precomputed side effects for claim that interact with external contracts. "Executes" the supplied exit (pays out the money). - */ - function _apply_claim_interactions( - Outcome.SingleAssetExit memory singleAssetExit, - Outcome.Allocation[] memory exitAllocations - ) internal { - // create a new tuple to avoid mutating singleAssetExit - _executeSingleAssetExit( - Outcome.SingleAssetExit( - singleAssetExit.asset, - singleAssetExit.metadata, - exitAllocations - ) - ); - } - - /** - * @notice Executes a single asset exit by paying out the asset and calling external contracts, as well as updating the holdings stored in this contract. - * @dev Executes a single asset exit by paying out the asset and calling external contracts, as well as updating the holdings stored in this contract. - * @param singleAssetExit The single asset exit to be paid out. - */ - function _executeSingleAssetExit(Outcome.SingleAssetExit memory singleAssetExit) internal { - address asset = singleAssetExit.asset; - for (uint256 j = 0; j < singleAssetExit.allocations.length; j++) { - bytes32 destination = singleAssetExit.allocations[j].destination; - uint256 amount = singleAssetExit.allocations[j].amount; - if (_isExternalDestination(destination)) { - _transferAsset(asset, _bytes32ToAddress(destination), amount); - } else { - holdings[asset][destination] += amount; - } - } - } - - /** - * @notice Transfers the given amount of this AssetHolders's asset type to a supplied ethereum address. - * @dev Transfers the given amount of this AssetHolders's asset type to a supplied ethereum address. - * @param destination ethereum address to be credited. - * @param amount Quantity of assets to be transferred. - */ - function _transferAsset( - address asset, - address destination, - uint256 amount - ) internal { - if (asset == address(0)) { - (bool success, ) = destination.call{value: amount}(''); //solhint-disable-line avoid-low-level-calls - require(success, 'Could not transfer ETH'); - } else { - IERC20(asset).transfer(destination, amount); - } - } - - /** - * @notice Checks if a given destination is external (and can therefore have assets transferred to it) or not. - * @dev Checks if a given destination is external (and can therefore have assets transferred to it) or not. - * @param destination Destination to be checked. - * @return True if the destination is external, false otherwise. - */ - function _isExternalDestination(bytes32 destination) internal pure returns (bool) { - return uint96(bytes12(destination)) == 0; - } - - /** - * @notice Converts an ethereum address to a nitro external destination. - * @dev Converts an ethereum address to a nitro external destination. - * @param participant The address to be converted. - * @return The input address left-padded with zeros. - */ - function _addressToBytes32(address participant) internal pure returns (bytes32) { - return bytes32(uint256(participant)); - } - - /** - * @notice Converts a nitro destination to an ethereum address. - * @dev Converts a nitro destination to an ethereum address. - * @param destination The destination to be converted. - * @return The rightmost 160 bits of the input string. - */ - function _bytes32ToAddress(bytes32 destination) internal pure returns (address payable) { - return address(uint160(uint256(destination))); - } - - // ************** - // Requirers - // ************** - - /** - * @notice Checks that a given variables hash to the data stored on chain. - * @dev Checks that a given variables hash to the data stored on chain. - */ - function _requireMatchingFingerprint( - bytes32 stateHash, - bytes32 outcomeHash, - bytes32 channelId - ) internal view { - (, , uint160 fingerprint) = _unpackStatus(channelId); - require( - fingerprint == _generateFingerprint(stateHash, outcomeHash), - 'incorrect fingerprint' - ); - } - - /** - * @notice Checks that a given channel is in the Finalized mode. - * @dev Checks that a given channel is in the Finalized mode. - * @param channelId Unique identifier for a channel. - */ - function _requireChannelFinalized(bytes32 channelId) internal view { - require(_mode(channelId) == ChannelMode.Finalized, 'Channel not finalized.'); - } - - function _updateFingerprint( - bytes32 channelId, - bytes32 stateHash, - bytes32 outcomeHash - ) internal { - (uint48 turnNumRecord, uint48 finalizesAt, ) = _unpackStatus(channelId); - - bytes32 newStatus = _generateStatus( - ChannelData(turnNumRecord, finalizesAt, stateHash, outcomeHash) - ); - statusOf[channelId] = newStatus; - } - - /** - * @notice Checks that the supplied indices are strictly increasing. - * @dev Checks that the supplied indices are strictly increasing. This allows us allows us to write a more efficient claim function. - */ - function _requireIncreasingIndices(uint256[] memory indices) internal pure { - for (uint256 i = 0; i + 1 < indices.length; i++) { - require(indices[i] < indices[i + 1], 'Indices must be sorted'); - } - } - - function min(uint256 a, uint256 b) internal pure returns (uint256) { - return a > b ? b : a; - } - - function decodeGuaranteeData(bytes memory data) internal pure returns (bytes32[] memory) { - return abi.decode(data, (bytes32[])); - } -} diff --git a/contracts/nitro-protocol/NitroAdjudicator.sol b/contracts/nitro-protocol/NitroAdjudicator.sol deleted file mode 100644 index f365bec..0000000 --- a/contracts/nitro-protocol/NitroAdjudicator.sol +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import './ForceMove.sol'; -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; -import './MultiAssetHolder.sol'; - -/** - * @dev The NitroAdjudicator contract extends MultiAssetHolder and ForceMove - */ -contract NitroAdjudicator is ForceMove, MultiAssetHolder { - /** - * @notice Finalizes a channel by providing a finalization proof, and liquidates all assets for the channel. - * @dev Finalizes a channel by providing a finalization proof, and liquidates all assets for the channel. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param appData Application specific data. - * @param outcomeBytes abi.encode of an array of Outcome.OutcomeItem structs. - * @param numStates The number of states in the finalization proof. - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param sigs Array of signatures, one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - */ - function concludeAndTransferAllAssets( - uint48 largestTurnNum, - FixedPart memory fixedPart, - bytes memory appData, - bytes memory outcomeBytes, - uint8 numStates, - uint8[] memory whoSignedWhat, - Signature[] memory sigs - ) public { - bytes32 channelId = _conclude( - largestTurnNum, - fixedPart, - appData, - outcomeBytes, - numStates, - whoSignedWhat, - sigs - ); - - transferAllAssets(channelId, outcomeBytes, bytes32(0)); - } - - /** - * @notice Liquidates all assets for the channel - * @dev Liquidates all assets for the channel - * @param channelId Unique identifier for a state channel - * @param outcomeBytes abi.encode of an array of Outcome.OutcomeItem structs. - * @param stateHash stored state hash for the channel - */ - function transferAllAssets( - bytes32 channelId, - bytes memory outcomeBytes, - bytes32 stateHash - ) public { - // checks - _requireChannelFinalized(channelId); - _requireMatchingFingerprint(stateHash, keccak256(outcomeBytes), channelId); - - // computation - bool allocatesOnlyZerosForAllAssets = true; - Outcome.SingleAssetExit[] memory outcome = Outcome.decodeExit(outcomeBytes); - Outcome.SingleAssetExit[] memory exit = new Outcome.SingleAssetExit[](outcome.length); - uint256[] memory initialHoldings = new uint256[](outcome.length); - uint256[] memory totalPayouts = new uint256[](outcome.length); - for (uint256 assetIndex = 0; assetIndex < outcome.length; assetIndex++) { - Outcome.SingleAssetExit memory assetOutcome = outcome[assetIndex]; - Outcome.Allocation[] memory allocations = assetOutcome.allocations; - address asset = outcome[assetIndex].asset; - initialHoldings[assetIndex] = holdings[asset][channelId]; - ( - Outcome.Allocation[] memory newAllocations, - bool allocatesOnlyZeros, - Outcome.Allocation[] memory exitAllocations, - uint256 totalPayoutsForAsset - ) = compute_transfer_effects_and_interactions( - initialHoldings[assetIndex], - allocations, - new uint256[](0) - ); - if (!allocatesOnlyZeros) allocatesOnlyZerosForAllAssets = false; - totalPayouts[assetIndex] = totalPayoutsForAsset; - outcome[assetIndex].allocations = newAllocations; - exit[assetIndex] = Outcome.SingleAssetExit( - asset, - assetOutcome.metadata, - exitAllocations - ); - } - - // effects - for (uint256 assetIndex = 0; assetIndex < outcome.length; assetIndex++) { - address asset = outcome[assetIndex].asset; - holdings[asset][channelId] -= totalPayouts[assetIndex]; - emit AllocationUpdated(channelId, assetIndex, initialHoldings[assetIndex]); - } - - if (allocatesOnlyZerosForAllAssets) { - delete statusOf[channelId]; - } else { - bytes32 outcomeHash = keccak256(abi.encode(outcomeBytes)); - _updateFingerprint(channelId, stateHash, outcomeHash); - } - - // interactions - _executeExit(exit); - } - - /** - * @notice Check that the submitted pair of states form a valid transition (public wrapper for internal function _requireValidTransition) - * @dev Check that the submitted pair of states form a valid transition (public wrapper for internal function _requireValidTransition) - * @param nParticipants Number of participants in the channel. - transition - * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final. - * @param ab Variable parts of each of the pair of states - * @param turnNumB turnNum of the later state of the pair. - * @param appDefinition Address of deployed contract containing application-specific validTransition function. - * @return true if the later state is a validTransition from its predecessor, reverts otherwise. - */ - function validTransition( - uint256 nParticipants, - bool[2] memory isFinalAB, // [a.isFinal, b.isFinal] - IForceMoveApp.VariablePart[2] memory ab, // [a,b] - uint48 turnNumB, - address appDefinition - ) public pure returns (bool) { - return _requireValidTransition(nParticipants, isFinalAB, ab, turnNumB, appDefinition); - } - - /** - * @notice Executes an exit by paying out assets and calling external contracts - * @dev Executes an exit by paying out assets and calling external contracts - * @param exit The exit to be paid out. - */ - function _executeExit(Outcome.SingleAssetExit[] memory exit) internal { - for (uint256 assetIndex = 0; assetIndex < exit.length; assetIndex++) { - _executeSingleAssetExit(exit[assetIndex]); - } - } -} diff --git a/contracts/nitro-protocol/StatusManager.sol b/contracts/nitro-protocol/StatusManager.sol deleted file mode 100644 index 63c75e2..0000000 --- a/contracts/nitro-protocol/StatusManager.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; - -import './interfaces/IStatusManager.sol'; - -/** - * @dev The StatusManager is responsible for on-chain storage of the status of active channels - */ -contract StatusManager is IStatusManager { - mapping(bytes32 => bytes32) public statusOf; - - /** - * @notice Computes the ChannelMode for a given channelId. - * @dev Computes the ChannelMode for a given channelId. - * @param channelId Unique identifier for a channel. - */ - function _mode(bytes32 channelId) internal view returns (ChannelMode) { - // Note that _unpackStatus(someRandomChannelId) returns (0,0,0), which is - // correct when nobody has written to storage yet. - - (, uint48 finalizesAt, ) = _unpackStatus(channelId); - if (finalizesAt == 0) { - return ChannelMode.Open; - // solhint-disable-next-line not-rely-on-time - } else if (finalizesAt <= block.timestamp) { - return ChannelMode.Finalized; - } else { - return ChannelMode.Challenge; - } - } - - /** - * @notice Formats the input data for on chain storage. - * @dev Formats the input data for on chain storage. - * @param channelData ChannelData data. - */ - function _generateStatus(ChannelData memory channelData) - internal - pure - returns (bytes32 status) - { - // The hash is constructed from left to right. - uint256 result; - uint16 cursor = 256; - - // Shift turnNumRecord 208 bits left to fill the first 48 bits - result = uint256(channelData.turnNumRecord) << (cursor -= 48); - - // logical or with finalizesAt padded with 160 zeros to get the next 48 bits - result |= (uint256(channelData.finalizesAt) << (cursor -= 48)); - - // logical or with the last 160 bits of the hash the remaining channelData fields - // (we call this the fingerprint) - result |= uint256(_generateFingerprint(channelData.stateHash, channelData.outcomeHash)); - - status = bytes32(result); - } - - function _generateFingerprint(bytes32 stateHash, bytes32 outcomeHash) - internal - pure - returns (uint160) - { - return uint160(uint256(keccak256(abi.encode(stateHash, outcomeHash)))); - } - - /** - * @notice Unpacks turnNumRecord, finalizesAt and fingerprint from the status of a particular channel. - * @dev Unpacks turnNumRecord, finalizesAt and fingerprint from the status of a particular channel. - * @param channelId Unique identifier for a state channel. - * @return turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant. - * @return finalizesAt The unix timestamp when `channelId` will finalize. - * @return fingerprint The last 160 bits of kecca256(stateHash, outcomeHash) - */ - function _unpackStatus(bytes32 channelId) - internal - view - returns ( - uint48 turnNumRecord, - uint48 finalizesAt, - uint160 fingerprint - ) - { - bytes32 status = statusOf[channelId]; - uint16 cursor = 256; - turnNumRecord = uint48(uint256(status) >> (cursor -= 48)); - finalizesAt = uint48(uint256(status) >> (cursor -= 48)); - fingerprint = uint160(uint256(status)); - } -} diff --git a/contracts/nitro-protocol/Token.sol b/contracts/nitro-protocol/Token.sol deleted file mode 100644 index 2d749f4..0000000 --- a/contracts/nitro-protocol/Token.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -import '@openzeppelin/contracts-3.4.2/token/ERC20/ERC20.sol'; - -/** - * @dev This contract extends an ERC20 implementation, and mints 10,000,000,000 tokens to the deploying account. Used for testing purposes. - */ -contract Token is ERC20 { - /** - * @dev Constructor function minting 10 billion tokens to the owner. Do not use msg.sender for default owner as that will not work with CREATE2 - * @param owner Tokens are minted to the owner address - */ - constructor(address owner) ERC20('TestToken', 'TEST') { - _mint(owner, 10_000_000_000); - } -} diff --git a/contracts/nitro-protocol/TrivialApp.sol b/contracts/nitro-protocol/TrivialApp.sol deleted file mode 100644 index f042dee..0000000 --- a/contracts/nitro-protocol/TrivialApp.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import './interfaces/IForceMoveApp.sol'; - -/** - * @dev The Trivialp contracts complies with the ForceMoveApp interface and allows all transitions, regardless of the data. Used for testing purposes. - */ -contract TrivialApp is IForceMoveApp { - /** - * @notice Encodes trivial rules. - * @dev Encodes trivial rules. - * @return true. - */ - function validTransition( - VariablePart memory, // a - VariablePart memory, // b - uint48, // turnNumB - uint256 // nParticipants - ) public override pure returns (bool) { - return true; - } -} diff --git a/contracts/nitro-protocol/examples/EmbeddedApplication.sol b/contracts/nitro-protocol/examples/EmbeddedApplication.sol deleted file mode 100644 index 2d7090f..0000000 --- a/contracts/nitro-protocol/examples/EmbeddedApplication.sol +++ /dev/null @@ -1,432 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import '../interfaces/IForceMoveApp.sol'; -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; -import '../interfaces/IForceMove.sol'; - -/** - * @dev This is a proposed new interface, which delegates turn-taking or other signature semantics to validTransition though the inclusion of a pair of signedBy fields. - */ -interface IForceMoveApp2 { - struct VariablePart { - bytes outcome; - bytes appData; - } - - /** - * @notice Encodes application-specific rules for a particular ForceMove-compliant state channel. - * @dev Encodes application-specific rules for a particular ForceMove-compliant state channel. - * @param a State being transitioned from. - * @param b State being transitioned to. - * @param turnNumB Turn number being transitioned to. - * @param nParticipants Number of participants in this state channel. - * @param signedByFrom Bit field showing which participants signed state a. - * @param signedByTo Bit field showing which participants signed state b. - * @return true if the transition conforms to this application's rules, false otherwise - */ - function validTransition( - VariablePart calldata a, - VariablePart calldata b, - uint48 turnNumB, - uint256 nParticipants, - uint256 signedByFrom, // Who has signed the "from" state? - uint256 signedByTo // Who has signed the "to" state? - ) external pure returns (bool); - - // signedBy - // 0b000 = 0 : No-one - // 0b001 = 1 : participant 0 - // 0b010 = 2 : participant 1 - // 0b011 = 3 : participant 0 and participant 1 - // 0b100 = 4 : participant 2 - // 0b101 = 5 : participant 0 and participant 2 - // 0b110 = 6 : participant 1 and participant 2 - // 0b111 = 7 : everyone -} - -library ForceMoveAppUtilities { - function isSignedBy(uint256 signedBy, uint8 participantIndex) internal pure returns (bool) { - return ((signedBy >> participantIndex) % 2 == 1); - } - - // This function can be used inside validTransition - // To recover the legacy "turn taking" semantics - function isRoundRobin( - uint256 nParticipants, - uint48 turnNumB, - uint256 signedByFrom, - uint256 signedByTo - ) internal pure returns (bool) { - require( - turnNumB > 0 && - isSignedBy(signedByFrom, uint8((turnNumB - 1) % nParticipants)) && - isSignedBy(signedByTo, uint8(turnNumB % nParticipants)), - 'roundRobin violation' - ); - return true; - } - - /** - * @notice Given a digest and ethereum digital signature, recover the signer - * @dev Given a digest and digital signature, recover the signer - * @param _d message digest - * @param sig ethereum digital signature - * @return signer - */ - function _recoverSigner(bytes32 _d, IForceMove.Signature memory sig) - internal - pure - returns (address) - { - bytes32 prefixedHash = keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n32', _d)); - address a = ecrecover(prefixedHash, sig.v, sig.r, sig.s); - require(a != address(0), 'Invalid signature'); - return (a); - } -} - -// NOTE: This contract should be treated as prototype code. It has not been carefully scrutinized from a security point of view. -// The EmbeddedApplication allows a 2-party subchannel X to be *embedded* in the current 3-party channel J. -// This is in contrast to having the application channel X being *funded* by the current channel J. -// J references X in its AppData. Each state for J contains a support proof for X. Initially, this can be the PreFundSetup of X. -// When there is a supported state (triply signed) in J containing a support proof for X, we say that X has been *embedded* in J. -// Participant 0 (Alice) and Participant 1 (Bob) can run X off-chain in the usual fashion. -// If the three parties agree, they can *un-embed* X from J off-chain by reverting J to a null app and updating the outcome accordingly. -// Any participant can challenge with the latest triply signed state. Then, Alice and Bob get exactly 1 chance each to progress J on chain. -// To progress J on chain, a support proof for X must be provided. Inferior support proofs are rejected. Participant 2 (Irene)'s balance is protected. -// Irene retains the unilateral right to close J -- Alice and Bob each get only 1 chance to update J before Irene's signature is required again. - -// How to do virtual funding with an EmbeddedApplication -// --- -// Off chain setup (substeps with a letter may be executed in any order): -// -// 0. Assume (as usual) that A,I and B,I have funded ledger channels already. -// 1. A, B, I sign prefund for J that allocates to {A, B, I} -// 2a. A and I sign a guarantee $G_{AI}$ targeting J with priority {A, I} -// 2b. B and I sign a guarantee $G_{BI}$ targeting J with priority {B, I} -// 3. A, B, I sign postfund for J that allocates to {A, B, I} and embeds X. - -// Off chain teardown: -// -// 1. A, B, I triple sign a None update to J that absorbs the latest outcome of X and unembeds X. -// 2a. A and I remove $G_{AI}$ and absorb the outcome of J into their ledger channel -// 2b. B and I remove $G_{BI}$ and absorb the outcome of J into their ledger channel - -// On chain challenge path: -// -// 1. J outcome recorded on chain. Each A and B can unilaterally progress the channel once. -// (So the the latency of finalizing a channel on chain is at most 6 timeout periods. In practice, since I never needs to update the channel, the latency is likely 3 timeout periods.) -// 2. Claim with $G_{AI}$ is called. -// 3. Claim with $G_{BI}$ is called. After this, all participants have pulled out their funds. - -/** - * @dev The EmbeddedApplication contract embeds a subchannel X. - */ -contract EmbeddedApplication is - IForceMoveApp2 // We need a new interface to allow signedBy information into the validTransition function -{ - // 2-party SupportProof - struct SupportProof { - IForceMove.FixedPart fixedPart; - VariablePart[] variableParts; // either one or two states - uint48 turnNumTo; - IForceMove.Signature[2] sigs; // one for each participant - uint8[2] whoSignedWhat; // whoSignedWhat = [0,0] or [0,1] or [1,0] - } - - // Finite states for J - enum AlreadyMoved {None, A, B, AB} - - // Application Data for J - struct AppData { - bytes32 channelIdForX; - SupportProof supportProofForX; - AlreadyMoved alreadyMoved; - } - - uint256 internal constant AIndex = 0; - uint256 internal constant BIndex = 1; - uint256 internal constant IIndex = 2; - - function validTransition( - VariablePart memory from, - VariablePart memory to, - uint48, // turnNumTo (unused) - uint256, // nParticipants (unused) - uint256, // signedByFrom (unused) - Who has signed the "from" state? - uint256 signedByTo // Who has signed the "to" state? - ) public override pure returns (bool) { - // parameter wrangling - bool signedByA = ForceMoveAppUtilities.isSignedBy(signedByTo, 0); - bool signedByB = ForceMoveAppUtilities.isSignedBy(signedByTo, 1); - AppData memory fromAppData = abi.decode(from.appData, (AppData)); - AppData memory toAppData = abi.decode(to.appData, (AppData)); - Outcome.Allocation[] memory fromAllocations = decode3PartyAllocation(from.outcome); - Outcome.Allocation[] memory toAllocations = decode3PartyAllocation(to.outcome); - - require( - fromAllocations[AIndex].destination == toAllocations[AIndex].destination && - fromAllocations[BIndex].destination == toAllocations[BIndex].destination && - fromAllocations[IIndex].destination == toAllocations[IIndex].destination, - 'destinations may not change' - ); - - require(fromAllocations[IIndex].amount == toAllocations[IIndex].amount, 'p2.amt !constant'); - require( - fromAllocations[AIndex].amount + - fromAllocations[BIndex].amount + - fromAllocations[IIndex].amount == - toAllocations[AIndex].amount + - toAllocations[BIndex].amount + - toAllocations[IIndex].amount, - 'total allocation changed' - ); - - // Allowed named-state transitions are - // AB - // ^^ - // / \ - // A B - // ^ ^ - // \ / - // None - - if (fromAppData.alreadyMoved == AlreadyMoved.None) { - require( - (toAppData.alreadyMoved == AlreadyMoved.A && signedByA) || - (toAppData.alreadyMoved == AlreadyMoved.B && signedByB), - 'incorrect move from None' - ); - } else { - // If a support proof has already been supplied, the current support proof must be greater - require( - toAppData.supportProofForX.turnNumTo > fromAppData.supportProofForX.turnNumTo, - 'inferior support proof' - ); - if (fromAppData.alreadyMoved == AlreadyMoved.A) { - require( - toAppData.alreadyMoved == AlreadyMoved.AB && signedByB, - 'incorrect move from A' - ); - } else if (fromAppData.alreadyMoved == AlreadyMoved.B) { - require( - toAppData.alreadyMoved == AlreadyMoved.AB && signedByA, - 'incorrect move from B' - ); - } else { - revert('move from None,A,B only'); - } - } - - // validate the supplied support proof - // extract the allocation - Outcome.Allocation[] memory Xallocations = validateSupportProofForX(fromAppData, toAppData); - - // ensure A,B part of the outcome of X has been absorbed into the outcome of J - require( - Xallocations[AIndex].amount == toAllocations[AIndex].amount && - Xallocations[BIndex].amount == toAllocations[BIndex].amount && - Xallocations[AIndex].destination == toAllocations[AIndex].destination && - Xallocations[BIndex].destination == toAllocations[BIndex].destination, - 'X / J outcome mismatch' - ); - return true; - } - - function validateSupportProofForX(AppData memory fromAppData, AppData memory toAppData) - internal - pure - returns (Outcome.Allocation[] memory Xallocations) - { - // The following checks follow the protocol-level validTransition function - // They are the members of FixedPart that do not affect the channelId - require( - fromAppData.supportProofForX.fixedPart.appDefinition == - toAppData.supportProofForX.fixedPart.appDefinition, - 'X.appDefinition changed' - ); - require( - fromAppData.supportProofForX.fixedPart.challengeDuration == - toAppData.supportProofForX.fixedPart.challengeDuration, - 'X.challengeDuration changed' - ); // this is actually never used so could be 0 - - // A support proof requires 2 signatures - // But it may have either 1 or two states. - // If both signatures on the same state, it is supported - // Else one signature per state and we must check for a valid transition - require( - toAppData.supportProofForX.variableParts.length == 1 || - toAppData.supportProofForX.variableParts.length == 2, - '1 or 2 states required' - ); - - // hash the greatest state first (either the later of a pair, or the only state provided) - - uint256 finalIndex = toAppData.supportProofForX.variableParts.length - 1; - - bytes memory greaterStateOutcome = toAppData.supportProofForX.variableParts[finalIndex] - .outcome; - - bytes32 greaterStateHash = _hashState( - toAppData.channelIdForX, - toAppData.supportProofForX.variableParts[0].appData, - greaterStateOutcome, - toAppData.supportProofForX.turnNumTo, - false - ); - - if ( - (toAppData.supportProofForX.whoSignedWhat[0] == 0) && - (toAppData.supportProofForX.whoSignedWhat[1] == 0) - ) { - require( - (ForceMoveAppUtilities._recoverSigner( - greaterStateHash, - toAppData.supportProofForX.sigs[0] - ) == toAppData.supportProofForX.fixedPart.participants[0]), - 'sig0 !by participant0' - ); - require( - ForceMoveAppUtilities._recoverSigner( - greaterStateHash, - toAppData.supportProofForX.sigs[1] - ) == toAppData.supportProofForX.fixedPart.participants[1], - 'sig1 !by participant1' - ); - } else { - bytes32 lesserStateHash = _hashState( - toAppData.channelIdForX, - toAppData.supportProofForX.variableParts[0].appData, - toAppData.supportProofForX.variableParts[0].outcome, - toAppData.supportProofForX.turnNumTo - 1, - false // Assume isFinal is false - ); - - if ( - (toAppData.supportProofForX.whoSignedWhat[0] == 0) && - (toAppData.supportProofForX.whoSignedWhat[1] == 1) - ) { - require( - (ForceMoveAppUtilities._recoverSigner( - lesserStateHash, - toAppData.supportProofForX.sigs[0] - ) == toAppData.supportProofForX.fixedPart.participants[0]), - 'sig0 on state0 !by participant0' - ); - require( - ForceMoveAppUtilities._recoverSigner( - greaterStateHash, - toAppData.supportProofForX.sigs[1] - ) == toAppData.supportProofForX.fixedPart.participants[1], - 'sig1 on state1 !by participant1' - ); - } else if ( - (toAppData.supportProofForX.whoSignedWhat[0] == 1) && - (toAppData.supportProofForX.whoSignedWhat[1] == 0) - ) { - require( - (ForceMoveAppUtilities._recoverSigner( - greaterStateHash, - toAppData.supportProofForX.sigs[0] - ) == toAppData.supportProofForX.fixedPart.participants[0]), - 'sig0 on state1 !by participant0' - ); - require( - ForceMoveAppUtilities._recoverSigner( - lesserStateHash, - toAppData.supportProofForX.sigs[1] - ) == toAppData.supportProofForX.fixedPart.participants[1], - 'sig1 on state0 !by participant1' - ); - } else revert('invalid whoSignedWhat'); - - require( - IForceMoveApp2(toAppData.supportProofForX.fixedPart.appDefinition).validTransition( - toAppData.supportProofForX.variableParts[0], - toAppData.supportProofForX.variableParts[1], - toAppData.supportProofForX.turnNumTo, - 2, // nParticipants - toAppData.supportProofForX.whoSignedWhat[0] == 0 ? 1 : 2, // signedByFrom = 0b01 or 0b10; participant 0 or 1 only. Implied by require statement above. - toAppData.supportProofForX.whoSignedWhat[0] == 0 ? 2 : 1 // signedByTo = 0b10 or 0b01; participant 1 or 0 only. Implied by require statement above. - ), - 'invalid transition in X' - ); - } - - return - decode2PartyAllocation( - toAppData.supportProofForX.variableParts[toAppData - .supportProofForX - .variableParts - .length - 1] - .outcome - ); - } - - // TODO write a reusable decodeNPartyAllocation fn - function decode3PartyAllocation(bytes memory outcomeBytes) - private - pure - returns (Outcome.Allocation[] memory allocations) - { - Outcome.SingleAssetExit[] memory outcome = Outcome.decodeExit(outcomeBytes); - - // Throws if more than one asset - require(outcome.length == 1, 'outcome: Exactly 1 asset allowed'); - - Outcome.SingleAssetExit memory assetOutcome = outcome[0]; - - allocations = assetOutcome.allocations; // TODO should we check each allocation is a "simple" one? - - // Throws unless there are exactly 3 allocations - require(allocations.length == 3, 'allocation.length != 3'); - } - - function decode2PartyAllocation(bytes memory outcomeBytes) - private - pure - returns (Outcome.Allocation[] memory allocations) - { - Outcome.SingleAssetExit[] memory outcome = Outcome.decodeExit(outcomeBytes); - - Outcome.SingleAssetExit memory assetOutcome = outcome[0]; - - allocations = assetOutcome.allocations; // TODO should we check each allocation is a "simple" one? - - // Throws unless there are exactly 3 allocations - require(allocations.length == 2, 'allocation.length != 3'); - } - - /** - * @notice Computes the hash of the state corresponding to the input data. - * @dev Computes the hash of the state corresponding to the input data. - * @param turnNum Turn number - * @param isFinal Is the state final? - * @param channelId Unique identifier for the channel - * @param appData Application specific date - * @param outcome Outcome bytes. Will be decoded to hash State properly - * @return The stateHash - */ - function _hashState( - bytes32 channelId, - bytes memory appData, - bytes memory outcome, - uint48 turnNum, - bool isFinal - ) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - channelId, - appData, - // Decoding to get an Outcome struct, since it is the one used in go-nitro State hashing - Outcome.decodeExit(outcome), - turnNum, - isFinal - ) - ); - } -} diff --git a/contracts/nitro-protocol/examples/HashLockedSwap.sol b/contracts/nitro-protocol/examples/HashLockedSwap.sol deleted file mode 100644 index 3e8aa04..0000000 --- a/contracts/nitro-protocol/examples/HashLockedSwap.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import '../interfaces/IForceMoveApp.sol'; -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; - -/** - * @dev The HashLockedSwap contract complies with the ForceMoveApp interface and implements a HashLockedSwaped payment - */ -contract HashLockedSwap is IForceMoveApp { - struct AppData { - bytes32 h; - bytes preImage; - } - - function validTransition( - VariablePart memory a, - VariablePart memory b, - uint48 turnNumB, - uint256 - ) public override pure returns (bool) { - // is this the first and only swap? - require(turnNumB == 4, 'turnNumB != 4'); - - // Decode variables. - // Assumptions: - // - single asset in this channel - // - two parties in this channel - // - not a "guarantee" channel (c.f. Nitro paper) - Outcome.Allocation[] memory allocationsA = decode2PartyAllocation(a.outcome); - Outcome.Allocation[] memory allocationsB = decode2PartyAllocation(b.outcome); - bytes memory preImage = abi.decode(b.appData, (AppData)).preImage; - bytes32 h = abi.decode(a.appData, (AppData)).h; - - // is the preimage correct? - require(sha256(preImage) == h, 'Incorrect preimage'); - // NOTE ON GAS COSTS - // The gas cost of hashing depends on the choice of hash function - // and the length of the the preImage. - // sha256 is twice as expensive as keccak256 - // https://ethereum.stackexchange.com/a/3200 - // But is compatible with bitcoin. - - // slots for each participant unchanged - require( - allocationsA[0].destination == allocationsB[0].destination && - allocationsA[1].destination == allocationsB[1].destination, - 'destinations may not change' - ); - - // was the payment made? - require( - allocationsA[0].amount == allocationsB[1].amount && - allocationsA[1].amount == allocationsB[0].amount, - 'amounts must be permuted' - ); - - return true; - } - - function decode2PartyAllocation(bytes memory outcomeBytes) - private - pure - returns (Outcome.Allocation[] memory allocations) - { - Outcome.SingleAssetExit[] memory outcome = abi.decode( - outcomeBytes, - (Outcome.SingleAssetExit[]) - ); - - Outcome.SingleAssetExit memory assetOutcome = outcome[0]; - - allocations = assetOutcome.allocations; // TODO should we check each allocation is a "simple" one? - - // Throws unless there are exactly 3 allocations - require(allocations.length == 2, 'allocation.length != 3'); - } -} diff --git a/contracts/nitro-protocol/examples/SingleAssetPayments.sol b/contracts/nitro-protocol/examples/SingleAssetPayments.sol deleted file mode 100644 index 8b80e19..0000000 --- a/contracts/nitro-protocol/examples/SingleAssetPayments.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import '../interfaces/IForceMoveApp.sol'; -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; - -/** - * @dev The SingleAssetPayments contract complies with the ForceMoveApp interface and implements a simple payment channel with a single asset type only. - */ -contract SingleAssetPayments is IForceMoveApp { - /** - * @notice Encodes the payment channel update rules. - * @dev Encodes the payment channel update rules. - * @param a State being transitioned from. - * @param b State being transitioned to. - * @param turnNumB Turn number being transitioned to. - * @param nParticipants Number of participants in this state channel. - * @return true if the transition conforms to the rules, false otherwise. - */ - function validTransition( - VariablePart memory a, - VariablePart memory b, - uint48 turnNumB, - uint256 nParticipants - ) public override pure returns (bool) { - Outcome.SingleAssetExit[] memory outcomeA = abi.decode( - a.outcome, - (Outcome.SingleAssetExit[]) - ); - Outcome.SingleAssetExit[] memory outcomeB = abi.decode( - b.outcome, - (Outcome.SingleAssetExit[]) - ); - - // Throws if more than one asset - require(outcomeA.length == 1, 'outcomeA: Only one asset allowed'); - require(outcomeB.length == 1, 'outcomeB: Only one asset allowed'); - - Outcome.SingleAssetExit memory assetOutcomeA = outcomeA[0]; - Outcome.SingleAssetExit memory assetOutcomeB = outcomeB[0]; - - // Throws unless that allocation has exactly n outcomes - Outcome.Allocation[] memory allocationsA = assetOutcomeA.allocations; - Outcome.Allocation[] memory allocationsB = assetOutcomeB.allocations; - - require(allocationsA.length == nParticipants, '|AllocationA|!=|participants|'); - require(allocationsB.length == nParticipants, '|AllocationB|!=|participants|'); - - for (uint256 i = 0; i < nParticipants; i++) { - require( - allocationsA[i].allocationType == uint8(Outcome.AllocationType.simple), - 'not a simple allocation' - ); - require( - allocationsB[i].allocationType == uint8(Outcome.AllocationType.simple), - 'not a simple allocation' - ); - } - - // Interprets the nth outcome as benefiting participant n - // checks the destinations have not changed - // Checks that the sum of assets hasn't changed - // And that for all non-movers - // the balance hasn't decreased - uint256 allocationSumA; - uint256 allocationSumB; - for (uint256 i = 0; i < nParticipants; i++) { - require( - allocationsB[i].destination == allocationsA[i].destination, - 'Destinations may not change' - ); - allocationSumA += allocationsA[i].amount; - allocationSumB += allocationsB[i].amount; - if (i != turnNumB % nParticipants) { - require( - allocationsB[i].amount >= allocationsA[i].amount, - 'Nonmover balance decreased' - ); - } - } - require(allocationSumA == allocationSumB, 'Total allocated cannot change'); - - return true; - } -} diff --git a/contracts/nitro-protocol/interfaces/IForceMove.sol b/contracts/nitro-protocol/interfaces/IForceMove.sol deleted file mode 100644 index 9d43df6..0000000 --- a/contracts/nitro-protocol/interfaces/IForceMove.sol +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import './IForceMoveApp.sol'; - -/** - * @dev The IForceMove interface defines the interface that an implementation of ForceMove should implement. ForceMove protocol allows state channels to be adjudicated and finalized. - */ -interface IForceMove { - struct Signature { - uint8 v; - bytes32 r; - bytes32 s; - } - - struct FixedPart { - uint256 chainId; - address[] participants; - uint48 channelNonce; - address appDefinition; - uint48 challengeDuration; - } - - struct State { - // participants sign the hash of this - bytes32 channelId; // keccack(chainId,participants,channelNonce,appDefinition,challengeDuration) - bytes appData; - bytes outcome; - uint48 turnNum; - bool isFinal; - } - - /** - * @notice Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time. - * @dev Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. - * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final. - * @param sigs An array of signatures that support the state with the `largestTurnNum`: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param challengerSig The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove'). - */ - function challenge( - FixedPart calldata fixedPart, - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] calldata variableParts, - uint8 isFinalCount, // how many of the states are final - Signature[] calldata sigs, - uint8[] calldata whoSignedWhat, - Signature calldata challengerSig - ) external; - - /** - * @notice Repsonds to an ongoing challenge registered against a state channel. - * @dev Repsonds to an ongoing challenge registered against a state channel. - * @param isFinalAB An pair of booleans describing if the challenge state and/or the response state have the `isFinal` property set to `true`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param variablePartAB An pair of structs, each decribing the properties of the state channel that may change with each state update (for the challenge state and for the response state). - * @param sig The responder's signature on the `responseStateHash`. - */ - function respond( - bool[2] calldata isFinalAB, - FixedPart calldata fixedPart, - IForceMoveApp.VariablePart[2] calldata variablePartAB, - // variablePartAB[0] = challengeVariablePart - // variablePartAB[1] = responseVariablePart - Signature calldata sig - ) external; - - /** - * @notice Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant. - * @dev Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. - * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final. - * @param sigs An array of signatures that support the state with the `largestTurnNum`: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - */ - function checkpoint( - FixedPart calldata fixedPart, - uint48 largestTurnNum, - IForceMoveApp.VariablePart[] calldata variableParts, - uint8 isFinalCount, // how many of the states are final - Signature[] calldata sigs, - uint8[] calldata whoSignedWhat - ) external; - - /** - * @notice Finalizes a channel by providing a finalization proof. - * @dev Finalizes a channel by providing a finalization proof. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param appData The keccak256 of the abi.encode of `(challengeDuration, appDefinition, appData)`. Applies to all states in the finalization proof. - * @param outcome An outcome structure bytes. - * @param numStates The number of states in the finalization proof. - * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`. - * @param sigs An array of signatures that support the state with the `largestTurnNum`:: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - */ - function conclude( - uint48 largestTurnNum, - FixedPart calldata fixedPart, - bytes memory appData, - bytes memory outcome, - uint8 numStates, - uint8[] calldata whoSignedWhat, - Signature[] calldata sigs - ) external; - - // events - - /** - * @dev Indicates that a challenge has been registered against `channelId`. - * @param channelId Unique identifier for a state channel. - * @param turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant. - * @param finalizesAt The unix timestamp when `channelId` will finalize. - * @param isFinal Boolean denoting whether the challenge state is final. - * @param fixedPart Data describing properties of the state channel that do not change with state updates. - * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. - * @param sigs A list of Signatures that supported the challenge: one for each participant, in participant order (e.g. [sig of participant[0], sig of participant[1], ...]). - * @param whoSignedWhat Indexing information to identify which signature was by which participant - */ - event ChallengeRegistered( - bytes32 indexed channelId, - uint48 turnNumRecord, - uint48 finalizesAt, - bool isFinal, - FixedPart fixedPart, - IForceMoveApp.VariablePart[] variableParts, - Signature[] sigs, - uint8[] whoSignedWhat - ); - - /** - * @dev Indicates that a challenge, previously registered against `channelId`, has been cleared. - * @param channelId Unique identifier for a state channel. - * @param newTurnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant. - */ - event ChallengeCleared(bytes32 indexed channelId, uint48 newTurnNumRecord); - - /** - * @dev Indicates that a challenge has been registered against `channelId`. - * @param channelId Unique identifier for a state channel. - * @param finalizesAt The unix timestamp when `channelId` finalized. - */ - event Concluded(bytes32 indexed channelId, uint48 finalizesAt); -} diff --git a/contracts/nitro-protocol/interfaces/IForceMoveApp.sol b/contracts/nitro-protocol/interfaces/IForceMoveApp.sol deleted file mode 100644 index 5b53985..0000000 --- a/contracts/nitro-protocol/interfaces/IForceMoveApp.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -/** - * @dev The IForceMoveApp interface calls for its children to implement an application-specific validTransition function, defining the state machine of a ForceMove state channel DApp. - */ -interface IForceMoveApp { - struct VariablePart { - bytes outcome; - bytes appData; - } - - /** - * @notice Encodes application-specific rules for a particular ForceMove-compliant state channel. - * @dev Encodes application-specific rules for a particular ForceMove-compliant state channel. - * @param a State being transitioned from. - * @param b State being transitioned to. - * @param turnNumB Turn number being transitioned to. - * @param nParticipants Number of participants in this state channel. - * @return true if the transition conforms to this application's rules, false otherwise - */ - function validTransition( - VariablePart calldata a, - VariablePart calldata b, - uint48 turnNumB, - uint256 nParticipants - ) external pure returns (bool); -} diff --git a/contracts/nitro-protocol/interfaces/IMultiAssetHolder.sol b/contracts/nitro-protocol/interfaces/IMultiAssetHolder.sol deleted file mode 100644 index 4aa15f7..0000000 --- a/contracts/nitro-protocol/interfaces/IMultiAssetHolder.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; - -import {ExitFormat as Outcome} from '@statechannels/exit-format/contracts/ExitFormat.sol'; - -/** - * @dev The IMultiAssetHolder interface calls for functions that allow assets to be transferred from one channel to other channel and/or external destinations, as well as for guarantees to be claimed. - */ -interface IMultiAssetHolder { - /** - * @notice Deposit ETH or erc20 assets against a given destination. - * @dev Deposit ETH or erc20 assets against a given destination. - * @param asset erc20 token address, or zero address to indicate ETH - * @param destination ChannelId to be credited. - * @param expectedHeld The number of wei the depositor believes are _already_ escrowed against the channelId. - * @param amount The intended number of wei to be deposited. - */ - function deposit( - address asset, - bytes32 destination, - uint256 expectedHeld, - uint256 amount - ) external payable; - - /** - * @notice Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. - * @dev Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. - * @param assetIndex Will be used to slice the outcome into a single asset outcome. - * @param fromChannelId Unique identifier for state channel to transfer funds *from*. - * @param outcomeBytes The encoded Outcome of this state channel - * @param stateHash The hash of the state stored when the channel finalized. - * @param indices Array with each entry denoting the index of a destination to transfer funds to. An empty array indicates "all". - */ - function transfer( - uint256 assetIndex, // TODO consider a uint48? - bytes32 fromChannelId, - bytes memory outcomeBytes, - bytes32 stateHash, - uint256[] memory indices - ) external; - - /** - * @param sourceChannelId Unique identifier for a guarantor state channel. - * @param sourceStateHash Hash of the state stored when the guarantor channel finalized. - * @param sourceOutcomeBytes The abi.encode of guarantor channel outcome - * @param sourceAssetIndex the index of the targetted asset in the source outcome. - * @param indexOfTargetInSource The index of the guarantee allocation to the target channel in the source outcome. - * @param targetStateHash Hash of the state stored when the target channel finalized. - * @param targetOutcomeBytes The abi.encode of target channel outcome - * @param targetAssetIndex the index of the targetted asset in the target outcome. - * @param targetAllocationIndicesToPayout Array with each entry denoting the index of a destination (in the target channel) to transfer funds to. Should be in increasing order. An empty array indicates "all" - */ - struct ClaimArgs { - bytes32 sourceChannelId; - bytes32 sourceStateHash; - bytes sourceOutcomeBytes; - uint256 sourceAssetIndex; - uint256 indexOfTargetInSource; - bytes32 targetStateHash; - bytes targetOutcomeBytes; - uint256 targetAssetIndex; - uint256[] targetAllocationIndicesToPayout; - } - - /** - * @notice Transfers as many funds escrowed against `sourceChannelId` as can be afforded for the destinations specified by indices in the beneficiaries of the __target__ of the channel at indexOfTargetInSource. - * @dev Transfers as many funds escrowed against `sourceChannelId` as can be afforded for the destinations specified by indices in the beneficiaries of the __target__ of the channel at indexOfTargetInSource. - * @param claimArgs arguments used in the claim function. Used to avoid stack too deep error. - */ - function claim(ClaimArgs memory claimArgs) external; - - /** - * @dev Indicates that `amountDeposited` has been deposited into `destination`. - * @param destination The channel being deposited into. - * @param amountDeposited The amount being deposited. - * @param destinationHoldings The new holdings for `destination`. - */ - event Deposited( - bytes32 indexed destination, - address asset, - uint256 amountDeposited, - uint256 destinationHoldings - ); - - /** - * @dev Indicates the assetOutcome for this channelId and assetIndex has changed due to a transfer or claim. Includes sufficient data to compute: - * - the new assetOutcome - * - the new holdings for this channelId and any others that were transferred to - * - the payouts to external destinations - * @param channelId The channelId of the funds being withdrawn. - * @param initialHoldings holdings[asset][channelId] **before** the allocations were updated. The asset in question can be inferred from the calldata of the transaction (it might be "all assets") - */ - event AllocationUpdated(bytes32 indexed channelId, uint256 assetIndex, uint256 initialHoldings); -} diff --git a/contracts/nitro-protocol/interfaces/IStatusManager.sol b/contracts/nitro-protocol/interfaces/IStatusManager.sol deleted file mode 100644 index 8807131..0000000 --- a/contracts/nitro-protocol/interfaces/IStatusManager.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; - -interface IStatusManager { - enum ChannelMode {Open, Challenge, Finalized} - - struct ChannelData { - uint48 turnNumRecord; - uint48 finalizesAt; - bytes32 stateHash; // keccak256(abi.encode(State)) - bytes32 outcomeHash; - } -} diff --git a/contracts/nitro-protocol/libraries/ECRecovery.sol b/contracts/nitro-protocol/libraries/ECRecovery.sol deleted file mode 100644 index 65df162..0000000 --- a/contracts/nitro-protocol/libraries/ECRecovery.sol +++ /dev/null @@ -1,28 +0,0 @@ -//SPDX-License-Identifier: MIT License -pragma solidity 0.7.4; - -library ECRecovery { - - /** - * @dev Recover signer address from a message by using his signature - * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. - * @param v v part of a signature - * @param r r part of a signature - * @param s s part of a signature - */ - function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { - - // Version of signature should be 27 or 28, but 0 and 1 are also possible versions - if (v < 27) { - v += 27; - } - - // If the version is correct return the signer address - if (v != 27 && v != 28) { - return (address(0)); - } else { - return ecrecover(hash, v, r, s); - } - } - -} diff --git a/contracts/nitro-protocol/test/TESTForceMove.sol b/contracts/nitro-protocol/test/TESTForceMove.sol deleted file mode 100644 index ccfec7c..0000000 --- a/contracts/nitro-protocol/test/TESTForceMove.sol +++ /dev/null @@ -1,127 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; -import '../ForceMove.sol'; - -/** - * @dev This contract extends the ForceMove contract to enable it to be more easily unit-tested. It exposes public or external functions that set storage variables or wrap otherwise internal functions. It should not be deployed in a production environment. - */ -contract TESTForceMove is ForceMove { - // Public wrappers for internal methods: - - /** - * @dev Wrapper for otherwise internal function. Tests whether a given address is in a given array of addresses. - * @param suspect A single address of interest. - * @param addresses A line-up of possible perpetrators. - * @return true if the address is in the array, false otherwise - */ - function isAddressInArray(address suspect, address[] memory addresses) - public - pure - returns (bool) - { - return _isAddressInArray(suspect, addresses); - } - - /** - * @dev Wrapper for otherwise internal function. Given an array of state hashes, checks the validity of the supplied signatures. Valid means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`. - * @param participants A list of addresses representing the participants of a channel. - * @param stateHashes Array of keccak256(State) submitted in support of a state, - * @param sigs Array of Signatures, one for each participant - * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]] - * @return true if the signatures are valid, false otherwise - */ - function validSignatures( - uint48 largestTurnNum, - address[] memory participants, - bytes32[] memory stateHashes, - Signature[] memory sigs, - uint8[] memory whoSignedWhat // whoSignedWhat[i] is the index of the state in stateHashes that was signed by participants[i] - ) public pure returns (bool) { - return _validSignatures(largestTurnNum, participants, stateHashes, sigs, whoSignedWhat); - } - - /** - * @dev Wrapper for otherwise internal function. Given a declaration of which state in the support proof was signed by which participant, check if this declaration is acceptable. Acceptable means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array. - * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]] - * @param largestTurnNum Largest turnNum of the support proof - * @param nParticipants Number of participants in the channel - * @param nStates Number of states in the support proof - * @return true if whoSignedWhat is acceptable, false otherwise - */ - function acceptableWhoSignedWhat( - uint8[] memory whoSignedWhat, - uint48 largestTurnNum, - uint256 nParticipants, - uint256 nStates - ) public pure returns (bool) { - return _acceptableWhoSignedWhat(whoSignedWhat, largestTurnNum, nParticipants, nStates); - } - - /** - * @dev Wrapper for otherwise internal function. Given a digest and digital signature, recover the signer - * @param _d message digest - * @param sig ethereum digital signature - * @return signer - */ - function recoverSigner(bytes32 _d, Signature memory sig) public pure returns (address) { - return _recoverSigner(_d, sig); - } - - // public setter for statusOf - - /** - * @dev Manually set the fingerprint for a given channelId. Shortcuts the public methods (ONLY USE IN A TESTING ENVIRONMENT). - * @param channelId Unique identifier for a state channel. - * @param channelData The channelData to be formatted and stored against the channelId - */ - function setStatusFromChannelData(bytes32 channelId, ChannelData memory channelData) public { - if (channelData.finalizesAt == 0) { - require( - channelData.stateHash == bytes32(0) && channelData.outcomeHash == bytes32(0), - 'Invalid open channel' - ); - } - - statusOf[channelId] = _generateStatus(channelData); - } - - /** - * @dev Manually set the fingerprint for a given channelId. Shortcuts the public methods (ONLY USE IN A TESTING ENVIRONMENT). - * @param channelId Unique identifier for a state channel. - * @param f The fingerprint to store against the channelId - */ - function setStatus(bytes32 channelId, bytes32 f) public { - statusOf[channelId] = f; - } - - /** - * @dev Wrapper for otherwise internal function. Hashes the input data and formats it for on chain storage. - * @param channelData ChannelData data. - */ - function generateStatus(ChannelData memory channelData) - public - pure - returns (bytes32 newStatus) - { - return _generateStatus(channelData); - } - - /** - * @dev Wrapper for otherwise internal function. Checks that a given ChannelData struct matches a supplied bytes32 when formatted for storage. - * @param cs A given ChannelData data structure. - * @param f Some data in on-chain storage format. - */ - function matchesStatus(ChannelData memory cs, bytes32 f) public pure returns (bool) { - return _matchesStatus(cs, f); - } - - /** - * @dev Wrapper for otherwise internal function. Checks that a given channel is in the Challenge mode. - * @param channelId Unique identifier for a channel. - */ - function requireChannelOpen(bytes32 channelId) public view { - _requireChannelOpen(channelId); - } -} diff --git a/contracts/nitro-protocol/test/TESTNitroAdjudicator.sol b/contracts/nitro-protocol/test/TESTNitroAdjudicator.sol deleted file mode 100644 index c4f8f13..0000000 --- a/contracts/nitro-protocol/test/TESTNitroAdjudicator.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.7.4; -pragma experimental ABIEncoderV2; -import '../NitroAdjudicator.sol'; -import './TESTForceMove.sol'; - -/** - * @dev This contract extends the NitroAdjudicator contract to enable it to be more easily unit-tested. It exposes public or external functions that set storage variables or wrap otherwise internal functions. It should not be deployed in a production environment. - */ -contract TESTNitroAdjudicator is NitroAdjudicator, TESTForceMove { - /** - * @dev Manually set the holdings mapping to a given amount for a given channelId. Shortcuts the deposit workflow (ONLY USE IN A TESTING ENVIRONMENT) - * @param channelId Unique identifier for a state channel. - * @param amount The number of assets that should now be "escrowed: against channelId - */ - function setHoldings( - address asset, - bytes32 channelId, - uint256 amount - ) external { - holdings[asset][channelId] = amount; - } - - /** - * @dev Wrapper for otherwise internal function. Checks if a given destination is external (and can therefore have assets transferred to it) or not. - * @param destination Destination to be checked. - * @return True if the destination is external, false otherwise. - */ - function isExternalDestination(bytes32 destination) public pure returns (bool) { - return _isExternalDestination(destination); - } - - /** - * @dev Wrapper for otherwise internal function. Converts an ethereum address to a nitro external destination. - * @param participant The address to be converted. - * @return The input address left-padded with zeros. - */ - function addressToBytes32(address participant) public pure returns (bytes32) { - return _addressToBytes32(participant); - } -} diff --git a/data/erc20-tokens.json b/data/erc20-tokens.json deleted file mode 100644 index 40fde84..0000000 --- a/data/erc20-tokens.json +++ /dev/null @@ -1,324 +0,0 @@ -{ - "tokens": [ - { - "num": 1, - "asset": "Bitcoin", - "tokenTicker": "wBTC", - "network": "Rinkeby", - "totalSupply": 21000000, - "marketPair": "wBTC/USDC", - "minPrice": 5000, - "maxPrice": 500000, - "dataFeed": "Binance", - "price": 41062, - "rawStep": 40000, - "factor": 10000, - "step": 4, - "targetStep": 5 - }, - { - "num": 3, - "asset": "BNB", - "tokenTicker": "wBNB", - "network": "Rinkeby", - "totalSupply": 165000000, - "marketPair": "wBNB/USDC", - "minPrice": 50, - "maxPrice": 5000, - "dataFeed": "Binance", - "price": 383.67, - "rawStep": 400, - "factor": 10000, - "step": 0.04, - "targetStep": 0.05 - }, - { - "num": 7, - "asset": "Cardano", - "tokenTicker": "wADA", - "network": "Rinkeby", - "totalSupply": 45000000000, - "marketPair": "wADA/USDC", - "minPrice": 0.1, - "maxPrice": 10, - "dataFeed": "Binance", - "price": 0.842958, - "rawStep": 0.8, - "factor": 1000, - "step": 0.0008, - "targetStep": 0.005 - }, - { - "num": 14, - "asset": "Chainlink", - "tokenTicker": "wLINK", - "network": "Rinkeby", - "totalSupply": 1000000000, - "marketPair": "wLINK/USDC", - "minPrice": 1, - "maxPrice": 100, - "dataFeed": "Binance", - "price": 14.7, - "rawStep": 10, - "factor": 1000, - "step": 0.01, - "targetStep": 0.01 - }, - { - "num": 17, - "asset": "Chiliz", - "tokenTicker": "wCHZ", - "network": "Rinkeby", - "totalSupply": 8000000000, - "marketPair": "wCHZ/USDC", - "minPrice": 0.01, - "maxPrice": 2, - "dataFeed": "Binance", - "price": 0.203234, - "rawStep": 0.2, - "factor": 1000, - "step": 0.0002, - "targetStep": 0.001 - }, - { - "num": 13, - "asset": "Cosmos", - "tokenTicker": "wATOM", - "network": "Rinkeby", - "totalSupply": 280000000, - "marketPair": "wATOM/USDC", - "minPrice": 2, - "maxPrice": 200, - "dataFeed": "Binance", - "price": "#N/A", - "rawStep": "#N/A", - "factor": "#N/A", - "step": "#N/A" - }, - { - "num": 8, - "asset": "Dogecoin", - "tokenTicker": "wDOGE", - "network": "Rinkeby", - "totalSupply": 130000000000, - "marketPair": "wDOGE/USDC", - "minPrice": 0.1, - "maxPrice": 1, - "dataFeed": "Binance", - "price": 0.117186, - "rawStep": 0.1, - "factor": 100, - "step": 0.001 - }, - { - "num": 2, - "asset": "Ethereum", - "tokenTicker": "wETH", - "network": "Rinkeby", - "totalSupply": 120000000, - "marketPair": "wETH/USDC", - "minPrice": 300, - "maxPrice": 30000, - "dataFeed": "Binance", - "price": 2770.36, - "rawStep": 3000, - "factor": 10000, - "step": 0.3 - }, - { - "num": 20, - "asset": "Filecoin", - "tokenTicker": "wFIL", - "network": "Rinkeby", - "totalSupply": 160000000, - "marketPair": "wFIL/USDC", - "minPrice": 2, - "maxPrice": 200, - "dataFeed": "Binance", - "price": 17.41, - "rawStep": 20, - "factor": 1000, - "step": 0.02 - }, - { - "num": 12, - "asset": "Litecoin", - "tokenTicker": "wLTC", - "network": "Rinkeby", - "totalSupply": 84000000, - "marketPair": "wLTC/USDC", - "minPrice": 10, - "maxPrice": 1000, - "dataFeed": "Binance", - "price": 110.2, - "rawStep": 100, - "factor": 1000, - "step": 0.1 - }, - { - "num": 9, - "asset": "Polkadot", - "tokenTicker": "wDOT", - "network": "Rinkeby", - "totalSupply": 1000000000, - "marketPair": "wDOT/USDC", - "minPrice": 2, - "maxPrice": 200, - "dataFeed": "Binance", - "price": 19.13, - "rawStep": 20, - "factor": 1000, - "step": 0.02 - }, - { - "num": 11, - "asset": "Polygon", - "tokenTicker": "wMATIC", - "network": "Rinkeby", - "totalSupply": 10000000000, - "marketPair": "wMATIC/USDC", - "minPrice": 0.1, - "maxPrice": 10, - "dataFeed": "Binance", - "price": 1.45, - "rawStep": 1, - "factor": 1000, - "step": 0.001 - }, - { - "num": 10, - "asset": "Shiba Inu", - "tokenTicker": "wSHIB", - "network": "Rinkeby", - "totalSupply": 550000000000000, - "marketPair": "wSHIB/USDC", - "minPrice": 0.000001, - "maxPrice": 0.0001, - "dataFeed": "Binance", - "price": 0.00002256, - "rawStep": 0.00002, - "factor": 100, - "step": 2.0000000000000002e-7 - }, - { - "num": 5, - "asset": "Solana", - "tokenTicker": "wSOL", - "network": "Rinkeby", - "totalSupply": 300000000, - "marketPair": "wSOL/USDC", - "minPrice": 10, - "maxPrice": 1000, - "dataFeed": "Binance", - "price": 88.37, - "rawStep": 90, - "factor": 1000, - "step": 0.09 - }, - { - "num": 18, - "asset": "Stellar", - "tokenTicker": "wXLM", - "network": "Rinkeby", - "totalSupply": 50000000000, - "marketPair": "wXLM/USDC", - "minPrice": 0.01, - "maxPrice": 2, - "dataFeed": "Binance", - "price": 0.187495, - "rawStep": 0.2, - "factor": 1000, - "step": 0.0002 - }, - { - "num": 6, - "asset": "Terra", - "tokenTicker": "wLUNA", - "network": "Rinkeby", - "totalSupply": 400000000, - "marketPair": "wLUNA/USDC", - "minPrice": 5, - "maxPrice": 500, - "dataFeed": "Binance", - "price": 87.64, - "rawStep": 90, - "factor": 1000, - "step": 0.09 - }, - { - "num": 19, - "asset": "Tezos", - "tokenTicker": "wXTZ", - "network": "Rinkeby", - "totalSupply": 800000000, - "marketPair": "wXTZ/USDC", - "minPrice": 0.1, - "maxPrice": 30, - "dataFeed": "Binance", - "price": 3.1, - "rawStep": 3, - "factor": 1000, - "step": 0.003 - }, - { - "num": 16, - "asset": "Tron", - "tokenTicker": "wTRX", - "network": "Rinkeby", - "totalSupply": 100000000000, - "marketPair": "wTRX/USDC", - "minPrice": 0.005, - "maxPrice": 0.5, - "dataFeed": "Binance", - "price": 0.060926, - "rawStep": 0.06, - "factor": 100, - "step": 0.0006 - }, - { - "num": 15, - "asset": "Uniswap", - "tokenTicker": "wUNI", - "network": "Rinkeby", - "totalSupply": 1000000000, - "marketPair": "wUNI/USDC", - "minPrice": 1, - "maxPrice": 100, - "dataFeed": "Binance", - "price": 9.12, - "rawStep": 9, - "factor": 1000, - "step": 0.009 - }, - { - "num": 21, - "asset": "USD Coin", - "tokenTicker": "USDC", - "network": "Rinkeby", - "totalSupply": 10000000000000, - "marketPair": "*no market", - "minPrice": "*no min price", - "maxPrice": "*no max price", - "dataFeed": "*no source", - "price": 0.999997, - "rawStep": 1, - "factor": 1000, - "step": 0.001 - }, - { - "num": 4, - "asset": "XRP", - "tokenTicker": "wXRP", - "network": "Rinkeby", - "totalSupply": 100000000000, - "marketPair": "wXRP/USDC", - "minPrice": 0.1, - "maxPrice": 10, - "dataFeed": "Binance", - "price": 0.790542, - "rawStep": 0.8, - "factor": 1000, - "step": 0.0008 - } - ] -} diff --git a/deployments/addresses.json b/deployments/addresses.json deleted file mode 100644 index a337164..0000000 --- a/deployments/addresses.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "31337": [ - { - "name": "localhost", - "chainId": "31337", - "contracts": { - "NitroAdjudicator": { - "address": "0xcB11FD11984590dF37441aE894a6AdF6fb918c3D" - }, - "DefaultProxyAdmin": { - "address": "0x3aFed347cFe8c94af51df111ff8F0fdac427e7fC" - }, - "SimpleVaultFactory_Implementation": { - "address": "0x40AA2623544db21c4d2954c02202F3bcb8968F67" - }, - "SimpleVaultFactory_Proxy": { - "address": "0x5Bae4038912A12De0Ea6afD15791fcb691d697a8" - }, - "SimpleVaultFactory": { - "address": "0x5Bae4038912A12De0Ea6afD15791fcb691d697a8" - }, - "wBTC": { - "address": "0xaae2a779b528f16D2420f192CAD43CFAfA051C68" - }, - "wBNB": { - "address": "0x93602E5EFf826E871f5F3eD8f178bd8899fF96dB" - }, - "wADA": { - "address": "0xE00d7Fc20F1b0Aab149e318375e9BFa3cD1fD689" - }, - "wLINK": { - "address": "0x7A7933baAD5f61eE4B8d36899ee9b1F006FAd87B" - }, - "wCHZ": { - "address": "0xDf3Dfc9896ED28fCc19898bEDa3F6391fbDD0b0f" - }, - "wATOM": { - "address": "0xB5252Ba9EADB5Bd133Cfb73B0E5c5CC5747b82d0" - }, - "wDOGE": { - "address": "0xF5a8163136900b9470FE1070C6aF6c3fF2353213" - }, - "wETH": { - "address": "0xa66853e09a5A37eA3bdab2De959363Dd06c27563" - }, - "wFIL": { - "address": "0x8B8b63DA3e7bF692637142D11F9acd025003d6d9" - }, - "wLTC": { - "address": "0x4152b5B6a0667ef19e9c8162a76260FBCD3476B5" - }, - "wDOT": { - "address": "0x610fe9f059747edF50a0AADE97fD79073cacA49B" - }, - "wMATIC": { - "address": "0x51c56626584aECc29212c58E1E4c819D2ceB124C" - }, - "wSHIB": { - "address": "0x661cF921639Baf3E214609a7Ab13F3a593Cf0Cd9" - }, - "wSOL": { - "address": "0x16838B19f1Df85A744A68D67065aD96fBddEEd7e" - }, - "wXLM": { - "address": "0x5922C2346C8768e0BAbd0C529ade312aa7eBBd9F" - }, - "wLUNA": { - "address": "0x1378BC797aCdcaB9935A2799bb5fcf4820BfbDd2" - }, - "wXTZ": { - "address": "0xFf39D9E9B5768e7A4d620fFC56d60703a0372Eba" - }, - "wTRX": { - "address": "0x21eF86C2E3689636a9A8Dd9E4918206a7f2aAfeb" - }, - "wUNI": { - "address": "0x1a967e5C169Bb61AB10cd5099fB273E5A5d0A1c6" - }, - "USDC": { - "address": "0x786D0e32Ba3c33C2997c1621df66f923fAd47cbe" - }, - "wXRP": { - "address": "0xE8c453346002fb281f1cf896aaE0c5a392303c16" - } - } - } - ] -} \ No newline at end of file diff --git a/hardhat-deploy/00-nitro-adjudicator.ts b/hardhat-deploy/00-nitro-adjudicator.ts deleted file mode 100644 index d75166b..0000000 --- a/hardhat-deploy/00-nitro-adjudicator.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {DeployFunction} from 'hardhat-deploy/types'; -import {HardhatRuntimeEnvironment} from 'hardhat/types'; - -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getNamedAccounts, getChainId} = hre; - const {deploy} = deployments; - const {deployer} = await getNamedAccounts(); - - const log = process.env.log !== undefined || false; - - if (log) { - console.log('Working on chain id #', await getChainId()); - } - - await deploy('NitroAdjudicator', { - from: deployer, - log: log, - }); -}; -export default func; -func.tags = ['NitroAdjudicator']; diff --git a/hardhat-deploy/01-simple-vault-factory.ts b/hardhat-deploy/01-simple-vault-factory.ts deleted file mode 100644 index 5788559..0000000 --- a/hardhat-deploy/01-simple-vault-factory.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {DeployFunction} from 'hardhat-deploy/types'; -import {HardhatRuntimeEnvironment} from 'hardhat/types'; - -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getNamedAccounts, getChainId} = hre; - const {deploy} = deployments; - const {deployer} = await getNamedAccounts(); - - const log = process.env.log !== undefined || false; - - if (log) { - console.log('Working on chain id #', await getChainId()); - } - - await deploy('SimpleVaultFactory', { - from: deployer, - proxy: { - proxyContract: 'OpenZeppelinTransparentProxy', - execute: { - init: { - methodName: 'initialize', - args: [], - }, - }, - }, - log: log, - }); -}; -export default func; -func.tags = ['SimpleVaultFactory']; diff --git a/hardhat-deploy/02-simple-erc20s.ts b/hardhat-deploy/02-simple-erc20s.ts deleted file mode 100644 index 889ed5f..0000000 --- a/hardhat-deploy/02-simple-erc20s.ts +++ /dev/null @@ -1,60 +0,0 @@ -import fs from 'fs'; - -import {ethers} from 'hardhat'; -import {DeployFunction} from 'hardhat-deploy/types'; -import {HardhatRuntimeEnvironment} from 'hardhat/types'; - -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getNamedAccounts, getChainId} = hre; - const {deploy, execute} = deployments; - - const IN = './data/erc20-tokens.json'; - const tokens = JSON.parse(fs.readFileSync(IN, 'utf8')).tokens; - - const log = process.env.log !== undefined || false; - - if (log) { - console.log('Working on chain id #', await getChainId()); - console.log(`Deploying ${tokens.length} tokens...`); - } - - const INITIAL_MINT_PART = 100000; - const {deployer} = await getNamedAccounts(); - - for await (const token of tokens) { - const SimpleERC20 = await deploy(token.tokenTicker, { - from: deployer, - contract: 'SimpleERC20', - args: [token.asset, token.tokenTicker, 18], - log: log, - }); - - const factoryAdress = (await deployments.get('SimpleVaultFactory')).address; - - await execute( - token.tokenTicker, - {from: deployer, log: log}, - 'grantRole', - ethers.utils.id('MINTER_ROLE'), - factoryAdress - ); - - await execute( - token.tokenTicker, - {from: deployer, log: log}, - 'grantRole', - ethers.utils.id('BURNER_ROLE'), - factoryAdress - ); - - await execute( - 'SimpleVaultFactory', - {from: deployer, log: log}, - 'addToken', - SimpleERC20.address, - token.totalSupply / INITIAL_MINT_PART - ); - } -}; -export default func; -func.tags = ['SimpleERC20']; diff --git a/scripts/custody-factory/deploy-factory-erc20.ts b/scripts/custody-factory/deploy-factory-erc20.ts deleted file mode 100644 index 3db90f9..0000000 --- a/scripts/custody-factory/deploy-factory-erc20.ts +++ /dev/null @@ -1,87 +0,0 @@ -import fs from 'fs'; - -import {ethers, upgrades} from 'hardhat'; - -import {deployAndAddToken} from '../../src/FactoryHelpers'; -import {SimpleVaultFactory} from '../../typechain'; - -/** - * @notice This script deploys SimpleVaultFactory, deploys and adds tokens to it specified in json file. - * Run script from custody folder with `[variables] npx hardhat run scripts/deploy-factory-erc20.ts (--network )` - * NOTE: relative path is specified from hardhat project root, not from scripts folder. - * 3 local variables can be specified for the script: - * - IN - json file to read token data from. './data/erc20-tokens.json' by default - * - LOG - LOGGING deployed addresses to console. 'false' by default. - * - OUT - file to write addresses data to. './data/factory-tokens-addresses.json' by default. - * To deploy to non-local blockchain, network must be defined in `hardhat.config.ts` and then specified in --network param to this script. - * For network to connect to real blockchain, an .env file must be populated with URLs and private keys for desired blockchains, as showed in `.env.example`. - */ - -interface IDeployedToken { - address: string; - asset: string; - tokenTicker: string; - initialMint: number; -} - -interface IDeployedFactoryTokens { - SimpleVaultFactory: string; - deployedTokens: IDeployedToken[]; -} - -async function main() { - const IN = process.env.IN || './data/erc20-tokens.json'; - const LOGGING = process.env.LOG || false; - const OUT = process.env.OUT || './data/factory-tokens-addresses.json'; - - const tokens = JSON.parse(fs.readFileSync(IN, 'utf8')).tokens; - - console.log(`Deploying SimpleVaultFactory and ${tokens.length} tokens...`); - - const INITIAL_MINT_PART = 100000; - - const deployedFactoryTokens: IDeployedFactoryTokens = { - SimpleVaultFactory: '', - deployedTokens: [], - }; - - const FactoryFactory = await ethers.getContractFactory('SimpleVaultFactory'); - const SimpleVaultFactory = await upgrades.deployProxy(FactoryFactory, []); - await SimpleVaultFactory.deployed(); - - deployedFactoryTokens.SimpleVaultFactory = SimpleVaultFactory.address; - if (LOGGING) { - console.log(`SimpleVaultFactory deployed to ${SimpleVaultFactory.address}\n`); - } - - for await (const token of tokens) { - const TokenContract = await deployAndAddToken( - SimpleVaultFactory as SimpleVaultFactory, - token.asset, - token.tokenTicker, - 18, - token.totalSupply / INITIAL_MINT_PART - ); - - deployedFactoryTokens.deployedTokens.push({ - address: TokenContract.address, - asset: token.asset, - tokenTicker: token.tokenTicker, - initialMint: token.totalSupply / INITIAL_MINT_PART, - }); - if (LOGGING) { - console.log( - `Deployed token ${token.asset} (${token.tokenTicker}) on address ${TokenContract.address}` - ); - } - } - - // eslint-disable-next-line @typescript-eslint/no-empty-function - fs.writeFile(OUT, JSON.stringify(deployedFactoryTokens), () => {}); - console.log(`SimpleVaultFactory and tokens deployed, addresses in ${OUT}`); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/custody/deploy-local.ts b/scripts/custody/deploy-local.ts deleted file mode 100644 index 48b609b..0000000 --- a/scripts/custody/deploy-local.ts +++ /dev/null @@ -1,113 +0,0 @@ -import fs from 'fs'; - -import {ethers} from 'hardhat'; - -const OUTPUT_PATH = './cache/deploy-local.env'; - -async function main() { - const envCache = readEnvCache(); - const signers = await ethers.getSigners(); - const [broker] = signers; - - const brokerWallet = new ethers.Wallet( - '266ccede2bb3d559a0616dadbb8a2f51583df10a01744f8c86c624765cc4613e', - ethers.provider - ); - if (!signers.find((s) => s.address === brokerWallet.address)) { - console.warn( - `Broker ${brokerWallet.address} is not in the list of signers. ETH will not be minted.` - ); - } - envCache.brokerPrivateKey = brokerWallet.privateKey.slice(2); // remove 0x - - const getTxsCountOfBlock = async (block: number) => - (((await ethers.provider.getBlock(block)) ?? {}).transactions ?? {}).length || 0; - // skip token deployment if deployed - const tokenName = 'LocalToken'; - const TestTokenContract = await ethers.getContractFactory('TestERC20'); - if ((await getTxsCountOfBlock(1)) === 0 || !envCache.testTokenAddress) { - const token = await TestTokenContract.deploy(tokenName, 'LOCAL', '0'); - await token.deployed(); - console.log(`${tokenName} deployed to:`, token.address); - envCache.testTokenAddress = token.address; - } else { - console.log(`(cached) ${tokenName} already deployed at ${envCache.testTokenAddress}`); - } - - // skip vault deployment if deployed - const vaultName = 'SimpleVault'; - const vaultFactory = await ethers.getContractFactory('SimpleVault'); - if ((await getTxsCountOfBlock(2)) === 0 || !envCache.vaultAddress) { - const brokerAddress = await broker.getAddress(); - console.log(`Broker address:`, brokerAddress); - const vaultContract = await vaultFactory.deploy(vaultName, brokerAddress); - await vaultContract.deployed(); - console.log(`${vaultName} deployed to:`, vaultContract.address); - envCache.vaultAddress = vaultContract.address; - } else { - console.log(`(cached) ${vaultName} already deployed at ${envCache.vaultAddress}`); - } - - // mint test token to specific account address - try { - const userTest = new ethers.Wallet( - '0x4576fdf6bde1fe670b17ee667d4da85ca3a4383219757a977dfa8cfe3b5c89ee', - ethers.provider - ); - if (!signers.find((s) => s.address === userTest.address)) { - console.warn( - `User test ${userTest.address} is not in the list of signers. ETH will not be minted.` - ); - } - const token = await TestTokenContract.attach(envCache.testTokenAddress); - const mintAmount = '10000'; - await (await token.connect(userTest).setBalance(ethers.utils.parseEther(mintAmount))).wait(); - envCache.userTestAddress = userTest.address; - envCache.userTestPrivateKey = userTest.privateKey; - console.log('UserAddress:', envCache.userTestAddress); - console.log('UserPrivateKey:', envCache.userTestPrivateKey); - console.log(`Set ${tokenName} balance to UserAddress for`, mintAmount, 'tokens'); - } catch (error) { - console.error(error); - } - - // write output - writeEnvCache(envCache); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -function readEnvCache() { - const cache = fs.readFileSync(OUTPUT_PATH, {flag: 'a+'}).toString(); - const parts = cache - .split('\n') - .filter(Boolean) - .map((r) => r.split('=')); - const result = { - brokerPrivateKey: (parts.find((r) => r[0] === 'CUSTODY_BROKER_PRIVATE_KEY') ?? ({} as any))[1], - vaultAddress: (parts.find((r) => r[0] === 'CUSTODY_VAULT_ADDRESS') ?? ({} as any))[1], - testTokenAddress: (parts.find((r) => r[0] === 'CUSTODY_TEST_TOKEN_ADDRESS') ?? ({} as any))[1], - userTestAddress: (parts.find((r) => r[0] === 'CUSTODY_USER_TEST_ADDRESS') ?? ({} as any))[1], - userTestPrivateKey: (parts.find((r) => r[0] === 'CUSTODY_USER_TEST_PRIVATE_KEY') ?? - ({} as any))[1], - }; - return result; -} - -function writeEnvCache(result: any) { - fs.writeFileSync( - OUTPUT_PATH, - [ - `CUSTODY_BROKER_PRIVATE_KEY=${result.brokerPrivateKey}`, - `CUSTODY_VAULT_ADDRESS=${result.vaultAddress}`, - `CUSTODY_TEST_TOKEN_ADDRESS=${result.testTokenAddress}`, - `CUSTODY_USER_TEST_ADDRESS=${result.userTestAddress}`, - `CUSTODY_USER_TEST_PRIVATE_KEY=${result.userTestPrivateKey}`, - ].join('\n'), - {flag: 'w'} - ); - return result; -} diff --git a/scripts/custody/deploy-simple-vault.ts b/scripts/custody/deploy-simple-vault.ts deleted file mode 100644 index 7936001..0000000 --- a/scripts/custody/deploy-simple-vault.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {ethers} from 'hardhat'; - -async function main() { - const vaultName = 'SimpleVault'; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const brokerAddress = process.env.BROKER_ADDRESS!; - console.log(`Broker address:`, brokerAddress); - - const vaultFactory = await ethers.getContractFactory('SimpleVault'); - const vaultContract = await vaultFactory.deploy(vaultName, brokerAddress); - await vaultContract.deployed(); - - console.log(`${vaultName} deployed to:`, vaultContract.address); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/custody/deploy-test-token.ts b/scripts/custody/deploy-test-token.ts deleted file mode 100644 index f71227b..0000000 --- a/scripts/custody/deploy-test-token.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {ethers} from 'hardhat'; - -async function main() { - const tokenName = 'TestToken'; - const TestTokenContract = await ethers.getContractFactory('TestERC20'); - const token = await TestTokenContract.deploy(tokenName, 'TOK', '0'); - - await token.deployed(); - - console.log(`${tokenName} deployed to:`, token.address); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/custody/deposit-withdraw.ts b/scripts/custody/deposit-withdraw.ts deleted file mode 100644 index c894fc4..0000000 --- a/scripts/custody/deposit-withdraw.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import {ethers} from 'hardhat'; - -import { - DepositType, - WithdrawType, - approve, - depositWithPayload, - withdrawWithPayload, - generatePayload, - generateSignature, -} from '../../test/custody/common'; - -const actionConfigs: { - [action: string]: { - type: string; - event: string; - send: typeof depositWithPayload | typeof withdrawWithPayload; - }; -} = { - deposit: { - type: DepositType, - event: 'Deposited', - send: depositWithPayload, - }, - withdraw: { - type: WithdrawType, - event: 'Withdrawn', - send: withdrawWithPayload, - }, -}; - -async function main() { - const signers = await ethers.getSigners(); - const [broker] = signers; - const user = new ethers.Wallet( - process.env.PVT_KEY || '0x4576fdf6bde1fe670b17ee667d4da85ca3a4383219757a977dfa8cfe3b5c89ee', - ethers.provider - ); - if (!signers.find((s) => s.address === user.address)) { - console.warn(`Account ${user.address} is not in the list of signers. ETH will not be minted.`); - } - - let action = actionConfigs[process.env.ACTION!]; - - const requestPayload = process.env.PAYLOAD ? JSON.parse(process.env.PAYLOAD!) : {}; - if (process.env.FINEX_REQUEST) { - const result = JSON.parse(process.env.FINEX_REQUEST!); - action = actionConfigs[result[2]]; - const [assetAddress, assetAmount] = result[3]; - requestPayload.assetAddress = assetAddress; - requestPayload.assetAmount = assetAmount; - } - if (process.env.FINEX_RESPONSE) { - const result = JSON.parse(process.env.FINEX_RESPONSE!); - const [rid, expire, signature] = result[3]; - requestPayload.rid = rid; - requestPayload.expire = expire; - requestPayload.signature = signature; - } - - console.log('contract address:', process.env.CONTRACT_ADDRESS); - console.log('payload:', requestPayload); - console.log('broker address:', await broker.getAddress()); - console.log('user address:', await user.getAddress()); - - if (!action) throw new Error('ACTION is invalid'); - console.log('action:', action.event); - - const isNative = requestPayload.assetAddress === ethers.constants.AddressZero; - - const VaultContract = await ethers.getContractFactory('SimpleVault'); - const vaultContract = await VaultContract.attach(process.env.CONTRACT_ADDRESS!); - const tokenContract = isNative - ? {address: requestPayload.assetAddress} - : await (await ethers.getContractFactory('TestERC20')).attach(requestPayload.assetAddress); - - const amount = requestPayload.assetAmount; - - if (!isNative && action.type === DepositType) { - await approve(user, vaultContract, tokenContract); - } - - const {payload, data} = generatePayload({ - rid: requestPayload.rid || ethers.utils.formatBytes32String(Math.random().toString(16)), - deadline: requestPayload.expire * 1000 || Date.now() + 600_000, - destination: user.address, - asset: tokenContract.address, - amount, - }); - console.log('data:', data); - - const ethAmount = tokenContract.address === ethers.constants.AddressZero ? amount : undefined; - - const signature = - process.env.SIGNATURE || - requestPayload.signature || - (await generateSignature(broker, action.type, payload)); - console.log('signature:', signature); - - const result = await action.send(user, action.type, broker, payload, vaultContract, true, { - ethAmount, - signature, - }); - - const event = result.events.find((e: any) => e.event === action.event); - console.log('result:', event); - console.log('Done'); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/custody/mint-test-token.ts b/scripts/custody/mint-test-token.ts deleted file mode 100644 index ffb69cd..0000000 --- a/scripts/custody/mint-test-token.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import {ethers} from 'hardhat'; - -async function main() { - const TestTokenContract = await ethers.getContractFactory('TestERC20'); - - const token = await TestTokenContract.attach(process.env.TOKEN_ADDRESS!); - await token.setUserBalance( - process.env.MINT_TO!, - ethers.utils.parseEther(process.env.MINT_AMOUNT!) - ); - - console.log( - `Minted ${await token.name()} to ${process.env.MINT_TO} amount ${process.env.MINT_AMOUNT}` - ); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/nitro-protocol/postdeploy.ts b/scripts/nitro-protocol/postdeploy.ts deleted file mode 100644 index a66cff0..0000000 --- a/scripts/nitro-protocol/postdeploy.ts +++ /dev/null @@ -1,18 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const {readFileSync, writeFileSync, rm} = require('fs'); - -const file_in = __dirname + '/../../addresses.json'; -const file_out = __dirname + '/../../deployments/addresses.json'; -const addresses = JSON.parse(readFileSync(file_in, 'utf8')); - -function deepDelete(object: any, keyToDelete: any) { - Object.keys(object).forEach((key) => { - if (key === keyToDelete) delete object[key]; - else if (typeof object[key] === 'object') deepDelete(object[key], keyToDelete); - }); -} -const keyToDelete = 'abi'; -deepDelete(addresses, keyToDelete); -writeFileSync(file_out, JSON.stringify(addresses, null, 2)); -// eslint-disable-next-line @typescript-eslint/no-empty-function -rm(file_in, () => {}); diff --git a/test/custody-factory/SimpleERC20.spec.ts b/test/custody-factory/SimpleERC20.spec.ts deleted file mode 100644 index 600c823..0000000 --- a/test/custody-factory/SimpleERC20.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {expect} from 'chai'; -import {ethers} from 'hardhat'; - -describe('SimpleERC20', async function () { - const DEFAULT_ADMIN_ROLE = ethers.constants.HashZero; - const MINTER_ROLE = ethers.utils.id('MINTER_ROLE'); - const BURNER_ROLE = ethers.utils.id('BURNER_ROLE'); - const TOKEN_AMOUNT = 1000; - const DECIMALS = 10; - - before(async function () { - const [owner, minter, burner, user, someone] = await ethers.getSigners(); - this.owner = owner; - this.minter = minter; - this.burner = burner; - this.user = user; - this.someone = someone; - - const tokenFactory = await ethers.getContractFactory('SimpleERC20'); - const SimpleERC20 = await tokenFactory.deploy('token', 'TKN', DECIMALS); - await SimpleERC20.deployed(); - this.SimpleERC20 = SimpleERC20; - }); - - describe('Roles', function () { - before(async function () { - const {SimpleERC20, owner, minter, burner} = this; - - await SimpleERC20.connect(owner).grantRole(MINTER_ROLE, minter.address); - await SimpleERC20.connect(owner).grantRole(BURNER_ROLE, burner.address); - }); - - it('owner has admin, minter, burner rights', async function () { - const {SimpleERC20, owner} = this; - - expect(await SimpleERC20.hasRole(DEFAULT_ADMIN_ROLE, owner.address)).to.be.true; - expect(await SimpleERC20.hasRole(MINTER_ROLE, owner.address)).to.be.true; - expect(await SimpleERC20.hasRole(BURNER_ROLE, owner.address)).to.be.true; - }); - - it('minter can mint', async function () { - const {SimpleERC20, minter, user} = this; - - expect(await SimpleERC20.hasRole(MINTER_ROLE, minter.address)).to.be.true; - await SimpleERC20.connect(minter).mintTo(user.address, TOKEN_AMOUNT); - expect(await SimpleERC20.balanceOf(user.address)).to.be.equal(TOKEN_AMOUNT); - }); - - it('burner can burn', async function () { - const {SimpleERC20, burner, user} = this; - - expect(await SimpleERC20.hasRole(BURNER_ROLE, burner.address)).to.be.true; - await SimpleERC20.connect(burner).burnFrom(user.address, TOKEN_AMOUNT); - expect(await SimpleERC20.balanceOf(user.address)).to.be.equal(0); - }); - - it("user can't change rights, mint or burn", async function () { - const {SimpleERC20, user, someone} = this; - - await expect(SimpleERC20.connect(user).grantRole(MINTER_ROLE, someone.address)).to.be - .reverted; - await expect(SimpleERC20.connect(user).mintTo(someone.address, TOKEN_AMOUNT)).to.be.reverted; - await expect(SimpleERC20.connect(user).burnFrom(someone.address, TOKEN_AMOUNT)).to.be - .reverted; - }); - }); - - describe('Properties', function () { - it('has correct decimals', async function () { - const {SimpleERC20} = this; - - expect(await SimpleERC20.decimals()).to.be.equal(DECIMALS); - }); - }); -}); diff --git a/test/custody-factory/SimpleVaultFactory.spec.ts b/test/custody-factory/SimpleVaultFactory.spec.ts deleted file mode 100644 index bc9f3f8..0000000 --- a/test/custody-factory/SimpleVaultFactory.spec.ts +++ /dev/null @@ -1,348 +0,0 @@ -import {Wallet} from '@ethersproject/wallet'; -import {expect} from 'chai'; -import {ethers, upgrades} from 'hardhat'; - -import { - DEFAULT_ADMIN_ROLE, - deployAndAddToken, - deployTokenGrantRoles, - deployVault, - MINTER_ROLE, - redeployVault, -} from '../../src/FactoryHelpers'; -import {SimpleVaultFactory} from '../../typechain'; - -const { - utils: {parseUnits}, -} = ethers; - -describe('SimpleVaultFactory', function () { - const MINT_PER_DEPLOYMENT = 1000; - - const TOKEN1_NAME = 'TestToken'; - const TOKEN1_SYMBOL = 'TSTTKN'; - const TOKEN1_DECIMALS = 18; - - const TOKEN2_NAME = 'TOKEN2'; - const TOKEN2_SYMBOL = 'TKN2'; - const TOKEN2_DECIMALS = 16; - - beforeEach(async function () { - const [owner, broker, user, someone] = await ethers.getSigners(); - this.owner = owner; - this.broker = broker; - this.user = user; - this.someone = someone; - - const factoryFactory = await ethers.getContractFactory('SimpleVaultFactory'); - const SimpleVaultFactory = await upgrades.deployProxy(factoryFactory, []); - await SimpleVaultFactory.deployed(); - this.SimpleVaultFactory = SimpleVaultFactory; - - this.Token1 = await deployTokenGrantRoles( - SimpleVaultFactory as SimpleVaultFactory, - TOKEN1_NAME, - TOKEN1_SYMBOL, - TOKEN1_DECIMALS - ); - }); - - describe('Upgrades', function () { - beforeEach(async function () { - const {SimpleVaultFactory} = this; - - this.AddedToken = await deployAndAddToken( - SimpleVaultFactory, - TOKEN1_NAME, - TOKEN1_SYMBOL, - TOKEN1_DECIMALS, - MINT_PER_DEPLOYMENT - ); - - const v2FactoryFactory = await ethers.getContractFactory('SimpleVaultFactoryTest'); - const v2Factory = await upgrades.upgradeProxy(SimpleVaultFactory.address, v2FactoryFactory); - await v2Factory.deployed(); - this.v2Factory = v2Factory; - }); - - it('contract is upgradable', async function () { - const {SimpleVaultFactory, v2Factory} = this; - - expect(v2Factory.address).to.equal(SimpleVaultFactory.address); - expect(v2Factory.AVAILABLE_AFTER_UPGRADE).to.not.undefined; - expect(await v2Factory.AVAILABLE_AFTER_UPGRADE()).to.equal(true); - }); - - it('token admin has not changed', async function () { - const {SimpleVaultFactory, v2Factory, AddedToken} = this; - - expect(await AddedToken.hasRole(DEFAULT_ADMIN_ROLE, SimpleVaultFactory.address)).to.be.true; - expect(await AddedToken.hasRole(DEFAULT_ADMIN_ROLE, v2Factory.address)).to.be.true; - }); - }); - - describe('Roles', function () { - it('admin can add admin', async function () { - const {SimpleVaultFactory, user} = this; - - await SimpleVaultFactory.addAdmin(user.address); - expect(await SimpleVaultFactory.hasRole(DEFAULT_ADMIN_ROLE, user.address)); - }); - - it("3rd party can't add/deploy/remove tokens, add admin", async function () { - const {SimpleVaultFactory, Token1, user, someone} = this; - - await expect(SimpleVaultFactory.connect(user).addToken(Token1.address, MINT_PER_DEPLOYMENT)) - .to.be.reverted; - await expect( - SimpleVaultFactory.connect(user).deployAndAddToken('any', 'any', 18, MINT_PER_DEPLOYMENT) - ).to.be.reverted; - await expect(SimpleVaultFactory.connect(user).removeToken(Token1.address)).to.be.reverted; - await expect(SimpleVaultFactory.connect(user).addAdmin(someone)).to.be.reverted; - }); - }); - - describe('Vaults', function () { - beforeEach(async function () { - const {SimpleVaultFactory} = this; - - this.Token2 = await deployTokenGrantRoles( - SimpleVaultFactory, - TOKEN2_NAME, - TOKEN2_SYMBOL, - TOKEN2_DECIMALS - ); - }); - - it('vault can be deployed', async function () { - const {SimpleVaultFactory, broker} = this; - - const vaultName = 'vault name'; - const vaultAddress = (await deployVault(SimpleVaultFactory, vaultName, broker.address)) - .address; - - const VaultFactory = await ethers.getContractFactory('SimpleVault'); - const VaultContract = VaultFactory.attach(vaultAddress); - expect(await VaultContract.name()).to.be.equal(vaultName); - }); - - it('grants admin role of deployed Vault to deployer', async function () { - const {SimpleVaultFactory, owner, broker} = this; - - const vaultName = 'vault name'; - const vaultAddress = (await deployVault(SimpleVaultFactory, vaultName, broker.address)) - .address; - - const VaultFactory = await ethers.getContractFactory('SimpleVault'); - const VaultContract = VaultFactory.attach(vaultAddress); - expect(await VaultContract.hasRole(DEFAULT_ADMIN_ROLE, owner.address)).to.be.true; - }); - - it('adding new vault mints all tokens to it', async function () { - const {SimpleVaultFactory, Token1, Token2, broker} = this; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - await SimpleVaultFactory.addToken(Token2.address, MINT_PER_DEPLOYMENT); - - const vaultName = 'vault name'; - - const vaultAddress = (await deployVault(SimpleVaultFactory, vaultName, broker.address)) - .address; - expect(await Token1.balanceOf(vaultAddress)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - expect(await Token2.balanceOf(vaultAddress)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN2_DECIMALS) - ); - }); - - it('can deploy two vaults with the same name for the same broker', async function () { - const {SimpleVaultFactory, broker} = this; - - const vaultName = 'vault name'; - await SimpleVaultFactory.deployVault(vaultName, broker.address); - await expect(SimpleVaultFactory.deployVault(vaultName, broker.address)).not.to.be.reverted; - }); - - it('vault can be redeployed', async function () { - const {SimpleVaultFactory, broker, Token1} = this; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - - const vaultName = 'vault name'; - const OldVault = await deployVault(SimpleVaultFactory, vaultName, broker.address); - const NewVault = await redeployVault(SimpleVaultFactory, OldVault.address); - - // new Vault has the same name, but different address - expect(await NewVault.name()).to.be.equal(vaultName); - expect(OldVault.address).not.to.be.equal(NewVault.address); - - // old Vault has no tokens, but new one does - expect(await Token1.balanceOf(OldVault.address)).to.be.equal(0); - expect(await Token1.balanceOf(NewVault.address)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - }); - - it("can't redeploy unadded vault", async function () { - const {SimpleVaultFactory} = this; - - const unexistingVaultAddress = Wallet.createRandom().address; - await expect(SimpleVaultFactory.redeployVault(unexistingVaultAddress)).to.be.revertedWith( - 'vault is not present' - ); - }); - - it("can't redeploy vault not having admin role in it", async function () { - const {SimpleVaultFactory, broker, someone} = this; - - const vaultName = 'vault name'; - const OldVault = await deployVault(SimpleVaultFactory, vaultName, broker.address); - await expect( - SimpleVaultFactory.connect(someone).redeployVault(OldVault.address) - ).to.be.revertedWith('account is not vault admin'); - }); - - it('vault can be removed', async function () { - const {SimpleVaultFactory, broker, Token1} = this; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - - const vaultName = 'vault name'; - const OldVault = await deployVault(SimpleVaultFactory, vaultName, broker.address); - await SimpleVaultFactory.removeVault(OldVault.address); - - // removed Vault does not have any tokens added previously - expect(await Token1.balanceOf(OldVault.address)).to.be.equal(0); - }); - - it("can't remove unadded vault", async function () { - const {SimpleVaultFactory} = this; - - const unexistingVaultAddress = Wallet.createRandom().address; - await expect(SimpleVaultFactory.removeVault(unexistingVaultAddress)).to.be.revertedWith( - 'vault is not present' - ); - }); - - it("can't remove vault not having adming role in it", async function () { - const {SimpleVaultFactory, broker, someone} = this; - - const vaultName = 'vault name'; - const OldVault = await deployVault(SimpleVaultFactory, vaultName, broker.address); - await expect( - SimpleVaultFactory.connect(someone).removeVault(OldVault.address) - ).to.be.revertedWith('account is not vault admin'); - }); - }); - - describe('Tokens', function () { - it('token can be deployed', async function () { - const {SimpleVaultFactory} = this; - - const TokenContract = await deployAndAddToken( - SimpleVaultFactory, - TOKEN1_NAME, - TOKEN1_SYMBOL, - TOKEN1_DECIMALS, - MINT_PER_DEPLOYMENT - ); - - expect(await TokenContract.name()).to.be.equal(TOKEN1_NAME); - }); - - it('deploying token grants deployer admin role', async function () { - const {SimpleVaultFactory, owner} = this; - - const TokenContract = await deployAndAddToken( - SimpleVaultFactory, - TOKEN1_NAME, - TOKEN1_SYMBOL, - TOKEN1_DECIMALS, - MINT_PER_DEPLOYMENT - ); - - expect(await TokenContract.hasRole(DEFAULT_ADMIN_ROLE, owner.address)).to.be.true; - }); - - it('reverts when factory does not have minter & burner roles on token being added', async function () { - const {SimpleVaultFactory} = this; - - const TokenFactory = await ethers.getContractFactory('SimpleERC20'); - const Token = await TokenFactory.deploy(TOKEN1_NAME, TOKEN1_SYMBOL, TOKEN1_DECIMALS); - await Token.deployed(); - - await expect( - SimpleVaultFactory.addToken(Token.address, MINT_PER_DEPLOYMENT) - ).to.be.revertedWith('factory is not minter'); - await Token.grantRole(MINTER_ROLE, SimpleVaultFactory.address); - await expect( - SimpleVaultFactory.addToken(Token.address, MINT_PER_DEPLOYMENT) - ).to.be.revertedWith('factory is not burner'); - }); - - it('adding new token mints amount to vaults', async function () { - const {SimpleVaultFactory, Token1, broker} = this; - - const vault1Name = 'v1'; - const vault2Name = 'v2'; - - const vault1Address = (await deployVault(SimpleVaultFactory, vault1Name, broker.address)) - .address; - const vault2Address = (await deployVault(SimpleVaultFactory, vault2Name, broker.address)) - .address; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - - expect(await Token1.balanceOf(vault1Address)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - expect(await Token1.balanceOf(vault2Address)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - }); - - it('removing token burns tokens from vaults', async function () { - const {SimpleVaultFactory, Token1, broker} = this; - - const vault1Name = 'v1'; - const vault2Name = 'v2'; - - const vault1Address = (await deployVault(SimpleVaultFactory, vault1Name, broker.address)) - .address; - const vault2Address = (await deployVault(SimpleVaultFactory, vault2Name, broker.address)) - .address; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - - expect(await Token1.balanceOf(vault1Address)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - expect(await Token1.balanceOf(vault2Address)).to.be.equal( - parseUnits(MINT_PER_DEPLOYMENT.toString(), TOKEN1_DECIMALS) - ); - - await SimpleVaultFactory.removeToken(Token1.address); - - expect(await Token1.balanceOf(vault1Address)).to.be.equal(0); - expect(await Token1.balanceOf(vault2Address)).to.be.equal(0); - }); - - it('reverts on adding existing token', async function () { - const {SimpleVaultFactory, Token1} = this; - - await SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT); - await expect( - SimpleVaultFactory.addToken(Token1.address, MINT_PER_DEPLOYMENT) - ).to.be.revertedWith('token is already present'); - }); - - it('reverts on removing unexisted token', async function () { - const {SimpleVaultFactory, Token1} = this; - - await expect(SimpleVaultFactory.removeToken(Token1.address)).to.be.revertedWith( - 'token is not present' - ); - }); - }); -}); diff --git a/test/custody/SimpleVault.spec.ts b/test/custody/SimpleVault.spec.ts deleted file mode 100644 index 7629e42..0000000 --- a/test/custody/SimpleVault.spec.ts +++ /dev/null @@ -1,417 +0,0 @@ -/* eslint no-unused-expressions: 0 */ - -import {expect} from 'chai'; -import {ethers} from 'hardhat'; - -import { - BrokerRole, - DepositType, - WithdrawType, - depositWithPayload, - deposit, - generatePayload, - withdrawWithPayload, - approve, - getGasFee, -} from './common'; - -describe('SimpleVault Contract', function () { - beforeEach(async function () { - const [owner, user, broker, someone] = await ethers.getSigners(); - this.owner = owner; - this.user = user; - this.broker = broker; - this.someone = someone; - this.BrokerRole = BrokerRole; - this.DepositType = DepositType; - this.WithdrawType = WithdrawType; - - const vaultName = 'SimpleVault'; - const vaultFactory = await ethers.getContractFactory('SimpleVault'); - const vaultContract = await vaultFactory.deploy(vaultName, broker.address); - await vaultContract.deployed(); - this.vaultContract = vaultContract; - - const tokenFactory = await ethers.getContractFactory('TestERC20'); - const tokenContract = await tokenFactory.deploy( - 'TestToken', - 'TOK', - ethers.utils.parseEther('2000000') - ); - await tokenContract.deployed(); - this.tokenContract = tokenContract; - - await tokenContract.setUserBalance(user.address, ethers.utils.parseEther('100')); - }); - - it('has right admin', async function () { - const {owner, vaultContract} = this; - expect(await vaultContract.hasRole(ethers.constants.HashZero, owner.address)).to.equal(true); - }); - - it('has right broker', async function () { - const {broker, BrokerRole, vaultContract} = this; - expect(await vaultContract.hasRole(BrokerRole, broker.address)).to.equal(true); - }); - - it('can change broker', async function () { - const {broker, someone, BrokerRole, vaultContract} = this; - expect(await vaultContract.changeBroker(someone.address)).to.not.undefined; - expect(await vaultContract.hasRole(BrokerRole, someone.address)).to.equal(true); - expect(await vaultContract.hasRole(BrokerRole, broker.address)).to.equal(false); - }); - - it('can deposit token', async function () { - const {user, broker, vaultContract, tokenContract, DepositType} = this; - const amount = ethers.utils.parseEther('10'); - - await approve(user, vaultContract, tokenContract); - const initialETHBalance = await user.getBalance(); - const result = await deposit(user, DepositType, amount, broker, vaultContract, tokenContract); - const depositEvent = result.events.find((e: any) => e.event === 'Deposited'); - - expect(depositEvent).to.not.undefined; - expect(depositEvent.args.account).to.equal(user.address); - expect(depositEvent.args.asset).to.equal(tokenContract.address); - expect(depositEvent.args.amount).to.equal(amount); - - // check balance - expect(await user.getBalance()).to.equal(initialETHBalance.sub(getGasFee(result))); - }); - - it('can deposit eth', async function () { - const {user, broker, vaultContract, DepositType} = this; - const amount = ethers.utils.parseEther('10'); - - const initialETHBalance = await user.getBalance(); - const result = await deposit(user, DepositType, amount, broker, vaultContract, { - address: ethers.constants.AddressZero, - }); - const depositEvent = result.events.find((e: any) => e.event === 'Deposited'); - - expect(depositEvent).to.not.undefined; - expect(depositEvent.args.account).to.equal(user.address); - expect(depositEvent.args.asset).to.equal(ethers.constants.AddressZero); - expect(depositEvent.args.amount).to.equal(amount); - - // check balance - expect(await user.getBalance()).to.equal(initialETHBalance.sub(amount).sub(getGasFee(result))); - }); - - it('can fully withdraw token', async function () { - const {user, broker, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const amount = ethers.utils.parseEther('10'); - const initialTokenBalance = await tokenContract.balanceOf(user.address); - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, amount, broker, vaultContract, tokenContract); - - // withdraw - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount, - }); - const result = await withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract); - const withdrawEvent = result.events.find((e: any) => e.event === 'Withdrawn'); - - expect(withdrawEvent).to.not.undefined; - expect(withdrawEvent.args.id).to.equal(2); - expect(withdrawEvent.args.account).to.equal(user.address); - - // check balance - const finalBalance = await tokenContract.balanceOf(user.address); - expect(finalBalance).to.equal(initialTokenBalance); - }); - - it('can fully withdraw eth', async function () { - const {user, broker, WithdrawType, vaultContract, DepositType} = this; - const initialETHBalance = await user.getBalance(); - const amount = ethers.utils.parseEther('10'); - - const depositTx = await deposit(user, DepositType, amount, broker, vaultContract, { - address: ethers.constants.AddressZero, - }); - - // withdraw - const {payload} = generatePayload({ - destination: user.address, - asset: ethers.constants.AddressZero, - amount, - }); - const result = await withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract); - const withdrawEvent = result.events.find((e: any) => e.event === 'Withdrawn'); - - expect(withdrawEvent).to.not.undefined; - expect(withdrawEvent.args.id).to.equal(2); - expect(withdrawEvent.args.account).to.equal(user.address); - - // check balance - const finalBalance = await user.getBalance(); - expect(finalBalance).to.equal( - initialETHBalance.sub(amount).sub(getGasFee(depositTx)).add(amount).sub(getGasFee(result)) - ); - }); - - it('can partial withdraw', async function () { - const {user, broker, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.utils.parseEther('10'); - const firstWithdrawAmount = ethers.utils.parseEther('6'); - const secondWithdrawAmount = ethers.utils.parseEther('1'); - const initialETHBalance = await user.getBalance(); - const initialTokenBalance = await tokenContract.balanceOf(user.address); - - const approveTx = await approve(user, vaultContract, tokenContract); - const depositTokenTx = await deposit( - user, - DepositType, - depositAmount, - broker, - vaultContract, - tokenContract - ); - const depositETHTx = await deposit(user, DepositType, depositAmount, broker, vaultContract, { - address: ethers.constants.AddressZero, - }); - - // withdraw - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: firstWithdrawAmount, - }); - const withdrawTokenTx = await withdrawWithPayload( - user, - WithdrawType, - broker, - payload, - vaultContract - ); - const withdrawTokenEvent = withdrawTokenTx.events.find((e: any) => e.event === 'Withdrawn'); - - expect(withdrawTokenEvent).to.not.undefined; - - const {payload: secondPayload} = generatePayload({ - destination: user.address, - assets: [ - [tokenContract.address, secondWithdrawAmount.toString()], - [ethers.constants.AddressZero, secondWithdrawAmount.toString()], - ], - }); - const withdrawBothTx = await withdrawWithPayload( - user, - WithdrawType, - broker, - secondPayload, - vaultContract - ); - - const withdrawEvents = withdrawBothTx.events.filter((e: any) => e.event === 'Withdrawn'); - - expect(withdrawEvents.length).to.equal(2); - - // check balance - const finalETHBalance = await user.getBalance(); - const finalTokenBalance = await tokenContract.balanceOf(user.address); - expect(finalTokenBalance).to.equal( - initialTokenBalance.sub(depositAmount).add(firstWithdrawAmount).add(secondWithdrawAmount) - ); - expect(finalETHBalance).to.equal( - initialETHBalance - .sub(getGasFee(approveTx)) - .sub(getGasFee(depositTokenTx)) - .sub(depositAmount) - .sub(getGasFee(depositETHTx)) - .sub(getGasFee(withdrawTokenTx)) - .add(secondWithdrawAmount) - .sub(getGasFee(withdrawBothTx)) - ); - }); - - it('can not deposit with malicious broker', async function () { - const {user, broker, someone, DepositType, vaultContract, tokenContract} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const depositTo = someone; - - await approve(user, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: depositTo.address, - asset: tokenContract.address, - amount: depositAmount, - }); - - await expect( - depositWithPayload(user, DepositType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: invalid request'); - await expect( - depositWithPayload( - user, - ethers.utils.id('INVALID_REQUEST_TYPE'), - broker, - payload, - vaultContract, - false - ) - ).to.be.revertedWith('Vault: invalid signature'); - }); - - it('can not withdraw with malicious broker', async function () { - const {user, broker, someone, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const withdrawAmount = ethers.BigNumber.from('100'); - const withdrawTo = someone; - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: withdrawTo.address, - asset: tokenContract.address, - amount: withdrawAmount, - }); - await expect( - withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: invalid request'); - await expect( - withdrawWithPayload( - user, - ethers.utils.id('INVALID_REQUEST_TYPE'), - broker, - payload, - vaultContract, - false - ) - ).to.be.revertedWith('Vault: invalid signature'); - }); - - it('can not deposit with malicious user', async function () { - const {user, broker, someone, DepositType, vaultContract, tokenContract} = this; - const depositAmount = ethers.BigNumber.from('2000'); - - await approve(user, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: depositAmount, - }); - await expect( - depositWithPayload(someone, DepositType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: invalid request'); - }); - - it('can not withdraw with malicious user', async function () { - const {user, broker, someone, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const withdrawAmount = ethers.BigNumber.from('100'); - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: withdrawAmount, - }); - await expect( - withdrawWithPayload(someone, WithdrawType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: invalid request'); - }); - - it('can not deposit when timeout', async function () { - const {user, broker, DepositType, vaultContract, tokenContract} = this; - const depositAmount = ethers.BigNumber.from('2000'); - - await approve(user, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: depositAmount, - deadline: Date.now() - 60_000, - }); - await expect( - depositWithPayload(user, DepositType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: request is expired'); - }); - - it('can not withdraw when timeout', async function () { - const {user, broker, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const withdrawAmount = ethers.BigNumber.from('100'); - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - - const {payload} = generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: withdrawAmount, - deadline: Date.now() - 60_000, - }); - await expect( - withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: request is expired'); - }); - - it('can not deposit when repeat use of payload & signature', async function () { - const {user, broker, DepositType, vaultContract, tokenContract} = this; - const depositAmount = ethers.BigNumber.from('2000'); - - await approve(user, vaultContract, tokenContract); - - const {payload} = generatePayload({ - rid: ethers.utils.formatBytes32String('1'), - destination: user.address, - asset: tokenContract.address, - amount: depositAmount, - }); - await depositWithPayload(user, DepositType, broker, payload, vaultContract); - await expect( - depositWithPayload(user, DepositType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: signature has been used'); - }); - - it('can not withdraw when repeat use of payload & signature', async function () { - const {user, broker, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const withdrawAmount = ethers.BigNumber.from('100'); - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - - const {payload} = generatePayload({ - rid: ethers.utils.formatBytes32String('1'), - destination: user.address, - asset: tokenContract.address, - amount: withdrawAmount, - }); - await withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract); - await expect( - withdrawWithPayload(user, WithdrawType, broker, payload, vaultContract, false) - ).to.be.revertedWith('Vault: signature has been used'); - }); - - it('can getLastId()', async function () { - const {user, broker, WithdrawType, vaultContract, tokenContract, DepositType} = this; - const depositAmount = ethers.BigNumber.from('2000'); - const withdrawAmount = ethers.BigNumber.from('100'); - const getPayload = () => - generatePayload({ - destination: user.address, - asset: tokenContract.address, - amount: withdrawAmount, - }).payload; - - await approve(user, vaultContract, tokenContract); - await deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - expect(await vaultContract.getLastId()).to.equal(1); - await withdrawWithPayload(user, WithdrawType, broker, getPayload(), vaultContract); - expect(await vaultContract.getLastId()).to.equal(2); - const dTx = deposit(user, DepositType, depositAmount, broker, vaultContract, tokenContract); - const wTx = withdrawWithPayload(user, WithdrawType, broker, getPayload(), vaultContract); - await Promise.all([dTx, wTx]); - expect(await vaultContract.getLastId()).to.equal(4); - }); -}); diff --git a/test/custody/common.ts b/test/custody/common.ts deleted file mode 100644 index a2babfd..0000000 --- a/test/custody/common.ts +++ /dev/null @@ -1,90 +0,0 @@ -import {ethers} from 'hardhat'; - -export const BrokerRole = ethers.utils.id('CUSTODY_BROKER_ROLE'); -export const DepositType = ethers.utils.id('CUSTODY_DEPOSIT_TYPE'); -export const WithdrawType = ethers.utils.id('CUSTODY_WITHDRAW_TYPE'); - -export async function approve( - signer: any, - vaultContract: any, - tokenContract: any, - amount: any = ethers.constants.MaxUint256 -) { - const tx = await tokenContract.connect(signer).approve(vaultContract.address, amount); - return tx.wait(); -} - -export async function deposit( - signer: any, - action: string, - amount: any, - broker: any, - vaultContract: any, - tokenContract: any -) { - const {payload} = generatePayload({ - destination: signer.address, - asset: tokenContract.address, - amount, - }); - const ethAmount = tokenContract.address === ethers.constants.AddressZero ? amount : undefined; - return depositWithPayload(signer, action, broker, payload, vaultContract, true, {ethAmount}); -} - -export async function depositWithPayload( - signer: any, - action: string, - broker: any, - payload: any, - vaultContract: any, - wait = true, - override: any = {} -) { - const signature = override.signature || (await generateSignature(broker, action, payload)); - const tx = await vaultContract - .connect(signer) - .deposit(payload, signature, {value: override.ethAmount}); - return wait ? tx.wait() : tx; -} - -export async function withdrawWithPayload( - signer: any, - action: string, - broker: any, - payload: any, - vaultContract: any, - wait = true, - override: any = {} -) { - const signature = override.signature || (await generateSignature(broker, action, payload)); - const tx = await vaultContract.connect(signer).withdraw(payload, signature); - return wait ? tx.wait() : tx; -} - -export async function generateSignature(broker: any, action: string, payload: any) { - const message = ethers.utils.solidityKeccak256(['bytes32', 'bytes'], [action, payload]); - return broker.signMessage(ethers.utils.arrayify(message)); -} - -export function generatePayload({ - rid = ethers.utils.formatBytes32String(Math.random().toString(16)), - deadline = Date.now() + 600_000, - destination, - asset, - amount, - assets = [], -}: any) { - assets = assets.length ? assets : [[asset, amount.toString()]]; - const expire = Math.floor(deadline / 1000); - return { - data: {rid, deadline, destination, assets}, - payload: ethers.utils.defaultAbiCoder.encode( - ['bytes32', 'uint64', 'address', 'tuple(address, uint256)[]'], - [rid, expire, destination, assets] - ), - }; -} - -export function getGasFee(tx: any) { - return tx.gasUsed.mul(tx.effectiveGasPrice); -} From d44467935e83faf7cf71b0a82530f9fb6bb2fa7d Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 14:21:28 +0300 Subject: [PATCH 02/10] move vault --- contracts/{yellow => vault}/IVault.sol | 0 contracts/{yellow => vault}/VaultImplBase.sol | 0 contracts/{yellow => vault}/VaultImplV1.sol | 0 contracts/{yellow => vault}/VaultProxy.sol | 0 contracts/{yellow => vault}/VaultProxyBase.sol | 0 contracts/{yellow => vault}/test/TESTVaultProxy.sol | 0 contracts/{yellow => vault}/test/TESTVaultUpgradability1.sol | 0 contracts/{yellow => vault}/test/TESTVaultUpgradability2.sol | 0 contracts/{yellow => vault}/test/TESTVaultUpgradability3.sol | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename contracts/{yellow => vault}/IVault.sol (100%) rename contracts/{yellow => vault}/VaultImplBase.sol (100%) rename contracts/{yellow => vault}/VaultImplV1.sol (100%) rename contracts/{yellow => vault}/VaultProxy.sol (100%) rename contracts/{yellow => vault}/VaultProxyBase.sol (100%) rename contracts/{yellow => vault}/test/TESTVaultProxy.sol (100%) rename contracts/{yellow => vault}/test/TESTVaultUpgradability1.sol (100%) rename contracts/{yellow => vault}/test/TESTVaultUpgradability2.sol (100%) rename contracts/{yellow => vault}/test/TESTVaultUpgradability3.sol (100%) diff --git a/contracts/yellow/IVault.sol b/contracts/vault/IVault.sol similarity index 100% rename from contracts/yellow/IVault.sol rename to contracts/vault/IVault.sol diff --git a/contracts/yellow/VaultImplBase.sol b/contracts/vault/VaultImplBase.sol similarity index 100% rename from contracts/yellow/VaultImplBase.sol rename to contracts/vault/VaultImplBase.sol diff --git a/contracts/yellow/VaultImplV1.sol b/contracts/vault/VaultImplV1.sol similarity index 100% rename from contracts/yellow/VaultImplV1.sol rename to contracts/vault/VaultImplV1.sol diff --git a/contracts/yellow/VaultProxy.sol b/contracts/vault/VaultProxy.sol similarity index 100% rename from contracts/yellow/VaultProxy.sol rename to contracts/vault/VaultProxy.sol diff --git a/contracts/yellow/VaultProxyBase.sol b/contracts/vault/VaultProxyBase.sol similarity index 100% rename from contracts/yellow/VaultProxyBase.sol rename to contracts/vault/VaultProxyBase.sol diff --git a/contracts/yellow/test/TESTVaultProxy.sol b/contracts/vault/test/TESTVaultProxy.sol similarity index 100% rename from contracts/yellow/test/TESTVaultProxy.sol rename to contracts/vault/test/TESTVaultProxy.sol diff --git a/contracts/yellow/test/TESTVaultUpgradability1.sol b/contracts/vault/test/TESTVaultUpgradability1.sol similarity index 100% rename from contracts/yellow/test/TESTVaultUpgradability1.sol rename to contracts/vault/test/TESTVaultUpgradability1.sol diff --git a/contracts/yellow/test/TESTVaultUpgradability2.sol b/contracts/vault/test/TESTVaultUpgradability2.sol similarity index 100% rename from contracts/yellow/test/TESTVaultUpgradability2.sol rename to contracts/vault/test/TESTVaultUpgradability2.sol diff --git a/contracts/yellow/test/TESTVaultUpgradability3.sol b/contracts/vault/test/TESTVaultUpgradability3.sol similarity index 100% rename from contracts/yellow/test/TESTVaultUpgradability3.sol rename to contracts/vault/test/TESTVaultUpgradability3.sol From a68896a8e9a4f23ab923d268fc7edec3cc74f390 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 14:22:26 +0300 Subject: [PATCH 03/10] remove unused vault import, fix some comments --- contracts/yellow/YellowClearingBase.sol | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/contracts/yellow/YellowClearingBase.sol b/contracts/yellow/YellowClearingBase.sol index c9ee567..54c4c84 100644 --- a/contracts/yellow/YellowClearingBase.sol +++ b/contracts/yellow/YellowClearingBase.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.16; import '@openzeppelin/contracts/access/AccessControl.sol'; import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol'; -import './IVault.sol'; /** * @notice Base contract for Yellow Clearing. Responsible for all operations regarding Yellow Network. @@ -187,7 +186,7 @@ abstract contract YellowClearingBase is AccessControl { // REVIEW: change docs comment after checks are added /** - * @notice Suspend participantand set their status to Suspended. Emit `ParticipantStatusChanged` event. + * @notice Suspend participant and set their status to Suspended. Emit `ParticipantStatusChanged` event. * @dev Require AUDITOR_ROLE to invoke. Participant must be present and not migrated * @param participant Address of participant to suspend. */ @@ -225,7 +224,7 @@ abstract contract YellowClearingBase is AccessControl { } /** - * @notice Set participiant data to data supplied. Emit `ParticipantDataChanged` event. + * @notice Set participant data to data supplied. Emit `ParticipantDataChanged` event. * @dev Require REGISTRY_MAINTAINER_ROLE to invoke. Participant must not have been migrated. * @param participant Address of participant to set data of. * @param data Data to set. @@ -320,8 +319,8 @@ abstract contract YellowClearingBase is AccessControl { } /** - * @notice Internal logic of migrating participant data. Can be overriden to change. - * @dev Internal logic of migrating participant data. Can be overriden to change. + * @notice Internal logic of migrating participant data. Can be overridden to change. + * @dev Internal logic of migrating participant data. Can be overridden to change. * @param participant Address of participant to migrate data of. * @param data Participant data to migrate. */ From 4a818b6faaf9d329ccc082620025be7beee07c3e Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 14:28:54 +0300 Subject: [PATCH 04/10] fix comments --- contracts/vault/test/TESTVaultProxy.sol | 4 ++-- contracts/yellow/test/TESTYellowClearingV1.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/vault/test/TESTVaultProxy.sol b/contracts/vault/test/TESTVaultProxy.sol index e58967d..4e3ca77 100644 --- a/contracts/vault/test/TESTVaultProxy.sol +++ b/contracts/vault/test/TESTVaultProxy.sol @@ -7,7 +7,7 @@ import '../VaultProxyBase.sol'; * @dev Use for TEST PURPOSES ONLY. !!! Contains security vulnerability !!! */ contract TESTVaultProxy is VaultProxyBase { - constructor(address startImplementation) VaultProxyBase(VaultImplBase(startImplementation)) {} - // SECUTIRY VULNERABILITY HERE ^^^ + constructor(address startImplementation) VaultProxyBase(startImplementation) {} + // SECURITY VULNERABILITY HERE ^^^ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } diff --git a/contracts/yellow/test/TESTYellowClearingV1.sol b/contracts/yellow/test/TESTYellowClearingV1.sol index 6eadefc..e69d164 100644 --- a/contracts/yellow/test/TESTYellowClearingV1.sol +++ b/contracts/yellow/test/TESTYellowClearingV1.sol @@ -8,7 +8,7 @@ import '../YellowClearingBase.sol'; */ contract TESTYellowClearingV1 is YellowClearingBase { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // SECUTIRY VULNERABILITY HERE \/ \/ \/ + // SECURITY VULNERABILITY HERE \/ \/ \/ constructor(YellowClearingBase previousImplementation) YellowClearingBase(previousImplementation) {} From a7acf1ac5295933677054565f2b2e1560e491334 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 15:38:30 +0300 Subject: [PATCH 05/10] structurize tests and src --- .../deploy-clearing-renounce-roles.ts | 0 scripts/export-accounts.ts | 5 +- scripts/{yellow => }/sign-self.ts | 2 +- .../deploy-vault-impl-renounce-roles.ts | 0 src/FactoryHelpers.ts | 69 ------------------- {test/yellow/src => src}/event-names.ts | 0 {test/yellow/src => src}/revert-reasons.ts | 0 {test/yellow/src => src}/signatures.ts | 0 {test/yellow/src => src}/signers.ts | 0 .../NetworkRegistry.spec.ts | 18 ++--- .../src}/deploy.ts | 2 +- .../src}/participantData.ts | 0 .../src}/transactions.ts | 2 +- test/{yellow => vault}/VaultImplV1.spec.ts | 19 +++-- .../VaultUpgradability.spec.ts | 0 .../src/VaultImpl => vault/src}/deploy.ts | 4 +- .../src/VaultImpl => vault/src}/payload.ts | 0 .../VaultImpl => vault/src}/transactions.ts | 0 18 files changed, 28 insertions(+), 93 deletions(-) rename scripts/{yellow => clearing}/deploy-clearing-renounce-roles.ts (100%) rename scripts/{yellow => }/sign-self.ts (92%) rename scripts/{yellow => vault}/deploy-vault-impl-renounce-roles.ts (100%) delete mode 100644 src/FactoryHelpers.ts rename {test/yellow/src => src}/event-names.ts (100%) rename {test/yellow/src => src}/revert-reasons.ts (100%) rename {test/yellow/src => src}/signatures.ts (100%) rename {test/yellow/src => src}/signers.ts (100%) rename test/{yellow => clearing}/NetworkRegistry.spec.ts (98%) rename test/{yellow/src/NetworkRegistry => clearing/src}/deploy.ts (97%) rename test/{yellow/src/NetworkRegistry => clearing/src}/participantData.ts (100%) rename test/{yellow/src/NetworkRegistry => clearing/src}/transactions.ts (90%) rename test/{yellow => vault}/VaultImplV1.spec.ts (98%) rename test/{yellow => vault}/VaultUpgradability.spec.ts (100%) rename test/{yellow/src/VaultImpl => vault/src}/deploy.ts (97%) rename test/{yellow/src/VaultImpl => vault/src}/payload.ts (100%) rename test/{yellow/src/VaultImpl => vault/src}/transactions.ts (100%) diff --git a/scripts/yellow/deploy-clearing-renounce-roles.ts b/scripts/clearing/deploy-clearing-renounce-roles.ts similarity index 100% rename from scripts/yellow/deploy-clearing-renounce-roles.ts rename to scripts/clearing/deploy-clearing-renounce-roles.ts diff --git a/scripts/export-accounts.ts b/scripts/export-accounts.ts index b3e25c3..5a6811a 100644 --- a/scripts/export-accounts.ts +++ b/scripts/export-accounts.ts @@ -61,7 +61,10 @@ async function main() { accounts.push({privateKey, address}); } - writeFileSync(__dirname + '/../deployments/accounts.json', JSON.stringify(accounts, null, 2)); + writeFileSync( + __dirname + '/../addresses/hardhat-accounts.json', + JSON.stringify(accounts, null, 2) + ); } main().catch((error) => { diff --git a/scripts/yellow/sign-self.ts b/scripts/sign-self.ts similarity index 92% rename from scripts/yellow/sign-self.ts rename to scripts/sign-self.ts index 7baf7d5..2794964 100644 --- a/scripts/yellow/sign-self.ts +++ b/scripts/sign-self.ts @@ -2,7 +2,7 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {Signer} from 'ethers'; import {ethers} from 'hardhat'; -import {signSelf} from '../../test/yellow/src/signatures'; +import {signSelf} from '../src/signatures'; async function main() { const provider = ethers.provider; diff --git a/scripts/yellow/deploy-vault-impl-renounce-roles.ts b/scripts/vault/deploy-vault-impl-renounce-roles.ts similarity index 100% rename from scripts/yellow/deploy-vault-impl-renounce-roles.ts rename to scripts/vault/deploy-vault-impl-renounce-roles.ts diff --git a/src/FactoryHelpers.ts b/src/FactoryHelpers.ts deleted file mode 100644 index 65df4f5..0000000 --- a/src/FactoryHelpers.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import {ethers} from 'hardhat'; - -import {SimpleVaultFactory} from '../typechain'; - -export const DEFAULT_ADMIN_ROLE = ethers.constants.HashZero; -export const MINTER_ROLE = ethers.utils.id('MINTER_ROLE'); -export const BURNER_ROLE = ethers.utils.id('BURNER_ROLE'); - -export async function deployVault( - SimpleVaultFactory: SimpleVaultFactory, - vaultName: string, - broker: string -) { - const tx = await SimpleVaultFactory.deployVault(vaultName, broker); - const result = await tx.wait(); - const vaultDeployedEv = result.events!.find((e) => e.event === 'VaultDeployed'); - const vaultAddress = vaultDeployedEv!.args!.vaultAddress; - - const VaultFactory = await ethers.getContractFactory('SimpleVault'); - return VaultFactory.attach(vaultAddress); -} - -export async function redeployVault(SimpleVaultFactory: SimpleVaultFactory, vault: string) { - const tx = await SimpleVaultFactory.redeployVault(vault); - const result = await tx.wait(); - const vaultDeployedEv = result.events!.find((e) => e.event === 'VaultDeployed'); - const vaultAddress = vaultDeployedEv!.args!.vaultAddress; - - const VaultFactory = await ethers.getContractFactory('SimpleVault'); - return VaultFactory.attach(vaultAddress); -} - -export async function deployAndAddToken( - SimpleVaultFactory: SimpleVaultFactory, - name: string, - symbol: string, - decimals: number, - mint_per_deployment: number -) { - const tx = await SimpleVaultFactory.deployAndAddToken( - name, - symbol, - decimals, - mint_per_deployment - ); - const result = await tx.wait(); - const tokenDeoloyedEv = result.events!.find((e) => e.event === 'TokenDeployed'); - const tokenAddress = tokenDeoloyedEv!.args!.tokenAddress; - - const TokenFactory = await ethers.getContractFactory('SimpleERC20'); - return TokenFactory.attach(tokenAddress); -} - -export async function deployTokenGrantRoles( - SimpleVaultFactory: SimpleVaultFactory, - name: string, - symbol: string, - decimals: number -) { - const TokenFactory = await ethers.getContractFactory('SimpleERC20'); - const Token = await TokenFactory.deploy(name, symbol, decimals); - await Token.deployed(); - - await Token.grantRole(MINTER_ROLE, SimpleVaultFactory.address); - await Token.grantRole(BURNER_ROLE, SimpleVaultFactory.address); - - return Token; -} diff --git a/test/yellow/src/event-names.ts b/src/event-names.ts similarity index 100% rename from test/yellow/src/event-names.ts rename to src/event-names.ts diff --git a/test/yellow/src/revert-reasons.ts b/src/revert-reasons.ts similarity index 100% rename from test/yellow/src/revert-reasons.ts rename to src/revert-reasons.ts diff --git a/test/yellow/src/signatures.ts b/src/signatures.ts similarity index 100% rename from test/yellow/src/signatures.ts rename to src/signatures.ts diff --git a/test/yellow/src/signers.ts b/src/signers.ts similarity index 100% rename from test/yellow/src/signers.ts rename to src/signers.ts diff --git a/test/yellow/NetworkRegistry.spec.ts b/test/clearing/NetworkRegistry.spec.ts similarity index 98% rename from test/yellow/NetworkRegistry.spec.ts rename to test/clearing/NetworkRegistry.spec.ts index fee3ead..0097998 100644 --- a/test/yellow/NetworkRegistry.spec.ts +++ b/test/clearing/NetworkRegistry.spec.ts @@ -4,13 +4,6 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {ethers} from 'hardhat'; import {TESTYellowClearingV1, TESTYellowClearingV2, TESTYellowClearingV3} from '../../typechain'; - -import { - deployAndLinkNextRegistry, - deployNextRegistry, - deployRegistry, -} from './src/NetworkRegistry/deploy'; -import {MockData, setParticipantStatus, Status} from './src/NetworkRegistry/participantData'; import { ACCOUNT_MISSING_ROLE, INVALID_NEXT_IMPL, @@ -23,9 +16,8 @@ import { PREV_IMPL_ROLE_REQUIRED, INVALID_SIGNER, INVALID_STATUS, -} from './src/revert-reasons'; -import {migrateParams, registerParams} from './src/NetworkRegistry/transactions'; -import {signEncoded} from './src/signatures'; +} from '../../src/revert-reasons'; +import {signEncoded} from '../../src/signatures'; import { NEXT_IMPL_SET, PARTICIPANT_DATA_SET, @@ -33,7 +25,11 @@ import { PARTICIPANT_MIGRATED_TO, PARTICIPANT_REGISTERED, PARTICIPANT_STATUS_CHANGED, -} from './src/event-names'; +} from '../../src/event-names'; + +import {deployAndLinkNextRegistry, deployNextRegistry, deployRegistry} from './src/deploy'; +import {MockData, setParticipantStatus, Status} from './src/participantData'; +import {migrateParams, registerParams} from './src/transactions'; const AddressZero = ethers.constants.AddressZero; const ADM_ROLE = ethers.constants.HashZero; diff --git a/test/yellow/src/NetworkRegistry/deploy.ts b/test/clearing/src/deploy.ts similarity index 97% rename from test/yellow/src/NetworkRegistry/deploy.ts rename to test/clearing/src/deploy.ts index 8782284..6cc1d6b 100644 --- a/test/yellow/src/NetworkRegistry/deploy.ts +++ b/test/clearing/src/deploy.ts @@ -1,7 +1,7 @@ import {Signer} from 'ethers'; import {ethers} from 'hardhat'; -import {YellowClearingBase} from '../../../../typechain'; +import {YellowClearingBase} from '../../../typechain'; const AddressZero = ethers.constants.AddressZero; diff --git a/test/yellow/src/NetworkRegistry/participantData.ts b/test/clearing/src/participantData.ts similarity index 100% rename from test/yellow/src/NetworkRegistry/participantData.ts rename to test/clearing/src/participantData.ts diff --git a/test/yellow/src/NetworkRegistry/transactions.ts b/test/clearing/src/transactions.ts similarity index 90% rename from test/yellow/src/NetworkRegistry/transactions.ts rename to test/clearing/src/transactions.ts index 38b91de..81e11d7 100644 --- a/test/yellow/src/NetworkRegistry/transactions.ts +++ b/test/clearing/src/transactions.ts @@ -1,6 +1,6 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; -import {signSelf} from '../signatures'; +import {signSelf} from '../../../src/signatures'; export type registerParams = [string, string]; diff --git a/test/yellow/VaultImplV1.spec.ts b/test/vault/VaultImplV1.spec.ts similarity index 98% rename from test/yellow/VaultImplV1.spec.ts rename to test/vault/VaultImplV1.spec.ts index 4bfc8e1..e4ac8e7 100644 --- a/test/yellow/VaultImplV1.spec.ts +++ b/test/vault/VaultImplV1.spec.ts @@ -3,9 +3,8 @@ import {Contract, providers, utils} from 'ethers'; import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {ethers} from 'hardhat'; -import VaultImplArtifact from '../../artifacts/contracts/yellow/VaultImplV1.sol/VaultImplV1.json'; -import {VaultImplV1 as VaultImplT, TESTVaultProxy, TestERC20, VaultImplV1} from '../../typechain'; - +import VaultImplArtifact from '../../artifacts/contracts/vault/VaultImplV1.sol/VaultImplV1.json'; +import {VaultImplV1 as VaultImplT, TESTVaultProxy, TestERC20} from '../../typechain'; import { ACCOUNT_MISSING_ROLE, INVALID_ADDRESS, @@ -19,10 +18,16 @@ import { AMOUNT_ZERO, INVALID_IMPL_ADDRESS, INVALID_CHAIN_ID, -} from './src/revert-reasons'; -import {depositParams, setAddressParams, withdrawParams} from './src/VaultImpl/transactions'; -import {BROKER_ADDRESS_SET, COSIGNER_ADDRESS_SET, DEPOSITED, WITHDRAWN} from './src/event-names'; -import {addAllocation, generalPayload, PartialPayload} from './src/VaultImpl/payload'; +} from '../../src/revert-reasons'; +import { + BROKER_ADDRESS_SET, + COSIGNER_ADDRESS_SET, + DEPOSITED, + WITHDRAWN, +} from '../../src/event-names'; + +import {depositParams, setAddressParams, withdrawParams} from './src/transactions'; +import {addAllocation, generalPayload, PartialPayload} from './src/payload'; const AddressZero = ethers.constants.AddressZero; const ADM_ROLE = ethers.constants.HashZero; diff --git a/test/yellow/VaultUpgradability.spec.ts b/test/vault/VaultUpgradability.spec.ts similarity index 100% rename from test/yellow/VaultUpgradability.spec.ts rename to test/vault/VaultUpgradability.spec.ts diff --git a/test/yellow/src/VaultImpl/deploy.ts b/test/vault/src/deploy.ts similarity index 97% rename from test/yellow/src/VaultImpl/deploy.ts rename to test/vault/src/deploy.ts index be438b2..7ad48f6 100644 --- a/test/yellow/src/VaultImpl/deploy.ts +++ b/test/vault/src/deploy.ts @@ -2,8 +2,8 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {Contract} from 'ethers'; import {ethers} from 'hardhat'; -import {VaultImplBase, VaultImplV1, VaultProxyBase} from '../../../../typechain'; -import {randomSignerWithAddress} from '../signers'; +import {randomSignerWithAddress} from '../../../src/signers'; +import {VaultImplBase, VaultImplV1, VaultProxyBase} from '../../../typechain'; // TODO: add functions and use them in `VaultUpgradability.spec.ts` and `VaultImplV1.spec.ts` diff --git a/test/yellow/src/VaultImpl/payload.ts b/test/vault/src/payload.ts similarity index 100% rename from test/yellow/src/VaultImpl/payload.ts rename to test/vault/src/payload.ts diff --git a/test/yellow/src/VaultImpl/transactions.ts b/test/vault/src/transactions.ts similarity index 100% rename from test/yellow/src/VaultImpl/transactions.ts rename to test/vault/src/transactions.ts From b65fffb9e4bec6ad6b82dda7c9fa631ad895b442 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 15:39:04 +0300 Subject: [PATCH 06/10] clearing extracted --- contracts/{yellow => clearing}/YellowClearingBase.sol | 0 contracts/{yellow => clearing}/YellowClearingV1.sol | 0 contracts/{yellow => clearing}/test/TESTYellowClearingV1.sol | 0 contracts/{yellow => clearing}/test/TESTYellowClearingV2.sol | 0 contracts/{yellow => clearing}/test/TESTYellowClearingV3.sol | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename contracts/{yellow => clearing}/YellowClearingBase.sol (100%) rename contracts/{yellow => clearing}/YellowClearingV1.sol (100%) rename contracts/{yellow => clearing}/test/TESTYellowClearingV1.sol (100%) rename contracts/{yellow => clearing}/test/TESTYellowClearingV2.sol (100%) rename contracts/{yellow => clearing}/test/TESTYellowClearingV3.sol (100%) diff --git a/contracts/yellow/YellowClearingBase.sol b/contracts/clearing/YellowClearingBase.sol similarity index 100% rename from contracts/yellow/YellowClearingBase.sol rename to contracts/clearing/YellowClearingBase.sol diff --git a/contracts/yellow/YellowClearingV1.sol b/contracts/clearing/YellowClearingV1.sol similarity index 100% rename from contracts/yellow/YellowClearingV1.sol rename to contracts/clearing/YellowClearingV1.sol diff --git a/contracts/yellow/test/TESTYellowClearingV1.sol b/contracts/clearing/test/TESTYellowClearingV1.sol similarity index 100% rename from contracts/yellow/test/TESTYellowClearingV1.sol rename to contracts/clearing/test/TESTYellowClearingV1.sol diff --git a/contracts/yellow/test/TESTYellowClearingV2.sol b/contracts/clearing/test/TESTYellowClearingV2.sol similarity index 100% rename from contracts/yellow/test/TESTYellowClearingV2.sol rename to contracts/clearing/test/TESTYellowClearingV2.sol diff --git a/contracts/yellow/test/TESTYellowClearingV3.sol b/contracts/clearing/test/TESTYellowClearingV3.sol similarity index 100% rename from contracts/yellow/test/TESTYellowClearingV3.sol rename to contracts/clearing/test/TESTYellowClearingV3.sol From cc40cacff772e7e6556c1054efdfe7a86989b6e9 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 15:39:17 +0300 Subject: [PATCH 07/10] move and rename accounts --- deployments/accounts.json => addresses/hardhat-accounts.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deployments/accounts.json => addresses/hardhat-accounts.json (100%) diff --git a/deployments/accounts.json b/addresses/hardhat-accounts.json similarity index 100% rename from deployments/accounts.json rename to addresses/hardhat-accounts.json From 5d8985c3e2f1b0fe394127cc153f6843cefbdbdd Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 17:45:56 +0300 Subject: [PATCH 08/10] fix constructor argument type --- contracts/vault/test/TESTVaultProxy.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/vault/test/TESTVaultProxy.sol b/contracts/vault/test/TESTVaultProxy.sol index 4e3ca77..97d3cf1 100644 --- a/contracts/vault/test/TESTVaultProxy.sol +++ b/contracts/vault/test/TESTVaultProxy.sol @@ -2,12 +2,13 @@ pragma solidity 0.8.16; import '../VaultProxyBase.sol'; +import '../VaultImplBase.sol'; /** * @dev Use for TEST PURPOSES ONLY. !!! Contains security vulnerability !!! */ contract TESTVaultProxy is VaultProxyBase { - constructor(address startImplementation) VaultProxyBase(startImplementation) {} + constructor(VaultImplBase startImplementation) VaultProxyBase(startImplementation) {} // SECURITY VULNERABILITY HERE ^^^ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } From e4e73a57b78612cebbcc11e90602ca15767f2c5b Mon Sep 17 00:00:00 2001 From: nksazonov Date: Fri, 14 Oct 2022 17:46:04 +0300 Subject: [PATCH 09/10] fix tests imports --- test/clearing/src/participantData.ts | 2 +- test/vault/VaultUpgradability.spec.ts | 11 +++++------ test/vault/src/payload.ts | 2 +- test/vault/src/transactions.ts | 2 +- test/yellow/Yellow.spec.ts | 24 +++++++++++++----------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/test/clearing/src/participantData.ts b/test/clearing/src/participantData.ts index ee9fb12..32e80b3 100644 --- a/test/clearing/src/participantData.ts +++ b/test/clearing/src/participantData.ts @@ -1,7 +1,7 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {BigNumber} from 'ethers'; -import {YellowClearingBase} from '../../../../typechain'; +import {YellowClearingBase} from '../../../typechain'; export enum Status { None, diff --git a/test/vault/VaultUpgradability.spec.ts b/test/vault/VaultUpgradability.spec.ts index 57af939..96268e1 100644 --- a/test/vault/VaultUpgradability.spec.ts +++ b/test/vault/VaultUpgradability.spec.ts @@ -3,10 +3,9 @@ import {Contract, Wallet} from 'ethers'; import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {ethers} from 'hardhat'; -import TESTVaultUpgradability1Artifact from '../../artifacts/contracts/yellow/test/TESTVaultUpgradability1.sol/TESTVaultUpgradability1.json'; -import TESTVaultUpgradability2Artifact from '../../artifacts/contracts/yellow/test/TESTVaultUpgradability2.sol/TESTVaultUpgradability2.json'; -import TESTVaultUpgradability3Artifact from '../../artifacts/contracts/yellow/test/TESTVaultUpgradability3.sol/TESTVaultUpgradability3.json'; - +import TESTVaultUpgradability1Artifact from '../../artifacts/contracts/vault/test/TESTVaultUpgradability1.sol/TESTVaultUpgradability1.json'; +import TESTVaultUpgradability2Artifact from '../../artifacts/contracts/vault/test/TESTVaultUpgradability2.sol/TESTVaultUpgradability2.json'; +import TESTVaultUpgradability3Artifact from '../../artifacts/contracts/vault/test/TESTVaultUpgradability3.sol/TESTVaultUpgradability3.json'; import { ALREADY_INITIALIZED, ALREADY_MIGRATED, @@ -18,8 +17,8 @@ import { NOT_MAINTAINER, INVALID_NEXT_IMPL, ACCOUNT_MISSING_ROLE, -} from './src/revert-reasons'; -import {NEXT_IMPL_SET, ROLE_GRANTED, UPGRADED} from './src/event-names'; +} from '../../src/revert-reasons'; +import {NEXT_IMPL_SET, ROLE_GRANTED, UPGRADED} from '../../src/event-names'; const AddressZero = ethers.constants.AddressZero; const ADM_ROLE = ethers.constants.HashZero; diff --git a/test/vault/src/payload.ts b/test/vault/src/payload.ts index 398fcfe..ec92b03 100644 --- a/test/vault/src/payload.ts +++ b/test/vault/src/payload.ts @@ -3,7 +3,7 @@ import {utils} from 'ethers'; import {ParamType} from 'ethers/lib/utils'; import {ethers} from 'hardhat'; -import {signEncoded} from '../signatures'; +import {signEncoded} from '../../../src/signatures'; // keccak256('YELLOW_VAULT_DEPOSIT_ACTION'); export const DEPOSIT_ACTION = '0xa2d4613c2e2e0782566f63085acedcb19fbd37900464a8316040997ccd6e9fea'; diff --git a/test/vault/src/transactions.ts b/test/vault/src/transactions.ts index 9104632..d79760f 100644 --- a/test/vault/src/transactions.ts +++ b/test/vault/src/transactions.ts @@ -1,7 +1,7 @@ import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers'; import {utils, Signer} from 'ethers'; -import {signEncoded} from '../signatures'; +import {signEncoded} from '../../../src/signatures'; import { PartialPayload, diff --git a/test/yellow/Yellow.spec.ts b/test/yellow/Yellow.spec.ts index 97c80fb..06c840b 100644 --- a/test/yellow/Yellow.spec.ts +++ b/test/yellow/Yellow.spec.ts @@ -109,19 +109,21 @@ describe('Yellow Contract', function () { expect(await yellowContract.balanceOf(user.address)).to.equal(initialAmount.sub(burnAmount)); // burnFrom - await expect(yellowContract.connect(someone).burnFrom(user.address, burnAmount)).to.be.revertedWith( - insufficientAllowanceError() - ); - expect(await yellowContract.connect(user).approve(someone.address, burnAmount)).to.not.be.undefined; - expect(await yellowContract.connect(someone).burnFrom(user.address, burnAmount)).to.not.be.undefined; - await expect(yellowContract.connect(someone).burnFrom(user.address, burnAmount)).to.be.revertedWith( - insufficientAllowanceError() - ); + await expect( + yellowContract.connect(someone).burnFrom(user.address, burnAmount) + ).to.be.revertedWith(insufficientAllowanceError()); + expect(await yellowContract.connect(user).approve(someone.address, burnAmount)).to.not.be + .undefined; + expect(await yellowContract.connect(someone).burnFrom(user.address, burnAmount)).to.not.be + .undefined; + await expect( + yellowContract.connect(someone).burnFrom(user.address, burnAmount) + ).to.be.revertedWith(insufficientAllowanceError()); expect(await yellowContract.balanceOf(user.address)).to.equal( initialAmount.sub(burnAmount).sub(burnAmount) ); - await expect(yellowContract.connect(user).burnFrom(user.address, burnAmount)).to.be.revertedWith( - insufficientAllowanceError() - ); + await expect( + yellowContract.connect(user).burnFrom(user.address, burnAmount) + ).to.be.revertedWith(insufficientAllowanceError()); }); }); From 2a4b967787d303b4fb4114c79540dba1f7fa7081 Mon Sep 17 00:00:00 2001 From: nksazonov Date: Mon, 17 Oct 2022 12:06:57 +0300 Subject: [PATCH 10/10] apply comment suggestions --- .openzeppelin/rinkeby.json | 365 -------------------------------- addresses/hardhat-accounts.json | 82 ------- 2 files changed, 447 deletions(-) delete mode 100644 .openzeppelin/rinkeby.json delete mode 100644 addresses/hardhat-accounts.json diff --git a/.openzeppelin/rinkeby.json b/.openzeppelin/rinkeby.json deleted file mode 100644 index 9da7208..0000000 --- a/.openzeppelin/rinkeby.json +++ /dev/null @@ -1,365 +0,0 @@ -{ - "manifestVersion": "3.2", - "admin": { - "address": "0xB492F2F6335537D3490CcB56971Dfd669508317A" - }, - "proxies": [ - { - "address": "0xfd77f1c1a0df7dfab9bcd9d8c67033f127a69a75", - "kind": "transparent" - } - ], - "impls": { - "d0187ee00520d32d90d92487d002c5b8d086d835f7a60b512c4e34812bbfe82d": { - "address": "0x2FEc650422aa927297Ff3c5d2a7E2e2Cacf1958c", - "layout": { - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:39" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:44" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC165Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" - }, - { - "label": "_roles", - "offset": 0, - "slot": "101", - "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:235" - }, - { - "label": "brokerAndVaultArr", - "offset": 0, - "slot": "151", - "type": "t_array(t_struct(BrokerAndVault)5002_storage)dyn_storage", - "contract": "SimpleVaultFactory", - "src": "contracts/custody-factory/SimpleVaultFactory.sol:18" - }, - { - "label": "tokenAndMintArr", - "offset": 0, - "slot": "152", - "type": "t_array(t_struct(TokenAndMint)5008_storage)dyn_storage", - "contract": "SimpleVaultFactory", - "src": "contracts/custody-factory/SimpleVaultFactory.sol:25" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(BrokerAndVault)5002_storage)dyn_storage": { - "label": "struct ISimpleVaultFactory.BrokerAndVault[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(TokenAndMint)5008_storage)dyn_storage": { - "label": "struct ISimpleVaultFactory.TokenAndMint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_contract(SimpleERC20)5132": { - "label": "contract SimpleERC20", - "numberOfBytes": "20" - }, - "t_contract(SimpleVault)6485": { - "label": "contract SimpleVault", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { - "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", - "numberOfBytes": "32" - }, - "t_struct(BrokerAndVault)5002_storage": { - "label": "struct ISimpleVaultFactory.BrokerAndVault", - "members": [ - { - "label": "broker", - "type": "t_address", - "offset": 0, - "slot": "0" - }, - { - "label": "vault", - "type": "t_contract(SimpleVault)6485", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_struct(RoleData)179_storage": { - "label": "struct AccessControlUpgradeable.RoleData", - "members": [ - { - "label": "members", - "type": "t_mapping(t_address,t_bool)", - "offset": 0, - "slot": "0" - }, - { - "label": "adminRole", - "type": "t_bytes32", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_struct(TokenAndMint)5008_storage": { - "label": "struct ISimpleVaultFactory.TokenAndMint", - "members": [ - { - "label": "token", - "type": "t_contract(SimpleERC20)5132", - "offset": 0, - "slot": "0" - }, - { - "label": "mint_per_deployment", - "type": "t_uint256", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - } - } - } - }, - "f0935a382f6bd75cd63a3538437680954e5a12f0882afca5395f6a1f2b863177": { - "address": "0x29E2440D6e90cCafe6F1E0BB862Dd554666941aD", - "txHash": "0xaff2cc2de7a8cfa53eb656d4e92721ef63282fe20f9521110ff7bb8694559fb3", - "layout": { - "storage": [ - { - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:39" - }, - { - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "t_bool", - "contract": "Initializable", - "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:44" - }, - { - "label": "__gap", - "offset": 0, - "slot": "1", - "type": "t_array(t_uint256)50_storage", - "contract": "ContextUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" - }, - { - "label": "__gap", - "offset": 0, - "slot": "51", - "type": "t_array(t_uint256)50_storage", - "contract": "ERC165Upgradeable", - "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" - }, - { - "label": "_roles", - "offset": 0, - "slot": "101", - "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" - }, - { - "label": "__gap", - "offset": 0, - "slot": "102", - "type": "t_array(t_uint256)49_storage", - "contract": "AccessControlUpgradeable", - "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:235" - }, - { - "label": "brokerAndVaultArr", - "offset": 0, - "slot": "151", - "type": "t_array(t_struct(BrokerAndVault)5002_storage)dyn_storage", - "contract": "SimpleVaultFactory", - "src": "contracts/custody-factory/SimpleVaultFactory.sol:18" - }, - { - "label": "tokenAndMintArr", - "offset": 0, - "slot": "152", - "type": "t_array(t_struct(TokenAndMint)5008_storage)dyn_storage", - "contract": "SimpleVaultFactory", - "src": "contracts/custody-factory/SimpleVaultFactory.sol:25" - } - ], - "types": { - "t_address": { - "label": "address", - "numberOfBytes": "20" - }, - "t_array(t_struct(BrokerAndVault)5002_storage)dyn_storage": { - "label": "struct ISimpleVaultFactory.BrokerAndVault[]", - "numberOfBytes": "32" - }, - "t_array(t_struct(TokenAndMint)5008_storage)dyn_storage": { - "label": "struct ISimpleVaultFactory.TokenAndMint[]", - "numberOfBytes": "32" - }, - "t_array(t_uint256)49_storage": { - "label": "uint256[49]", - "numberOfBytes": "1568" - }, - "t_array(t_uint256)50_storage": { - "label": "uint256[50]", - "numberOfBytes": "1600" - }, - "t_bool": { - "label": "bool", - "numberOfBytes": "1" - }, - "t_bytes32": { - "label": "bytes32", - "numberOfBytes": "32" - }, - "t_contract(SimpleERC20)5132": { - "label": "contract SimpleERC20", - "numberOfBytes": "20" - }, - "t_contract(SimpleVault)6605": { - "label": "contract SimpleVault", - "numberOfBytes": "20" - }, - "t_mapping(t_address,t_bool)": { - "label": "mapping(address => bool)", - "numberOfBytes": "32" - }, - "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { - "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", - "numberOfBytes": "32" - }, - "t_struct(BrokerAndVault)5002_storage": { - "label": "struct ISimpleVaultFactory.BrokerAndVault", - "members": [ - { - "label": "broker", - "type": "t_address", - "offset": 0, - "slot": "0" - }, - { - "label": "vault", - "type": "t_contract(SimpleVault)6605", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_struct(RoleData)179_storage": { - "label": "struct AccessControlUpgradeable.RoleData", - "members": [ - { - "label": "members", - "type": "t_mapping(t_address,t_bool)", - "offset": 0, - "slot": "0" - }, - { - "label": "adminRole", - "type": "t_bytes32", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_struct(TokenAndMint)5008_storage": { - "label": "struct ISimpleVaultFactory.TokenAndMint", - "members": [ - { - "label": "token", - "type": "t_contract(SimpleERC20)5132", - "offset": 0, - "slot": "0" - }, - { - "label": "mint_per_deployment", - "type": "t_uint256", - "offset": 0, - "slot": "1" - } - ], - "numberOfBytes": "64" - }, - "t_uint256": { - "label": "uint256", - "numberOfBytes": "32" - } - } - } - } - } -} diff --git a/addresses/hardhat-accounts.json b/addresses/hardhat-accounts.json deleted file mode 100644 index 5973f74..0000000 --- a/addresses/hardhat-accounts.json +++ /dev/null @@ -1,82 +0,0 @@ -[ - { - "privateKey": "0xc9795c87e547cc6aa4e3d9208c9b3ae8b86ed69df7a983733fbd8415bad485a8", - "address": "0x239E603FE5Eb22411A470D5064b6d9f7bEDFFA57" - }, - { - "privateKey": "0x29cdbdb2bcb57ea143adf55ef1fa7aaef9e94c1d530d72cc4cf9d2587d562bfa", - "address": "0x1236A8F9b35aeA3F4e05e3f012A3b306579598F4" - }, - { - "privateKey": "0x08f75a6d669c3de01a5633e72a89e1785d34829ac21c79bdc678e88be74f72e5", - "address": "0xA7210D453115535ccD0FA4aAe1986deA23725Ef2" - }, - { - "privateKey": "0xda86c32864fa66a47f42cefaf660d459412e1a1be4cbaf62428742c97c864a93", - "address": "0x8637Ed052d2B992Ef0bAD1A32753C5cfF3ee90B9" - }, - { - "privateKey": "0x165d8557e050be3a002208cb0431a8eb8dc0514ea1537dbb77c836b15fe7b2b8", - "address": "0xf53Aa3b3D995662B2Af1011C87B1Ffc030573bf6" - }, - { - "privateKey": "0xd1c9f8f5c158fc2b7ae7ce68c45894e3ef0794274862566a12e666484d83b945", - "address": "0x84EDe85BaBb66691c93Cf04e75115e5638d8c9EE" - }, - { - "privateKey": "0x6143b22e1e0ad3eeece0e84491c80b933b6da15c87011be6ffaaa0c2a3a3bf14", - "address": "0x28E28fcc5dc74ba0cDf961d0969dCfd2F6A87274" - }, - { - "privateKey": "0x6416c32e0865912dac8124f7b1c8cfb8747289b4f1d3bc593fcd16b049aa4b24", - "address": "0xD649AC5d9B8C03f93CEb7CA1B7A39e3DBD813FAb" - }, - { - "privateKey": "0xde7db0d393c241772daf4fc9ccca339516d48c57d7971d7de414c7824660871b", - "address": "0x77e419756eE68DDaD479e7B0B1bf2595803C8303" - }, - { - "privateKey": "0x9fadb0dae94f35ea9caadac940e58e105181a4d14b72ff91cf027584c668f303", - "address": "0x7d14a08A30326c4bb27cF26845A1e0709F06c1B4" - }, - { - "privateKey": "0x68765332801bf134b2468ff2b1cc9cf1bf68d01d3ee41424acd82e83b29b468c", - "address": "0x931829eCF2c740f655B9e23eb51E79921172696f" - }, - { - "privateKey": "0x5d913d217b6dd61ce6bca192c591d5ac4a0b6db83843490a542128832c33c2d9", - "address": "0xF053B50Ac774BE3A51801Ec5F0834F10c0e4b151" - }, - { - "privateKey": "0xd66f21389bce72bf21f5d6c08a73d254cdc8d31c40bff59fe5a63331d5da83c1", - "address": "0x669FdBF1fC88695B7d289E20a0B48Ff07E933F42" - }, - { - "privateKey": "0xab71d9e4ec796062d6ce75dcb99bed07e22dff56ce27d65a21cbbdde4bbad272", - "address": "0xC60184a2B7313F55cc4DDbF6c492AeC1A65444d7" - }, - { - "privateKey": "0xf1f924244dc0400d2072a7b0e58de11aca65af4c5021de697d8d0e593f52c230", - "address": "0xE04044E4B3B73D16a0CBE4847F77E83171deb1Dd" - }, - { - "privateKey": "0xbcb84154a198216ab2e6cecbb131d3d6098b6a17bd7ee2b2467911e8290cab5f", - "address": "0xD80ab9Defd3561CCcb88D76E0d0FB9DdA136B4EB" - }, - { - "privateKey": "0x2f043e57a756c45750e13fd5ca65713b2b7a8d00fdbd861b015cd8e54e9bd084", - "address": "0xf74621744Af2D2d05F718f99f26Ea2eC90368aeA" - }, - { - "privateKey": "0x68f202ec464a88f7b6970148a45a5350c6bf0e4ec1c1eb7e593eb1a3970238ba", - "address": "0xd480084E0466134c34bD5b8b2566A4c5b9c40Be1" - }, - { - "privateKey": "0xc70ca11a1825e8aed1bf02dbc8a0a805eb3db5d532ea096096ba11600f9a9547", - "address": "0x2a9fc27f8B61340492Ff5b333825eFC50B1eFdEf" - }, - { - "privateKey": "0x3fe96647727cfae3f1b7ab3f69ca11fc016ca9226e41eba668b6075b75b741c1", - "address": "0x5cb19e00e8cd80E552586D556393fd01245De3b7" - } -] \ No newline at end of file