From 275930bff9a5dc1237ee61945fcfac86f973c5c8 Mon Sep 17 00:00:00 2001 From: Michael Kim Date: Thu, 23 May 2024 13:54:31 +0900 Subject: [PATCH] Apply version 2.0.0 of loyalty-tokens --- active_contracts.json | 19 +- packages/contracts-lib/package.json | 4 +- packages/contracts/contracts/Reference.sol | 10 +- .../contracts/controllers/LoyaltyBridge.sol | 19 +- .../controllers/LoyaltyBridgeStorage.sol | 4 +- .../contracts/controllers/LoyaltyBurner.sol | 2 +- .../controllers/LoyaltyBurnerStorage.sol | 2 +- .../contracts/controllers/LoyaltyConsumer.sol | 2 +- .../controllers/LoyaltyExchanger.sol | 2 +- .../controllers/LoyaltyExchangerStorage.sol | 2 +- .../contracts/controllers/LoyaltyProvider.sol | 2 +- .../controllers/LoyaltyProviderStorage.sol | 2 +- .../contracts/controllers/LoyaltyTransfer.sol | 13 +- .../interfaces/IPhoneLinkCollection.sol | 11 + .../contracts/contracts/ledger/Ledger.sol | 13 +- .../contracts/ledger/LedgerStorage.sol | 2 +- .../contracts/phone/PhoneLinkCollection.sol | 221 +++++++++++++++++- .../contracts/phone/PhoneStorage.sol | 46 ++++ .../deploy/main_chain_devnet/deploy.ts | 61 ++++- .../deploy/side_chain_devnet/deploy.ts | 81 +++++-- packages/contracts/package.json | 24 +- packages/contracts/src/utils/ContractUtils.ts | 8 +- packages/contracts/test/04-Ledger.test.ts | 51 +++- packages/contracts/test/05-Bridge.test.ts | 19 +- packages/contracts/test/07-PhoneLink.test.ts | 184 +++++++++++++++ packages/contracts/test/helper/Deployments.ts | 33 ++- packages/faker/contracts/Reference.sol | 26 +-- packages/faker/package.json | 19 +- packages/relay/contracts/Reference.sol | 28 +-- packages/relay/docker-compose.yml | 1 - packages/relay/package.json | 19 +- packages/relay/src/routers/BridgeRouter.ts | 16 +- packages/relay/src/routers/LedgerRouter.ts | 30 ++- packages/relay/src/routers/TokenRouter.ts | 28 ++- packages/relay/src/utils/ContractUtils.ts | 8 +- packages/relay/src/utils/Errors.ts | 1 + packages/relay/test/Bridge.test.ts | 12 +- packages/relay/test/DelegatedTransfer.test.ts | 12 +- packages/relay/test/LoyaltyBridge.test.ts | 12 +- packages/relay/test/LoyaltyTransfer.test.ts | 6 +- packages/relay/test/helper/Deployments.ts | 28 ++- yarn.lock | 114 ++++----- 42 files changed, 952 insertions(+), 245 deletions(-) create mode 100644 packages/contracts/contracts/interfaces/IPhoneLinkCollection.sol create mode 100644 packages/contracts/contracts/phone/PhoneStorage.sol create mode 100644 packages/contracts/test/07-PhoneLink.test.ts diff --git a/active_contracts.json b/active_contracts.json index d9882389..8db1afa8 100644 --- a/active_contracts.json +++ b/active_contracts.json @@ -29,16 +29,17 @@ }, "loyalty_devnet": { "LoyaltyToken": "0xB1A90a5C6e30d64Ab6f64C30eD392F46eDBcb022", - "Validator": "0x4Ca91738C7cD24895467c6d550D96BE8dC4b33AA", - "CurrencyRate": "0x979a62090BDCff36F2e140F6915fbAdA7510cb6a", - "LoyaltyBurner": "0x5B4f8F9566706D4dB7f5E3020cE0485f96415749", - "LoyaltyProvider": "0xDD91A65534847537c290FEbc721cf8457f860744", - "LoyaltyConsumer": "0xb9CE93eeb00a74Deeec319cBCD37938b5aAE6314", - "LoyaltyExchanger": "0x1ae7b2564Ae7a7Fb1E7976F3F71cAF43ef49ac6F", + "PhoneLinkCollection": "0x4Ca91738C7cD24895467c6d550D96BE8dC4b33AA", + "Validator": "0x979a62090BDCff36F2e140F6915fbAdA7510cb6a", + "CurrencyRate": "0x5B4f8F9566706D4dB7f5E3020cE0485f96415749", + "LoyaltyBurner": "0xDD91A65534847537c290FEbc721cf8457f860744", + "LoyaltyProvider": "0xb9CE93eeb00a74Deeec319cBCD37938b5aAE6314", + "LoyaltyConsumer": "0x1ae7b2564Ae7a7Fb1E7976F3F71cAF43ef49ac6F", + "LoyaltyExchanger": "0xd73e6a2f2e47236F1Ff737E72497f598652122F9", "LoyaltyTransfer": "0xcAE5A9f266991dcEdc62bb9291f15E112f212820", "BridgeValidator": "0xE7D4f38Fad1C1C5EAA8A1280678B860a7A9519c1", - "LoyaltyBridge": "0xd73e6a2f2e47236F1Ff737E72497f598652122F9", - "Shop": "0xB4B0d4D6aAd2f963CC2FaeCBb4B8C94C3eeE6DB8", - "Ledger": "0xcAde85D03A2ABd41b608004BBB25440D28C64912" + "LoyaltyBridge": "0xB4B0d4D6aAd2f963CC2FaeCBb4B8C94C3eeE6DB8", + "Shop": "0x0c6B5326058F28Daf7D9ED40Ff2e3755a0bb664d", + "Ledger": "0x0E41917eBc8e06f01e47693a3D79Da136c10A1Eb" } } diff --git a/packages/contracts-lib/package.json b/packages/contracts-lib/package.json index 995fab78..db6348ae 100644 --- a/packages/contracts-lib/package.json +++ b/packages/contracts-lib/package.json @@ -1,6 +1,6 @@ { - "name": "dms-osx-lib", - "version": "2.14.0", + "name": "dms-contracts-lib-v2", + "version": "2.0.0", "description": "", "main": "dist/bundle-cjs.js", "module": "dist/bundle-esm.js", diff --git a/packages/contracts/contracts/Reference.sol b/packages/contracts/contracts/Reference.sol index a2927baf..a11fba1f 100644 --- a/packages/contracts/contracts/Reference.sol +++ b/packages/contracts/contracts/Reference.sol @@ -8,8 +8,8 @@ import "multisig-wallet-contracts/contracts/MultiSigWallet.sol"; import "loyalty-tokens/contracts/LoyaltyToken.sol"; import "loyalty-tokens/contracts/LYT.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridge.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridgeLiquidity.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridgeValidator.sol"; -import "dms-bridge-contracts/contracts/bridge/Bridge.sol"; -import "dms-bridge-contracts/contracts/bridge/BridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridge.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridgeLiquidity.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/Bridge.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/BridgeValidator.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyBridge.sol b/packages/contracts/contracts/controllers/LoyaltyBridge.sol index 4eba929b..22b05661 100644 --- a/packages/contracts/contracts/controllers/LoyaltyBridge.sol +++ b/packages/contracts/contracts/controllers/LoyaltyBridge.sol @@ -10,9 +10,9 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "loyalty-tokens/contracts/BIP20/BIP20DelegatedTransfer.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridge.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridgeValidator.sol"; -import "dms-bridge-contracts/contracts/lib/BridgeLib.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridge.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/lib/BridgeLib.sol"; import "../interfaces/ILedger.sol"; import "./LoyaltyBridgeStorage.sol"; @@ -81,14 +81,25 @@ contract LoyaltyBridge is LoyaltyBridgeStorage, Initializable, OwnableUpgradeabl bytes32 _depositId, address _account, uint256 _amount, + uint256 _expiry, bytes calldata _signature ) external payable override notExistDeposit(_depositId) { require(_tokenId == tokenId, "1713"); require(_account != foundationAccount, "1052"); + bytes32 dataHash = keccak256( - abi.encode(_account, address(this), _amount, block.chainid, ledgerContract.nonceOf(_account)) + abi.encode( + block.chainid, + address(tokenContract), + _account, + address(this), + _amount, + ledgerContract.nonceOf(_account), + _expiry + ) ); require(ECDSA.recover(ECDSA.toEthSignedMessageHash(dataHash), _signature) == _account, "1501"); + require(_expiry > block.timestamp, "1506"); require(ledgerContract.tokenBalanceOf(_account) >= _amount, "1511"); require(_amount % 1 gwei == 0, "1030"); require(_amount > fee * 2, "1031"); diff --git a/packages/contracts/contracts/controllers/LoyaltyBridgeStorage.sol b/packages/contracts/contracts/controllers/LoyaltyBridgeStorage.sol index 4bb54a91..62b7b707 100644 --- a/packages/contracts/contracts/controllers/LoyaltyBridgeStorage.sol +++ b/packages/contracts/contracts/controllers/LoyaltyBridgeStorage.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.2; import "loyalty-tokens/contracts/BIP20/BIP20DelegatedTransfer.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridge.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridge.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridgeValidator.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyBurner.sol b/packages/contracts/contracts/controllers/LoyaltyBurner.sol index 05e7d171..79ef69b5 100644 --- a/packages/contracts/contracts/controllers/LoyaltyBurner.sol +++ b/packages/contracts/contracts/controllers/LoyaltyBurner.sol @@ -10,7 +10,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/IValidator.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyBurnerStorage.sol b/packages/contracts/contracts/controllers/LoyaltyBurnerStorage.sol index 921ea050..d87ffb00 100644 --- a/packages/contracts/contracts/controllers/LoyaltyBurnerStorage.sol +++ b/packages/contracts/contracts/controllers/LoyaltyBurnerStorage.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.2; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/IValidator.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyConsumer.sol b/packages/contracts/contracts/controllers/LoyaltyConsumer.sol index 72c26bbb..e7dc89ca 100644 --- a/packages/contracts/contracts/controllers/LoyaltyConsumer.sol +++ b/packages/contracts/contracts/controllers/LoyaltyConsumer.sol @@ -10,7 +10,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/IShop.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyExchanger.sol b/packages/contracts/contracts/controllers/LoyaltyExchanger.sol index 9936ff54..b21ed983 100644 --- a/packages/contracts/contracts/controllers/LoyaltyExchanger.sol +++ b/packages/contracts/contracts/controllers/LoyaltyExchanger.sol @@ -10,7 +10,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyExchangerStorage.sol b/packages/contracts/contracts/controllers/LoyaltyExchangerStorage.sol index 5efdcd95..c2b6d325 100644 --- a/packages/contracts/contracts/controllers/LoyaltyExchangerStorage.sol +++ b/packages/contracts/contracts/controllers/LoyaltyExchangerStorage.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.2; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyProvider.sol b/packages/contracts/contracts/controllers/LoyaltyProvider.sol index 736eba6d..9455546f 100644 --- a/packages/contracts/contracts/controllers/LoyaltyProvider.sol +++ b/packages/contracts/contracts/controllers/LoyaltyProvider.sol @@ -10,7 +10,7 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/IValidator.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyProviderStorage.sol b/packages/contracts/contracts/controllers/LoyaltyProviderStorage.sol index e1863de4..4e2447b7 100644 --- a/packages/contracts/contracts/controllers/LoyaltyProviderStorage.sol +++ b/packages/contracts/contracts/controllers/LoyaltyProviderStorage.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.2; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/IValidator.sol"; diff --git a/packages/contracts/contracts/controllers/LoyaltyTransfer.sol b/packages/contracts/contracts/controllers/LoyaltyTransfer.sol index 88bea731..6a2c2058 100644 --- a/packages/contracts/contracts/controllers/LoyaltyTransfer.sol +++ b/packages/contracts/contracts/controllers/LoyaltyTransfer.sol @@ -46,11 +46,20 @@ contract LoyaltyTransfer is LoyaltyTransferStorage, Initializable, OwnableUpgrad require(_msgSender() == owner(), "Unauthorized access"); } - function transferToken(address _from, address _to, uint256 _amount, bytes calldata _signature) external { + function transferToken( + address _from, + address _to, + uint256 _amount, + uint256 _expiry, + bytes calldata _signature + ) external { require(_from != foundationAccount, "1051"); require(_to != foundationAccount, "1052"); - bytes32 dataHash = keccak256(abi.encode(_from, _to, _amount, block.chainid, ledgerContract.nonceOf(_from))); + bytes32 dataHash = keccak256( + abi.encode(block.chainid, address(this), _from, _to, _amount, ledgerContract.nonceOf(_from), _expiry) + ); require(ECDSA.recover(ECDSA.toEthSignedMessageHash(dataHash), _signature) == _from, "1501"); + require(_expiry > block.timestamp, "1506"); require(ledgerContract.tokenBalanceOf(_from) >= _amount + fee, "1511"); require(_amount % 1 gwei == 0, "1030"); diff --git a/packages/contracts/contracts/interfaces/IPhoneLinkCollection.sol b/packages/contracts/contracts/interfaces/IPhoneLinkCollection.sol new file mode 100644 index 00000000..16154ba4 --- /dev/null +++ b/packages/contracts/contracts/interfaces/IPhoneLinkCollection.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.2; + +interface IPhoneLinkCollection { + function toAddress(bytes32 _phone) external view returns (address); + + function toPhone(address _wallet) external view returns (bytes32); + + function nonceOf(address _wallet) external view returns (uint256); +} diff --git a/packages/contracts/contracts/ledger/Ledger.sol b/packages/contracts/contracts/ledger/Ledger.sol index b0765738..952e7aab 100644 --- a/packages/contracts/contracts/ledger/Ledger.sol +++ b/packages/contracts/contracts/ledger/Ledger.sol @@ -9,8 +9,8 @@ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "loyalty-tokens/contracts/BIP20/BIP20DelegatedTransfer.sol"; -import "dms-bridge-contracts/contracts/interfaces/IBridgeLiquidity.sol"; -import "dms-bridge-contracts/contracts/lib/BridgeLib.sol"; +import "dms-bridge-contracts-v2/contracts/interfaces/IBridgeLiquidity.sol"; +import "dms-bridge-contracts-v2/contracts/lib/BridgeLib.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/ILedger.sol"; @@ -383,12 +383,17 @@ contract Ledger is LedgerStorage, Initializable, OwnableUpgradeable, UUPSUpgrade } /// @notice 브리지를 위한 유동성 자금을 예치합니다. - function depositLiquidity(bytes32 _tokenId, uint256 _amount, bytes calldata _signature) external payable override { + function depositLiquidity( + bytes32 _tokenId, + uint256 _amount, + uint256 _expiry, + bytes calldata _signature + ) external payable override { require(_tokenId == tokenId, "1713"); require(tokenContract.balanceOf(_msgSender()) >= _amount, "1511"); require(_amount % 1 gwei == 0, "1030"); - if (tokenContract.delegatedTransfer(_msgSender(), address(this), _amount, _signature)) { + if (tokenContract.delegatedTransfer(_msgSender(), address(this), _amount, _expiry, _signature)) { tokenBalances[bridgeAddress] += _amount; liquidity[_msgSender()] += _amount; emit DepositedLiquidity(_tokenId, _msgSender(), _amount, liquidity[_msgSender()]); diff --git a/packages/contracts/contracts/ledger/LedgerStorage.sol b/packages/contracts/contracts/ledger/LedgerStorage.sol index d7e88226..39176684 100644 --- a/packages/contracts/contracts/ledger/LedgerStorage.sol +++ b/packages/contracts/contracts/ledger/LedgerStorage.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.2; import "loyalty-tokens/contracts/BIP20/IBIP20DelegatedTransfer.sol"; -import "del-osx-artifacts/contracts/interfaces/IPhoneLinkCollection.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; import "../interfaces/ICurrencyRate.sol"; import "../interfaces/ILedger.sol"; diff --git a/packages/contracts/contracts/phone/PhoneLinkCollection.sol b/packages/contracts/contracts/phone/PhoneLinkCollection.sol index 721c1a1e..ccd641b6 100644 --- a/packages/contracts/contracts/phone/PhoneLinkCollection.sol +++ b/packages/contracts/contracts/phone/PhoneLinkCollection.sol @@ -2,4 +2,223 @@ pragma solidity ^0.8.2; -import "del-osx-artifacts/contracts/PhoneLinkCollection.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +import "./PhoneStorage.sol"; +import "../interfaces/IPhoneLinkCollection.sol"; + +/// Contract for converting e-mail to wallet +contract PhoneLinkCollection is PhoneStorage, Initializable, OwnableUpgradeable, UUPSUpgradeable, IPhoneLinkCollection { + /// @notice 등록요청인 완료된 후 발생되는 이벤트 + event AddedRequestItem(bytes32 id, bytes32 phone, address wallet); + /// @notice 등록요청이 승인된 후 발생되는 이벤트 + event AcceptedRequestItem(bytes32 id, bytes32 phone, address wallet); + /// @notice 등록요청이 거부된 후 발생되는 이벤트 + event RejectedRequestItem(bytes32 id, bytes32 phone, address wallet); + + event RemovedItem(bytes32 phone, address wallet); + + /// @notice 생성자 + /// @param _validators 검증자들 + function initialize(address[] memory _validators) external initializer { + __UUPSUpgradeable_init(); + __Ownable_init_unchained(); + for (uint256 i = 0; i < _validators.length; ++i) { + ValidatorItem memory item = ValidatorItem({ + validator: _validators[i], + index: i, + endpoint: "", + status: ValidatorStatus.ACTIVE + }); + validatorAddresses.push(_validators[i]); + validators[_validators[i]] = item; + } + + quorum = uint256(2000) / uint256(3); + } + + function _authorizeUpgrade(address newImplementation) internal virtual override { + require(_msgSender() == owner(), "Unauthorized access"); + } + + /// @notice 검증자들만 호출할 수 있도록 해준다. + modifier onlyValidator() { + require(validators[_msgSender()].status == ValidatorStatus.ACTIVE, "Not validator"); + _; + } + + /// @notice 이용할 수 있는 아이디 인지 알려준다. + /// @param _id 요청 아이디 + function isAvailable(bytes32 _id) public view returns (bool) { + if (requests[_id].status == RequestStatus.INVALID) return true; + else return false; + } + + /// @notice 휴대전화번호-지갑주소 항목의 등록을 요청한다 + /// @param _id 요청 아이디 + /// @param _phone 휴대전화번호의 해시 + /// @param _wallet 지갑주소 + /// @param _signature 지갑주소의 서명 + function addRequest(bytes32 _id, bytes32 _phone, address _wallet, bytes calldata _signature) external { + require(requests[_id].status == RequestStatus.INVALID, "Invalid ID"); + require(_phone != NULL, "Invalid phone hash"); + bytes32 dataHash = keccak256(abi.encode(_phone, _wallet, block.chainid, nonce[_wallet])); + require(ECDSA.recover(ECDSA.toEthSignedMessageHash(dataHash), _signature) == _wallet, "Invalid signature"); + + nonce[_wallet]++; + + requests[_id].id = _id; + requests[_id].phone = _phone; + requests[_id].wallet = _wallet; + requests[_id].signature = _signature; + requests[_id].status = RequestStatus.REQUESTED; + requestIds.push(_id); + + emit AddedRequestItem(_id, _phone, _wallet); + } + + /// @notice 검증자들이 휴대전화번호 검증결과를 등록한다. + /// @param _id 요청 아이디 + function voteRequest(bytes32 _id) external onlyValidator { + require(requests[_id].status != RequestStatus.INVALID, "Invalid ID"); + RequestItem storage req = requests[_id]; + if (req.status == RequestStatus.REQUESTED) { + if (req.voters[_msgSender()] == false) { + req.voters[_msgSender()] = true; + req.agreement++; + } + } + } + + /// @notice 개표를 진행할 수 있는지를 확인한다. + /// @param _id 요청 아이디 + function canCountVote(bytes32 _id) external view returns (uint8) { + RequestItem storage req = requests[_id]; + if (req.status == RequestStatus.REQUESTED) { + if ((req.agreement * 1000) / validatorAddresses.length >= quorum) { + return uint8(1); + } else { + return uint8(2); + } + } + return uint8(0); + } + + /// @notice 개표를 진행한다. + /// @param _id 요청 아이디 + function countVote(bytes32 _id) external onlyValidator { + RequestItem storage req = requests[_id]; + if (req.status == RequestStatus.REQUESTED) { + if ((req.agreement * 1000) / validatorAddresses.length >= quorum) { + if ((addressToPhone[req.wallet] == req.phone) && (phoneToAddress[req.phone] == req.wallet)) { + req.status = RequestStatus.ACCEPTED; + emit AcceptedRequestItem(req.id, req.phone, req.wallet); + } else { + // 기존 링크를 삭제한다. 새로운 지갑주소와 링크되어 있었던 이전의 전화번호의 링크를 삭제한다. + bytes32 oldPhone = addressToPhone[req.wallet]; + if (oldPhone != bytes32(0x00)) { + delete phoneToAddress[oldPhone]; + } + + // 기존 링크를 삭제한다. 새로운 전화번호와 링크되어 있었던 이전의 지갑주소의 링크를 삭제한다. + address oldWallet = phoneToAddress[req.phone]; + if (oldWallet != address(0x00)) { + delete addressToPhone[oldWallet]; + } + + phoneToAddress[req.phone] = req.wallet; + addressToPhone[req.wallet] = req.phone; + + req.status = RequestStatus.ACCEPTED; + emit AcceptedRequestItem(req.id, req.phone, req.wallet); + } + } + } + } + + /// @notice 휴대전화번호-지갑주소 항목을 삭제한다. + /// @param _wallet 지갑주소 + /// @param _signature 지갑주소의 서명 + function remove(address _wallet, bytes calldata _signature) external { + bytes32 dataHash = keccak256(abi.encode(_wallet, block.chainid, nonce[_wallet])); + require(ECDSA.recover(ECDSA.toEthSignedMessageHash(dataHash), _signature) == _wallet, "Invalid signature"); + + nonce[_wallet]++; + + bytes32 phone = addressToPhone[_wallet]; + if (phone != 0) { + delete addressToPhone[_wallet]; + address account = phoneToAddress[phone]; + if (account != address(0x0)) { + delete phoneToAddress[phone]; + } + emit RemovedItem(phone, _wallet); + } + } + + /// @notice 검증자 자신의 API 엔드포인트를 등록한다. + /// @param _endpoint API 엔드포인트 + function updateEndpoint(string memory _endpoint) public onlyValidator { + require(validators[_msgSender()].status != ValidatorStatus.INVALID, "No exists validator's info"); + validators[_msgSender()].endpoint = _endpoint; + } + + /// @notice 휴대전화번호해시와 연결된 지갑주소를 리턴한다. + /// @param _phone 휴대전화번호의 해시 + function toAddress(bytes32 _phone) public view override returns (address) { + return phoneToAddress[_phone]; + } + + /// @notice 지갑주소와 연결된 휴대전화번호해시를 리턴한다. + /// @param _wallet 지갑주소 + function toPhone(address _wallet) public view override returns (bytes32) { + return addressToPhone[_wallet]; + } + + /// @notice nonce를 리턴한다 + /// @param _wallet 지갑주소 + function nonceOf(address _wallet) public view override returns (uint256) { + return nonce[_wallet]; + } + + /// @notice 검증자들의 정보를 리턴한다. + function getValidators() public view returns (ValidatorItem[] memory) { + uint256 len = validatorAddresses.length; + ValidatorItem[] memory items = new ValidatorItem[](len); + for (uint256 i = 0; i < len; i++) { + items[i] = validators[validatorAddresses[i]]; + } + return items; + } + + /// @notice 검증자들의 주소를 리턴한다. + function getAddressOfValidators() public view returns (address[] memory) { + uint256 len = validatorAddresses.length; + address[] memory items = new address[](len); + for (uint256 i = 0; i < len; i++) { + items[i] = validatorAddresses[i]; + } + return items; + } + + /// @notice 검증자들의 갯수를 리턴한다 + function getValidatorLength() public view returns (uint256) { + return validatorAddresses.length; + } + + /// @notice 검증자의 정보를 리턴한다. + /// @param _idx 검증자의 인덱스 + function getValidator(uint _idx) public view returns (ValidatorItem memory) { + require(_idx < validatorAddresses.length, "Out of range"); + return validators[validatorAddresses[_idx]]; + } + + function getRequestItem(bytes32 _id) public view returns (uint32 agreement, RequestStatus status) { + return (requests[_id].agreement, requests[_id].status); + } +} diff --git a/packages/contracts/contracts/phone/PhoneStorage.sol b/packages/contracts/contracts/phone/PhoneStorage.sol new file mode 100644 index 00000000..f784713e --- /dev/null +++ b/packages/contracts/contracts/phone/PhoneStorage.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +pragma solidity ^0.8.2; + +contract PhoneStorage { + /// @notice 요청 아이템의 상태코드 + enum RequestStatus { + INVALID, + REQUESTED, + ACCEPTED, + REJECTED + } + + struct RequestItem { + bytes32 id; + bytes32 phone; + address wallet; + bytes signature; + uint32 agreement; + mapping(address => bool) voters; + RequestStatus status; + } + + /// @notice 검증자의 상태코드 + enum ValidatorStatus { + INVALID, // 초기값 + ACTIVE // 검증자의 기능이 활성화됨 + } + + struct ValidatorItem { + address validator; // 검증자의 지갑주소 + uint256 index; + string endpoint; + ValidatorStatus status; // 검증자의 상태 + } + + bytes32 public constant NULL = 0x32105b1d0b88ada155176b58ee08b45c31e4f2f7337475831982c313533b880c; + mapping(bytes32 => address) internal phoneToAddress; + mapping(address => bytes32) internal addressToPhone; + mapping(address => uint256) internal nonce; + mapping(bytes32 => RequestItem) internal requests; + bytes32[] internal requestIds; + uint256 internal quorum; + mapping(address => ValidatorItem) internal validators; + address[] internal validatorAddresses; +} diff --git a/packages/contracts/deploy/main_chain_devnet/deploy.ts b/packages/contracts/deploy/main_chain_devnet/deploy.ts index 6b7e73da..f1a8b07d 100644 --- a/packages/contracts/deploy/main_chain_devnet/deploy.ts +++ b/packages/contracts/deploy/main_chain_devnet/deploy.ts @@ -17,8 +17,8 @@ import { ethers, upgrades } from "hardhat"; const network = "main_chain_devnet"; export const MULTI_SIG_WALLET_ADDRESSES: { [key: string]: string } = { - main_chain_devnet: "0x6d9493FB6D8c8bD3534a3E1F4163921161BEf187", - side_chain_devnet: "0x6d9493FB6D8c8bD3534a3E1F4163921161BEf187", + main_chain_devnet: "0x580f0F058D1eD4A317FF4Ce2668Ae25fbF21A2d9", + side_chain_devnet: "0x580f0F058D1eD4A317FF4Ce2668Ae25fbF21A2d9", }; export const LOYALTY_TOKEN_ADDRESSES: { [key: string]: string } = { @@ -248,7 +248,43 @@ class Deployments { } } -async function deployToken(accounts: IAccount, deployment: Deployments) { +async function mintInitialSupplyToken(accounts: IAccount, deployment: Deployments) { + const contractName = "LoyaltyToken"; + + const contract = deployment.getContract("LoyaltyToken") as LoyaltyToken; + + const amount = BOACoin.make(10_000_000_000); + + const encodedData = contract.interface.encodeFunctionData("mint", [amount.value]); + const wallet = deployment.getContract("MultiSigWallet") as MultiSigWallet; + const transactionId = await ContractUtils.getEventValueBigNumber( + await wallet + .connect(accounts.tokenOwners[0]) + .submitTransaction("Mint", `Mint ${amount.toDisplayString()}`, contract.address, 0, encodedData), + wallet.interface, + "Submission", + "transactionId" + ); + + if (transactionId === undefined) { + console.error(`Failed to submit transaction for token mint`); + } else { + const executedTransactionId = await ContractUtils.getEventValueBigNumber( + await wallet.connect(accounts.tokenOwners[1]).confirmTransaction(transactionId), + wallet.interface, + "Execution", + "transactionId" + ); + + if (executedTransactionId === undefined || !transactionId.eq(executedTransactionId)) { + console.error(`Failed to confirm transaction for token mint`); + } + } + + console.log(`Mint ${contractName} to ${wallet.address}`); +} + +async function distributeToken(accounts: IAccount, deployment: Deployments) { const contractName = "LoyaltyToken"; const contract = deployment.getContract("LoyaltyToken") as LoyaltyToken; @@ -312,7 +348,7 @@ async function deployToken(accounts: IAccount, deployment: Deployments) { await ContractUtils.delay(3000); } } - console.log(`Deployed ${contractName} to ${contract.address}`); + console.log(`Distribute ${contractName}`); } async function deployBridgeValidator(accounts: IAccount, deployment: Deployments) { @@ -368,15 +404,18 @@ async function deployLoyaltyBridge(accounts: IAccount, deployment: Deployments) const assetAmount = Amount.make(8_000_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to SideChainBridge (tx: ${tx1.hash})...`); await tx1.wait(); } @@ -415,15 +454,18 @@ async function deployMainChainBridge(accounts: IAccount, deployment: Deployments const assetAmount = Amount.make(100_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to SideChainBridge (tx: ${tx1.hash})...`); await tx1.wait(); } @@ -434,7 +476,8 @@ async function main() { await deployments.attachPreviousContracts(); - deployments.addDeployer(deployToken); + deployments.addDeployer(mintInitialSupplyToken); + deployments.addDeployer(distributeToken); deployments.addDeployer(deployBridgeValidator); deployments.addDeployer(deployLoyaltyBridge); deployments.addDeployer(deployMainChainBridge); diff --git a/packages/contracts/deploy/side_chain_devnet/deploy.ts b/packages/contracts/deploy/side_chain_devnet/deploy.ts index ae266f28..3eb85b23 100644 --- a/packages/contracts/deploy/side_chain_devnet/deploy.ts +++ b/packages/contracts/deploy/side_chain_devnet/deploy.ts @@ -32,14 +32,9 @@ import * as hre from "hardhat"; const network = "side_chain_devnet"; -export const PHONE_LINK_COLLECTION_ADDRESSES: { [key: string]: string } = { - main_chain_devnet: "0xaE7018CaF086EB2Ca62eAA7b91B61dDA6b046F70", - side_chain_devnet: "0xaE7018CaF086EB2Ca62eAA7b91B61dDA6b046F70", -}; - export const MULTI_SIG_WALLET_ADDRESSES: { [key: string]: string } = { - main_chain_devnet: "0x6d9493FB6D8c8bD3534a3E1F4163921161BEf187", - side_chain_devnet: "0x6d9493FB6D8c8bD3534a3E1F4163921161BEf187", + main_chain_devnet: "0x580f0F058D1eD4A317FF4Ce2668Ae25fbF21A2d9", + side_chain_devnet: "0x580f0F058D1eD4A317FF4Ce2668Ae25fbF21A2d9", }; export const LOYALTY_TOKEN_ADDRESSES: { [key: string]: string } = { @@ -176,9 +171,6 @@ class Deployments { } public async attachPreviousContracts() { - this.PHONE_LINK_COLLECTION_CONTRACT = (await hre.ethers.getContractFactory("PhoneLinkCollection")).attach( - PHONE_LINK_COLLECTION_ADDRESSES[network] - ) as PhoneLinkCollection; this.MULTI_SIG_WALLET_CONTRACT = (await hre.ethers.getContractFactory("MultiSigWallet")).attach( MULTI_SIG_WALLET_ADDRESSES[network] ) as MultiSigWallet; @@ -196,9 +188,7 @@ class Deployments { } public getContract(name: string): BaseContract | undefined { - if (name === "PhoneLinkCollection") { - return this.PHONE_LINK_COLLECTION_CONTRACT; - } else if (name === "MultiSigWallet") { + if (name === "MultiSigWallet") { return this.MULTI_SIG_WALLET_CONTRACT; } else if (name === "LoyaltyToken") { return this.LOYALTY_TOKEN_CONTRACT; @@ -212,9 +202,7 @@ class Deployments { } public getContractAddress(name: string): string | undefined { - if (name === "PhoneLinkCollection") { - return PHONE_LINK_COLLECTION_ADDRESSES[network]; - } else if (name === "MultiSigWallet") { + if (name === "MultiSigWallet") { return MULTI_SIG_WALLET_ADDRESSES[network]; } else if (name === "LoyaltyToken") { return LOYALTY_TOKEN_ADDRESSES[network]; @@ -289,7 +277,43 @@ async function deployPhoneLink(accounts: IAccount, deployment: Deployments) { console.log(`Deployed ${contractName} to ${contract.address}`); } -async function deployToken(accounts: IAccount, deployment: Deployments) { +async function mintInitialSupplyToken(accounts: IAccount, deployment: Deployments) { + const contractName = "LoyaltyToken"; + + const contract = deployment.getContract("LoyaltyToken") as LoyaltyToken; + + const amount = BOACoin.make(10_000_000_000); + + const encodedData = contract.interface.encodeFunctionData("mint", [amount.value]); + const wallet = deployment.getContract("MultiSigWallet") as MultiSigWallet; + const transactionId = await ContractUtils.getEventValueBigNumber( + await wallet + .connect(accounts.tokenOwners[0]) + .submitTransaction("Mint", `Mint ${amount.toDisplayString()}`, contract.address, 0, encodedData), + wallet.interface, + "Submission", + "transactionId" + ); + + if (transactionId === undefined) { + console.error(`Failed to submit transaction for token mint`); + } else { + const executedTransactionId = await ContractUtils.getEventValueBigNumber( + await wallet.connect(accounts.tokenOwners[1]).confirmTransaction(transactionId), + wallet.interface, + "Execution", + "transactionId" + ); + + if (executedTransactionId === undefined || !transactionId.eq(executedTransactionId)) { + console.error(`Failed to confirm transaction for token mint`); + } + } + + console.log(`Mint ${contractName} to ${wallet.address}`); +} + +async function distributeToken(accounts: IAccount, deployment: Deployments) { const contractName = "LoyaltyToken"; const contract = deployment.getContract("LoyaltyToken") as LoyaltyToken; @@ -351,7 +375,7 @@ async function deployToken(accounts: IAccount, deployment: Deployments) { // await tx.wait(); } } - console.log(`Deployed ${contractName} to ${contract.address}`); + console.log(`Distribute ${contractName}`); } async function deployValidator(accounts: IAccount, deployment: Deployments) { @@ -864,15 +888,20 @@ async function deployLedger(accounts: IAccount, deployment: Deployments) { const tokenContract = (await deployment.getContract("LoyaltyToken")) as LoyaltyToken; const tokenId = ContractUtils.getTokenId(await tokenContract.name(), await tokenContract.symbol()); const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount2, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount2, signature); + const tx1 = await contract + .connect(accounts.owner) + .depositLiquidity(tokenId, assetAmount2, expiry, signature); console.log(`Deposit liquidity token (tx: ${tx1.hash})...`); // await tx1.wait(); } @@ -908,15 +937,18 @@ async function deploySideChainBridge(accounts: IAccount, deployment: Deployments await contract.connect(accounts.deployer).registerToken(tokenId, tokenContract.address); const assetAmount = Amount.make(500_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to SideChainBridge (tx: ${tx1.hash})...`); // await tx1.wait(); } @@ -927,8 +959,9 @@ async function main() { await deployments.attachPreviousContracts(); - // deployments.addDeployer(deployPhoneLink); - deployments.addDeployer(deployToken); + deployments.addDeployer(deployPhoneLink); + deployments.addDeployer(mintInitialSupplyToken); + deployments.addDeployer(distributeToken); deployments.addDeployer(deployValidator); deployments.addDeployer(deployCurrencyRate); deployments.addDeployer(deployLoyaltyBurner); diff --git a/packages/contracts/package.json b/packages/contracts/package.json index bb318102..7b95435c 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -1,6 +1,6 @@ { - "name": "dms-osx-artifacts", - "version": "2.14.0", + "name": "dms-contracts-v2", + "version": "2.0.0", "description": "Smart contracts that decentralized point systems", "files": [ "**/*.sol" @@ -21,7 +21,8 @@ "test:Shop": "hardhat test test/03-Shop.test.ts", "test:Ledger": "hardhat test test/04-Ledger.test.ts", "test:Bridge": "hardhat test test/05-Bridge.test.ts", - "test:ShopId": "hardhat test test/06-ShopId.test.ts" + "test:ShopId": "hardhat test test/06-ShopId.test.ts", + "test:PhoneLink": "hardhat test test/07-PhoneLink.test.ts" }, "repository": { "type": "git", @@ -37,9 +38,6 @@ "@ethersproject/constants": "^5.7.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.2", - "@openzeppelin/contracts": "^4.9.5", - "@openzeppelin/contracts-upgradeable": "^4.9.5", - "@openzeppelin/hardhat-upgrades": "^1.28.0", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.3.5", @@ -50,10 +48,10 @@ "chai-http": "^4.3.7", "dotenv": "^10.0.0", "ethereum-waffle": "^4.0.10", - "ethers": "5.7.0", + "ethers": "^5.7.0", "hardhat": "^2.12.7", "hardhat-gas-reporter": "^1.0.7", - "mocha": "10.1.0", + "mocha": "^10.1.0", "prettier": "^2.5.1", "prettier-plugin-solidity": "^1.1.1", "solhint": "^3.3.6", @@ -66,9 +64,11 @@ "typescript": "^4.5.5" }, "dependencies": { - "del-osx-artifacts": "2.3.0", - "dms-bridge-contracts": "1.5.0", - "multisig-wallet-contracts": "1.1.0", - "loyalty-tokens": "1.1.0" + "@openzeppelin/contracts": "^4.9.5", + "@openzeppelin/contracts-upgradeable": "^4.9.5", + "@openzeppelin/hardhat-upgrades": "^1.28.0", + "dms-bridge-contracts-v2": "~2.0.0", + "loyalty-tokens": "~2.0.0", + "multisig-wallet-contracts": "~2.0.0" } } diff --git a/packages/contracts/src/utils/ContractUtils.ts b/packages/contracts/src/utils/ContractUtils.ts index d8ce2227..3537e0d0 100644 --- a/packages/contracts/src/utils/ContractUtils.ts +++ b/packages/contracts/src/utils/ContractUtils.ts @@ -529,15 +529,17 @@ export class ContractUtils { } public static getTransferMessage( + chainId: BigNumberish, + tokenAddress: string, from: string, to: string, amount: BigNumberish, nonce: BigNumberish, - chainId?: BigNumberish + expiry: number ): Uint8Array { const encodedResult = defaultAbiCoder.encode( - ["address", "address", "uint256", "uint256", "uint256"], - [from, to, amount, chainId ? chainId : hre.ethers.provider.network.chainId, nonce] + ["uint256", "address", "address", "address", "uint256", "uint256", "uint256"], + [chainId, tokenAddress, from, to, amount, nonce, expiry] ); return arrayify(keccak256(encodedResult)); } diff --git a/packages/contracts/test/04-Ledger.test.ts b/packages/contracts/test/04-Ledger.test.ts index d263dbeb..3611c4ee 100644 --- a/packages/contracts/test/04-Ledger.test.ts +++ b/packages/contracts/test/04-Ledger.test.ts @@ -1,7 +1,5 @@ import "@nomiclabs/hardhat-ethers"; -import "@nomiclabs/hardhat-waffle"; import "@openzeppelin/hardhat-upgrades"; -import { waffle } from "hardhat"; import { Amount } from "../src/utils/Amount"; import { ContractUtils, LoyaltyNetworkID } from "../src/utils/ContractUtils"; @@ -27,6 +25,8 @@ import { BigNumber, Wallet } from "ethers"; import { AddressZero } from "@ethersproject/constants"; import { Deployments } from "./helper/Deployments"; +import * as hre from "hardhat"; + chai.use(solidity); interface IPurchaseData { @@ -469,7 +469,10 @@ describe("Test for Ledger", () => { .to.emit(linkContract, "AddedRequestItem") .withArgs(requestId, hash, deployments.accounts.users[3].address); await linkContract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await linkContract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); await linkContract.connect(deployments.accounts.linkValidators[0]).countVote(requestId); + expect(await linkContract.toAddress(hash)).to.be.equal(deployments.accounts.users[3].address); + expect(await linkContract.toPhone(deployments.accounts.users[3].address)).to.be.equal(hash); }); it("Save Purchase Data (user: 3, point type : 0) - phone and address are registered (user: 3, point type : 0)", async () => { @@ -740,6 +743,7 @@ describe("Test for Ledger", () => { .to.emit(linkContract, "AddedRequestItem") .withArgs(requestId, hash, deployments.accounts.users[4].address); await linkContract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await linkContract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); await linkContract.connect(deployments.accounts.linkValidators[0]).countVote(requestId); }); @@ -837,7 +841,7 @@ describe("Test for Ledger", () => { const unPayableAmount = await ledgerContract.unPayablePointBalanceOf(phoneHash); await expect( exchangerContract - .connect(deployments.accounts.users[userIndex].connect(waffle.provider)) + .connect(deployments.accounts.users[userIndex].connect(hre.ethers.provider)) .changeToPayablePoint(phoneHash, deployments.accounts.users[userIndex].address, signature) ) .to.emit(exchangerContract, "ChangedToPayablePoint") @@ -931,6 +935,7 @@ describe("Test for Ledger", () => { .to.emit(linkContract, "AddedRequestItem") .withArgs(requestId, hash, deployments.accounts.users[userIndex].address); await linkContract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await linkContract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); await linkContract.connect(deployments.accounts.linkValidators[0]).countVote(requestId); }); @@ -1699,7 +1704,7 @@ describe("Test for Ledger", () => { const signature = await ContractUtils.signMessage(shopData[shopIndex].wallet, message); await expect( shopContract - .connect(shopData[shopIndex].wallet.connect(waffle.provider)) + .connect(shopData[shopIndex].wallet.connect(hre.ethers.provider)) .openWithdrawal(shop.shopId, amount2, shopData[shopIndex].wallet.address, signature) ) .to.emit(shopContract, "OpenedWithdrawal") @@ -1722,7 +1727,7 @@ describe("Test for Ledger", () => { const signature = await ContractUtils.signMessage(shopData[shopIndex].wallet, message); await expect( shopContract - .connect(shopData[shopIndex].wallet.connect(waffle.provider)) + .connect(shopData[shopIndex].wallet.connect(hre.ethers.provider)) .closeWithdrawal(shop.shopId, shopData[shopIndex].wallet.address, signature) ) .to.emit(shopContract, "ClosedWithdrawal") @@ -2286,7 +2291,7 @@ describe("Test for Ledger", () => { const signature = await ContractUtils.signMessage(shopData[shopIndex].wallet, message); await expect( shopContract - .connect(shopData[shopIndex].wallet.connect(waffle.provider)) + .connect(shopData[shopIndex].wallet.connect(hre.ethers.provider)) .openWithdrawal(shop.shopId, amount2, shopData[shopIndex].wallet.address, signature) ) .to.emit(shopContract, "OpenedWithdrawal") @@ -2310,7 +2315,7 @@ describe("Test for Ledger", () => { const signature = await ContractUtils.signMessage(shopData[shopIndex].wallet, message); await expect( shopContract - .connect(shopData[shopIndex].wallet.connect(waffle.provider)) + .connect(shopData[shopIndex].wallet.connect(hre.ethers.provider)) .closeWithdrawal(shop.shopId, shopData[shopIndex].wallet.address, signature) ) .to.emit(shopContract, "ClosedWithdrawal") @@ -2394,11 +2399,15 @@ describe("Test for Ledger", () => { it("Transfer token - foundation account ", async () => { const transferAmount = amount.value; const nonce = await ledgerContract.nonceOf(deployments.accounts.foundation.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = await ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + transferContract.address, deployments.accounts.foundation.address, deployments.accounts.users[1].address, transferAmount, - nonce + nonce, + expiry ); const signature = ContractUtils.signMessage(deployments.accounts.foundation, message); await expect( @@ -2406,6 +2415,7 @@ describe("Test for Ledger", () => { deployments.accounts.foundation.address, deployments.accounts.users[1].address, transferAmount, + expiry, signature ) ).to.revertedWith("1051"); @@ -2414,11 +2424,15 @@ describe("Test for Ledger", () => { it("Transfer token - foundation account ", async () => { const transferAmount = amount.value; const nonce = await ledgerContract.nonceOf(deployments.accounts.users[0].address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = await ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + transferContract.address, deployments.accounts.users[0].address, deployments.accounts.foundation.address, transferAmount, - nonce + nonce, + expiry ); const signature = ContractUtils.signMessage(deployments.accounts.users[0], message); await expect( @@ -2426,19 +2440,25 @@ describe("Test for Ledger", () => { deployments.accounts.users[0].address, deployments.accounts.foundation.address, transferAmount, + expiry, signature ) ).to.revertedWith("1052"); }); it("Transfer token - Insufficient balance", async () => { - const transferAmount = amount.value.mul(2); + const fromBalance = await ledgerContract.tokenBalanceOf(deployments.accounts.users[0].address); + const transferAmount = fromBalance.mul(2); const nonce = await ledgerContract.nonceOf(deployments.accounts.users[0].address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = await ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + transferContract.address, deployments.accounts.users[0].address, deployments.accounts.users[1].address, transferAmount, - nonce + nonce, + expiry ); const signature = ContractUtils.signMessage(deployments.accounts.users[0], message); await expect( @@ -2446,6 +2466,7 @@ describe("Test for Ledger", () => { deployments.accounts.users[0].address, deployments.accounts.users[1].address, transferAmount, + expiry, signature ) ).to.revertedWith("1511"); @@ -2457,11 +2478,15 @@ describe("Test for Ledger", () => { const oldTokenBalance1 = await ledgerContract.tokenBalanceOf(deployments.accounts.users[1].address); const transferAmount = oldTokenBalance0.sub(fee); const nonce = await ledgerContract.nonceOf(deployments.accounts.users[0].address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = await ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + transferContract.address, deployments.accounts.users[0].address, deployments.accounts.users[1].address, transferAmount, - nonce + nonce, + expiry ); const signature = ContractUtils.signMessage(deployments.accounts.users[0], message); await expect( @@ -2469,6 +2494,7 @@ describe("Test for Ledger", () => { deployments.accounts.users[0].address, deployments.accounts.users[1].address, transferAmount, + expiry, signature ) ) @@ -2646,6 +2672,7 @@ describe("Test for Ledger", () => { .to.emit(linkContract, "AddedRequestItem") .withArgs(requestId, hash, deployments.accounts.users[userIndex].address); await linkContract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await linkContract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); await linkContract.connect(deployments.accounts.linkValidators[0]).countVote(requestId); }); diff --git a/packages/contracts/test/05-Bridge.test.ts b/packages/contracts/test/05-Bridge.test.ts index 1a205365..cafa08b5 100644 --- a/packages/contracts/test/05-Bridge.test.ts +++ b/packages/contracts/test/05-Bridge.test.ts @@ -20,13 +20,14 @@ import { TestLYT, Validator, } from "../typechain-types"; +import { Deployments } from "./helper/Deployments"; import chai, { expect } from "chai"; import { solidity } from "ethereum-waffle"; import { Wallet } from "ethers"; -import { Deployments } from "./helper/Deployments"; +import * as hre from "hardhat"; chai.use(solidity); @@ -98,18 +99,22 @@ describe("Test for Ledger", () => { const oldLiquidity = await tokenContract.balanceOf(bridgeContract.address); const oldTokenBalance = await tokenContract.balanceOf(deployments.accounts.users[0].address); const nonce = await tokenContract.nonceOf(deployments.accounts.users[0].address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + tokenContract.address, deployments.accounts.users[0].address, bridgeContract.address, amount, - nonce + nonce, + expiry ); depositId = ContractUtils.getRandomId(deployments.accounts.users[0].address); const signature = await ContractUtils.signMessage(deployments.accounts.users[0], message); await expect( bridgeContract .connect(deployments.accounts.certifiers[0]) - .depositToBridge(tokenId, depositId, deployments.accounts.users[0].address, amount, signature) + .depositToBridge(tokenId, depositId, deployments.accounts.users[0].address, amount, expiry, signature) ) .to.emit(bridgeContract, "BridgeDeposited") .withNamedArgs({ @@ -160,18 +165,22 @@ describe("Test for Ledger", () => { const oldTokenBalance = await ledgerContract.tokenBalanceOf(deployments.accounts.users[0].address); const nonce = await ledgerContract.nonceOf(deployments.accounts.users[0].address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + tokenContract.address, deployments.accounts.users[0].address, loyaltyBridgeContract.address, amount, - nonce + nonce, + expiry ); depositId = ContractUtils.getRandomId(deployments.accounts.users[0].address); const signature = await ContractUtils.signMessage(deployments.accounts.users[0], message); await expect( loyaltyBridgeContract .connect(deployments.accounts.certifiers[0]) - .depositToBridge(tokenId, depositId, deployments.accounts.users[0].address, amount, signature) + .depositToBridge(tokenId, depositId, deployments.accounts.users[0].address, amount, expiry, signature) ) .to.emit(loyaltyBridgeContract, "BridgeDeposited") .withNamedArgs({ diff --git a/packages/contracts/test/07-PhoneLink.test.ts b/packages/contracts/test/07-PhoneLink.test.ts new file mode 100644 index 00000000..99b567c2 --- /dev/null +++ b/packages/contracts/test/07-PhoneLink.test.ts @@ -0,0 +1,184 @@ +import "@nomiclabs/hardhat-ethers"; +import "@nomiclabs/hardhat-waffle"; +import "@openzeppelin/hardhat-upgrades"; +import { ethers, upgrades, waffle } from "hardhat"; + +import { ContractUtils } from "../src/utils/ContractUtils"; +import { ERC20, PhoneLinkCollection } from "../typechain-types"; + +import assert from "assert"; +import chai, { expect } from "chai"; +import { solidity } from "ethereum-waffle"; + +import { BigNumber } from "ethers"; + +// tslint:disable-next-line:no-implicit-dependencies +import { AddressZero, HashZero } from "@ethersproject/constants"; +import { Deployments } from "./helper/Deployments"; + +chai.use(solidity); + +describe("Test for PhoneLinkCollection", () => { + const deployments = new Deployments(); + + let contract: PhoneLinkCollection; + let requestId: string; + + before(async () => { + await deployments.doDeployLedger(); + contract = deployments.getContract("PhoneLinkCollection") as PhoneLinkCollection; + }); + + it("Add an request item", async () => { + const nonce = await contract.nonceOf(deployments.accounts.users[0].address); + assert.deepStrictEqual(nonce.toString(), "0"); + const phone = "08201012341234"; + const hash = ContractUtils.getPhoneHash(phone); + const message = ContractUtils.getRequestMessage(hash, deployments.accounts.users[0].address, nonce); + const signature = await ContractUtils.signMessage(deployments.accounts.users[0], message); + requestId = ContractUtils.getRequestId(hash, deployments.accounts.users[0].address, nonce); + expect(await contract.connect(deployments.accounts.certifiers[0]).isAvailable(requestId)).to.equal(true); + await expect( + contract + .connect(deployments.accounts.certifiers[0]) + .addRequest(requestId, hash, deployments.accounts.users[0].address, signature) + ) + .to.emit(contract, "AddedRequestItem") + .withArgs(requestId, hash, deployments.accounts.users[0].address); + assert.deepStrictEqual((await contract.nonceOf(deployments.accounts.users[0].address)).toString(), "1"); + expect(await contract.connect(deployments.accounts.certifiers[0]).isAvailable(requestId)).to.equal(false); + }); + + it("Vote of request item", async () => { + const phone = "08201012341234"; + const hash = ContractUtils.getPhoneHash(phone); + await contract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await contract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); + + await expect(contract.connect(deployments.accounts.linkValidators[0]).countVote(requestId)) + .to.emit(contract, "AcceptedRequestItem") + .withArgs(requestId, hash, deployments.accounts.users[0].address); + + assert.deepStrictEqual(await contract.toAddress(hash), deployments.accounts.users[0].address); + assert.deepStrictEqual(await contract.toPhone(deployments.accounts.users[0].address), hash); + }); + + it("Update an item", async () => { + const phone = "08201012341234"; + const hash = ContractUtils.getPhoneHash(phone); + + const nonce = await contract.nonceOf(deployments.accounts.users[1].address); + const message = ContractUtils.getRequestMessage(hash, deployments.accounts.users[1].address, nonce); + const signature = await ContractUtils.signMessage(deployments.accounts.users[1], message); + + requestId = ContractUtils.getRequestId(hash, deployments.accounts.users[1].address, nonce); + expect(await contract.connect(deployments.accounts.certifiers[0]).isAvailable(requestId)).to.equal(true); + await expect( + contract + .connect(deployments.accounts.certifiers[0]) + .addRequest(requestId, hash, deployments.accounts.users[1].address, signature) + ) + .to.emit(contract, "AddedRequestItem") + .withArgs(requestId, hash, deployments.accounts.users[1].address); + assert.deepStrictEqual((await contract.nonceOf(deployments.accounts.users[1].address)).toString(), "1"); + expect(await contract.connect(deployments.accounts.certifiers[0]).isAvailable(requestId)).to.equal(false); + }); + + it("Vote of update item", async () => { + const phone = "08201012341234"; + const hash = ContractUtils.getPhoneHash(phone); + await contract.connect(deployments.accounts.linkValidators[0]).voteRequest(requestId); + await contract.connect(deployments.accounts.linkValidators[1]).voteRequest(requestId); + + await expect(contract.connect(deployments.accounts.linkValidators[0]).countVote(requestId)) + .to.emit(contract, "AcceptedRequestItem") + .withArgs(requestId, hash, deployments.accounts.users[1].address); + + assert.deepStrictEqual(await contract.toAddress(hash), deployments.accounts.users[1].address); + assert.deepStrictEqual(await contract.toPhone(deployments.accounts.users[1].address), hash); + }); + + it("Remove item", async () => { + const phone = "08201012341234"; + const hash = ContractUtils.getPhoneHash(phone); + const nonce = await contract.nonceOf(deployments.accounts.users[1].address); + const message = ContractUtils.getRemoveMessage(deployments.accounts.users[1].address, nonce); + const signature = await ContractUtils.signMessage(deployments.accounts.users[1], message); + + await expect( + contract + .connect(deployments.accounts.linkValidators[0]) + .remove(deployments.accounts.users[1].address, signature) + ) + .to.emit(contract, "RemovedItem") + .withArgs(hash, deployments.accounts.users[1].address); + + assert.deepStrictEqual(await contract.toAddress(hash), AddressZero); + assert.deepStrictEqual(await contract.toPhone(deployments.accounts.users[1].address), HashZero); + }); + + it("Check Null", async () => { + const phone = ""; + const hash = ContractUtils.getPhoneHash(phone); + expect(hash).to.equal("0x32105b1d0b88ada155176b58ee08b45c31e4f2f7337475831982c313533b880c"); + const nonce = await contract.nonceOf(deployments.accounts.users[2].address); + const message = ContractUtils.getRequestMessage(hash, deployments.accounts.users[2].address, nonce); + const signature = await ContractUtils.signMessage(deployments.accounts.users[2], message); + requestId = ContractUtils.getRequestId(hash, deployments.accounts.users[2].address, nonce); + await expect( + contract + .connect(deployments.accounts.certifiers[0]) + .addRequest(requestId, hash, deployments.accounts.users[2].address, signature) + ).to.be.revertedWith("Invalid phone hash"); + }); + + it("Validator's data", async () => { + const res = await contract.getValidators(); + assert.deepStrictEqual(res.length, deployments.accounts.linkValidators.length); + let idx = 0; + for (const item of res) { + assert.strictEqual(item.validator, deployments.accounts.linkValidators[idx++].address); + assert.strictEqual(item.status, 1); + } + }); + + it("Validator's address", async () => { + const res = await contract.getAddressOfValidators(); + assert.deepStrictEqual( + res, + deployments.accounts.linkValidators.map((m) => m.address) + ); + }); + + it("Validator length", async () => { + const res = await contract.getValidatorLength(); + assert.deepStrictEqual(res, BigNumber.from(3)); + }); + + it("Check Validator", async () => { + const length = (await contract.getValidatorLength()).toNumber(); + for (let idx = 0; idx < length; idx++) { + const res = await contract.getValidator(idx); + assert.strictEqual(res.validator, deployments.accounts.linkValidators[idx++].address); + assert.strictEqual(res.status, 1); + } + }); + + it("Set endpoint", async () => { + for (let idx = 0; idx < deployments.accounts.linkValidators.length; idx++) { + const res = await contract.getValidator(idx); + assert.strictEqual(res.endpoint, ""); + } + + for (let idx = 0; idx < deployments.accounts.linkValidators.length; idx++) { + const res = await contract + .connect(deployments.accounts.linkValidators[idx]) + .updateEndpoint(`http://127.0.0.1:${idx + 7070}`); + } + + for (let idx = 0; idx < deployments.accounts.linkValidators.length; idx++) { + const res = await contract.getValidator(idx); + assert.strictEqual(res.endpoint, `http://127.0.0.1:${idx + 7070}`); + } + }); +}); diff --git a/packages/contracts/test/helper/Deployments.ts b/packages/contracts/test/helper/Deployments.ts index 34a9a15a..f6501485 100644 --- a/packages/contracts/test/helper/Deployments.ts +++ b/packages/contracts/test/helper/Deployments.ts @@ -26,6 +26,9 @@ import { Validator, } from "../../typechain-types"; +// tslint:disable-next-line:no-duplicate-imports +import * as hre from "hardhat"; + interface IShopData { shopId: string; name: string; @@ -141,8 +144,8 @@ export class Deployments { fee, txFee, validators: [validator01, validator02, validator03], - linkValidators: [bridgeValidator1], - bridgeValidators: [validator04, validator05, validator06], + linkValidators: [linkValidator1, linkValidator2, linkValidator3], + bridgeValidators: [bridgeValidator1, bridgeValidator2, bridgeValidator3], certifiers: [ certifier01, certifier02, @@ -627,9 +630,18 @@ async function deployBridge(accounts: IAccount, deployment: Deployments) { await contract.connect(accounts.deployer).registerToken(tokenId, tokenContract.address); const assetAmount = Amount.make(1_000_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); - const message = ContractUtils.getTransferMessage(accounts.owner.address, contract.address, assetAmount, nonce); + const expiry = ContractUtils.getTimeStamp() + 3600; + const message = ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + tokenContract.address, + accounts.owner.address, + contract.address, + assetAmount, + nonce, + expiry + ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token (tx: ${tx1.hash})...`); await tx1.wait(); } @@ -820,9 +832,18 @@ async function deployLedger(accounts: IAccount, deployment: Deployments) { const tokenId = ContractUtils.getTokenId(await tokenContract.name(), await tokenContract.symbol()); const assetAmount = Amount.make(1_000_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); - const message = ContractUtils.getTransferMessage(accounts.owner.address, contract.address, assetAmount, nonce); + const expiry = ContractUtils.getTimeStamp() + 3600; + const message = ContractUtils.getTransferMessage( + hre.ethers.provider.network.chainId, + tokenContract.address, + accounts.owner.address, + contract.address, + assetAmount, + nonce, + expiry + ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx22 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx22 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token (tx: ${tx22.hash})...`); await tx22.wait(); } diff --git a/packages/faker/contracts/Reference.sol b/packages/faker/contracts/Reference.sol index 019016d3..34147232 100644 --- a/packages/faker/contracts/Reference.sol +++ b/packages/faker/contracts/Reference.sol @@ -2,17 +2,17 @@ pragma solidity ^0.8.2; -import "dms-osx-artifacts/contracts/controllers/LoyaltyBurner.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyConsumer.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyProvider.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyExchanger.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyTransfer.sol"; -import "dms-osx-artifacts/contracts/currency/CurrencyRate.sol"; -import "del-osx-artifacts/contracts/PhoneLinkCollection.sol"; -import "dms-osx-artifacts/contracts/ledger/Ledger.sol"; -import "dms-osx-artifacts/contracts/shop/Shop.sol"; -import "dms-osx-artifacts/contracts/validator/Validator.sol"; -import "dms-osx-artifacts/contracts/token/TestLYT.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyBurner.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyConsumer.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyProvider.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyExchanger.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyTransfer.sol"; +import "dms-contracts-v2/contracts/currency/CurrencyRate.sol"; +import "dms-contracts-v2/contracts/phone/PhoneLinkCollection.sol"; +import "dms-contracts-v2/contracts/ledger/Ledger.sol"; +import "dms-contracts-v2/contracts/shop/Shop.sol"; +import "dms-contracts-v2/contracts/validator/Validator.sol"; +import "dms-contracts-v2/contracts/token/TestLYT.sol"; -import "dms-bridge-contracts/contracts/bridge/Bridge.sol"; -import "dms-bridge-contracts/contracts/bridge/BridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/Bridge.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/BridgeValidator.sol"; diff --git a/packages/faker/package.json b/packages/faker/package.json index da6d67ce..de7a6d40 100644 --- a/packages/faker/package.json +++ b/packages/faker/package.json @@ -1,6 +1,6 @@ { "name": "dms-faker", - "version": "1.0.0", + "version": "2.0.0", "description": "", "main": "src/main.js", "directories": { @@ -25,7 +25,7 @@ "url": "https://github.com/bosagora/dms-osx/issues" }, "homepage": "https://github.com/bosagora/dms-osx#readme", - "devDependencies": { + "dependencies": { "@ethersproject/experimental": "^5.7.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.2", @@ -43,25 +43,22 @@ "@types/mocha": "^10.0.0", "@types/node": "^12.20.43", "@types/node-cron": "^3.0.1", - "@types/urijs": "^1.19.12" - }, - "dependencies": { + "@types/urijs": "^1.19.12", "argparse": "^2.0.1", "assert": "^2.0.0", "axios": "^1.6.7", "chai": "^4.3.7", - "del-osx-artifacts": "2.3.0", - "dms-bridge-contracts": "1.5.0", - "dms-osx-artifacts": "2.14.0", + "dms-bridge-contracts-v2": "~2.0.0", + "dms-contracts-v2": "~2.0.0", "dotenv": "^10.0.0", "ethereum-waffle": "^4.0.10", - "ethers": "5.7.0", + "ethers": "^5.7.0", "extend": "^3.0.2", "hardhat": "^2.12.7", "hardhat-gas-reporter": "^1.0.7", "ip": "^1.1.5", - "loyalty-tokens": "^1.1.0", - "multisig-wallet-contracts": "^1.1.0", + "loyalty-tokens": "~2.0.0", + "multisig-wallet-contracts": "~2.0.0", "node-cron": "^3.0.0", "prettier": "^2.5.1", "prettier-plugin-solidity": "^1.1.1", diff --git a/packages/relay/contracts/Reference.sol b/packages/relay/contracts/Reference.sol index 17468e6e..69e0dbb9 100644 --- a/packages/relay/contracts/Reference.sol +++ b/packages/relay/contracts/Reference.sol @@ -2,22 +2,22 @@ pragma solidity ^0.8.2; -import "dms-osx-artifacts/contracts/controllers/LoyaltyBurner.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyConsumer.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyProvider.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyExchanger.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyTransfer.sol"; -import "dms-osx-artifacts/contracts/controllers/LoyaltyBridge.sol"; -import "dms-osx-artifacts/contracts/currency/CurrencyRate.sol"; -import "del-osx-artifacts/contracts/PhoneLinkCollection.sol"; -import "dms-osx-artifacts/contracts/ledger/Ledger.sol"; -import "dms-osx-artifacts/contracts/shop/Shop.sol"; -import "dms-osx-artifacts/contracts/validator/Validator.sol"; -import "dms-osx-artifacts/contracts/token/TestLYT.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyBurner.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyConsumer.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyProvider.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyExchanger.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyTransfer.sol"; +import "dms-contracts-v2/contracts/controllers/LoyaltyBridge.sol"; +import "dms-contracts-v2/contracts/currency/CurrencyRate.sol"; +import "dms-contracts-v2/contracts/phone/PhoneLinkCollection.sol"; +import "dms-contracts-v2/contracts/ledger/Ledger.sol"; +import "dms-contracts-v2/contracts/shop/Shop.sol"; +import "dms-contracts-v2/contracts/validator/Validator.sol"; +import "dms-contracts-v2/contracts/token/TestLYT.sol"; import "multisig-wallet-contracts/contracts/MultiSigWalletFactory.sol"; import "multisig-wallet-contracts/contracts/MultiSigWallet.sol"; import "loyalty-tokens/contracts/LYT.sol"; -import "dms-bridge-contracts/contracts/bridge/Bridge.sol"; -import "dms-bridge-contracts/contracts/bridge/BridgeValidator.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/Bridge.sol"; +import "dms-bridge-contracts-v2/contracts/bridge/BridgeValidator.sol"; diff --git a/packages/relay/docker-compose.yml b/packages/relay/docker-compose.yml index 50452020..1a6e23a7 100644 --- a/packages/relay/docker-compose.yml +++ b/packages/relay/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.3' services: postgres: image: postgres:14 diff --git a/packages/relay/package.json b/packages/relay/package.json index 0c24f121..81c79beb 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -1,6 +1,6 @@ { "name": "dms-relay", - "version": "1.0.0", + "version": "2.0.0", "description": "Relay the transaction for the decentralized mileage system", "main": "src/main.js", "directories": { @@ -39,7 +39,7 @@ "url": "https://github.com/bosagora/dms-osx/issues" }, "homepage": "https://github.com/bosagora/dms-osx#readme", - "devDependencies": { + "dependencies": { "@ethersproject/experimental": "^5.7.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-waffle": "^2.0.2", @@ -60,9 +60,7 @@ "@types/node": "^12.20.43", "@types/node-cron": "^3.0.1", "@types/pg": "^8.10.7", - "@types/urijs": "^1.19.12" - }, - "dependencies": { + "@types/urijs": "^1.19.12", "argparse": "^2.0.1", "assert": "^2.0.0", "axios": "^1.6.7", @@ -70,13 +68,12 @@ "chai": "^4.3.7", "chai-http": "^4.3.7", "cors": "^2.8.5", - "del-osx-artifacts": "2.3.0", - "dms-bridge-contracts": "1.5.0", - "dms-osx-artifacts": "2.14.0", + "dms-bridge-contracts-v2": "~2.0.0", + "dms-contracts-v2": "~2.0.0", "dotenv": "^10.0.0", "ethereum-waffle": "^4.0.10", "ethereumjs-util": "^7.1.5", - "ethers": "5.7.0", + "ethers": "^5.7.0", "expo-server-sdk": "^3.7.0", "express": "^4.17.1", "express-validator": "^6.14.0", @@ -85,8 +82,8 @@ "hardhat": "^2.12.7", "hardhat-gas-reporter": "^1.0.7", "ip": "^1.1.5", - "loyalty-tokens": "1.1.0", - "multisig-wallet-contracts": "1.1.0", + "loyalty-tokens": "~2.0.0", + "multisig-wallet-contracts": "~2.0.0", "mybatis-mapper": "^0.7.1", "node-cron": "^3.0.0", "pg": "^8.11.3", diff --git a/packages/relay/src/routers/BridgeRouter.ts b/packages/relay/src/routers/BridgeRouter.ts index 6c98c538..53a4686b 100644 --- a/packages/relay/src/routers/BridgeRouter.ts +++ b/packages/relay/src/routers/BridgeRouter.ts @@ -87,6 +87,7 @@ export class BridgeRouter { [ body("account").exists().trim().isEthereumAddress(), body("amount").exists().custom(Validation.isAmount), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -100,6 +101,7 @@ export class BridgeRouter { [ body("account").exists().trim().isEthereumAddress(), body("amount").exists().custom(Validation.isAmount), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -135,6 +137,7 @@ export class BridgeRouter { try { const account: string = String(req.body.account).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.sideTokenContract.balanceOf(account); @@ -142,11 +145,13 @@ export class BridgeRouter { const nonce = await this.contractManager.sideTokenContract.nonceOf(account); const message = ContractUtils.getTransferMessage( + this.contractManager.sideChainId, + this.contractManager.sideTokenContract.address, account, this.contractManager.sideChainBridgeContract.address, amount, nonce, - this.contractManager.sideChainId + expiry ); if (!ContractUtils.verifyMessage(account, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); @@ -158,7 +163,7 @@ export class BridgeRouter { const depositId = await this.getDepositIdSideChain(account); const tx = await this.contractManager.sideChainBridgeContract .connect(signerItem.signer) - .depositToBridge(tokenId, depositId, account, amount, signature); + .depositToBridge(tokenId, depositId, account, amount, expiry, signature); return res.status(200).json(this.makeResponseData(0, { tokenId, depositId, amount, txHash: tx.hash })); } catch (error: any) { @@ -183,6 +188,7 @@ export class BridgeRouter { try { const account: string = String(req.body.account).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.mainTokenContract.balanceOf(account); @@ -190,11 +196,13 @@ export class BridgeRouter { const nonce = await this.contractManager.mainTokenContract.nonceOf(account); const message = ContractUtils.getTransferMessage( + this.contractManager.mainChainId, + this.contractManager.mainTokenContract.address, account, this.contractManager.mainChainBridgeContract.address, amount, nonce, - this.contractManager.mainChainId + expiry ); if (!ContractUtils.verifyMessage(account, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); @@ -206,7 +214,7 @@ export class BridgeRouter { const depositId = await this.getDepositIdMainChain(account); const tx = await this.contractManager.mainChainBridgeContract .connect(signerItem.signer) - .depositToBridge(tokenId, depositId, account, amount, signature); + .depositToBridge(tokenId, depositId, account, amount, expiry, signature); return res.status(200).json(this.makeResponseData(0, { tokenId, depositId, amount, txHash: tx.hash })); } catch (error: any) { diff --git a/packages/relay/src/routers/LedgerRouter.ts b/packages/relay/src/routers/LedgerRouter.ts index b8a5d609..9a54b66a 100644 --- a/packages/relay/src/routers/LedgerRouter.ts +++ b/packages/relay/src/routers/LedgerRouter.ts @@ -169,6 +169,7 @@ export class LedgerRouter { body("amount").exists().custom(Validation.isAmount), body("from").exists().trim().isEthereumAddress(), body("to").exists().trim().isEthereumAddress(), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -182,6 +183,7 @@ export class LedgerRouter { [ body("account").exists().trim().isEthereumAddress(), body("amount").exists().custom(Validation.isAmount), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -195,6 +197,7 @@ export class LedgerRouter { [ body("account").exists().trim().isEthereumAddress(), body("amount").exists().custom(Validation.isAmount), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -566,18 +569,27 @@ export class LedgerRouter { const from: string = String(req.body.from).trim(); const to: string = String(req.body.to).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.sideLedgerContract.tokenBalanceOf(from); if (balance.lt(amount)) return res.status(200).json(ResponseMessage.getErrorMessage("1511")); const nonce = await this.contractManager.sideLedgerContract.nonceOf(from); - const message = ContractUtils.getTransferMessage(from, to, amount, nonce, this.contractManager.sideChainId); + const message = ContractUtils.getTransferMessage( + this.contractManager.sideChainId, + this.contractManager.sideLoyaltyTransferContract.address, + from, + to, + amount, + nonce, + expiry + ); if (!ContractUtils.verifyMessage(from, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); const tx = await this.contractManager.sideLoyaltyTransferContract .connect(signerItem.signer) - .transferToken(from, to, amount, signature); + .transferToken(from, to, amount, expiry, signature); this.metrics.add("success", 1); return res.status(200).json(this.makeResponseData(0, { from, to, amount, txHash: tx.hash })); } catch (error: any) { @@ -616,6 +628,7 @@ export class LedgerRouter { try { const account: string = String(req.body.account).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.sideLedgerContract.tokenBalanceOf(account); @@ -623,11 +636,13 @@ export class LedgerRouter { const nonce = await this.contractManager.sideLedgerContract.nonceOf(account); const message = ContractUtils.getTransferMessage( + this.contractManager.sideChainId, + this.contractManager.sideTokenContract.address, account, this.contractManager.sideLoyaltyBridgeContract.address, amount, nonce, - this.contractManager.sideChainId + expiry ); if (!ContractUtils.verifyMessage(account, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); @@ -639,7 +654,7 @@ export class LedgerRouter { const depositId = await this.getDepositIdSideChain(account); const tx = await this.contractManager.sideLoyaltyBridgeContract .connect(signerItem.signer) - .depositToBridge(tokenId, depositId, account, amount, signature); + .depositToBridge(tokenId, depositId, account, amount, expiry, signature); return res.status(200).json(this.makeResponseData(0, { tokenId, depositId, amount, txHash: tx.hash })); } catch (error: any) { @@ -664,6 +679,7 @@ export class LedgerRouter { try { const account: string = String(req.body.account).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.mainTokenContract.balanceOf(account); @@ -671,11 +687,13 @@ export class LedgerRouter { const nonce = await this.contractManager.mainTokenContract.nonceOf(account); const message = ContractUtils.getTransferMessage( + this.contractManager.mainChainId, + this.contractManager.mainTokenContract.address, account, this.contractManager.mainLoyaltyBridgeContract.address, amount, nonce, - this.contractManager.mainChainId + expiry ); if (!ContractUtils.verifyMessage(account, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); @@ -687,7 +705,7 @@ export class LedgerRouter { const depositId = await this.getDepositIdMainChain(account); const tx = await this.contractManager.mainLoyaltyBridgeContract .connect(signerItem.signer) - .depositToBridge(tokenId, depositId, account, amount, signature); + .depositToBridge(tokenId, depositId, account, amount, expiry, signature); return res.status(200).json(this.makeResponseData(0, { tokenId, depositId, amount, txHash: tx.hash })); } catch (error: any) { diff --git a/packages/relay/src/routers/TokenRouter.ts b/packages/relay/src/routers/TokenRouter.ts index 461451e0..17b64532 100644 --- a/packages/relay/src/routers/TokenRouter.ts +++ b/packages/relay/src/routers/TokenRouter.ts @@ -114,6 +114,7 @@ export class TokenRouter { body("amount").exists().custom(Validation.isAmount), body("from").exists().trim().isEthereumAddress(), body("to").exists().trim().isEthereumAddress(), + body("expiry").exists().isNumeric(), body("signature") .exists() .trim() @@ -127,6 +128,7 @@ export class TokenRouter { [ body("amount").exists().custom(Validation.isAmount), body("from").exists().trim().isEthereumAddress(), + body("expiry").exists().isNumeric(), body("to").exists().trim().isEthereumAddress(), body("signature") .exists() @@ -222,17 +224,26 @@ export class TokenRouter { const from: string = String(req.body.from).trim(); const to: string = String(req.body.to).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.mainTokenContract.balanceOf(from); if (balance.lt(amount)) return res.status(200).json(ResponseMessage.getErrorMessage("1511")); const nonce = await this.contractManager.mainTokenContract.nonceOf(from); - const message = ContractUtils.getTransferMessage(from, to, amount, nonce, this.contractManager.mainChainId); + const message = ContractUtils.getTransferMessage( + this.contractManager.mainChainId, + this.contractManager.mainTokenContract.address, + from, + to, + amount, + nonce, + expiry + ); if (!ContractUtils.verifyMessage(from, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); const tx = await this.contractManager.mainTokenContract .connect(signerItem.signer) - .delegatedTransfer(from, to, amount, signature); + .delegatedTransfer(from, to, amount, expiry, signature); this.metrics.add("success", 1); return res.status(200).json(this.makeResponseData(0, { from, to, amount, txHash: tx.hash })); } catch (error: any) { @@ -258,17 +269,26 @@ export class TokenRouter { const from: string = String(req.body.from).trim(); const to: string = String(req.body.to).trim(); const amount: BigNumber = BigNumber.from(req.body.amount); + const expiry: number = Number(req.body.expiry); const signature: string = String(req.body.signature).trim(); const balance = await this.contractManager.sideTokenContract.balanceOf(from); if (balance.lt(amount)) return res.status(200).json(ResponseMessage.getErrorMessage("1511")); const nonce = await this.contractManager.sideTokenContract.nonceOf(from); - const message = ContractUtils.getTransferMessage(from, to, amount, nonce, this.contractManager.sideChainId); + const message = ContractUtils.getTransferMessage( + this.contractManager.sideChainId, + this.contractManager.sideTokenContract.address, + from, + to, + amount, + nonce, + expiry + ); if (!ContractUtils.verifyMessage(from, message, signature)) return res.status(200).json(ResponseMessage.getErrorMessage("1501")); const tx = await this.contractManager.sideTokenContract .connect(signerItem.signer) - .delegatedTransfer(from, to, amount, signature); + .delegatedTransfer(from, to, amount, expiry, signature); this.metrics.add("success", 1); return res.status(200).json(this.makeResponseData(0, { from, to, amount, txHash: tx.hash })); } catch (error: any) { diff --git a/packages/relay/src/utils/ContractUtils.ts b/packages/relay/src/utils/ContractUtils.ts index 89e56a63..4fb77159 100644 --- a/packages/relay/src/utils/ContractUtils.ts +++ b/packages/relay/src/utils/ContractUtils.ts @@ -612,15 +612,17 @@ export class ContractUtils { } public static getTransferMessage( + chainId: BigNumberish, + tokenAddress: string, from: string, to: string, amount: BigNumberish, nonce: BigNumberish, - chainId: BigNumberish + expiry: number ): Uint8Array { const encodedResult = defaultAbiCoder.encode( - ["address", "address", "uint256", "uint256", "uint256"], - [from, to, amount, chainId, nonce] + ["uint256", "address", "address", "address", "uint256", "uint256", "uint256"], + [chainId, tokenAddress, from, to, amount, nonce, expiry] ); return arrayify(keccak256(encodedResult)); } diff --git a/packages/relay/src/utils/Errors.ts b/packages/relay/src/utils/Errors.ts index 10d1a0ca..7377a47a 100644 --- a/packages/relay/src/utils/Errors.ts +++ b/packages/relay/src/utils/Errors.ts @@ -36,6 +36,7 @@ export class ResponseMessage { ["1502", "Unregistered phone number"], ["1503", "Does not match registered wallet address"], ["1505", "Invalid secret key"], + ["1506", "Expired signature"], ["1510", "Insufficient foundation balance"], ["1511", "Insufficient balance"], ["1512", "Not allowed deposit"], diff --git a/packages/relay/test/Bridge.test.ts b/packages/relay/test/Bridge.test.ts index 984bccb3..3c55b93e 100644 --- a/packages/relay/test/Bridge.test.ts +++ b/packages/relay/test/Bridge.test.ts @@ -111,17 +111,21 @@ describe("Test of Bridge", function () { const balance2 = await contractManager.sideTokenContract.balanceOf(account.address); const nonce = await contractManager.mainTokenContract.nonceOf(account.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.mainChainId, + contractManager.mainTokenContract.address, account.address, contractManager.mainChainBridgeContract.address, amount, nonce, - contractManager.mainChainId + expiry ); const signature = await ContractUtils.signMessage(account, message); const response = await client.post(URI(serverURL).directory("/v1/bridge/deposit").toString(), { account: account.address, amount: amount.toString(), + expiry, signature, }); @@ -172,17 +176,21 @@ describe("Test of Bridge", function () { const balance2 = await contractManager.sideTokenContract.balanceOf(account.address); const nonce = await contractManager.sideTokenContract.nonceOf(account.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.sideChainId, + contractManager.sideTokenContract.address, account.address, contractManager.sideChainBridgeContract.address, amount, nonce, - contractManager.sideChainId + expiry ); const signature = await ContractUtils.signMessage(account, message); const response = await client.post(URI(serverURL).directory("/v1/bridge/withdraw").toString(), { account: account.address, amount: amount.toString(), + expiry, signature, }); diff --git a/packages/relay/test/DelegatedTransfer.test.ts b/packages/relay/test/DelegatedTransfer.test.ts index 18661c9b..50bc1ba0 100644 --- a/packages/relay/test/DelegatedTransfer.test.ts +++ b/packages/relay/test/DelegatedTransfer.test.ts @@ -102,18 +102,22 @@ describe("Test of delegated transfer", function () { const balance1 = await contractManager.mainTokenContract.balanceOf(target.address); const amount = Amount.make(500, 18).value; const nonce = await contractManager.mainTokenContract.nonceOf(source.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.mainChainId, + contractManager.mainTokenContract.address, source.address, target.address, amount, nonce, - contractManager.sideChainId + expiry ); const signature = await ContractUtils.signMessage(source, message); const response = await client.post(URI(serverURL).directory("/v1/token/main/transfer").toString(), { from: source.address, to: target.address, amount: amount.toString(), + expiry, signature, }); @@ -132,18 +136,22 @@ describe("Test of delegated transfer", function () { const balance1 = await contractManager.sideTokenContract.balanceOf(target.address); const amount = Amount.make(500, 18).value; const nonce = await contractManager.sideTokenContract.nonceOf(source.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.sideChainId, + contractManager.sideTokenContract.address, source.address, target.address, amount, nonce, - contractManager.sideChainId + expiry ); const signature = await ContractUtils.signMessage(source, message); const response = await client.post(URI(serverURL).directory("/v1/token/side/transfer").toString(), { from: source.address, to: target.address, amount: amount.toString(), + expiry, signature, }); diff --git a/packages/relay/test/LoyaltyBridge.test.ts b/packages/relay/test/LoyaltyBridge.test.ts index 1696d324..c0258774 100644 --- a/packages/relay/test/LoyaltyBridge.test.ts +++ b/packages/relay/test/LoyaltyBridge.test.ts @@ -111,17 +111,21 @@ describe("Test of LoyaltyBridge", function () { const balance2 = await contractManager.sideLedgerContract.tokenBalanceOf(account.address); const nonce = await contractManager.mainTokenContract.nonceOf(account.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.mainChainId, + contractManager.mainTokenContract.address, account.address, contractManager.mainLoyaltyBridgeContract.address, amount, nonce, - contractManager.mainChainId + expiry ); const signature = await ContractUtils.signMessage(account, message); const response = await client.post(URI(serverURL).directory("/v1/ledger/deposit_via_bridge").toString(), { account: account.address, amount: amount.toString(), + expiry, signature, }); @@ -172,17 +176,21 @@ describe("Test of LoyaltyBridge", function () { const balance2 = await contractManager.sideLedgerContract.tokenBalanceOf(account.address); const nonce = await contractManager.sideLedgerContract.nonceOf(account.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.sideChainId, + contractManager.sideTokenContract.address, account.address, contractManager.sideLoyaltyBridgeContract.address, amount, nonce, - contractManager.sideChainId + expiry ); const signature = await ContractUtils.signMessage(account, message); const response = await client.post(URI(serverURL).directory("/v1/ledger/withdraw_via_bridge").toString(), { account: account.address, amount: amount.toString(), + expiry, signature, }); diff --git a/packages/relay/test/LoyaltyTransfer.test.ts b/packages/relay/test/LoyaltyTransfer.test.ts index 45841fce..a869a0b6 100644 --- a/packages/relay/test/LoyaltyTransfer.test.ts +++ b/packages/relay/test/LoyaltyTransfer.test.ts @@ -127,18 +127,22 @@ describe("Test of LoyaltyTransfer", function () { const fee = await contractManager.sideLoyaltyTransferContract.getFee(); const amount = Amount.make(500, 18).value; const nonce = await contractManager.sideLedgerContract.nonceOf(source.address); + const expiry = ContractUtils.getTimeStamp() * 600; const message = await ContractUtils.getTransferMessage( + contractManager.sideChainId, + contractManager.sideLoyaltyTransferContract.address, source.address, target.address, amount, nonce, - contractManager.sideChainId + expiry ); const signature = await ContractUtils.signMessage(source, message); const response = await client.post(URI(serverURL).directory("/v1/ledger/transfer").toString(), { from: source.address, to: target.address, amount: amount.toString(), + expiry, signature, }); diff --git a/packages/relay/test/helper/Deployments.ts b/packages/relay/test/helper/Deployments.ts index 0030da5a..9190df79 100644 --- a/packages/relay/test/helper/Deployments.ts +++ b/packages/relay/test/helper/Deployments.ts @@ -583,15 +583,18 @@ async function deploySideChainBridge(accounts: IAccount, deployment: Deployments await contract.connect(accounts.deployer).registerToken(tokenId, tokenContract.address); const assetAmount = Amount.make(1_000_000_000, 18).value; const nonce = await (deployment.getContract("TestLYT") as TestLYT).nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to SideChainBridge (tx: ${tx1.hash})...`); await tx1.wait(); } @@ -785,15 +788,18 @@ async function deployLedger(accounts: IAccount, deployment: Deployments) { const tokenId = ContractUtils.getTokenId(await tokenContract.name(), await tokenContract.symbol()); const assetAmount = Amount.make(1_000_000_000, 18).value; const nonce = await (deployment.getContract("TestLYT") as TestLYT).nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx21 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx21 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token (tx: ${tx21.hash})...`); await tx21.wait(); } @@ -865,15 +871,18 @@ async function deployMainChainBridge(accounts: IAccount, deployment: Deployments await contract.connect(accounts.deployer).registerToken(tokenId, tokenContract.address); const assetAmount = Amount.make(8_000_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to MainChainBridge (tx: ${tx1.hash})...`); await tx1.wait(); } @@ -910,15 +919,18 @@ async function deployMainChainLoyaltyBridge(accounts: IAccount, deployment: Depl await contract.connect(accounts.deployer).registerToken(tokenId, tokenContract.address); const assetAmount = Amount.make(1_000_000_000, 18).value; const nonce = await tokenContract.nonceOf(accounts.owner.address); + const expiry = ContractUtils.getTimeStamp() + 3600; const message = ContractUtils.getTransferMessage( + chainId, + tokenContract.address, accounts.owner.address, contract.address, assetAmount, nonce, - chainId + expiry ); const signature = await ContractUtils.signMessage(accounts.owner, message); - const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, signature); + const tx1 = await contract.connect(accounts.owner).depositLiquidity(tokenId, assetAmount, expiry, signature); console.log(`Deposit liquidity token to MainChainLoyaltyBridge (tx: ${tx1.hash})...`); await tx1.wait(); } diff --git a/yarn.lock b/yarn.lock index a0af3cab..0b386487 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3275,11 +3275,6 @@ define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4, de has-property-descriptors "^1.0.0" object-keys "^1.1.1" -del-osx-artifacts@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/del-osx-artifacts/-/del-osx-artifacts-2.3.0.tgz#eae1293951b2e857056d5f6253485ba92c5a29f5" - integrity sha512-W5/WSXqitJ6qT8QWFcO3JQpWlgYQTMrGdsG8BUER80SFPtzOt6AiLb0veLqqShSc9JamFZOKL+H+pApyXUfjvw== - delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" @@ -3350,10 +3345,15 @@ discontinuous-range@1.0.0: resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" integrity sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ== -dms-bridge-contracts@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/dms-bridge-contracts/-/dms-bridge-contracts-1.5.0.tgz#b8d202599a8994ef6b9ff726fd63476ba339e116" - integrity sha512-NPheXtZMk5gkqkUf6gt3TyfcmKeD/7vJ7fuY2Bp8JPZi2APfgwpeArU/ff/WY11ixiYKLb8WsFvx3IMX0NHvdw== +dms-bridge-contracts-v2@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dms-bridge-contracts-v2/-/dms-bridge-contracts-v2-2.0.0.tgz#d43720c5679bb48a4db0dc9a0167b990a10c7198" + integrity sha512-rapcN25LVOl4BF1hdnPr9VmW95+QewIO+ID852Sy3eeCOSvZlHcB2k2P1a8hLxnI6+NixCczvzE/gUFQUxx3Zg== + dependencies: + "@openzeppelin/contracts" "^4.9.5" + "@openzeppelin/contracts-upgradeable" "^4.9.5" + "@openzeppelin/hardhat-upgrades" "^1.28.0" + loyalty-tokens "~2.0.0" dns-over-http-resolver@^1.2.3: version "1.2.3" @@ -4553,6 +4553,17 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@8.1.0, glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + glob@9.3.5: version "9.3.5" resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" @@ -4586,17 +4597,6 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^8.0.3: - version "8.1.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -6002,10 +6002,13 @@ loupe@^2.3.1: dependencies: get-func-name "^2.0.0" -loyalty-tokens@1.1.0, loyalty-tokens@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loyalty-tokens/-/loyalty-tokens-1.1.0.tgz#466d5afb299699201b241674247dbbbb5087edb5" - integrity sha512-AtWw5Jc/rBy76TF9Dqo+LGBzSBC4Qlz7Z0xnKRKqsWUxlG29YjuaJ6uoZhkBNthx2HxbDD7RCDgFdAO9G9aSKA== +loyalty-tokens@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loyalty-tokens/-/loyalty-tokens-2.0.0.tgz#5e9e24674598fd8cdf43f14462ff8ca898da19f2" + integrity sha512-XDKfITphWr+DYSO0RGl/Kec8WA7UQ7odskcmllK0Kr2eomX+jkmKa19tNEKVsD0IBHx3TsaIMqLp57MPRMG7fg== + dependencies: + "@openzeppelin/contracts" "^4.9.5" + multisig-wallet-contracts "^2.0.0" lru-cache@^5.1.1: version "5.1.1" @@ -6293,33 +6296,6 @@ mnemonist@^0.38.0: dependencies: obliterator "^2.0.0" -mocha@10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" - integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - nanoid "3.3.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - mocha@7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.1.2.tgz#8e40d198acf91a52ace122cd7599c9ab857b29e6" @@ -6377,6 +6353,32 @@ mocha@^10.0.0: yargs-parser "20.2.4" yargs-unparser "2.0.0" +mocha@^10.1.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.4.0.tgz#ed03db96ee9cfc6d20c56f8e2af07b961dbae261" + integrity sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "8.1.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mocha@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" @@ -6461,10 +6463,12 @@ multiformats@^9.4.13, multiformats@^9.4.2, multiformats@^9.4.5, multiformats@^9. resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.9.0.tgz#c68354e7d21037a8f1f8833c8ccd68618e8f1d37" integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg== -multisig-wallet-contracts@1.1.0, multisig-wallet-contracts@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/multisig-wallet-contracts/-/multisig-wallet-contracts-1.1.0.tgz#680b28bdbf9b2860bb853abdbe2b5910b1b0dfee" - integrity sha512-dJCxmOBqZZicKjshiC9SS17XPZJWSU/FpZ8eCw1WWTH08jjMudRaKMtJ/l0pjadFRUQ/wDhCUInIixoGhHyCyg== +multisig-wallet-contracts@^2.0.0, multisig-wallet-contracts@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/multisig-wallet-contracts/-/multisig-wallet-contracts-2.0.0.tgz#b9b57eb487c5e93d966b9acda10dea28924c69f1" + integrity sha512-knROI/F5ujaj2uRiyctC2BfMQ4gAb7HAou3qODvPP+YDhF5FxtHGu8mjFoFZZf1sILFMD8gsg1pl2vNV7JCBJA== + dependencies: + "@openzeppelin/contracts" "^4.9.5" mustache@^4.2.0: version "4.2.0"