From ab6f301e66275e106f108ab6207eae01340a6147 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 29 Aug 2022 18:43:27 +0300 Subject: [PATCH 01/62] Add auxiliary functions --- proxy/contracts/MessageProxy.sol | 3 +- .../schain/MessageProxyForSchain.sol | 39 +++++++++++++++---- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol index 36c8ba12a..1b1317014 100644 --- a/proxy/contracts/MessageProxy.sol +++ b/proxy/contracts/MessageProxy.sol @@ -57,8 +57,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr // schainHash => ConnectedChainInfo mapping(bytes32 => ConnectedChainInfo) public connectedChains; // schainHash => contract address => allowed - // solhint-disable-next-line private-vars-leading-underscore - mapping(bytes32 => mapping(address => bool)) internal deprecatedRegistryContracts; + mapping(bytes32 => mapping(address => bool)) internal _deprecatedRegistryContracts; uint256 public gasLimit; diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index 4ce9bad84..d304f0d69 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -99,6 +99,10 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { string public version; bool public override messageInProgress; + // if receiver has no sFuil it's balance is topupped from etherbase + // if value is 0 MINIMUM_BALANCE is used + uint256 public minimumReceiverBalance; + /** * @dev Reentrancy guard for postIncomingMessages. */ @@ -203,7 +207,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { for (uint256 i = 0; i < messages.length; i++) { _callReceiverContract(fromChainHash, messages[i], startingCounter + 1); } - _topUpBalance(); + _topUpSenderBalance(); } /** @@ -219,6 +223,10 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { version = newVersion; } + function setMinimumReceiverBalance(uint256 balance) external onlyConstantSetter { + minimumReceiverBalance = balance; + } + /** * @dev Verify if the message metadata is valid. */ @@ -372,20 +380,35 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } /** - * @dev Move skETH from Etherbase if the balance is too low + * @dev Move skETH from Etherbase if the sender balance is too low */ - function _topUpBalance() private { + function _topUpSenderBalance() private { uint balance = msg.sender.balance + gasleft() * tx.gasprice; + if (balance < MINIMUM_BALANCE) { + _transferFromEtherbase(payable(msg.sender), MINIMUM_BALANCE - balance); + } + } + + function _topUpReceiverBalance(address payable receiver) private { + uint256 balance = receiver.balance; + uint256 threashold = minimumReceiverBalance; + if (threashold == 0) { + threashold = MINIMUM_BALANCE; + } + if (balance < threashold) { + _transferFromEtherbase(receiver, threashold - balance); + } + } + + function _transferFromEtherbase(address payable target, uint256 value) private { IEtherbaseUpgradeable etherbase = _getEtherbase(); if (address(etherbase).isContract() && etherbase.hasRole(etherbase.ETHER_MANAGER_ROLE(), address(this)) - && balance < MINIMUM_BALANCE ) { - uint missingAmount = MINIMUM_BALANCE - balance; - if (missingAmount < address(etherbase).balance) { - etherbase.partiallyRetrieve(payable(msg.sender), missingAmount); + if (value < address(etherbase).balance) { + etherbase.partiallyRetrieve(target, value); } else { - etherbase.retrieve(payable(msg.sender)); + etherbase.retrieve(target); } } } From f65b87287851fc7dca45b3a30aeb0474b79c567e Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 31 Aug 2022 18:07:32 +0300 Subject: [PATCH 02/62] Implement receiver topping up --- proxy/contracts/MessageProxy.sol | 2 +- .../schain/MessageProxyForSchain.sol | 25 ++++++++++--------- proxy/contracts/schain/TokenManagerLinker.sol | 1 + .../TokenManagers/TokenManagerERC1155.sol | 2 ++ .../TokenManagers/TokenManagerERC20.sol | 1 + .../TokenManagers/TokenManagerERC721.sol | 1 + .../TokenManagerERC721WithMetadata.sol | 1 + .../schain/TokenManagers/TokenManagerEth.sol | 1 + proxy/package.json | 2 +- proxy/yarn.lock | 8 +++--- 10 files changed, 26 insertions(+), 18 deletions(-) diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol index 1b1317014..336847e11 100644 --- a/proxy/contracts/MessageProxy.sol +++ b/proxy/contracts/MessageProxy.sol @@ -57,7 +57,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr // schainHash => ConnectedChainInfo mapping(bytes32 => ConnectedChainInfo) public connectedChains; // schainHash => contract address => allowed - mapping(bytes32 => mapping(address => bool)) internal _deprecatedRegistryContracts; + mapping(bytes32 => mapping(address => bool)) private _deprecatedRegistryContracts; uint256 public gasLimit; diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index d304f0d69..688f6ceb2 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -223,10 +223,22 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { version = newVersion; } - function setMinimumReceiverBalance(uint256 balance) external onlyConstantSetter { + function setMinimumReceiverBalance(uint256 balance) external override onlyConstantSetter { minimumReceiverBalance = balance; } + function topUpReceiverBalance(address payable receiver) external override { + _authorizeOutgoingMessageSender(schainHash); + uint256 balance = receiver.balance; + uint256 threashold = minimumReceiverBalance; + if (threashold == 0) { + threashold = MINIMUM_BALANCE; + } + if (balance < threashold) { + _transferFromEtherbase(receiver, threashold - balance); + } + } + /** * @dev Verify if the message metadata is valid. */ @@ -389,17 +401,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } - function _topUpReceiverBalance(address payable receiver) private { - uint256 balance = receiver.balance; - uint256 threashold = minimumReceiverBalance; - if (threashold == 0) { - threashold = MINIMUM_BALANCE; - } - if (balance < threashold) { - _transferFromEtherbase(receiver, threashold - balance); - } - } - function _transferFromEtherbase(address payable target, uint256 value) private { IEtherbaseUpgradeable etherbase = _getEtherbase(); if (address(etherbase).isContract() diff --git a/proxy/contracts/schain/TokenManagerLinker.sol b/proxy/contracts/schain/TokenManagerLinker.sol index ac9501c2a..5d5d75bb0 100644 --- a/proxy/contracts/schain/TokenManagerLinker.sol +++ b/proxy/contracts/schain/TokenManagerLinker.sol @@ -173,6 +173,7 @@ contract TokenManagerLinker is ITokenManagerLinker, AccessControlEnumerableUpgra * @dev Check if {tokenManager} is registered in IMA. */ function hasTokenManager(ITokenManager tokenManager) external view override returns (bool) { + // TODO: optimize algorithm to save gas uint index; uint length = tokenManagers.length; for (index = 0; index < length; index++) { diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol index dc463d18b..94cc5f040 100644 --- a/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol +++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC1155.sol @@ -355,6 +355,7 @@ contract TokenManagerERC1155 is _asSingletonArray(id), _asSingletonArray(amount) ); + messageProxy.topUpReceiverBalance(payable(receiver)); return receiver; } @@ -405,6 +406,7 @@ contract TokenManagerERC1155 is contractOnSchain.mintBatch(receiver, ids, amounts, ""); } emit ERC1155TokenReceived(fromChainHash, token, address(contractOnSchain), ids, amounts); + messageProxy.topUpReceiverBalance(payable(receiver)); return receiver; } diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol index 6d72b1fdb..72738fae7 100644 --- a/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol +++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC20.sol @@ -253,6 +253,7 @@ contract TokenManagerERC20 is TokenManager, ITokenManagerERC20 { ); } emit ERC20TokenReceived(fromChainHash, token, address(contractOnSchain), amount); + messageProxy.topUpReceiverBalance(payable(receiver)); return receiver; } diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol index 3f815e833..d84a6d1f8 100644 --- a/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol +++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC721.sol @@ -245,6 +245,7 @@ contract TokenManagerERC721 is TokenManager, ITokenManagerERC721 { contractOnSchain.mint(receiver, tokenId); } emit ERC721TokenReceived(fromChainHash, token, address(contractOnSchain), tokenId); + messageProxy.topUpReceiverBalance(payable(receiver)); return receiver; } diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol b/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol index 51807eeef..076322482 100644 --- a/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol +++ b/proxy/contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol @@ -120,6 +120,7 @@ contract TokenManagerERC721WithMetadata is TokenManagerERC721 { contractOnSchain.setTokenURI(tokenId, tokenURI); } emit ERC721TokenReceived(fromChainHash, token, address(contractOnSchain), tokenId); + messageProxy.topUpReceiverBalance(payable(receiver)); return receiver; } diff --git a/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol b/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol index 28f3aaf03..ea379a736 100644 --- a/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol +++ b/proxy/contracts/schain/TokenManagers/TokenManagerEth.sol @@ -81,6 +81,7 @@ contract TokenManagerEth is TokenManager, ITokenManagerEth { address receiver = decodedMessage.receiver; require(receiver != address(0), "Incorrect receiver"); ethErc20.mint(receiver, decodedMessage.amount); + messageProxy.topUpReceiverBalance(payable(receiver)); } /** diff --git a/proxy/package.json b/proxy/package.json index e6daef673..66dbe6792 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "1.0.0-develop.20", + "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.0", "@skalenetwork/skale-manager-interfaces": "1.0.0", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index 1732af0fa..00782a50b 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@1.0.0-develop.20": - version "1.0.0-develop.20" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-develop.20.tgz#e4ae92f9832c08d289690f080b22363fa8f3a339" - integrity sha512-OV6lHSg/UiezfLHM/STawOlu2P0IxAXXVL0LilyunuOAtSg3lLfRRyTJKD3D+JePfhgIc25B8DUxJiRyQg4UIg== +"@skalenetwork/ima-interfaces@^1.0.0-onboarding.0": + version "1.0.0-onboarding.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.0.tgz#d65c4f7929e79f826a36180fc7de95c8df9f336d" + integrity sha512-jGYZn6yhIRBjxIxPakufs2R4Y3qcZ4do7FDGc26luBIiprnTOQPdDNVVAm82g3+/VE6BLpkikGdaTvO+vlGneA== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From 190212b00121079887ac3c993dbb3595ac614890 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 2 Sep 2022 19:19:48 +0300 Subject: [PATCH 03/62] Replace contracts registry with TokenManagerLinker --- proxy/contracts/MessageProxy.sol | 7 +++- .../mainnet/MessageProxyForMainnet.sol | 6 ++-- proxy/contracts/schain/CommunityLocker.sol | 2 +- proxy/contracts/schain/DefaultAddresses.sol | 29 +++++++++++++++ .../schain/MessageProxyForSchain.sol | 35 +++++++++++++++---- proxy/contracts/schain/TokenManagerLinker.sol | 4 +-- .../MessageProxyForSchainWithoutSignature.sol | 3 +- proxy/migrations/deploySchain.ts | 14 +++++--- proxy/package.json | 2 +- proxy/yarn.lock | 8 ++--- 10 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 proxy/contracts/schain/DefaultAddresses.sol diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol index 336847e11..ea6ef2eb2 100644 --- a/proxy/contracts/MessageProxy.sol +++ b/proxy/contracts/MessageProxy.sol @@ -132,7 +132,12 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr modifier onlyConstantSetter() { require(hasRole(CONSTANT_SETTER_ROLE, msg.sender), "Not enough permissions to set constant"); _; - } + } + + modifier onlyOwner() { + require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "DEFAULT_ADMIN_ROLE is required"); + _; + } /** * @dev Sets gasLimit to a new value. diff --git a/proxy/contracts/mainnet/MessageProxyForMainnet.sol b/proxy/contracts/mainnet/MessageProxyForMainnet.sol index 56bf1aa04..99ea803db 100644 --- a/proxy/contracts/mainnet/MessageProxyForMainnet.sol +++ b/proxy/contracts/mainnet/MessageProxyForMainnet.sol @@ -138,8 +138,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro * - `msg.sender` must be granted as DEFAULT_ADMIN_ROLE. * - Address of CommunityPool contract must not be null. */ - function setCommunityPool(ICommunityPool newCommunityPoolAddress) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "Not authorized caller"); + function setCommunityPool(ICommunityPool newCommunityPoolAddress) external override onlyOwner { require(address(newCommunityPoolAddress) != address(0), "CommunityPool address has to be set"); communityPool = newCommunityPoolAddress; } @@ -272,8 +271,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro * * - `msg.sender` must be granted DEFAULT_ADMIN_ROLE. */ - function setVersion(string calldata newVersion) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "DEFAULT_ADMIN_ROLE is required"); + function setVersion(string calldata newVersion) external override onlyOwner { emit VersionUpdated(version, newVersion); version = newVersion; } diff --git a/proxy/contracts/schain/CommunityLocker.sol b/proxy/contracts/schain/CommunityLocker.sol index b853ed679..a94f03d9f 100644 --- a/proxy/contracts/schain/CommunityLocker.sol +++ b/proxy/contracts/schain/CommunityLocker.sol @@ -165,7 +165,7 @@ contract CommunityLocker is ICommunityLocker, AccessControlEnumerableUpgradeable */ function checkAllowedToSendMessage(address receiver) external override { require( - tokenManagerLinker.hasTokenManager(ITokenManager(msg.sender)), + tokenManagerLinker.hasTokenManager(msg.sender), "Sender is not registered token manager" ); require(activeUsers[receiver], "Recipient must be active"); diff --git a/proxy/contracts/schain/DefaultAddresses.sol b/proxy/contracts/schain/DefaultAddresses.sol new file mode 100644 index 000000000..213eb059c --- /dev/null +++ b/proxy/contracts/schain/DefaultAddresses.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * DefaultAddresses.sol - SKALE Interchain Messaging Agent + * Copyright (C) 2021-Present SKALE Labs + * @author Dmytro Stebaiev + * + * SKALE IMA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SKALE IMA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with SKALE IMA. If not, see . + */ + + pragma solidity 0.8.16; + +library DefaultAddresses { + // 17 0x00 bytes + address public constant ETHERBASE = address(0xd2bA3e << (17 * 8)); + // 16 0x00 bytes + address public constant TOKEN_MANAGER_LINKER = address(0xD2aAA008 << (16 * 8)); +} \ No newline at end of file diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index 688f6ceb2..b3002eace 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -27,6 +27,8 @@ import "@skalenetwork/etherbase-interfaces/IEtherbaseUpgradeable.sol"; import "../MessageProxy.sol"; import "./bls/SkaleVerifier.sol"; +import "./DefaultAddresses.sol"; +import "./TokenManagerLinker.sol"; /** @@ -55,7 +57,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; IEtherbaseUpgradeable public constant ETHERBASE = IEtherbaseUpgradeable( - payable(0xd2bA3e0000000000000000000000000000000000) + payable(DefaultAddresses.ETHERBASE) ); uint public constant MINIMUM_BALANCE = 1 ether; @@ -99,10 +101,18 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { string public version; bool public override messageInProgress; - // if receiver has no sFuil it's balance is topupped from etherbase - // if value is 0 MINIMUM_BALANCE is used + /** + * @dev if receiver has no sFuil it's balance is topupped from etherbase for the value + * if the value is 0 MINIMUM_BALANCE is used + */ uint256 public minimumReceiverBalance; + /** + * @dev Address of TokenManagerLinker + * May be set to 0 for old contracts + */ + TokenManagerLinker private _tokenManagerLinker; + /** * @dev Reentrancy guard for postIncomingMessages. */ @@ -217,8 +227,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { * * - `msg.sender` must be granted DEFAULT_ADMIN_ROLE. */ - function setVersion(string calldata newVersion) external override { - require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "DEFAULT_ADMIN_ROLE is required"); + function setVersion(string calldata newVersion) external override onlyOwner { emit VersionUpdated(version, newVersion); version = newVersion; } @@ -228,7 +237,8 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } function topUpReceiverBalance(address payable receiver) external override { - _authorizeOutgoingMessageSender(schainHash); + // allow only TokenManager to call this function + require(_getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); uint256 balance = receiver.balance; uint256 threashold = minimumReceiverBalance; if (threashold == 0) { @@ -239,6 +249,10 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } + function setTokenManagerLinker(ITokenManagerLinker tokenManagerLinker) external override onlyOwner { + _tokenManagerLinker = TokenManagerLinker(address(tokenManagerLinker)); + } + /** * @dev Verify if the message metadata is valid. */ @@ -414,6 +428,15 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } + function _getTokenManagerLinker() private returns (TokenManagerLinker) { + if (address(_tokenManagerLinker) == address(0)) { + require(DefaultAddresses.TOKEN_MANAGER_LINKER.isContract(), "Can't find TokenManagerLinker"); + return TokenManagerLinker(DefaultAddresses.TOKEN_MANAGER_LINKER); + } else { + return _tokenManagerLinker; + } + } + /** * @dev Calculate a message hash. */ diff --git a/proxy/contracts/schain/TokenManagerLinker.sol b/proxy/contracts/schain/TokenManagerLinker.sol index 5d5d75bb0..048dae3e2 100644 --- a/proxy/contracts/schain/TokenManagerLinker.sol +++ b/proxy/contracts/schain/TokenManagerLinker.sol @@ -172,12 +172,12 @@ contract TokenManagerLinker is ITokenManagerLinker, AccessControlEnumerableUpgra /** * @dev Check if {tokenManager} is registered in IMA. */ - function hasTokenManager(ITokenManager tokenManager) external view override returns (bool) { + function hasTokenManager(address tokenManager) external view override returns (bool) { // TODO: optimize algorithm to save gas uint index; uint length = tokenManagers.length; for (index = 0; index < length; index++) { - if (tokenManagers[index] == tokenManager) { + if (address(tokenManagers[index]) == tokenManager) { return true; } } diff --git a/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol b/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol index 47e63829b..c287cf1d0 100644 --- a/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol +++ b/proxy/contracts/test/MessageProxyForSchainWithoutSignature.sol @@ -25,7 +25,8 @@ import "./MessageProxyForSchainTester.sol"; contract MessageProxyForSchainWithoutSignature is MessageProxyForSchainTester { - constructor(string memory schainName) MessageProxyForSchainTester(IKeyStorage(address(0)), schainName) + constructor(string memory schainName) + MessageProxyForSchainTester(IKeyStorage(address(0)), schainName) // solhint-disable-next-line no-empty-blocks {} diff --git a/proxy/migrations/deploySchain.ts b/proxy/migrations/deploySchain.ts index c73d15c21..c338e476d 100644 --- a/proxy/migrations/deploySchain.ts +++ b/proxy/migrations/deploySchain.ts @@ -40,7 +40,8 @@ import { TokenManagerERC721, TokenManagerEth, TokenManagerLinker, - TokenManagerERC721WithMetadata + TokenManagerERC721WithMetadata, + MessageProxyForSchainWithoutSignature } from '../typechain'; import { TokenManagerERC1155 } from '../typechain/TokenManagerERC1155'; import { getVersion } from './tools/version'; @@ -154,17 +155,19 @@ async function main() { deployed.set( "KeyStorage", { address: keyStorage.address, interface: keyStorage.interface } ); console.log("Contract KeyStorage deployed to", keyStorage.address); - let messageProxy: Contract; + let messageProxy: MessageProxyForSchain | MessageProxyForSchainWithoutSignature; if( process.env.NO_SIGNATURES === "true" ) { console.log( "Deploy IMA without signature verification" ); console.log("Deploy MessageProxyForSchainWithoutSignature"); - messageProxy = await (await ethers.getContractFactory("MessageProxyForSchainWithoutSignature")).deploy(schainName); + messageProxy = await + (await ethers.getContractFactory("MessageProxyForSchainWithoutSignature")) + .deploy(schainName) as MessageProxyForSchainWithoutSignature; } else { console.log("Deploy MessageProxyForSchain"); messageProxy = await upgrades.deployProxy( await ethers.getContractFactory("MessageProxyForSchain"), [keyStorage.address, schainName] - ); + ) as MessageProxyForSchain; } await messageProxy.deployTransaction.wait(); deployed.set( "MessageProxyForSchain", { address: messageProxy.address, interface: messageProxy.interface } ); @@ -172,7 +175,7 @@ async function main() { try { console.log(`Set version ${version}`) - await (await (messageProxy as MessageProxyForSchain).setVersion(version)).wait(); + await (await messageProxy.setVersion(version)).wait(); } catch { console.log("Failed to set ima version on schain"); } @@ -183,6 +186,7 @@ async function main() { await tokenManagerLinker.deployTransaction.wait(); deployed.set( "TokenManagerLinker", { address: tokenManagerLinker.address, interface: tokenManagerLinker.interface } ); console.log("Contract TokenManagerLinker deployed to", tokenManagerLinker.address); + await messageProxy.setTokenManagerLinker(tokenManagerLinker.address); console.log("Deploy CommunityLocker"); const communityLockerFactory = await ethers.getContractFactory("CommunityLocker"); diff --git a/proxy/package.json b/proxy/package.json index 66dbe6792..6b1f97dba 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.0", + "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.3", "@skalenetwork/skale-manager-interfaces": "1.0.0", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index 00782a50b..993d09ed9 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@^1.0.0-onboarding.0": - version "1.0.0-onboarding.0" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.0.tgz#d65c4f7929e79f826a36180fc7de95c8df9f336d" - integrity sha512-jGYZn6yhIRBjxIxPakufs2R4Y3qcZ4do7FDGc26luBIiprnTOQPdDNVVAm82g3+/VE6BLpkikGdaTvO+vlGneA== +"@skalenetwork/ima-interfaces@^1.0.0-onboarding.3": + version "1.0.0-onboarding.3" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.3.tgz#658b01c56edc4d8d968e4cb04d974fb1d34c76e0" + integrity sha512-k2m6n/V7UafuGuiIhOj7dJly/7qIuj0LiDKKDCO478UNh577RcQidBAryKiaeJnyjPFj/IIc698IAh8UZIX0UQ== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From d65a06a0940cc6d27347979e27d3b41a3ef9e035 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 5 Sep 2022 12:18:22 +0300 Subject: [PATCH 04/62] Add TokenManagerLinker address in tests --- proxy/test/TokenManagerERC1155.ts | 1 + proxy/test/TokenManagerERC20.ts | 1 + proxy/test/TokenManagerERC721.ts | 1 + proxy/test/TokenManagerERC721WithMetadata.ts | 1 + proxy/test/TokenManagerEth.ts | 1 + 5 files changed, 5 insertions(+) diff --git a/proxy/test/TokenManagerERC1155.ts b/proxy/test/TokenManagerERC1155.ts index 18e46ca82..6b6c78bde 100644 --- a/proxy/test/TokenManagerERC1155.ts +++ b/proxy/test/TokenManagerERC1155.ts @@ -89,6 +89,7 @@ describe("TokenManagerERC1155", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 2e327d982..75c2369b5 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -88,6 +88,7 @@ describe("TokenManagerERC20", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); communityLocker = await deployCommunityLocker(schainName, messageProxyForSchain.address, tokenManagerLinker, fakeCommunityPool); tokenManagerErc20 = await deployTokenManagerERC20(schainName, messageProxyForSchain.address, tokenManagerLinker, communityLocker, fakeDepositBox); await erc20OnChain.connect(deployer).grantRole(await erc20OnChain.MINTER_ROLE(), tokenManagerErc20.address); diff --git a/proxy/test/TokenManagerERC721.ts b/proxy/test/TokenManagerERC721.ts index 19cc6971e..60bf2a139 100644 --- a/proxy/test/TokenManagerERC721.ts +++ b/proxy/test/TokenManagerERC721.ts @@ -86,6 +86,7 @@ describe("TokenManagerERC721", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; diff --git a/proxy/test/TokenManagerERC721WithMetadata.ts b/proxy/test/TokenManagerERC721WithMetadata.ts index 1aea17527..c1513f833 100644 --- a/proxy/test/TokenManagerERC721WithMetadata.ts +++ b/proxy/test/TokenManagerERC721WithMetadata.ts @@ -87,6 +87,7 @@ describe("TokenManagerERC721WithMetadata", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; diff --git a/proxy/test/TokenManagerEth.ts b/proxy/test/TokenManagerEth.ts index 635d73d0e..da04bddac 100644 --- a/proxy/test/TokenManagerEth.ts +++ b/proxy/test/TokenManagerEth.ts @@ -78,6 +78,7 @@ describe("TokenManagerEth", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); fakeDepositBox = tokenManagerLinker.address; fakeCommunityPool = tokenManagerLinker.address; communityLocker = await deployCommunityLocker(schainName, messageProxyForSchain.address, tokenManagerLinker, fakeCommunityPool); From 84ec7b16313a6778f6f9a8213ee74844c3b91189 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 5 Sep 2022 16:31:19 +0300 Subject: [PATCH 05/62] Set TokenManagerLinker for second MessageProxy --- proxy/test/TokenManagerERC1155.ts | 1 + proxy/test/TokenManagerERC20.ts | 1 + proxy/test/TokenManagerERC721.ts | 1 + proxy/test/TokenManagerERC721WithMetadata.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/proxy/test/TokenManagerERC1155.ts b/proxy/test/TokenManagerERC1155.ts index 6b6c78bde..51e910a34 100644 --- a/proxy/test/TokenManagerERC1155.ts +++ b/proxy/test/TokenManagerERC1155.ts @@ -212,6 +212,7 @@ describe("TokenManagerERC1155", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); + await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 75c2369b5..06490bbfd 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -265,6 +265,7 @@ describe("TokenManagerERC20", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); + await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerErc202 = await deployTokenManagerERC20(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc20OnTargetChain.connect(deployer).grantRole(await erc20OnTargetChain.MINTER_ROLE(), tokenManagerErc202.address); diff --git a/proxy/test/TokenManagerERC721.ts b/proxy/test/TokenManagerERC721.ts index 60bf2a139..765b4bebe 100644 --- a/proxy/test/TokenManagerERC721.ts +++ b/proxy/test/TokenManagerERC721.ts @@ -221,6 +221,7 @@ describe("TokenManagerERC721", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); + await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC7212 = await deployTokenManagerERC721(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC7212.address); diff --git a/proxy/test/TokenManagerERC721WithMetadata.ts b/proxy/test/TokenManagerERC721WithMetadata.ts index c1513f833..c695bc021 100644 --- a/proxy/test/TokenManagerERC721WithMetadata.ts +++ b/proxy/test/TokenManagerERC721WithMetadata.ts @@ -226,6 +226,7 @@ describe("TokenManagerERC721WithMetadata", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); + await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC721WithMetadata2 = await deployTokenManagerERC721WithMetadata(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC721WithMetadata2.address); From ce775b8d4b31516b49ca63d3b1669598da6d64f3 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 5 Sep 2022 17:01:56 +0300 Subject: [PATCH 06/62] Fix ERC1155 tests --- proxy/test/TokenManagerERC1155.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/test/TokenManagerERC1155.ts b/proxy/test/TokenManagerERC1155.ts index 51e910a34..c3ffb3528 100644 --- a/proxy/test/TokenManagerERC1155.ts +++ b/proxy/test/TokenManagerERC1155.ts @@ -1168,6 +1168,7 @@ describe("TokenManagerERC1155", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); + await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); From ec11bae8ff9f42b179de9bd40df5af0f5deb47fb Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 5 Sep 2022 18:14:25 +0300 Subject: [PATCH 07/62] Fix ETH test --- proxy/test/TokenManagerEth.ts | 41 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/proxy/test/TokenManagerEth.ts b/proxy/test/TokenManagerEth.ts index da04bddac..f72db8d1f 100644 --- a/proxy/test/TokenManagerEth.ts +++ b/proxy/test/TokenManagerEth.ts @@ -66,8 +66,8 @@ describe("TokenManagerEth", () => { let messages: MessagesTester; let ethERC20: EthErc20; let communityLocker: CommunityLocker; - let fakeDepositBox: any; - let fakeCommunityPool: any; + let fakeDepositBox: string; + let fakeCommunityPool: string; const mainnetHash = stringValue(web3.utils.soliditySha3("Mainnet")); before(async () => { @@ -285,9 +285,7 @@ describe("TokenManagerEth", () => { const to = user.address; // for transfer eth bytesData should be equal `0x01`. See the `.fallbackOperationTypeConvert` function const bytesData = await messages.encodeTransferEthMessage(to, amount); - // redeploy tokenManagerEth with `developer` address instead `messageProxyForSchain.address` - // to avoid `Not a sender` error - tokenManagerEth = await deployTokenManagerEth(schainName, deployer.address, tokenManagerLinker, communityLocker, fakeDepositBox, ethERC20.address); + // add schain to avoid the `Receiver chain is incorrect` error await tokenManagerEth .connect(deployer) @@ -295,19 +293,26 @@ describe("TokenManagerEth", () => { await ethERC20.connect(deployer).grantRole(await ethERC20.MINTER_ROLE(), tokenManagerEth.address); await ethERC20.connect(deployer).grantRole(await ethERC20.BURNER_ROLE(), tokenManagerEth.address); // execution - await tokenManagerEth - .connect(deployer) - .postMessage(fromSchainId, sender, bytesData) - .should.be.eventually.rejectedWith("Receiver chain is incorrect"); - - await tokenManagerEth - .connect(deployer) - .postMessage(mainnetHash, sender, bytesData) - .should.be.eventually.rejectedWith("Receiver chain is incorrect"); - - await tokenManagerEth - .connect(deployer) - .postMessage(mainnetHash, fakeDepositBox, bytesData); + await messageProxyForSchain.postMessage( + tokenManagerEth.address, + fromSchainId, + sender, + bytesData + ).should.be.eventually.rejectedWith("Receiver chain is incorrect"); + + await messageProxyForSchain.postMessage( + tokenManagerEth.address, + mainnetHash, + sender, + bytesData + ).should.be.eventually.rejectedWith("Receiver chain is incorrect"); + + await messageProxyForSchain.postMessage( + tokenManagerEth.address, + mainnetHash, + fakeDepositBox, + bytesData + ); // expectation expect(parseInt((BigNumber.from(await ethERC20.balanceOf(to))).toString(), 10)) .to.be.equal(parseInt(amount, 10)); From 711f175090117c1f846984f9ce13ad8c81ea8117 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 6 Sep 2022 17:09:03 +0300 Subject: [PATCH 08/62] Add receiver top up test --- proxy/test/TokenManagerERC20.ts | 69 +++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 06490bbfd..2bee3feb8 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -31,10 +31,11 @@ import { TokenManagerERC20, TokenManagerLinker, MessageProxyForSchainTester, - CommunityLocker + CommunityLocker, + EtherbaseMock } from "../typechain"; -import { randomString, stringValue } from "./utils/helper"; +import { randomString } from "./utils/helper"; chai.should(); chai.use((chaiAsPromised as any)); @@ -46,7 +47,7 @@ import { deployTokenManagerLinker } from "./utils/deploy/schain/tokenManagerLink import { deployMessages } from "./utils/deploy/messages"; import { deployCommunityLocker } from "./utils/deploy/schain/communityLocker"; -import { ethers, web3 } from "hardhat"; +import { ethers } from "hardhat"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address"; import { BigNumber } from "ethers"; @@ -60,8 +61,8 @@ describe("TokenManagerERC20", () => { const mainnetName = "Mainnet"; const schainName = "D2-chain"; - const schainId = stringValue(web3.utils.soliditySha3(schainName)); - const mainnetId = stringValue(web3.utils.soliditySha3("Mainnet")); + const schainId = ethers.utils.solidityKeccak256(["string"], [schainName]); + const mainnetId = ethers.utils.solidityKeccak256(["string"], ["Mainnet"]); let fakeDepositBox: string; let fakeCommunityPool: any; let erc20OnChain: ERC20OnChain; @@ -256,7 +257,7 @@ describe("TokenManagerERC20", () => { let tokenManagerErc202: TokenManagerERC20; let communityLocker2: CommunityLocker; const newSchainName = "NewChain"; - const newSchainId = stringValue(web3.utils.soliditySha3(newSchainName)); + const newSchainId = ethers.utils.solidityKeccak256(["string"], [newSchainName]); beforeEach(async () => { erc20OnOriginChain = await deployERC20OnChain("NewToken", "NTN"); @@ -1255,7 +1256,7 @@ describe("TokenManagerERC20", () => { const to = user.address; const remoteTokenManagerAddress = fakeDepositBox; const fromSchainName = randomString(10); - const fromSchainHash = stringValue(web3.utils.soliditySha3(fromSchainName)); + const fromSchainHash = ethers.utils.solidityKeccak256(["string"], [fromSchainName]); await tokenManagerErc20.addTokenManager(fromSchainName, remoteTokenManagerAddress); // await tokenManagerErc20.connect(schainOwner).addERC20TokenByOwner(mainnetName, erc20OnMainnet.address, erc20OnChain.address); @@ -1286,7 +1287,7 @@ describe("TokenManagerERC20", () => { // preparation const remoteTokenManagerAddress = fakeDepositBox; const fromSchainName = randomString(10); - const fromSchainHash = stringValue(web3.utils.soliditySha3(fromSchainName)); + const fromSchainHash = ethers.utils.solidityKeccak256(["string"], [fromSchainName]); await messageProxyForSchain.connect(deployer).addConnectedChain(fromSchainName); await tokenManagerErc20.addTokenManager(fromSchainName, remoteTokenManagerAddress); await tokenManagerErc20.connect(schainOwner).addERC20TokenByOwner(fromSchainName, erc20OnMainnet.address, erc20OnChain.address); @@ -1311,11 +1312,11 @@ describe("TokenManagerERC20", () => { .to.be.equal(amount); }); - it("should should transfer token to schain and automaticaly deploy", async () => { + it("should should transfer token to schain and automatically deploy", async () => { // preparation const remoteTokenManagerAddress = fakeDepositBox; const fromSchainName = randomString(10); - const fromSchainHash = stringValue(web3.utils.soliditySha3(fromSchainName)); + const fromSchainHash = ethers.utils.solidityKeccak256(["string"], [fromSchainName]); await tokenManagerErc20.addTokenManager(fromSchainName, remoteTokenManagerAddress); const amount = 10; @@ -1364,7 +1365,7 @@ describe("TokenManagerERC20", () => { const to = user.address; const remoteTokenManagerAddress = fakeDepositBox; const fromSchainName = randomString(10); - const fromSchainHash = stringValue(web3.utils.soliditySha3(fromSchainName)); + const fromSchainHash = ethers.utils.solidityKeccak256(["string"], [fromSchainName]); await tokenManagerErc20.addTokenManager(fromSchainName, remoteTokenManagerAddress); await tokenManagerErc20.connect(schainOwner).addERC20TokenByOwner(mainnetName, erc20OnMainnet.address, erc20OnChain.address); @@ -1395,5 +1396,51 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain.postMessage(tokenManagerErc20.address, mainnetId, fakeDepositBox, data) .should.be.eventually.rejectedWith("Total supply exceeded"); }); + + it("should top up a receiver", async () => { + const amount = 10; + const receiver = ethers.Wallet.createRandom().connect(ethers.provider); + const remoteTokenManager = ethers.Wallet.createRandom(); + const sourceSchainName = randomString(10); + const sourceSchainHash = ethers.utils.solidityKeccak256(["string"], [sourceSchainName]) + await tokenManagerErc20.addTokenManager(sourceSchainName, remoteTokenManager.address); + const etherbase = await (await ethers.getContractFactory("EtherbaseMock")).deploy() as EtherbaseMock; + await etherbase.initialize(deployer.address); + await etherbase.grantRole(await etherbase.ETHER_MANAGER_ROLE(), messageProxyForSchain.address); + await messageProxyForSchain.setEtherbase(etherbase.address); + await deployer.sendTransaction({to: etherbase.address, value: ethers.utils.parseEther("3")}); + + (await receiver.getBalance()).should.be.equal(0); + + const data = await messages.encodeTransferErc20AndTokenInfoMessage( + erc20OnMainnet.address, + receiver.address, + amount, + 2 * amount, + { + name: await erc20OnMainnet.name(), + symbol: await erc20OnMainnet.symbol(), + decimals: await erc20OnMainnet.decimals() + } + ); + await tokenManagerErc20.connect(schainOwner).enableAutomaticDeploy(); + await messageProxyForSchain.postMessage( + tokenManagerErc20.address, + sourceSchainHash, + remoteTokenManager.address, + data); + + (await receiver.getBalance()).should.be.equal(await messageProxyForSchain.MINIMUM_BALANCE()); + + await messageProxyForSchain.setMinimumReceiverBalance(ethers.utils.parseEther("2")); + + await messageProxyForSchain.postMessage( + tokenManagerErc20.address, + sourceSchainHash, + remoteTokenManager.address, + data); + + (await receiver.getBalance()).should.be.equal(await messageProxyForSchain.minimumReceiverBalance()); + }) }); }); From 37adc34fa27b170954b3de70931bb31de9570540 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 7 Sep 2022 15:52:45 +0300 Subject: [PATCH 09/62] Add test with wrong sender --- .../schain/MessageProxyForSchain.sol | 20 +++++++++---------- proxy/package.json | 2 +- proxy/test/MessageProxy.ts | 15 ++++++++++++++ proxy/yarn.lock | 8 ++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index fc462baf4..b91c69f58 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -238,7 +238,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { function topUpReceiverBalance(address payable receiver) external override { // allow only TokenManager to call this function - require(_getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); + require(getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); uint256 balance = receiver.balance; uint256 threashold = minimumReceiverBalance; if (threashold == 0) { @@ -358,6 +358,15 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { _idxTail[dstChainHash] += 1; } + function getTokenManagerLinker() public view override returns (ITokenManagerLinker) { + if (address(_tokenManagerLinker) == address(0)) { + require(DefaultAddresses.TOKEN_MANAGER_LINKER.isContract(), "Can't find TokenManagerLinker"); + return ITokenManagerLinker(DefaultAddresses.TOKEN_MANAGER_LINKER); + } else { + return _tokenManagerLinker; + } + } + // private /** @@ -429,15 +438,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } - function _getTokenManagerLinker() private returns (TokenManagerLinker) { - if (address(_tokenManagerLinker) == address(0)) { - require(DefaultAddresses.TOKEN_MANAGER_LINKER.isContract(), "Can't find TokenManagerLinker"); - return TokenManagerLinker(DefaultAddresses.TOKEN_MANAGER_LINKER); - } else { - return _tokenManagerLinker; - } - } - /** * @dev Calculate a message hash. */ diff --git a/proxy/package.json b/proxy/package.json index b5bc7f2c3..2dde4d9bf 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.4", + "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.5", "@skalenetwork/skale-manager-interfaces": "1.0.0", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/test/MessageProxy.ts b/proxy/test/MessageProxy.ts index 10764f82b..2877354c3 100644 --- a/proxy/test/MessageProxy.ts +++ b/proxy/test/MessageProxy.ts @@ -61,6 +61,7 @@ import { deployMessageProxyForSchainTester } from "./utils/deploy/test/messagePr import { deployCommunityPool } from "./utils/deploy/mainnet/communityPool"; import { createNode } from "./utils/skale-manager-utils/nodes"; import { skipTime } from "./utils/time"; +import { deployTokenManagerLinker } from "./utils/deploy/schain/tokenManagerLinker"; chai.should(); chai.use((chaiAsPromised)); @@ -1490,6 +1491,20 @@ describe("MessageProxy", () => { }); }); + it("should not allow anyone to top up balance with sFuel", async () => { + await messageProxyForSchain.getTokenManagerLinker() + .should.be.rejectedWith("Can't find TokenManagerLinker"); // because contract is not predeployed + + const tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); + + await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); + await messageProxyForSchain.getTokenManagerLinker() + .should.eventually.be.equal(tokenManagerLinker.address); + + await messageProxyForSchain.connect(user).topUpReceiverBalance(user.address) + .should.be.rejectedWith("Sender is not TokenManager"); + }); + describe("register and remove extra contracts", async () => { it("should register extra contract", async () => { const fakeContractOnSchain = deployer.address; diff --git a/proxy/yarn.lock b/proxy/yarn.lock index e0ad19e8b..499989ff5 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@^1.0.0-onboarding.4": - version "1.0.0-onboarding.4" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.4.tgz#094d2b9a02401005fc1b5421388178a2791a1074" - integrity sha512-G1CkWIu7z6FGB4dmjYB4qU5zmrTSqpwB6LhmP6amz5nF6vMfEoEPWZcIuRc/2xOJd0W7hOzbgfBBEKDUIjWhQw== +"@skalenetwork/ima-interfaces@^1.0.0-onboarding.5": + version "1.0.0-onboarding.5" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.5.tgz#85db63db903680a92c14bde32ac52f3759c3e02c" + integrity sha512-NMvKKr9LYubBgcZ7SX9MvbpwCnH85RdrsRkRGkWNu6tfcADxetHYpUtje7PE8nv76hvb/BhWh3uSS/DkihxouQ== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From 74dc0239fd41086d1ff24abf72dc70f0ee4d0aff Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 23 Sep 2022 11:53:22 +0300 Subject: [PATCH 10/62] Disable onboarding feature by default --- .../schain/MessageProxyForSchain.sol | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index b91c69f58..69dbdba83 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -35,9 +35,9 @@ import "./TokenManagerLinker.sol"; * @title MessageProxyForSchain * @dev Entry point for messages that come from mainnet or other SKALE chains * and contract that emits messages for mainnet or other SKALE chains. - * + * * Messages are submitted by IMA-agent and secured with threshold signature. - * + * * IMA-agent monitors events of {MessageProxyForSchain} and sends messages to other chains. * NOTE: 16 Agents @@ -125,9 +125,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { /** * @dev Allows MessageProxy to register extra contract for being able to transfer messages from custom contracts. - * + * * Requirements: - * + * * - Function caller has to be granted with {EXTRA_CONTRACT_REGISTRAR_ROLE}. * - Destination chain hash cannot be equal to itself */ @@ -147,9 +147,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { /** * @dev Allows MessageProxy to remove extra contract, * thus `extraContract` will no longer be available to transfer messages from chain to chain. - * + * * Requirements: - * + * * - Function caller has to be granted with {EXTRA_CONTRACT_REGISTRAR_ROLE}. * - Destination chain hash cannot be equal to itself */ @@ -170,9 +170,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { * @dev Link external chain. * * NOTE: Mainnet is linked automatically. - * + * * Requirements: - * + * * - Function caller has to be granted with {CHAIN_CONNECTOR_ROLE}. * - Target chain must be different from the current. */ @@ -180,14 +180,14 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { bytes32 chainHash = keccak256(abi.encodePacked(chainName)); require(chainHash != schainHash, "Schain cannot connect itself"); _addConnectedChain(chainHash); - } + } /** * @dev Entry point for incoming messages. * This function is called by IMA-agent to deliver incoming messages from external chains. - * + * * Requirements: - * + * * - Origin chain has to be registered. * - Amount of messages must be no more than {MESSAGES_LENGTH}. * - Messages batch has to be signed with threshold signature. @@ -198,7 +198,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { string calldata fromChainName, uint256 startingCounter, Message[] calldata messages, - Signature calldata signature + Signature calldata signature ) external override(IMessageProxy, MessageProxy) @@ -222,9 +222,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { /** * @dev Sets new version of contracts on schain - * + * * Requirements: - * + * * - `msg.sender` must be granted DEFAULT_ADMIN_ROLE. */ function setVersion(string calldata newVersion) external override onlyOwner { @@ -241,9 +241,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { require(getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); uint256 balance = receiver.balance; uint256 threashold = minimumReceiverBalance; - if (threashold == 0) { - threashold = MINIMUM_BALANCE; - } if (balance < threashold) { _transferFromEtherbase(receiver, threashold - balance); } @@ -308,9 +305,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { /** * @dev Unlink external SKALE chain. - * + * * Requirements: - * + * * - Function caller has to be granted with {CHAIN_CONNECTOR_ROLE}. * - Target chain must be different from Mainnet. */ @@ -329,9 +326,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { /** * @dev This function is called by a smart contract * that wants to make a cross-chain call. - * + * * Requirements: - * + * * - Destination chain has to be registered. * - Sender contract has to be registered. */ @@ -428,7 +425,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { function _transferFromEtherbase(address payable target, uint256 value) private { IEtherbaseUpgradeable etherbase = _getEtherbase(); if (address(etherbase).isContract() - && etherbase.hasRole(etherbase.ETHER_MANAGER_ROLE(), address(this)) + && etherbase.hasRole(etherbase.ETHER_MANAGER_ROLE(), address(this)) ) { if (value < address(etherbase).balance) { etherbase.partiallyRetrieve(target, value); @@ -450,5 +447,5 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { message.data ); return keccak256(data); - } + } } From 66be17ac3937e906ccfa716f31c23db49cc50024 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 23 Sep 2022 12:25:44 +0300 Subject: [PATCH 11/62] Update tests --- proxy/test/TokenManagerERC20.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 27ad3a319..35f0e9d87 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -1532,7 +1532,7 @@ describe("TokenManagerERC20", () => { remoteTokenManager.address, data); - (await receiver.getBalance()).should.be.equal(await messageProxyForSchain.MINIMUM_BALANCE()); + (await receiver.getBalance()).should.be.equal(0); await messageProxyForSchain.setMinimumReceiverBalance(ethers.utils.parseEther("2")); From 0ab424b78962f6a161f70e890a5ce3cc18fcc3e3 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 4 Oct 2022 17:35:27 +0300 Subject: [PATCH 12/62] Add MinimumReceiverBalanceChanged event --- proxy/contracts/schain/MessageProxyForSchain.sol | 12 +++++++++--- proxy/test/TokenManagerERC20.ts | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index 69dbdba83..1c1286b9b 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -113,6 +113,11 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { */ TokenManagerLinker private _tokenManagerLinker; + event MinimumReceiverBalanceChanged ( + uint256 oldValue, + uint256 newValue + ); + /** * @dev Reentrancy guard for postIncomingMessages. */ @@ -233,6 +238,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } function setMinimumReceiverBalance(uint256 balance) external override onlyConstantSetter { + emit MinimumReceiverBalanceChanged(minimumReceiverBalance, balance); minimumReceiverBalance = balance; } @@ -240,9 +246,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { // allow only TokenManager to call this function require(getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); uint256 balance = receiver.balance; - uint256 threashold = minimumReceiverBalance; - if (balance < threashold) { - _transferFromEtherbase(receiver, threashold - balance); + uint256 threshold = minimumReceiverBalance; + if (balance < threshold) { + _transferFromEtherbase(receiver, threshold - balance); } } diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 35f0e9d87..373dd15f1 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -1534,7 +1534,9 @@ describe("TokenManagerERC20", () => { (await receiver.getBalance()).should.be.equal(0); - await messageProxyForSchain.setMinimumReceiverBalance(ethers.utils.parseEther("2")); + await expect(messageProxyForSchain.setMinimumReceiverBalance(ethers.utils.parseEther("2"))) + .to.emit(messageProxyForSchain, 'MinimumReceiverBalanceChanged') + .withArgs(0, ethers.utils.parseEther("2")); await messageProxyForSchain.postMessage( tokenManagerErc20.address, From 9e9c0e64ba921983d4e531a1e4380fc530dce91b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 12 Oct 2022 14:07:09 +0300 Subject: [PATCH 13/62] Change smart contracts --- proxy/contracts/MessageProxy.sol | 54 +++++++++---------- .../schain/MessageProxyForSchain.sol | 22 +------- proxy/migrations/deploySchain.ts | 1 - proxy/package.json | 2 +- proxy/test/MessageProxy.ts | 11 +--- proxy/test/TokenManagerERC1155.ts | 3 -- proxy/test/TokenManagerERC20.ts | 2 - proxy/test/TokenManagerERC721.ts | 2 - proxy/test/TokenManagerERC721WithMetadata.ts | 2 - proxy/test/TokenManagerEth.ts | 1 - proxy/yarn.lock | 8 +-- 11 files changed, 34 insertions(+), 74 deletions(-) diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol index 8d83c3e7e..30b067316 100644 --- a/proxy/contracts/MessageProxy.sol +++ b/proxy/contracts/MessageProxy.sol @@ -150,9 +150,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Sets gasLimit to a new value. - * + * * Requirements: - * + * * - `msg.sender` must be granted CONSTANT_SETTER_ROLE. */ function setNewGasLimit(uint256 newGasLimit) external override onlyConstantSetter { @@ -176,9 +176,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows `msg.sender` to register extra contract for all schains * for being able to transfer messages from custom contracts. - * + * * Requirements: - * + * * - `msg.sender` must be granted as EXTRA_CONTRACT_REGISTRAR_ROLE. * - Passed address should be contract. * - Extra contract must not be registered. @@ -193,9 +193,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows `msg.sender` to remove extra contract for all schains. * Extra contract will no longer be able to send messages through MessageProxy. - * + * * Requirements: - * + * * - `msg.sender` must be granted as EXTRA_CONTRACT_REGISTRAR_ROLE. */ function removeExtraContractForAll(address extraContract) external override onlyExtraContractRegistrar { @@ -213,7 +213,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Should return a range of contracts registered by schainHash. - * + * * Requirements: * range should be less or equal 10 contracts */ @@ -239,9 +239,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Returns number of outgoing messages. - * + * * Requirements: - * + * * - Target schain must be initialized. */ function getOutgoingMessagesCounter(string calldata targetSchainName) @@ -267,9 +267,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Returns number of incoming messages. - * + * * Requirements: - * + * * - Source schain must be initialized. */ function getIncomingMessagesCounter(string calldata fromSchainName) @@ -295,11 +295,11 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Posts message from this contract to `targetChainHash` MessageProxy contract. * This is called by a smart contract to make a cross-chain call. - * + * * Emits an {OutgoingMessage} event. * * Requirements: - * + * * - Target chain must be initialized. * - Target chain must be registered as external contract. */ @@ -314,7 +314,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr { require(connectedChains[targetChainHash].inited, "Destination chain is not initialized"); _authorizeOutgoingMessageSender(targetChainHash); - + uint outgoingMessageCounter = connectedChains[targetChainHash].outgoingMessageCounter; emit OutgoingMessage( targetChainHash, @@ -333,9 +333,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows CHAIN_CONNECTOR_ROLE to remove connected chain from this contract. - * + * * Requirements: - * + * * - `msg.sender` must be granted CHAIN_CONNECTOR_ROLE. * - `schainName` must be initialized. */ @@ -343,7 +343,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr bytes32 schainHash = keccak256(abi.encodePacked(schainName)); require(connectedChains[schainHash].inited, "Chain is not initialized"); delete connectedChains[schainHash]; - } + } /** * @dev Checks whether chain is currently connected. @@ -377,9 +377,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows MessageProxy to register extra contract for being able to transfer messages from custom contracts. - * + * * Requirements: - * + * * - Extra contract address must be contract. * - Extra contract must not be registered. * - Extra contract must not be registered for all chains. @@ -389,14 +389,14 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr address extraContract ) internal - { + { require(extraContract.isContract(), "Given address is not a contract"); require(!_getRegistryContracts()[chainHash].contains(extraContract), "Extra contract is already registered"); require( !_getRegistryContracts()[bytes32(0)].contains(extraContract), "Extra contract is already registered for all chains" ); - + _getRegistryContracts()[chainHash].add(extraContract); emit ExtraContractRegistered(chainHash, extraContract); } @@ -404,9 +404,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows MessageProxy to remove extra contract, * thus `extraContract` will no longer be available to transfer messages from mainnet to schain. - * + * * Requirements: - * + * * - Extra contract must be registered. */ function _removeExtraContract( @@ -422,9 +422,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr /** * @dev Allows MessageProxy to connect schain with MessageProxyOnMainnet for transferring messages. - * + * * Requirements: - * + * * - `msg.sender` must be granted CHAIN_CONNECTOR_ROLE. * - SKALE chain must not be connected. */ @@ -525,7 +525,7 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr require( isContractRegistered(bytes32(0), msg.sender) || isContractRegistered(targetChainHash, msg.sender), "Sender contract is not registered" - ); + ); } /** @@ -572,6 +572,6 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr for(uint i = 0; i < slicedEnd; i++){ sliced[i] = text[i]; } - return sliced; + return sliced; } } diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index 1c1286b9b..cb38093f1 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -107,12 +107,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { */ uint256 public minimumReceiverBalance; - /** - * @dev Address of TokenManagerLinker - * May be set to 0 for old contracts - */ - TokenManagerLinker private _tokenManagerLinker; - event MinimumReceiverBalanceChanged ( uint256 oldValue, uint256 newValue @@ -243,8 +237,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } function topUpReceiverBalance(address payable receiver) external override { - // allow only TokenManager to call this function - require(getTokenManagerLinker().hasTokenManager(msg.sender), "Sender is not TokenManager"); + require(_getRegistryContracts()[0].contains(msg.sender), "Sender is not registered"); uint256 balance = receiver.balance; uint256 threshold = minimumReceiverBalance; if (balance < threshold) { @@ -252,10 +245,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } - function setTokenManagerLinker(ITokenManagerLinker tokenManagerLinker) external override onlyOwner { - _tokenManagerLinker = TokenManagerLinker(address(tokenManagerLinker)); - } - /** * @dev Verify if the message metadata is valid. */ @@ -361,15 +350,6 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { _idxTail[dstChainHash] += 1; } - function getTokenManagerLinker() public view override returns (ITokenManagerLinker) { - if (address(_tokenManagerLinker) == address(0)) { - require(DefaultAddresses.TOKEN_MANAGER_LINKER.isContract(), "Can't find TokenManagerLinker"); - return ITokenManagerLinker(DefaultAddresses.TOKEN_MANAGER_LINKER); - } else { - return _tokenManagerLinker; - } - } - // private /** diff --git a/proxy/migrations/deploySchain.ts b/proxy/migrations/deploySchain.ts index c338e476d..014d89236 100644 --- a/proxy/migrations/deploySchain.ts +++ b/proxy/migrations/deploySchain.ts @@ -186,7 +186,6 @@ async function main() { await tokenManagerLinker.deployTransaction.wait(); deployed.set( "TokenManagerLinker", { address: tokenManagerLinker.address, interface: tokenManagerLinker.interface } ); console.log("Contract TokenManagerLinker deployed to", tokenManagerLinker.address); - await messageProxy.setTokenManagerLinker(tokenManagerLinker.address); console.log("Deploy CommunityLocker"); const communityLockerFactory = await ethers.getContractFactory("CommunityLocker"); diff --git a/proxy/package.json b/proxy/package.json index d9c9723cc..31e900b63 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.6", + "@skalenetwork/ima-interfaces": "^1.0.0-onboarding.7", "@skalenetwork/skale-manager-interfaces": "1.0.0", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/test/MessageProxy.ts b/proxy/test/MessageProxy.ts index 2877354c3..9c4e72c4c 100644 --- a/proxy/test/MessageProxy.ts +++ b/proxy/test/MessageProxy.ts @@ -1492,17 +1492,8 @@ describe("MessageProxy", () => { }); it("should not allow anyone to top up balance with sFuel", async () => { - await messageProxyForSchain.getTokenManagerLinker() - .should.be.rejectedWith("Can't find TokenManagerLinker"); // because contract is not predeployed - - const tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); - await messageProxyForSchain.getTokenManagerLinker() - .should.eventually.be.equal(tokenManagerLinker.address); - await messageProxyForSchain.connect(user).topUpReceiverBalance(user.address) - .should.be.rejectedWith("Sender is not TokenManager"); + .should.be.rejectedWith("Sender is not registered"); }); describe("register and remove extra contracts", async () => { diff --git a/proxy/test/TokenManagerERC1155.ts b/proxy/test/TokenManagerERC1155.ts index 54a8ac809..92b3425ae 100644 --- a/proxy/test/TokenManagerERC1155.ts +++ b/proxy/test/TokenManagerERC1155.ts @@ -90,7 +90,6 @@ describe("TokenManagerERC1155", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; @@ -213,7 +212,6 @@ describe("TokenManagerERC1155", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); - await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); @@ -1256,7 +1254,6 @@ describe("TokenManagerERC1155", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); - await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index 373dd15f1..fd9dde3ef 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -90,7 +90,6 @@ describe("TokenManagerERC20", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); communityLocker = await deployCommunityLocker(schainName, messageProxyForSchain.address, tokenManagerLinker, fakeCommunityPool); tokenManagerErc20 = await deployTokenManagerERC20(schainName, messageProxyForSchain.address, tokenManagerLinker, communityLocker, fakeDepositBox); await erc20OnChain.connect(deployer).grantRole(await erc20OnChain.MINTER_ROLE(), tokenManagerErc20.address); @@ -267,7 +266,6 @@ describe("TokenManagerERC20", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); - await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerErc202 = await deployTokenManagerERC20(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc20OnTargetChain.connect(deployer).grantRole(await erc20OnTargetChain.MINTER_ROLE(), tokenManagerErc202.address); diff --git a/proxy/test/TokenManagerERC721.ts b/proxy/test/TokenManagerERC721.ts index f1f395d67..29190ef7c 100644 --- a/proxy/test/TokenManagerERC721.ts +++ b/proxy/test/TokenManagerERC721.ts @@ -87,7 +87,6 @@ describe("TokenManagerERC721", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; @@ -222,7 +221,6 @@ describe("TokenManagerERC721", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); - await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC7212 = await deployTokenManagerERC721(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC7212.address); diff --git a/proxy/test/TokenManagerERC721WithMetadata.ts b/proxy/test/TokenManagerERC721WithMetadata.ts index 18bad21b1..653f8cb94 100644 --- a/proxy/test/TokenManagerERC721WithMetadata.ts +++ b/proxy/test/TokenManagerERC721WithMetadata.ts @@ -88,7 +88,6 @@ describe("TokenManagerERC721WithMetadata", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); messages = await deployMessages(); fakeDepositBox = messages.address; fakeCommunityPool = messages.address; @@ -227,7 +226,6 @@ describe("TokenManagerERC721WithMetadata", () => { const keyStorage2 = await deployKeyStorageMock(); messageProxyForSchain2 = await deployMessageProxyForSchainTester(keyStorage2.address, newSchainName); tokenManagerLinker2 = await deployTokenManagerLinker(messageProxyForSchain2, deployer.address); - await messageProxyForSchain2.setTokenManagerLinker(tokenManagerLinker2.address); communityLocker2 = await deployCommunityLocker(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, fakeCommunityPool); tokenManagerERC721WithMetadata2 = await deployTokenManagerERC721WithMetadata(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC721WithMetadata2.address); diff --git a/proxy/test/TokenManagerEth.ts b/proxy/test/TokenManagerEth.ts index 888243d44..ee0a72f34 100644 --- a/proxy/test/TokenManagerEth.ts +++ b/proxy/test/TokenManagerEth.ts @@ -78,7 +78,6 @@ describe("TokenManagerEth", () => { const keyStorage = await deployKeyStorageMock(); messageProxyForSchain = await deployMessageProxyForSchainTester(keyStorage.address, schainName); tokenManagerLinker = await deployTokenManagerLinker(messageProxyForSchain, deployer.address); - await messageProxyForSchain.setTokenManagerLinker(tokenManagerLinker.address); fakeDepositBox = tokenManagerLinker.address; fakeCommunityPool = tokenManagerLinker.address; communityLocker = await deployCommunityLocker(schainName, messageProxyForSchain.address, tokenManagerLinker, fakeCommunityPool); diff --git a/proxy/yarn.lock b/proxy/yarn.lock index b07884375..a394ef91d 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@^1.0.0-onboarding.6": - version "1.0.0-onboarding.6" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.6.tgz#f28044b9c36d392245e70a76c17b5e3999ca052c" - integrity sha512-SWaixGS49kXpd58etfBdQNm/KSoUWtBnZh0/wELpcP/T/z5GNKrDxB1uwQlBBEAb5biJ6/GRQwxVZJzLPqyPrw== +"@skalenetwork/ima-interfaces@^1.0.0-onboarding.7": + version "1.0.0-onboarding.7" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-onboarding.7.tgz#e444c36fa8c476c81bfd603d2e09335e4733ebd9" + integrity sha512-2mgqXZjbLxjgGqE/ncmbrwtx2rS5yeJG2selo5obP7kYPf9lCFrWaa8QU09F0xncRplXCHr9LhIvlso2/1c9jw== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From a9dbf7d215f307d9a79e142894b8bec97de97061 Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:25:03 +0300 Subject: [PATCH 14/62] Add small improvements --- proxy/contracts/schain/MessageProxyForSchain.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index cb38093f1..2f7339a97 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -237,7 +237,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } function topUpReceiverBalance(address payable receiver) external override { - require(_getRegistryContracts()[0].contains(msg.sender), "Sender is not registered"); + require(isContractRegistered(bytes32(0), msg.sender), "Sender is not registered"); uint256 balance = receiver.balance; uint256 threshold = minimumReceiverBalance; if (balance < threshold) { From a942352da630959cc85d08174bad6f63764070a0 Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:25:29 +0300 Subject: [PATCH 15/62] Add tests for TokenManagerERC20 --- proxy/test/TokenManagerERC20.ts | 77 +++++++++++++-------------------- 1 file changed, 30 insertions(+), 47 deletions(-) diff --git a/proxy/test/TokenManagerERC20.ts b/proxy/test/TokenManagerERC20.ts index fd9dde3ef..d14906448 100644 --- a/proxy/test/TokenManagerERC20.ts +++ b/proxy/test/TokenManagerERC20.ts @@ -135,6 +135,8 @@ describe("TokenManagerERC20", () => { const data2 = await messages.encodeTransferErc20AndTokenInfoMessage(erc20OnMainnet.address, to, amount, totalSupply, { name, symbol, decimals: 18 }); await tokenManagerErc20.connect(schainOwner).enableAutomaticDeploy(); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + // execution const res = await (await messageProxyForSchain.postMessage(tokenManagerErc20.address, mainnetId, fakeDepositBox, data)).wait(); @@ -144,7 +146,7 @@ describe("TokenManagerERC20", () => { assert("No events were emitted"); } else { newAddress = "0x" + res.events[res.events.length - 1].topics[3].slice(-40); - const newERC20Contract = await (await ethers.getContractFactory("ERC20OnChain")).attach(newAddress) as ERC20OnChain; + const newERC20Contract = (await ethers.getContractFactory("ERC20OnChain")).attach(newAddress) as ERC20OnChain; let balance = await newERC20Contract.functions.balanceOf(to); parseInt(balance.toString(), 10).should.be.equal(amount); // expectation @@ -306,7 +308,7 @@ describe("TokenManagerERC20", () => { outgoingMessagesCounter.should.be.deep.equal(BigNumber.from(1)); }); - it("should reject `transferToSchainERC20` when executing earlier then allowed", async () => { + it("should reject `transferToSchainERC20` when executing earlier than allowed", async () => { const amount = "20000000000000000"; await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); @@ -461,18 +463,20 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data).should.be.eventually.rejectedWith("Automatic deploy is disabled"); await tokenManagerErc202.enableAutomaticDeploy(); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data); const addressERC20OnSchain = await tokenManagerErc202.clonesErc20(schainId, erc20OnOriginChain.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect((await targetErc20OnChain.functions.balanceOf(user.address)).toString()).to.be.equal(amount); }); - it("should invoke `transferToSchainERC20` and receive tokens without mistakes double", async () => { + it("should invoke `transferToSchainERC20` and receive tokens without mistakes back and forward twice", async () => { const amount = "20000000000000000"; await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -528,7 +532,7 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data); const addressERC20OnSchain = await tokenManagerErc202.clonesErc20(schainId, erc20OnOriginChain.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect((await targetErc20OnChain.functions.balanceOf(user.address)).toString()).to.be.equal(amount); const amount2 = "50000000000000000"; @@ -558,6 +562,7 @@ describe("TokenManagerERC20", () => { it("should invoke `transferToSchainERC20` and receive tokens without mistakes double with attached token", async () => { const amount = "20000000000000000"; await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -641,7 +646,8 @@ describe("TokenManagerERC20", () => { it("should invoke `transferToSchainERC20` and transfer back without mistakes", async () => { const amount = "20000000000000000"; - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -697,7 +703,7 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data); const addressERC20OnSchain = await tokenManagerErc202.clonesErc20(schainId, erc20OnOriginChain.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect((await targetErc20OnChain.functions.balanceOf(user.address)).toString()).to.be.equal(amount); await tokenManagerErc202 @@ -717,13 +723,6 @@ describe("TokenManagerERC20", () => { await targetErc20OnChain.connect(user).approve(tokenManagerErc202.address, amount); - await tokenManagerErc202 - .connect(user) - .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerErc202.address); - await tokenManagerErc202 .connect(user) .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount); @@ -741,7 +740,8 @@ describe("TokenManagerERC20", () => { it("should invoke `transferToSchainERC20` and transfer back without mistakes with attached tokens", async () => { const amount = "20000000000000000"; - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -812,13 +812,6 @@ describe("TokenManagerERC20", () => { await erc20OnTargetChain.connect(user).approve(tokenManagerErc202.address, amount); - await tokenManagerErc202 - .connect(user) - .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerErc202.address); - await tokenManagerErc202 .connect(user) .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount); @@ -837,7 +830,8 @@ describe("TokenManagerERC20", () => { it("should invoke `transferToSchainERC20` and transfer back without mistakes double", async () => { const amount = "20000000000000000"; - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -893,7 +887,7 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data); const addressERC20OnSchain = await tokenManagerErc202.clonesErc20(schainId, erc20OnOriginChain.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect((await targetErc20OnChain.functions.balanceOf(user.address)).toString()).to.be.equal(amount); await tokenManagerErc202 @@ -913,13 +907,6 @@ describe("TokenManagerERC20", () => { await targetErc20OnChain.connect(user).approve(tokenManagerErc202.address, amount); - await tokenManagerErc202 - .connect(user) - .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerErc202.address); - await tokenManagerErc202 .connect(user) .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount); @@ -1007,7 +994,8 @@ describe("TokenManagerERC20", () => { it("should invoke `transferToSchainERC20` and transfer back without mistakes double with attached tokens", async () => { const amount = "20000000000000000"; - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1078,13 +1066,6 @@ describe("TokenManagerERC20", () => { await erc20OnTargetChain.connect(user).approve(tokenManagerErc202.address, amount); - await tokenManagerErc202 - .connect(user) - .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerErc202.address); - await tokenManagerErc202 .connect(user) .transferToSchainERC20(schainName, erc20OnOriginChain.address, amount); @@ -1212,6 +1193,7 @@ describe("TokenManagerERC20", () => { await tokenManagerErc202.connect(deployer).grantRole(await tokenManagerErc202.TOKEN_REGISTRAR_ROLE(), schainOwner.address); await tokenManagerErc202.connect(schainOwner).addERC20TokenByOwner(schainName, erc20OnOriginChain.address, erc20OnTargetChain.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); await messageProxyForSchain2.postMessage(tokenManagerErc202.address, schainId, tokenManagerErc20.address, data); @@ -1237,7 +1219,6 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain2.connect(deployer).grantRole(await messageProxyForSchain2.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain2.connect(deployer).addConnectedChain(newSchainNameZ); - await messageProxyForSchain2.registerExtraContract(newSchainNameZ, tokenManagerErc202.address); await tokenManagerErc202.addTokenManager(newSchainNameZ, tokenManagerErc20Z.address); await erc20OnTargetChain.connect(user).approve(tokenManagerErc202.address, amount); @@ -1255,7 +1236,8 @@ describe("TokenManagerERC20", () => { it("should not be able to transfer main chain token or clone to mainnet", async () => { const amount = "20000000000000000"; - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerErc20.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerErc202.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1316,7 +1298,6 @@ describe("TokenManagerERC20", () => { .exitToMainERC20(erc20OnTargetChain.address, amount) .should.be.eventually.rejectedWith("Incorrect main chain token"); - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerErc202.address); await tokenManagerErc202 .connect(user) @@ -1333,8 +1314,6 @@ describe("TokenManagerERC20", () => { await erc20OnOriginChain.connect(user).approve(tokenManagerErc20.address, amount); - await messageProxyForSchain.registerExtraContract("Mainnet", tokenManagerErc20.address); - await tokenManagerErc20 .connect(user) .exitToMainERC20(erc20OnOriginChain.address, amount) @@ -1350,6 +1329,10 @@ describe("TokenManagerERC20", () => { }); describe("tests for `postMessage` function", async () => { + beforeEach(async () => { + await messageProxyForSchain.registerExtraContractForAll(tokenManagerErc20.address); + }); + it("should transfer ERC20 token with token info", async () => { // preparation const amount = 10; @@ -1378,7 +1361,7 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain.postMessage(tokenManagerErc20.address, fromSchainHash, remoteTokenManagerAddress, data); // expectation const addressERC20OnSchain = await tokenManagerErc20.clonesErc20(fromSchainHash, erc20OnMainnet.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect(parseInt((await targetErc20OnChain.functions.balanceOf(to)).toString(), 10)) .to.be.equal(amount); }); @@ -1407,7 +1390,7 @@ describe("TokenManagerERC20", () => { await messageProxyForSchain.postMessage(tokenManagerErc20.address, fromSchainHash, remoteTokenManagerAddress, data); // expectation const addressERC20OnSchain = await tokenManagerErc20.clonesErc20(fromSchainHash, erc20OnMainnet.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect(parseInt((await targetErc20OnChain.functions.balanceOf(to)).toString(), 10)) .to.be.equal(amount); }); @@ -1444,7 +1427,7 @@ describe("TokenManagerERC20", () => { // expectation const addressERC20OnSchain = await tokenManagerErc20.clonesErc20(fromSchainHash, erc20OnMainnet.address); - const targetErc20OnChain = await (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; + const targetErc20OnChain = (await ethers.getContractFactory("ERC20OnChain")).attach(addressERC20OnSchain) as ERC20OnChain; expect(parseInt((await targetErc20OnChain.functions.balanceOf(to)).toString(), 10)) .to.be.equal(amount); }); From 0db859bc0bc13fdb05a94933f721566f4c22bf4c Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:25:37 +0300 Subject: [PATCH 16/62] Add tests for TokenManagerERC721 --- proxy/test/TokenManagerERC721.ts | 47 ++++++-------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/proxy/test/TokenManagerERC721.ts b/proxy/test/TokenManagerERC721.ts index 29190ef7c..9ebd39326 100644 --- a/proxy/test/TokenManagerERC721.ts +++ b/proxy/test/TokenManagerERC721.ts @@ -225,6 +225,7 @@ describe("TokenManagerERC721", () => { tokenManagerERC7212 = await deployTokenManagerERC721(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC7212.address); await tokenManagerLinker2.registerTokenManager(tokenManagerERC7212.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerERC7212.address); }); it("should invoke `transferToSchainERC721` without mistakes", async () => { @@ -580,7 +581,7 @@ describe("TokenManagerERC721", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -654,13 +655,6 @@ describe("TokenManagerERC721", () => { await targetErc721OnChain.connect(user).approve(tokenManagerERC7212.address, tokenId); - await tokenManagerERC7212 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC7212.address); - await tokenManagerERC7212 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -677,7 +671,7 @@ describe("TokenManagerERC721", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes with attached tokens", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -746,13 +740,6 @@ describe("TokenManagerERC721", () => { await erc721OnTargetChain.connect(user).approve(tokenManagerERC7212.address, tokenId); - await tokenManagerERC7212 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC7212.address); - await tokenManagerERC7212 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -770,7 +757,7 @@ describe("TokenManagerERC721", () => { it("should invoke `transferToSchainERC721` and transfer back without mistakes double", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -844,13 +831,6 @@ describe("TokenManagerERC721", () => { await targetErc721OnChain.connect(user).approve(tokenManagerERC7212.address, tokenId); - await tokenManagerERC7212 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC7212.address); - await tokenManagerERC7212 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -935,7 +915,7 @@ describe("TokenManagerERC721", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes double with attached tokens", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1004,13 +984,6 @@ describe("TokenManagerERC721", () => { await erc721OnTargetChain.connect(user).approve(tokenManagerERC7212.address, tokenId); - await tokenManagerERC7212 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC7212.address); - await tokenManagerERC7212 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -1157,7 +1130,6 @@ describe("TokenManagerERC721", () => { await messageProxyForSchain2.connect(deployer).grantRole(await messageProxyForSchain2.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain2.connect(deployer).addConnectedChain(newSchainNameZ); - await messageProxyForSchain2.registerExtraContract(newSchainNameZ, tokenManagerERC7212.address); await tokenManagerERC7212.addTokenManager(newSchainNameZ, tokenManagerERC721Z.address); await erc721OnTargetChain.connect(user).approve(tokenManagerERC7212.address, tokenId); @@ -1174,7 +1146,7 @@ describe("TokenManagerERC721", () => { }); it("should not be able to transfer main chain token or clone to mainnet", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1233,8 +1205,6 @@ describe("TokenManagerERC721", () => { .exitToMainERC721(erc721OnTargetChain.address, tokenId) .should.be.eventually.rejectedWith("Incorrect main chain token"); - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC7212.address); - await tokenManagerERC7212 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -1250,8 +1220,6 @@ describe("TokenManagerERC721", () => { await erc721OnOriginChain.connect(user).approve(tokenManagerERC721.address, tokenId); - await messageProxyForSchain.registerExtraContract("Mainnet", tokenManagerERC721.address); - await tokenManagerERC721 .connect(user) .exitToMainERC721(erc721OnOriginChain.address, tokenId) @@ -1267,6 +1235,9 @@ describe("TokenManagerERC721", () => { }); describe("tests for `postMessage` function", async () => { + beforeEach(async () => { + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721.address); + }); it("should transfer ERC721 token token with token info", async () => { // preparation From a582e9189d94bd65da0e1c467c0949983cf6279a Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:25:48 +0300 Subject: [PATCH 17/62] Add tests for TokenManagerERC721WithMetadata --- proxy/test/TokenManagerERC721WithMetadata.ts | 47 ++++---------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/proxy/test/TokenManagerERC721WithMetadata.ts b/proxy/test/TokenManagerERC721WithMetadata.ts index 653f8cb94..6b1dc9502 100644 --- a/proxy/test/TokenManagerERC721WithMetadata.ts +++ b/proxy/test/TokenManagerERC721WithMetadata.ts @@ -230,6 +230,7 @@ describe("TokenManagerERC721WithMetadata", () => { tokenManagerERC721WithMetadata2 = await deployTokenManagerERC721WithMetadata(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc721OnTargetChain.connect(deployer).grantRole(await erc721OnTargetChain.MINTER_ROLE(), tokenManagerERC721WithMetadata2.address); await tokenManagerLinker2.registerTokenManager(tokenManagerERC721WithMetadata2.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerERC721WithMetadata2.address); }); it("should invoke `transferToSchainERC721` without mistakes", async () => { @@ -605,7 +606,7 @@ describe("TokenManagerERC721WithMetadata", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721WithMetadata.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -682,13 +683,6 @@ describe("TokenManagerERC721WithMetadata", () => { await targetErc721OnChain.connect(user).approve(tokenManagerERC721WithMetadata2.address, tokenId); - await tokenManagerERC721WithMetadata2 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC721WithMetadata2.address); - await tokenManagerERC721WithMetadata2 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -707,7 +701,7 @@ describe("TokenManagerERC721WithMetadata", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes with attached tokens", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721WithMetadata.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -778,13 +772,6 @@ describe("TokenManagerERC721WithMetadata", () => { await erc721OnTargetChain.connect(user).approve(tokenManagerERC721WithMetadata2.address, tokenId); - await tokenManagerERC721WithMetadata2 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC721WithMetadata2.address); - await tokenManagerERC721WithMetadata2 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -804,7 +791,7 @@ describe("TokenManagerERC721WithMetadata", () => { it("should invoke `transferToSchainERC721` and transfer back without mistakes double", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721WithMetadata.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -881,13 +868,6 @@ describe("TokenManagerERC721WithMetadata", () => { await targetErc721OnChain.connect(user).approve(tokenManagerERC721WithMetadata2.address, tokenId); - await tokenManagerERC721WithMetadata2 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC721WithMetadata2.address); - await tokenManagerERC721WithMetadata2 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -986,7 +966,7 @@ describe("TokenManagerERC721WithMetadata", () => { }); it("should invoke `transferToSchainERC721` and transfer back without mistakes double with attached tokens", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721WithMetadata.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1057,13 +1037,6 @@ describe("TokenManagerERC721WithMetadata", () => { await erc721OnTargetChain.connect(user).approve(tokenManagerERC721WithMetadata2.address, tokenId); - await tokenManagerERC721WithMetadata2 - .connect(user) - .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC721WithMetadata2.address); - await tokenManagerERC721WithMetadata2 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -1227,7 +1200,6 @@ describe("TokenManagerERC721WithMetadata", () => { await messageProxyForSchain2.connect(deployer).grantRole(await messageProxyForSchain2.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain2.connect(deployer).addConnectedChain(newSchainNameZ); - await messageProxyForSchain2.registerExtraContract(newSchainNameZ, tokenManagerERC721WithMetadata2.address); await tokenManagerERC721WithMetadata2.addTokenManager(newSchainNameZ, tokenManagerERC721WithMetadataZ.address); await erc721OnTargetChain.connect(user).approve(tokenManagerERC721WithMetadata2.address, tokenId); @@ -1244,7 +1216,7 @@ describe("TokenManagerERC721WithMetadata", () => { }); it("should not be able to transfer main chain token or clone to mainnet", async () => { - await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC721WithMetadata.address); + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); @@ -1306,8 +1278,6 @@ describe("TokenManagerERC721WithMetadata", () => { .exitToMainERC721(erc721OnTargetChain.address, tokenId) .should.be.eventually.rejectedWith("Incorrect main chain token"); - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC721WithMetadata2.address); - await tokenManagerERC721WithMetadata2 .connect(user) .transferToSchainERC721(schainName, erc721OnOriginChain.address, tokenId); @@ -1325,8 +1295,6 @@ describe("TokenManagerERC721WithMetadata", () => { await erc721OnOriginChain.connect(user).approve(tokenManagerERC721WithMetadata.address, tokenId); - await messageProxyForSchain.registerExtraContract("Mainnet", tokenManagerERC721WithMetadata.address); - await tokenManagerERC721WithMetadata .connect(user) .exitToMainERC721(erc721OnOriginChain.address, tokenId) @@ -1342,6 +1310,9 @@ describe("TokenManagerERC721WithMetadata", () => { }); describe("tests for `postMessage` function", async () => { + beforeEach(async () => { + await messageProxyForSchain.registerExtraContractForAll(tokenManagerERC721WithMetadata.address); + }); it("should transfer ERC721 token token with token info", async () => { // preparation From 2fc591445779679baa2e58248de6a78b23c7545d Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:25:59 +0300 Subject: [PATCH 18/62] Add tests for TokenManagerERC1155 --- proxy/test/TokenManagerERC1155.ts | 72 +------------------------------ 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/proxy/test/TokenManagerERC1155.ts b/proxy/test/TokenManagerERC1155.ts index 92b3425ae..2415c017f 100644 --- a/proxy/test/TokenManagerERC1155.ts +++ b/proxy/test/TokenManagerERC1155.ts @@ -216,6 +216,7 @@ describe("TokenManagerERC1155", () => { tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); await tokenManagerLinker2.registerTokenManager(tokenManagerERC11552.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerERC11552.address); }); it("should invoke `transferToSchainERC1155` without mistakes", async () => { @@ -624,13 +625,6 @@ describe("TokenManagerERC1155", () => { await targetErc1155OnChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount); @@ -716,13 +710,6 @@ describe("TokenManagerERC1155", () => { await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount); @@ -813,13 +800,6 @@ describe("TokenManagerERC1155", () => { await targetErc1155OnChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount); @@ -973,13 +953,6 @@ describe("TokenManagerERC1155", () => { await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount); @@ -1066,8 +1039,6 @@ describe("TokenManagerERC1155", () => { }); it("should not be able to transfer X->Y->Z", async () => { - // await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC1155.address); - // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain.connect(deployer).addConnectedChain(newSchainName); @@ -1129,7 +1100,6 @@ describe("TokenManagerERC1155", () => { await messageProxyForSchain2.connect(deployer).grantRole(await messageProxyForSchain2.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain2.connect(deployer).addConnectedChain(newSchainNameZ); - await messageProxyForSchain2.registerExtraContract(newSchainNameZ, tokenManagerERC11552.address); await tokenManagerERC11552.addTokenManager(newSchainNameZ, tokenManagerERC1155Z.address); await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); @@ -1146,8 +1116,6 @@ describe("TokenManagerERC1155", () => { }); it("should not be able to transfer main chain token or clone to mainnet", async () => { - // await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC1155.address); - // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain.connect(deployer).addConnectedChain(newSchainName); @@ -1205,8 +1173,6 @@ describe("TokenManagerERC1155", () => { .exitToMainERC1155(erc1155OnTargetChain.address, id, amount) .should.be.eventually.rejectedWith("Incorrect main chain token"); - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155(schainName, erc1155OnOriginChain.address, id, amount); @@ -1258,6 +1224,7 @@ describe("TokenManagerERC1155", () => { tokenManagerERC11552 = await deployTokenManagerERC1155(newSchainName, messageProxyForSchain2.address, tokenManagerLinker2, communityLocker2, fakeDepositBox); await erc1155OnTargetChain.connect(deployer).grantRole(await erc1155OnTargetChain.MINTER_ROLE(), tokenManagerERC11552.address); await tokenManagerLinker2.registerTokenManager(tokenManagerERC11552.address); + await messageProxyForSchain2.registerExtraContractForAll(tokenManagerERC11552.address); }); it("should invoke `transferToSchainERC1155` without mistakes", async () => { @@ -1699,13 +1666,6 @@ describe("TokenManagerERC1155", () => { await targetErc1155OnChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts); @@ -1796,13 +1756,6 @@ describe("TokenManagerERC1155", () => { await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts); @@ -1905,13 +1858,6 @@ describe("TokenManagerERC1155", () => { await targetErc1155OnChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts); @@ -2092,13 +2038,6 @@ describe("TokenManagerERC1155", () => { await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); - await tokenManagerERC11552 - .connect(user) - .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts) - .should.be.eventually.rejectedWith("Sender contract is not registered"); - - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts); @@ -2212,8 +2151,6 @@ describe("TokenManagerERC1155", () => { }); it("should not be able to transfer X->Y->Z", async () => { - // await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC1155.address); - // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain.connect(deployer).addConnectedChain(newSchainName); @@ -2280,7 +2217,6 @@ describe("TokenManagerERC1155", () => { await messageProxyForSchain2.connect(deployer).grantRole(await messageProxyForSchain2.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain2.connect(deployer).addConnectedChain(newSchainNameZ); - await messageProxyForSchain2.registerExtraContract(newSchainNameZ, tokenManagerERC11552.address); await tokenManagerERC11552.addTokenManager(newSchainNameZ, tokenManagerERC1155Z.address); await erc1155OnTargetChain.connect(user).setApprovalForAll(tokenManagerERC11552.address, true); @@ -2297,8 +2233,6 @@ describe("TokenManagerERC1155", () => { }); it("should not be able to transfer main chain token or clone to mainnet", async () => { - // await messageProxyForSchain.registerExtraContract(newSchainName, tokenManagerERC1155.address); - // add connected chain: await messageProxyForSchain.connect(deployer).grantRole(await messageProxyForSchain.CHAIN_CONNECTOR_ROLE(), deployer.address); await messageProxyForSchain.connect(deployer).addConnectedChain(newSchainName); @@ -2361,8 +2295,6 @@ describe("TokenManagerERC1155", () => { .exitToMainERC1155Batch(erc1155OnTargetChain.address, ids, amounts) .should.be.eventually.rejectedWith("Incorrect main chain token"); - await messageProxyForSchain2.registerExtraContract(schainName, tokenManagerERC11552.address); - await tokenManagerERC11552 .connect(user) .transferToSchainERC1155Batch(schainName, erc1155OnOriginChain.address, ids, amounts); From 5c4c26e79e0683522d5eccf2c66adf10895dfc72 Mon Sep 17 00:00:00 2001 From: Vadim Yavorsky Date: Thu, 13 Oct 2022 20:26:09 +0300 Subject: [PATCH 19/62] Add tests for TokenManagerEth --- proxy/test/TokenManagerEth.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/test/TokenManagerEth.ts b/proxy/test/TokenManagerEth.ts index ee0a72f34..cf5a183c0 100644 --- a/proxy/test/TokenManagerEth.ts +++ b/proxy/test/TokenManagerEth.ts @@ -277,6 +277,7 @@ describe("TokenManagerEth", () => { it("should transfer eth", async () => { // preparation + await messageProxyForSchain.registerExtraContractForAll(tokenManagerEth.address); const fromSchainName = randomString(10); const fromSchainId = stringValue(web3.utils.soliditySha3(fromSchainName)); const amount = "10"; From cf48dd9ad81ed6cebc9568533771a0558adf9f20 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Mon, 31 Oct 2022 15:34:30 +0000 Subject: [PATCH 20/62] VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d0149fef7..80e78df68 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.4 +1.3.5 From 7df47172c5e9731eced6ca946cb9b5a63a103652 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Mon, 31 Oct 2022 16:06:04 +0000 Subject: [PATCH 21/62] IMA Agent features for release 2.1 --- .github/workflows/cla.yml | 37 + .gitignore | 1 + agent/CLI.md | 293 ++ agent/bls.js | 182 +- agent/cli.js | 48 +- agent/main.js | 78 +- agent/package.json | 6 +- agent/rpc-call.js | 120 +- agent/run.sh | 3 +- agent/yarn.lock | 306 +- npms/skale-cc/cc.js | 57 + npms/skale-cool-socket/.eslintrc.js | 102 + npms/skale-cool-socket/event_dispatcher.js | 115 + npms/skale-cool-socket/package.json | 35 + npms/skale-cool-socket/server.js | 141 + npms/skale-cool-socket/settings.js | 197 ++ npms/skale-cool-socket/socket.js | 2703 +++++++++++++++++ npms/skale-cool-socket/test.js | 164 + npms/skale-cool-socket/test_server.js | 47 + .../test_signaling_server.js | 734 +++++ npms/skale-cool-socket/test_worker.js | 52 + npms/skale-cool-socket/utils.js | 253 ++ npms/skale-cool-socket/yarn.lock | 1510 +++++++++ npms/skale-ima/index.js | 141 +- npms/skale-ima/package.json | 2 +- npms/skale-ima/yarn.lock | 11 + npms/skale-observer/observer.js | 325 +- npms/skale-observer/observer_worker.js | 210 ++ npms/skale-observer/package.json | 6 +- npms/skale-observer/yarn.lock | 176 +- npms/skale-owasp/owasp-util.js | 40 +- 31 files changed, 7693 insertions(+), 402 deletions(-) create mode 100644 .github/workflows/cla.yml create mode 100644 agent/CLI.md create mode 100644 npms/skale-cool-socket/.eslintrc.js create mode 100644 npms/skale-cool-socket/event_dispatcher.js create mode 100644 npms/skale-cool-socket/package.json create mode 100644 npms/skale-cool-socket/server.js create mode 100644 npms/skale-cool-socket/settings.js create mode 100644 npms/skale-cool-socket/socket.js create mode 100644 npms/skale-cool-socket/test.js create mode 100644 npms/skale-cool-socket/test_server.js create mode 100644 npms/skale-cool-socket/test_signaling_server.js create mode 100644 npms/skale-cool-socket/test_worker.js create mode 100644 npms/skale-cool-socket/utils.js create mode 100644 npms/skale-cool-socket/yarn.lock create mode 100644 npms/skale-observer/observer_worker.js diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 000000000..66b7580a8 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,37 @@ +name: "cla" +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, closed, synchronize] + +jobs: + cla: + runs-on: ubuntu-latest + steps: + - name: "Get Team Members" + id: team + # github-script, v6.1.0 + uses: actions/github-script@7a5c598405937d486b0331594b5da2b14db670da + with: + github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + result-encoding: string + script: | + const members = await github.paginate( + github.rest.orgs.listMembers, + { org: "skalenetwork" }, + ); + return members.map(m => m.login).join(","); + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' + # Beta Release, v2.1.3-beta + uses: cla-assistant/github-action@ba066dbae3769e2ce93ec8cfc4fdc51b9db628ba + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }} + with: + path-to-signatures: 'signatures/version1/cla.json' + path-to-document: 'https://skale.network/cla.txt' + remote-organization-name: 'skalenetwork' + remote-repository-name: cla-sigs + allowlist: '${{ steps.team.outputs.result }},*[bot]' diff --git a/.gitignore b/.gitignore index 7b0773a12..d6174759c 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ npms/skale-ima/node_modules npms/skale-log/node_modules npms/skale-observer/node_modules npms/skale-owasp/node_modules +npms/skale-cool-socket/node_modules # TypeScript v1 declaration files typings/ diff --git a/agent/CLI.md b/agent/CLI.md new file mode 100644 index 000000000..4a8f572b7 --- /dev/null +++ b/agent/CLI.md @@ -0,0 +1,293 @@ + + +# IMA Command Line Interface + +**IMA** runs message transfer loop between **Ethereum(Main Net)** and **S-Chain**, also between assigned **S-Chain** and all connected to it other **S-Chains**. IMA also offers set of test tasks in its CLI. + +IMA operates with 3 types of chains: + +- **Ethereum(Main Net)** +- **S-Chain**, source **S-Chain** +- **T-Chain**, target **S-Chain** + +In the most of use cases only **Ethereum(Main Net)** and source **S-Chain** are needed. + +**IMA** supports the following groups of operations: + +- Run message loop. +- Perform **S-Chain** registration and initialization. +- Confiure and change gas reimbursement. +- Do **ETH**, **ERC20**, **ERC721**, **ERC1155**, batch **ERC1155** payments between chains. +- View amount of **ETH** can be received on Main Net. +- Mint **ERC20**, **ERC721**, **ERC1155** tokens. +- Show **ETH**, **ERC20**, **ERC721**, **ERC1155** balances. +- Browse **SKALE network**. +- Download source **S-Chain** information. +- Discover set of **S-Chains** connected to specifed **S-Chains**. +- Discover chain ID of specified chain with `--discover-cid`. +- Run monitoring service and expose its JSON RPC, the `--monitoring-port=number` option turns on monitoring web socket RPC server on specified port. By default monitoring server is disabled. + +Here is list of options running operations described above: + +``` +--show-config...................Show configuration values and exit. +--show-balance..................Show ETH and/or token balances on Main-net and/or S-Chain and exit. +--m2s-payment...................Do one payment from Main-net user account to S-chain user account. +--s2m-payment...................Do one payment from S-chain user account to Main-net user account. +--s2m-receive...................Receive one payment from S-chain user account to Main-net user account(ETH only, receives all the ETH pending in transfer). +--s2m-view......................View money amount user can receive as payment from S-chain user account to Main-net user account(ETH only, receives all the ETH pending in transfer). +--s2s-payment...................Do one payment from S-chain user account to other S-chain user account. +--s2s-forward...................Indicates S<->S transfer direction is forward. I.e. source S-chain is token minter and instantiator. This is default mode. +--s2s-reverse...................Indicates S<->S transfer direction is reverse. I.e. destination S-chain is token minter and instantiator. +--m2s-transfer..................Do single money transfer loop from Main-net to S-chain. +--s2m-transfer..................Do single money transfer loop from S-chain to Main-net. +--s2s-transfer..................Do single money transfer loop from S-chain to S-chain. +--with-metadata.................Makes ERC721 transfer using special version of Token Manager to transfer token metadata. +--transfer......................Run single M<->S and, optionally, S->S transfer loop iteration. +--loop..........................Run M<->S and, optionally, S->S transfer loop. +--browse-s-chain................Download own S-Chain network information. +--browse-skale-network..........Download entire SKALE network description. +--browse-connected-schains......Download S-Chains conected to S-Chain with name specified in id-s-chain command line parameter. +--mint-erc20....................Mint ERC20 tokens. +--mint-erc721...................Mint ERC721 tokens. +--mint-erc1155..................Mint ERC1155 tokens. +--burn-erc20....................Burn ERC20 tokens. +--burn-erc721...................Burn ERC721 tokens. +--burn-erc1155..................Burn ERC1155 tokens. +``` + +Please notice, token testing commands require `--tm-url-t-chain`, `cid-t-chain`, `erc20-t-chain` or `erc721-t-chain` or `erc1155-t-chain`, account information (like private key `key-t-chain`) command line arguments specified. Token amounts are specified via amount command line arguments specified. Token IDs are specified via tid or tids command line arguments. + +One or more of the following URL, chain name and chain ID parameters are needed for most of **IMA** operations: + +``` +--url-main-net=URL..............Main-net URL. Value is automatically loaded from the URL_W3_ETHEREUM environment variable if not specified. +--url-s-chain=URL...............S-chain URL. Value is automatically loaded from the URL_W3_S_CHAIN environment variable if not specified. +--url-t-chain=URL...............S<->S Target S-chain URL. Value is automatically loaded from the URL_W3_S_CHAIN_TARGET environment variable if +--id-main-net=number............Main-net Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_ETHEREUM environment variable if not specified. Default value is "Mainnet". +--id-s-chain=number.............S-chain Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_SCHAIN environment variable if not specified. Default value is "id-S-chain". +--id-t-chain=number.............S<->S Target S-chain Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_SCHAIN_TARET environment variable if not specified. Default value is "id-T-chain". +--cid-main-net=number...........Main-net Ethereum chain ID. Value is automatically loaded from the CID_ETHEREUM environment variable if not specified. Default value is -4. +--cid-s-chain=number............S-chain Ethereum chain ID. Value is automatically loaded from the CID_SCHAIN environment variable if not specified. Default value is -4. +--cid-t-chain=number............S<->S Target S-chain Ethereum chain ID. Value is automatically loaded from the CID_SCHAIN_TARGET environment variable if not specified. Default value is -4. +``` + +For most of operatons, **IMA** needs ABIs of **Skale Manager**, **Ethereum(Main Net)**, **S-Chain(s)**: + +``` +--abi-skale-manager=path........Path to JSON file containing Skale Manager ABI. Optional parameter. It's needed for S-Chain to S-Chain transfers. +--abi-main-net=path.............Path to JSON file containing IMA ABI for Main-net. +--abi-s-chain=path..............Path to JSON file containing IMA ABI for S-chain. +--abi-t-chain=path..............Path to JSON file containing IMA ABI for S<->S Target S-chain. +``` + +Token transfer commands require token APIs on approproate chains. + +**ERC20** options: + +``` +--erc20-main-net=path...........Path to JSON file containing ERC20 ABI for Main-net. +--erc20-s-chain=path............Path to JSON file containing ERC20 ABI for S-chain. +--addr-erc20-s-chain=address....Explicit ERC20 address in S-chain. +--erc20-t-chain=path............Path to JSON file containing ERC20 ABI for S<->S Target S-chain. +--addr-erc20-t-chain=address....Explicit ERC20 address in S<->S Target S-chain. +``` + +**ERC721** options: + +``` +--erc721-main-net=path..........Path to JSON file containing ERC721 ABI for Main-net. +--erc721-s-chain=path...........Path to JSON file containing ERC721 ABI for S-chain. +--addr-erc721-s-chain=address...Explicit ERC721 address in S-chain. +--erc721-t-chain=path...........Path to JSON file containing ERC721 ABI for S<->S S-chain. +--addr-erc721-t-chain=address...Explicit ERC721 address in S<->S S-chain. +``` + +**ERC1155** options: + +``` +--erc1155-main-net=path.........Path to JSON file containing ERC1155 ABI for Main-net. +--erc1155-s-chain=path..........Path to JSON file containing ERC1155 ABI for S-chain. +--addr-erc1155-s-chain=address..Explicit ERC1155 address in S-chain. +--erc1155-t-chain=path..........Path to JSON file containing ERC1155 ABI for S<->S S-chain. +--addr-erc1155-t-chain=address..Explicit ERC1155 address in S<->S S-chain. +``` + +**IMA** can sign transactions using one of following ways: + +- Using **Transaction Manager** JSON RPC +- Using **SGX wallet** JSON RPC +- Using explicitly specified private key +- Using wallet address, for read only operations only + +The folllowing parameters needed to use **Transaction Manager**: + +``` +--tm-url-main-net=URL...........Transaction Manager server URL for Main-net. Value is automatically loaded from the TRANSACTION_MANAGER_URL_ETHEREUM environment variable if not specified. Example: redis://@127.0.0.1:6379 +--tm-url-s-chain=URL............Transaction Manager server URL for S-chain. Value is automatically loaded from the TRANSACTION_MANAGER_URL_S_CHAIN environment variable if not specified. +--tm-url-t-chain=URL............Transaction Manager server URL for S<->S Target S-chain. Value is automatically loaded from the TRANSACTION_MANAGER_URL_S_CHAIN_TARGET environment variable if not specified. +--tm-priority-main-net=URL......Transaction Manager priority for Main-net. Value is automatically loaded from the TRANSACTION_MANAGER_PRIORITY_ETHEREUM environment variable if not specified. Default is 5. +--tm-priority-s-chain=URL.......Transaction Manager priority for S-chain. Value is automatically loaded from the TRANSACTION_MANAGER_PRIORITY_S_CHAIN environment variable if not specified. Default is 5. +--tm-priority-t-chain=URL.......Transaction Manager priority for S<->S Target S-chain. Value is automatically loaded from the TRANSACTION_MANAGER_PRIORITY_S_CHAIN_TARGET environment variable if not specified. Default is 5. +``` + +The folllowing parameters needed to use **SGX wallet**: + +``` +--sgx-url-main-net=URL..........SGX server URL for Main-net. Value is automatically loaded from the SGX_URL_ETHEREUM environment variable if not specified. +--sgx-url-s-chain=URL...........SGX server URL for S-chain. Value is automatically loaded from the SGX_URL_S_CHAIN environment variable if not specified. +--sgx-url-t-chain=URL...........SGX server URL for S<->S Target S-chain. Value is automatically loaded from the SGX_URL_S_CHAIN_TARGET environment variable if not specified. +--sgx-ecdsa-key-main-net=name...SGX/ECDSA key name for Main-net. Value is automatically loaded from the SGX_KEY_ETHEREUM environment variable if not specified. +--sgx-ecdsa-key-s-chain=name....SGX/ECDSA key name for S-chain. Value is automatically loaded from the SGX_KEY_S_CHAIN environment variable if not specified. +--sgx-ecdsa-key-t-chain=name....SGX/ECDSA key name for S<->S Target S-chain. Value is automatically loaded from the SGX_KEY_S_CHAIN_TARGET environment variable if not specified. +--sgx-ssl-key-main-net=path.....Path to SSL key file for SGX wallet of Main-net. Value is automatically loaded from the SGX_SSL_KEY_FILE_ETHEREUM environment variable if not specified. +--sgx-ssl-key-s-chain=path......Path to SSL key file for SGX wallet of S-chain. Value is automatically loaded from the SGX_SSL_KEY_FILE_S_CHAIN environment variable if not specified. +--sgx-ssl-key-t-chain=path......Path to SSL key file for SGX wallet of S<->S Target S-chain. Value is automatically loaded from the SGX_SSL_KEY_FILE_S_CHAIN_TARGET environment variable if not specified. +--sgx-ssl-cert-main-net=path....Path to SSL certificate file for SGX wallet of Main-net. Value is automatically loaded from the SGX_SSL_CERT_FILE_ETHEREUM environment variable if not specified. +--sgx-ssl-cert-s-chain=path.....Path to SSL certificate file for SGX wallet of S-chain. Value is automatically loaded from the SGX_SSL_CERT_FILE_S_CHAIN environment variable if not specified. +--sgx-ssl-cert-t-chain=path.....Path to SSL certificate file for SGX wallet of S<->S Target S-chain. Value is automatically loaded from the SGX_SSL_CERT_FILE_S_CHAIN_TARGET environment variable if not specified. +``` + +Using explicitly specified private key: + +``` +--address-main-net=value........Main-net user account address. Value is automatically loaded from the ACCOUNT_FOR_ETHEREUM environment variable if not specified. +--address-s-chain=value.........S-chain user account address. Value is automatically loaded from the ACCOUNT_FOR_SCHAIN environment variable if not specified. +--address-t-chain=value.........S<->S Target S-chain user account address. Value is automatically loaded from the ACCOUNT_FOR_SCHAIN_TARGET environment variable if not specified. +``` + +For read only operations, only wallet address can be specified: + +``` +--key-main-net=value............Private key for Main-net user account address. Value is automatically loaded from the PRIVATE_KEY_FOR_ETHEREUM environment variable if not specified. +--key-s-chain=value.............Private key for S-Chain user account address. Value is automatically loaded from the PRIVATE_KEY_FOR_SCHAIN environment variable if not specified. +--key-t-chain=value.............Private key for S<->S Target S-Chain user account address. Value is automatically loaded from the PRIVATE_KEY_FOR_SCHAIN_TARGET environment variable if not specified. +``` + +Please notice, **IMA** prefer to use transaction manager to sign blockchain transactions if `--tm-url-main-net`/`--tm-url-s-chain` command line values or `TRANSACTION_MANAGER_URL_ETHEREUM`/`TRANSACTION_MANAGER_URL_S_CHAIN` shell variables were specified. Next preferred option is **SGX wallet** which is used if `--sgx-url-main-net`/`--sgx-url-s-chain` command line values or `SGX_URL_ETHEREUM`/`SGX_URL_S_CHAIN` shell variables were specified. SGX signing also needs key name, key and certificate files. Finally, **IMA** attempts to use explicitly provided private key to sign blockchain transactions if `--key-main-net`/`--key-s-chain` command line values or `PRIVATE_KEY_FOR_ETHEREUM`/`PRIVATE_KEY_FOR_SCHAIN` shell variables were specified. + +**ETH** transfers operations require amout of **ETH** to be specied with one of the following options: + +``` +--value=numberunitName..........Amount of unitName to transfer, where unitName is well known Ethereum unit name like ether or wei. +--wei=number....................Amount of wei to transfer. +--babbage=number................Amount of babbage(wei*1000) to transfer. +--lovelace=number...............Amount of lovelace(wei*1000*1000) to transfer. +--shannon=number................Amount of shannon(wei*1000*1000*1000) to transfer. +--szabo=number..................Amount of szabo(wei*1000*1000*1000*1000) to transfer. +--finney=number.................Amount of finney(wei*1000*1000*1000*1000*1000) to transfer. +--ether=number..................Amount of ether(wei*1000*1000*1000*1000*1000*1000) to transfer. +``` + +Token transfer operations require token amounts and/or token IDs: + +``` +--amount=number.................Amount of tokens to transfer. +--tid=number....................ERC721 or ERC1155 token id to transfer. +--amounts=array of numbers......ERC1155 token id to transfer in batch. +--tids=array of numbers.........ERC1155 token amount to transfer in batch. +--sleep-between-tx=number.......Sleep time (in milliseconds) between transactions during complex operations. +--wait-next-block...............Wait for next block between transactions during complex operations. +``` + +**Gas reumbursement** can be configure with the following options: + +``` +--reimbursement-chain=name......Specifies chain name. +--reimbursement-recharge=vu.....Recharge user wallet with specified value v, unit name u is well known Ethereum unit name like ether or wei. +--reimbursement-withdraw=vu.....Withdraw user wallet with specified value v, unit name u is well known Ethereum unit name like ether or wei. +--reimbursement-balance.........Show wallet balance. +--reimbursement-range=number....Sets minimal time interval between transfers from S-Chain to Main Net. +``` + +**Gas reumbursement** can be **Oracle**-based if the following options are specified: + +--enable-oracle.................Enable call to Oracle to compute gas price for gas reimbursement. Default mode. +--disable-oracle................Disable call to Oracle to compute gas price for gas reimbursement. + +**IMA** must be initialized and its **S-Chain** must be registered once after creation with the following options: + +``` +--register......................Register(perform all steps). +--check-registration............Perform registration status check(perform all steps). +``` + +**S-Chain** to **S-Chain** transfers must be turned on and require periodic **SKALE network re-discovery**: + +``` +--s2s-enable....................Enables S-Chain to S-Chain transfers. Default mode. The abi-skale-manager path must be provided. +--s2s-disable...................Disables S-Chain to S-Chain transfers. +--net-rediscover=number.........SKALE NETWORK re-discovery interval(in seconds). Default is 3600 seconds or 1 hour, specify 0 to disable SKALE NETWORK re-discovery. +``` + +**IMA** loop can optionally use dry run, group **IMA** messages and supports varuous customizations: + +``` +--no-wait-s-chain...............Do not wait until S-Chain is started. +--max-wait-attempts=value.......Max number of S-Chain call attempts to do while it became alive and sane. +--skip-dry-run..................Skip dry run contract method calls. +--ignore-dry-run................Ignore result of dry run contract method calls and continue execute. +--dry-run.......................Use error results of dry run contract method calls as actual errors and stop execute. +--m2s-transfer-block-size.......Number of transactions in one block to use in money transfer loop from Main-net to S-chain. +--s2m-transfer-block-size.......Number of transactions in one block to use in money transfer loop from S-chain to Main-net. +--s2s-transfer-block-size.......Number of transactions in one block to use in money transfer loop from S-chain to S-chain. +--transfer-block-size...........Number of transactions in one block to use in both money transfer loops. +--m2s-max-transactions..........Maximal number of transactions to do in money transfer loop from Main-net to S-chain(0 is unlimited). +--s2m-max-transactions..........Maximal number of transactions to do in money transfer loop from S-chain to Main-net(0 is unlimited). +--s2s-max-transactions..........Maximal number of transactions to do in money transfer loop from S-chain to S-chain(0 is unlimited). +--max-transactions..............Maximal number of transactions to do in both money transfer loops(0 is unlimited). +--m2s-await-blocks..............Maximal number of blocks to wait to appear in blockchain before transaction from Main-net to S-chain(0 is no wait). +--s2m-await-blocks..............Maximal number of blocks to wait to appear in blockchain before transaction from S-chain to Main-net(0 is no wait). +--s2s-await-blocks..............Maximal number of blocks to wait to appear in blockchain before transaction from S-chain to S-chain(0 is no wait). +--await-blocks..................Maximal number of blocks to wait to appear in blockchain before transaction between both S-chain and Main-net(0 is no wait). +--m2s-await-time................Minimal age of transaction message(in seconds) before it will be transferred from Main-net to S-chain(0 is no wait). +--s2m-await-time................Minimal age of transaction message(in seconds) before it will be transferred from S-chain to Main-net(0 is no wait). +--s2s-await-time................Minimal age of transaction message(in seconds) before it will be transferred from S-chain to S-chain(0 is no wait). +--await-time....................Minimal age of transaction message(in seconds) before it will be transferred between both S-chain and Main-net(0 is no wait). +--period........................Transfer loop period(in seconds). +--node-number=value.............S-Chain node number(0-based). +--nodes-count=value.............S-Chain nodes count. +--time-framing=value............Specifies period(in seconds) for time framing(0 to disable time framing). +--time-gap=value................Specifies gap(in seconds) before next time frame. +``` + +**IMA** transfer loop must **BLS**-sign messages and needs paths to **BLS** command line utilities: + +``` +--sign-messages.................Sign transferred messages. +--bls-glue=path.................Specifies path to bls_glue application. +--hash-g1=path..................Specifies path to hash_g1 application. +--bls-verify=path...............Optional parameter, specifies path to verify_bls application. +``` + +**IMA** transfer loop needs to scan **IMA smart contract** events, scanning can be customized with the following options: + +``` +--bs-step-size=number...........Specifies step block range size to search iterative past events step by step. 0 to disable iterative search. +--bs-max-all-range=number.......Specifies max number of steps to allow to search as [0...latest] range. 0 to disable iterative search. +--bs-progressive-enable.........Enables progressive block scan to search past events. +--bs-progressive-disable........Disables progressive block scan to search past events. +``` + +Like any command line application, **IMA** produces various command line output and supports logging. Logging can be customized with the following options: + +``` +--expose........................Expose low-level log details after successful operations. By default details exposed only on errors. +--no-expose.....................Expose low-level log details only after errors. Default expose mode. +--verbose=value.................Set level of output details. +--verbose-list..................List available verbose levels and exit. +--log=path......................Write program output to specified log file(multiple files can be specified). +--log-size=value................Max size(in bytes) of one log file(affects to log log rotation). +--log-files=value...............Maximum number of log files for log rotation. +--gathered......................Print details of gathering data from command line arguments. Default mode. +--no-gathered...................Do not print details of gathering data from command line arguments. +--expose-security-info..........Expose security-related values in log output. This mode is needed for debugging purposes only. +--no-expose-security-info.......Do not expose security-related values in log output. Default mode. +``` + +Command line output and loggging can be plain or ANSI-colorized: + +``` +--colors........................Use ANSI-colorized logging. +--no-colors.....................Use monochrome logging. +``` \ No newline at end of file diff --git a/agent/bls.js b/agent/bls.js index 95371c189..4442863d8 100644 --- a/agent/bls.js +++ b/agent/bls.js @@ -30,6 +30,8 @@ const child_process = require( "child_process" ); const shell = require( "shelljs" ); const { Keccak } = require( "sha3" ); +const { cc } = require( "./utils" ); +const owaspUtils = require( "../npms/skale-owasp/owasp-util" ); function init() { owaspUtils.owaspAddUsageRef(); @@ -44,7 +46,7 @@ async function with_timeout( strDescription, promise, seconds ) { let result_err = null, isComplete = false; promise.catch( function( err ) { isComplete = true; - result_err = new Error( strDescription + "error: " + err.toString() ); + result_err = new Error( strDescription + "error: " + owaspUtils.extract_error_message( err ) ); } ).finally( function() { isComplete = true; } ); @@ -61,6 +63,8 @@ async function with_timeout( strDescription, promise, seconds ) { function discover_bls_threshold( joSChainNetworkInfo ) { joSChainNetworkInfo = joSChainNetworkInfo || imaState.joSChainNetworkInfo; + if( ! joSChainNetworkInfo ) + return -1; const jarrNodes = joSChainNetworkInfo.network; for( let i = 0; i < jarrNodes.length; ++i ) { const joNode = jarrNodes[i]; @@ -75,6 +79,8 @@ function discover_bls_threshold( joSChainNetworkInfo ) { function discover_bls_participants( joSChainNetworkInfo ) { joSChainNetworkInfo = joSChainNetworkInfo || imaState.joSChainNetworkInfo; + if( ! joSChainNetworkInfo ) + return -1; const jarrNodes = joSChainNetworkInfo.network; for( let i = 0; i < jarrNodes.length; ++i ) { const joNode = jarrNodes[i]; @@ -361,7 +367,7 @@ function perform_bls_glue( // fnShellRestore(); } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "BLS glue CRITICAL ERROR:" ) + cc.error( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "BLS glue CRITICAL ERROR:" ) + cc.error( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "BLS glue output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -460,7 +466,7 @@ function perform_bls_glue_u256( details, u256, arrSignResults ) { // fnShellRestore(); } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "BLS glue CRITICAL ERROR:" ) + cc.error( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "BLS glue CRITICAL ERROR:" ) + cc.error( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "BLS glue output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -524,7 +530,7 @@ function perform_bls_verify_i( fnShellRestore(); return true; } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " BLS node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify error:" ) + cc.normal( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " BLS node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify error:" ) + cc.normal( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "CRITICAL ERROR:" ) + cc.error( " BLS node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -550,6 +556,7 @@ function perform_bls_verify_i_u256( details, nZeroBasedNodeIndex, joResultFromNo let strOutput = ""; try { shell.cd( strActionDir ); + // const joMsg = { message: keccak256_u256( u256, true ) }; details.write( strLogPrefix + cc.debug( "BLS u256 node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.debug( " verify message " ) + cc.j( joMsg ) + cc.debug( " composed from " ) + cc.j( u256 ) + cc.debug( " using glue " ) + cc.j( joResultFromNode ) + cc.debug( " and public key " ) + cc.j( joPublicKey ) + "\n" ); const strSignResultFileName = strActionDir + "/sign-result" + nZeroBasedNodeIndex + ".json"; @@ -573,7 +580,7 @@ function perform_bls_verify_i_u256( details, nZeroBasedNodeIndex, joResultFromNo fnShellRestore(); return true; } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " BLS u256 node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify error:" ) + cc.normal( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " BLS u256 node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify error:" ) + cc.normal( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "CRITICAL ERROR:" ) + cc.error( " BLS u256 node " ) + cc.notice( "#" ) + cc.info( nZeroBasedNodeIndex ) + cc.error( " verify output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -642,7 +649,7 @@ function perform_bls_verify( fnShellRestore(); return true; } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "BLS/summary verify CRITICAL ERROR:" ) + cc.normal( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "BLS/summary verify CRITICAL ERROR:" ) + cc.normal( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "BLS/summary verify output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -700,7 +707,7 @@ function perform_bls_verify_u256( details, joGlueResult, u256, joCommonPublicKey fnShellRestore(); return true; } catch ( err ) { - const s1 = strLogPrefix + cc.fatal( "BLS u256/summary verify CRITICAL ERROR:" ) + cc.normal( " error description is: " ) + cc.warning( err.toString() ) + "\n"; + const s1 = strLogPrefix + cc.fatal( "BLS u256/summary verify CRITICAL ERROR:" ) + cc.normal( " error description is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; const s2 = strLogPrefix + cc.error( "BLS u256/summary verify output is:\n" ) + cc.notice( strOutput ) + "\n"; log.write( s1 ); details.write( s1 ); @@ -784,7 +791,7 @@ async function check_correctness_of_messages_to_sign( details, strLogPrefix, str cc.error( " Correctness validation failed for message " ) + cc.info( idxMessage ) + cc.error( " sent to " ) + cc.info( joChainName ) + cc.error( ", message is: " ) + cc.j( joMessage ) + - cc.error( ", error information: " ) + cc.warning( err.toString() ) + + cc.error( ", error information: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( s ); details.write( s ); @@ -918,18 +925,20 @@ async function do_sign_messages_impl( cc.normal( "(" ) + cc.bright( i ) + cc.normal( "/" ) + cc.bright( jarrNodes.length ) + cc.normal( ", ID " ) + cc.info( joNode.nodeID ) + cc.normal( ")" ) + cc.normal( ", " ) + cc.notice( "sequence ID" ) + cc.normal( " is " ) + cc.attention( sequence_id ); const rpcCallOpts = null; - await rpcCall.create( strNodeURL, rpcCallOpts, async function( joCall, err ) { + /*await*/ rpcCall.create( strNodeURL, rpcCallOpts, async function( joCall, err ) { if( err ) { ++joGatheringTracker.nCountReceived; // including errors ++joGatheringTracker.nCountErrors; const strErrorMessage = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed, RPC call was not created, error: " ) + cc.warning( err ) + + cc.error( " failed, RPC call was not created, error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); + if( joCall ) + await joCall.disconnect(); return; } let targetChainName = ""; @@ -951,8 +960,10 @@ async function do_sign_messages_impl( fromChainName = "" + joExtraSignOpts.chain_id_src; // targetChainURL = owaspUtils.w3_2_url( joExtraSignOpts.w3_dst ); // fromChainURL = owaspUtils.w3_2_url( joExtraSignOpts.w3_src ); - } else + } else { + await joCall.disconnect(); throw new Error( "CRITICAL ERROR: Failed do_sign_messages_impl() with unknown directon \"" + strDirection + "\"" ); + } const joParams = { direction: "" + strDirection, @@ -986,11 +997,12 @@ async function do_sign_messages_impl( const strErrorMessage = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed, RPC call reported error: " ) + cc.warning( err ) + + cc.error( " failed, RPC call reported error: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); + await joCall.disconnect(); return; } details.write( @@ -1004,25 +1016,16 @@ async function do_sign_messages_impl( "\n" ); if( joOut.result == null || joOut.result == undefined || ( !typeof joOut.result == "object" ) ) { ++joGatheringTracker.nCountErrors; - if( "error" in joOut && "message" in joOut.error ) { - const strErrorMessage = - strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + - cc.error( "S-Chain node " ) + strNodeDescColorized + - cc.error( " reported wallet error: " ) + cc.warning( joOut.error.message ) + - cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + - "\n"; - log.write( strErrorMessage ); - details.write( strErrorMessage ); - } else { - const strErrorMessage = - strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + - cc.error( "JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed with " ) + cc.warning( "unknown wallet error" ) + - cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + - "\n"; - log.write( strErrorMessage ); - details.write( strErrorMessage ); - } + const strErrorMessage = + strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + + cc.error( "S-Chain node " ) + strNodeDescColorized + + cc.error( " reported wallet error: " ) + + cc.warning( owaspUtils.extract_error_message( joOut, "unknown wallet error(1)" ) ) + + cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + + "\n"; + log.write( strErrorMessage ); + details.write( strErrorMessage ); + await joCall.disconnect(); return; } details.write( strLogPrefix + cc.normal( "Node " ) + cc.info( joNode.nodeID ) + cc.normal( " sign result: " ) + cc.j( joOut.result ? joOut.result : null ) + "\n" ); @@ -1043,6 +1046,7 @@ async function do_sign_messages_impl( cc.debug( " because " ) + cc.info( nThreshold ) + cc.debug( "/" ) + cc.info( nCountOfBlsPartsToCollect ) + cc.debug( " threshold number of BLS signature parts already gathered" ) + "\n" ); + await joCall.disconnect(); return; } const arrTmp = joOut.result.signResult.signatureShare.split( ":" ); @@ -1065,15 +1069,13 @@ async function do_sign_messages_impl( ) ) { details.write( strLogPrefixA + cc.success( "Got successful BLS verification result for node " ) + cc.info( joNode.nodeID ) + cc.success( " with index " ) + cc.info( nZeroBasedNodeIndex ) + "\n" ); bNodeSignatureOKay = true; // node verification passed - } else { - const strError = "BLS verify failed"; - details.write( strLogPrefixA + cc.fatal( "CRITICAL ERROR:" ) + " " + cc.error( strError ) + "\n" ); - } + } else + details.write( strLogPrefixA + cc.fatal( "CRITICAL ERROR:" ) + " " + cc.error( "BLS verification failed" ) + "\n" ); } catch ( err ) { const strErrorMessage = strLogPrefixA + cc.error( "S-Chain node " ) + strNodeDescColorized + cc.error( " sign " ) + cc.error( " CRITICAL ERROR:" ) + cc.error( " partial signature fail from with index " ) + cc.info( nZeroBasedNodeIndex ) + - cc.error( ", error is " ) + cc.warning( err.toString() ) + + cc.error( ", error is " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + "\n"; log.write( strErrorMessage ); @@ -1100,16 +1102,17 @@ async function do_sign_messages_impl( ++joGatheringTracker.nCountErrors; } } catch ( err ) { - ++nCountErrors; + ++joGatheringTracker.nCountErrors; const strErrorMessage = strLogPrefix + cc.error( "S-Chain node " ) + strNodeDescColorized + " " + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " signature fail from node " ) + cc.info( joNode.nodeID ) + - cc.error( ", error is " ) + cc.warning( err.toString() ) + + cc.error( ", error is " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + cc.error( ", " ) + cc.notice( "sequence ID" ) + cc.error( " is " ) + cc.attention( sequence_id ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); } + await joCall.disconnect(); } ); // joCall.call ... } ); // rpcCall.create ... } // for( let i = 0; i < jarrNodes.length; ++i ) @@ -1118,7 +1121,7 @@ async function do_sign_messages_impl( details.write( strLogPrefix + cc.debug( "Waiting for BLS glue result " ) + "\n" ); let errGathering = null; const promise_gathering_complete = new Promise( ( resolve, reject ) => { - const iv = setInterval( async function() { + const iv = setInterval( function() { ++ joGatheringTracker.nWaitIntervalStepsDone; cntSuccess = joGatheringTracker.nCountReceived - joGatheringTracker.nCountErrors; if( cntSuccess >= nCountOfBlsPartsToCollect ) { @@ -1146,7 +1149,7 @@ async function do_sign_messages_impl( strSuccessfulResultDescription = "Got successful summary BLS verification result"; details.write( strLogPrefixB + cc.success( strSuccessfulResultDescription ) + "\n" ); } else { - strError = "BLS verify failed"; + strError = "BLS verification failed"; log.write( strLogPrefixB + cc.fatal( "CRITICAL ERROR:" ) + cc.error( strError ) + "\n" ); details.write( strLogPrefixB + cc.fatal( "CRITICAL ERROR:" ) + cc.error( strError ) + "\n" ); } @@ -1161,10 +1164,10 @@ async function do_sign_messages_impl( log.write( cc.debug( "Will call sending function (fn)" ) + "\n" ); details.write( cc.debug( "Will call sending function (fn) for " ) + "\n" ); /*await*/ fn( strError, jarrMessages, joGlueResult ).catch( ( err ) => { - const strErrorMessage = cc.error( "Problem(2) in BLS sign result handler: " ) + cc.warning( err.toString() ) + "\n"; + const strErrorMessage = cc.error( "Problem(2) in BLS sign result handler: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); - errGathering = "Problem(2) in BLS sign result handler: " + err.toString(); + errGathering = "Problem(2) in BLS sign result handler: " + owaspUtils.extract_error_message( err ); return; } ); bHaveResultReportCalled = true; @@ -1177,16 +1180,16 @@ async function do_sign_messages_impl( } if( joGatheringTracker.nCountReceived >= jarrNodes.length ) { clearInterval( iv ); - await fn( "signature error(2), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", jarrMessages, null ).catch( ( err ) => { + /*await*/ fn( "signature error(2), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", jarrMessages, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(3) in BLS sign result handler, not enough successful BLS signature parts(" ) + - cc.info( cntSuccess ) + cc.error( " when all attempts done, error details: " ) + cc.warning( err.toString() ) + + cc.info( cntSuccess ) + cc.error( " when all attempts done, error details: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); errGathering = "Problem(3) in BLS sign result handler, not enough successful BLS signature parts(" + - cntSuccess + " when all attempts done, error details: " + err.toString(); + cntSuccess + " when all attempts done, error details: " + owaspUtils.extract_error_message( err ); reject( new Error( errGathering ) ); } ); bHaveResultReportCalled = true; @@ -1194,16 +1197,16 @@ async function do_sign_messages_impl( } if( joGatheringTracker.nWaitIntervalStepsDone >= joGatheringTracker.nWaitIntervalMaxSteps ) { clearInterval( iv ); - await fn( "signature error(3), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", jarrMessages, null ).catch( ( err ) => { + /*await*/ fn( "signature error(3), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", jarrMessages, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(4) in BLS sign result handler, not enough successful BLS signature parts(" ) + cc.info( cntSuccess ) + cc.error( ") and timeout reached, error details: " ) + - cc.warning( err.toString() ) + "\n"; + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); errGathering = "Problem(4) in BLS sign result handler, not enough successful BLS signature parts(" + - cntSuccess + ") and timeout reached, error details: " + err.toString(); + cntSuccess + ") and timeout reached, error details: " + owaspUtils.extract_error_message( err ); reject( new Error( errGathering ) ); } ); bHaveResultReportCalled = true; @@ -1217,7 +1220,7 @@ async function do_sign_messages_impl( details.write( cc.success( "BLS verification and sending promise awaited." ) + "\n" ); log.write( cc.success( "BLS verification and sending promise awaited." ) + "\n" ); } ).catch( err => { - const strErrorMessage = cc.error( "Failed to verify BLS and send message : " ) + cc.warning( err.toString() ) + "\n"; + const strErrorMessage = cc.error( "Failed to verify BLS and send message : " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); } ); @@ -1229,14 +1232,14 @@ async function do_sign_messages_impl( bHaveResultReportCalled = true; await fn( "Failed to gather BLS signatures in " + jarrNodes.length + " node(s), trakcer data is: " + - JSON.stringify( joGatheringTracker ) + ", error: " + errGathering.toString(), + JSON.stringify( joGatheringTracker ) + ", error is: " + errGathering.toString(), jarrMessages, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(5) in BLS sign result handler, not enough successful BLS signature parts(" ) + cc.info( cntSuccess ) + cc.error( ") and timeout reached, error details: " ) + - cc.warning( err.toString() ) + "\n"; + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); details.exposeDetailsTo( log, strGatheredDetailsName, false ); @@ -1247,7 +1250,9 @@ async function do_sign_messages_impl( return; } if( ! bHaveResultReportCalled ) { - const strErrorMessage = cc.error( "Failed BLS sign result awaiting(2): " ) + cc.warning( err.toString() ) + "\n"; + const strErrorMessage = cc.error( "Failed BLS sign result awaiting(2): " ) + + cc.warning( "No reports were arrived" ) + // cc.warning( owaspUtils.extract_error_message( err ) ) + + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); bHaveResultReportCalled = true; @@ -1255,7 +1260,7 @@ async function do_sign_messages_impl( const strErrorMessage = cc.error( "Problem(6) in BLS sign result handler, not enough successful BLS signature parts(" ) + cc.info( cntSuccess ) + cc.error( ") and timeout reached, error details: " ) + - cc.warning( err ) + "\n"; + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); details.exposeDetailsTo( log, strGatheredDetailsName, false ); @@ -1264,14 +1269,15 @@ async function do_sign_messages_impl( } ); } } catch ( err ) { - const strErrorMessage = cc.error( "Failed BLS sign due to generic flow exception: " ) + cc.warning( err.toString() ) + "\n"; + const strErrorMessage = + cc.error( "Failed BLS sign due to generic flow exception: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); if( details ) details.write( strErrorMessage ); if( ! bHaveResultReportCalled ) { bHaveResultReportCalled = true; - await fn( "Failed BLS sign due to exception: " + err.toString(), jarrMessages, null ).catch( ( err ) => { - const strErrorMessage = cc.error( "Failed BLS sign due to error-erporting callback exception: " ) + cc.warning( err.toString() ) + "\n"; + await fn( "Failed BLS sign due to exception: " + owaspUtils.extract_error_message( err ), jarrMessages, null ).catch( ( err ) => { + const strErrorMessage = cc.error( "Failed BLS sign due to error-erporting callback exception: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); if( details ) { details.write( strErrorMessage ); @@ -1397,9 +1403,11 @@ async function do_sign_u256( u256, details, fn ) { const strErrorMessage = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed, RPC call was not created, error: " ) + cc.warning( err ) + "\n"; + cc.error( " failed, RPC call was not created, error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); + if( joCall ) + await joCall.disconnect(); return; } details.write( @@ -1409,7 +1417,7 @@ async function do_sign_u256( u256, details, fn ) { await joCall.call( { method: "skale_imaBSU256", params: { - valueToSign: u256 + valueToSign: u256 // must be 0x string, came from outside 0x string } }, async function( joIn, joOut, err ) { ++joGatheringTracker.nCountReceived; // including errors @@ -1418,9 +1426,10 @@ async function do_sign_u256( u256, details, fn ) { const strErrorMessage = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed, RPC call reported error: " ) + cc.warning( err ) + "\n"; + cc.error( " failed, RPC call reported error: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); + await joCall.disconnect(); return; } details.write( @@ -1430,21 +1439,15 @@ async function do_sign_u256( u256, details, fn ) { "\n" ); if( joOut.result == null || joOut.result == undefined || ( !typeof joOut.result == "object" ) ) { ++joGatheringTracker.nCountErrors; - if( "error" in joOut && "message" in joOut.error ) { - const strErrorMessage = - strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + - cc.error( "S-Chain node " ) + strNodeDescColorized + - cc.error( " reported wallet error: " ) + cc.warning( joOut.error.message ) + "\n"; - log.write( strErrorMessage ); - details.write( strErrorMessage ); - } else { - const strErrorMessage = - strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + - cc.error( "JSON RPC call to S-Chain node " ) + strNodeDescColorized + - cc.error( " failed with " ) + cc.warning( "unknown wallet error" ) + "\n"; - log.write( strErrorMessage ); - details.write( strErrorMessage ); - } + const strErrorMessage = + strLogPrefix + cc.fatal( "Wallet CRITICAL ERROR:" ) + " " + + cc.error( "S-Chain node " ) + strNodeDescColorized + + cc.error( " reported wallet error: " ) + + cc.warning( owaspUtils.extract_error_message( joOut, "unknown wallet error(2)" ) ) + + "\n"; + log.write( strErrorMessage ); + details.write( strErrorMessage ); + await joCall.disconnect(); return; } details.write( strLogPrefix + cc.normal( "Node " ) + cc.info( joNode.nodeID ) + cc.normal( " sign result: " ) + cc.j( joOut.result ? joOut.result : null ) + "\n" ); @@ -1488,7 +1491,7 @@ async function do_sign_u256( u256, details, fn ) { const strErrorMessage = strLogPrefixA + cc.error( "S-Chain node " ) + strNodeDescColorized + cc.error( " sign " ) + cc.error( " CRITICAL ERROR:" ) + cc.error( " partial signature fail from with index " ) + cc.info( nZeroBasedNodeIndex ) + - cc.error( ", error is " ) + cc.warning( err.toString() ) + "\n"; + cc.error( ", error is " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); } @@ -1513,14 +1516,15 @@ async function do_sign_u256( u256, details, fn ) { ++joGatheringTracker.nCountErrors; } } catch ( err ) { - ++nCountErrors; + ++joGatheringTracker.nCountErrors; const strErrorMessage = strLogPrefix + cc.error( "S-Chain node " ) + strNodeDescColorized + " " + cc.fatal( "CRITICAL ERROR:" ) + cc.error( " signature fail from node " ) + cc.info( joNode.nodeID ) + - cc.error( ", error is " ) + cc.warning( err.toString() ) + "\n"; + cc.error( ", error is " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); } + await joCall.disconnect(); } ); // joCall.call ... } ); // rpcCall.create ... } @@ -1529,7 +1533,7 @@ async function do_sign_u256( u256, details, fn ) { details.write( strLogPrefix + cc.debug( "Waiting for BLS glue result " ) + "\n" ); errGathering = null; const promise_gathering_complete = new Promise( ( resolve, reject ) => { - const iv = setInterval( async function() { + const iv = setInterval( function() { ++ joGatheringTracker.nWaitIntervalStepsDone; const cntSuccess = joGatheringTracker.nCountReceived - joGatheringTracker.nCountErrors; if( cntSuccess >= nCountOfBlsPartsToCollect ) { @@ -1546,7 +1550,7 @@ async function do_sign_u256( u256, details, fn ) { strSuccessfulResultDescription = "Got successful summary BLS u256 verification result"; details.write( strLogPrefixB + cc.success( strSuccessfulResultDescription ) + "\n" ); } else { - strError = "BLS verify failed"; + strError = "BLS verification failed"; log.write( strLogPrefixB + cc.fatal( "CRITICAL ERROR:" ) + cc.error( strError ) + "\n" ); details.write( strLogPrefixB + cc.fatal( "CRITICAL ERROR:" ) + cc.error( strError ) + "\n" ); } @@ -1560,11 +1564,11 @@ async function do_sign_u256( u256, details, fn ) { } log.write( cc.debug( "Will call sending function (fn)" ) + "\n" ); details.write( cc.debug( "Will call sending function (fn) for " ) + "\n" ); - await fn( strError, u256, joGlueResult ).catch( ( err ) => { - const strErrorMessage = cc.error( "Problem(2) in BLS u256 sign result handler: " ) + cc.warning( err.toString() ) + "\n"; + /*await*/ fn( strError, u256, joGlueResult ).catch( ( err ) => { + const strErrorMessage = cc.error( "Problem(2) in BLS u256 sign result handler: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); - errGathering = "Problem(2) in BLS u256 sign result handler: " + err.toString(); + errGathering = "Problem(2) in BLS u256 sign result handler: " + owaspUtils.extract_error_message( err ); } ); if( strError ) { errGathering = strError; @@ -1575,32 +1579,32 @@ async function do_sign_u256( u256, details, fn ) { } if( joGatheringTracker.nCountReceived >= jarrNodes.length ) { clearInterval( iv ); - await fn( "signature error(2, u256), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", u256, null ).catch( ( err ) => { + /*await*/ fn( "signature error(2, u256), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", u256, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(3) in BLS u256 sign result handler, not enough successful BLS signature parts(" ) + - cc.info( cntSuccess ) + cc.error( " when all attempts done, error details: " ) + cc.warning( err.toString() ) + + cc.info( cntSuccess ) + cc.error( " when all attempts done, error details: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); errGathering = "Problem(3) in BLS u256 sign result handler, not enough successful BLS signature parts(" + - cntSuccess + " when all attempts done, error details: " + err.toString(); + cntSuccess + " when all attempts done, error details: " + owaspUtils.extract_error_message( err ); reject( new Error( errGathering ) ); } ); return; } if( joGatheringTracker.nWaitIntervalStepsDone >= joGatheringTracker.nWaitIntervalMaxSteps ) { clearInterval( iv ); - await fn( "signature error(3, u256), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", u256, null ).catch( ( err ) => { + /*await*/ fn( "signature error(3, u256), got " + joGatheringTracker.nCountErrors + " errors(s) for " + jarrNodes.length + " node(s)", u256, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(4) in BLS u256 sign result handler, not enough successful BLS signature parts(" ) + cc.info( cntSuccess ) + cc.error( ") and timeout reached, error details: " ) + - cc.warning( err.toString() ) + "\n"; + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); errGathering = "Problem(4) in BLS u256 sign result handler, not enough successful BLS signature parts(" + - cntSuccess + ") and timeout reached, error details: " + err.toString(); + cntSuccess + ") and timeout reached, error details: " + owaspUtils.extract_error_message( err ); reject( new Error( errGathering ) ); } ); return; @@ -1613,7 +1617,7 @@ async function do_sign_u256( u256, details, fn ) { details.write( cc.info( "BLS u256 sign promise awaited." ) + "\n" ); log.write( cc.info( "BLS u256 sign promise awaited." ) + "\n" ); } ).catch( err => { - const strErrorMessage = cc.error( "Failed to verify BLS and send message : " ) + cc.warning( err.toString() ) + "\n"; + const strErrorMessage = cc.error( "Failed to verify BLS and send message : " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); details.write( strErrorMessage ); } ); diff --git a/agent/cli.js b/agent/cli.js index a8fb69514..9188a5173 100644 --- a/agent/cli.js +++ b/agent/cli.js @@ -110,22 +110,32 @@ function ensure_have_chain_credentials( strFriendlyChainName, joAccount, isExitI if( isExitIfEmpty ) process.exit( 126 ); } - if( "strTransactionManagerURL" in joAccount && typeof joAccount.strTransactionManagerURL == "string" && joAccount.strTransactionManagerURL.length > 0 ) + let cntAccountVariantsSpecified = 0; + if( "strTransactionManagerURL" in joAccount && typeof joAccount.strTransactionManagerURL == "string" && joAccount.strTransactionManagerURL.length > 0 ) { + ++ cntAccountVariantsSpecified; ensure_have_value( "" + strFriendlyChainName + "/TM/URL", joAccount.strTransactionManagerURL, isExitIfEmpty, isPrintValue ); - else if( "strSgxURL" in joAccount && typeof joAccount.strSgxURL == "string" && joAccount.strSgxURL.length > 0 && - "strSgxKeyName" in joAccount && typeof joAccount.strSgxKeyName == "string" && joAccount.strSgxKeyName.length > 0 - ) { + } + if( "strSgxURL" in joAccount && typeof joAccount.strSgxURL == "string" && joAccount.strSgxURL.length > 0 ) { + ++ cntAccountVariantsSpecified; ensure_have_value( "" + strFriendlyChainName + "/SGX/URL", joAccount.strSgxURL, isExitIfEmpty, isPrintValue ); - ensure_have_value( "" + strFriendlyChainName + "/SGX/keyName", joAccount.strSgxKeyName, isExitIfEmpty, isPrintValue ); if( "strPathSslKey" in joAccount && typeof joAccount.strPathSslKey == "string" && joAccount.strPathSslKey.length > 0 ) ensure_have_value( "" + strFriendlyChainName + "/SGX/SSL/keyPath", joAccount.strPathSslKey, isExitIfEmpty, isPrintValue ); if( "strPathSslCert" in joAccount && typeof joAccount.strPathSslCert == "string" && joAccount.strPathSslCert.length > 0 ) ensure_have_value( "" + strFriendlyChainName + "/SGX/SSL/certPath", joAccount.strPathSslCert, isExitIfEmpty, isPrintValue ); - } else if( "privateKey" in joAccount && typeof joAccount.privateKey == "string" && joAccount.privateKey.length > 0 ) + } + if( "strSgxKeyName" in joAccount && typeof joAccount.strSgxKeyName == "string" && joAccount.strSgxKeyName.length > 0 ) { + ++ cntAccountVariantsSpecified; + ensure_have_value( "" + strFriendlyChainName + "/SGX/keyName", joAccount.strSgxKeyName, isExitIfEmpty, isPrintValue ); + } + if( "privateKey" in joAccount && typeof joAccount.privateKey == "string" && joAccount.privateKey.length > 0 ) { + ++ cntAccountVariantsSpecified; ensure_have_value( "" + strFriendlyChainName + "/privateKey", joAccount.privateKey, isExitIfEmpty, isPrintValue ); - else if( "address_" in joAccount && typeof joAccount.address_ == "string" && joAccount.address_.length > 0 ) + } + if( "address_" in joAccount && typeof joAccount.address_ == "string" && joAccount.address_.length > 0 ) { + ++ cntAccountVariantsSpecified; ensure_have_value( "" + strFriendlyChainName + "/walletAddress", joAccount.address_, isExitIfEmpty, isPrintValue ); - else { + } + if( cntAccountVariantsSpecified == 0 ) { log.write( cc.error( "ARGUMENTS VALIDATION WARNING:" ) + cc.warning( " bad credentials information specified for " ) + cc.info( strFriendlyChainName ) + cc.warning( " chain, no explicit SGX, no explicit private key, no wallet address found" ) + "\n" @@ -390,7 +400,7 @@ function parse( joExternalHandlers, argv ) { console.log( soi + cc.debug( "--" ) + cc.bright( "bls-verify" ) + cc.sunny( "=" ) + cc.note( "path" ) + cc.debug( "..............." ) + cc.debug( "Optional parameter, specifies path to " ) + cc.note( "verify_bls" ) + cc.debug( " application." ) ); // console.log( cc.sunny( "MONITORING" ) + cc.info( " options:" ) ); - console.log( soi + cc.debug( "--" ) + cc.bright( "monitoring-port" ) + cc.sunny( "=" ) + cc.note( "number" ) + cc.debug( "........" ) + cc.notice( "Run " ) + cc.note( "monitoring web socket RPC server" ) + cc.notice( " on specified port. " ) + cc.debug( "By default monitoring server is " ) + cc.error( "disabled" ) + cc.notice( "." ) ); + console.log( soi + cc.debug( "--" ) + cc.bright( "monitoring-port" ) + cc.sunny( "=" ) + cc.note( "number" ) + cc.debug( "........" ) + cc.notice( "Run " ) + cc.note( "monitoring web socket RPC server" ) + cc.notice( " on specified port. " ) + cc.debug( "Specify " ) + cc.sunny( "0" ) + cc.debug( " to " ) + cc.error( "disable" ) + cc.notice( "." ) + cc.debug( " By default monitoring server is " ) + cc.error( "disabled" ) + cc.notice( "." ) ); // console.log( cc.sunny( "GAS REIMBURSEMENT" ) + cc.info( " options:" ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "reimbursement-chain" ) + cc.sunny( "=" ) + cc.note( "name" ) + cc.debug( "......" ) + cc.notice( "Specifies chain name." ) ); @@ -482,6 +492,11 @@ function parse( joExternalHandlers, argv ) { imaState.strChainName_s_chain = joArg.value; continue; } + if( joArg.name == "id-origin-chain" ) { + owaspUtils.verifyArgumentWithNonEmptyValue( joArg ); + imaState.strChainName_origin_chain = joArg.value; + continue; + } if( joArg.name == "id-t-chain" ) { owaspUtils.verifyArgumentWithNonEmptyValue( joArg ); imaState.strChainName_t_chain = joArg.value; @@ -1130,7 +1145,7 @@ function parse( joExternalHandlers, argv ) { continue; } if( joArg.name == "monitoring-port" ) { - owaspUtils.verifyArgumentIsIntegerIpPortNumber( joArg ); + owaspUtils.verifyArgumentIsIntegerIpPortNumber( joArg, true ); imaState.nMonitoringPort = owaspUtils.toInteger( joArg.value ); continue; } @@ -1230,8 +1245,9 @@ function parse( joExternalHandlers, argv ) { return 0; } -function getWeb3FromURL( strURL ) { +function getWeb3FromURL( strURL, log ) { let w3 = null; + log = log || { write: console.log }; try { const u = cc.safeURL( strURL ); const strProtocol = u.protocol.trim().toLowerCase().replace( ":", "" ).replace( "/", "" ); @@ -1261,7 +1277,7 @@ function getWeb3FromURL( strURL ) { } catch ( err ) { log.write( cc.fatal( "CRITICAL ERROR:" ) + cc.error( " Failed to create " ) + cc.attention( "Web3" ) + cc.error( " connection to " ) + cc.info( strURL ) + - cc.error( ": " ) + cc.warning( err.toString() ) + "\n" ); + cc.error( ": " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); w3 = null; } return w3; @@ -1282,7 +1298,7 @@ async function async_check_url_at_startup( u, name ) { } catch ( err ) { details.write( cc.fatal( "ERROR:" ) + cc.error( " Failed to check URL " ) + - cc.u( u ) + cc.error( " connectivity for " ) + cc.info( name ) + cc.error( " at start-up, error is: " ) + cc.warning( err.toString() ) + + cc.u( u ) + cc.error( " connectivity for " ) + cc.info( name ) + cc.error( " at start-up, error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } // details.exposeDetailsTo( log, "async_check_url_at_startup( \"" + u + "\", \"" + name + "\" )", true ); @@ -1483,7 +1499,7 @@ function ima_common_init() { if( imaState.strURL_main_net && typeof imaState.strURL_main_net == "string" && imaState.strURL_main_net.length > 0 ) { const u = imaState.strURL_main_net; async_check_url_at_startup( u, "Main-net" ); - imaState.w3_main_net = getWeb3FromURL( u ); + imaState.w3_main_net = getWeb3FromURL( u, log ); } else { log.write( cc.error( "WARNING:" ) + cc.warning( " No " ) + cc.note( "Main-net" ) + @@ -1495,7 +1511,7 @@ function ima_common_init() { if( imaState.strURL_s_chain && typeof imaState.strURL_s_chain == "string" && imaState.strURL_s_chain.length > 0 ) { const u = imaState.strURL_s_chain; async_check_url_at_startup( u, "S-Chain" ); - imaState.w3_s_chain = getWeb3FromURL( u ); + imaState.w3_s_chain = getWeb3FromURL( u, log ); } else { log.write( cc.error( "WARNING:" ) + cc.warning( " No " ) + cc.note( "S-Chain" ) + @@ -1507,7 +1523,7 @@ function ima_common_init() { if( imaState.strURL_t_chain && typeof imaState.strURL_t_chain == "string" && imaState.strURL_t_chain.length > 0 ) { const u = imaState.strURL_t_chain; async_check_url_at_startup( u, "S<->S Target S-Chain" ); - imaState.w3_t_chain = getWeb3FromURL( u ); + imaState.w3_t_chain = getWeb3FromURL( u, log ); } else { log.write( cc.error( "WARNING:" ) + cc.warning( " No " ) + cc.note( "S<->S Target S-Chain" ) + diff --git a/agent/main.js b/agent/main.js index d1f9bc425..63b93918b 100644 --- a/agent/main.js +++ b/agent/main.js @@ -320,21 +320,24 @@ const fnInitActionSkaleNetworkScanForS2S = function() { "secondsToReDiscoverSkaleNetwork": imaState.s2s_opts.secondsToReDiscoverSkaleNetwork }; const addressFrom = imaState.joAccount_main_net.address( imaState.w3_main_net ); - const strError = await skale_observer.cache_schains( - imaState.strChainName_s_chain, // strChainNameConnectedTo - imaState.w3_main_net, - addressFrom, - opts - ); - if( strError ) { - log.write( strLogPrefix + cc.error( "Failed to get " ) + cc.info( "SKALE NETWORK" ) + cc.error( " information: " ) + cc.warning( strError ) + "\n" ); - return true; - } - const arr_schains = skale_observer.get_last_cached_schains(); - log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( "SKALE NETWORK" ) + cc.normal( " information: " ) + cc.j( arr_schains ) + "\n" ); + // const strError = await skale_observer.cache_schains( + // imaState.strChainName_s_chain, // strChainNameConnectedTo + // imaState.w3_main_net, + // imaState.w3_s_chain, + // addressFrom, + // opts + // ); + // if( strError ) { + // log.write( strLogPrefix + cc.error( "Failed to get " ) + cc.info( "SKALE NETWORK" ) + cc.error( " information: " ) + cc.warning( strError ) + "\n" ); + // return true; + // } + // const arr_schains = skale_observer.get_last_cached_schains(); + // log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( "SKALE NETWORK" ) + cc.normal( " information: " ) + cc.j( arr_schains ) + "\n" ); + log.write( strLogPrefix + cc.debug( "Will start periodic S-Chains caching..." ) + "\n" ); await skale_observer.periodic_caching_start( imaState.strChainName_s_chain, // strChainNameConnectedTo imaState.w3_main_net, + imaState.w3_s_chain, addressFrom, opts ); @@ -1385,6 +1388,8 @@ imaCLI.parse( { await rpcCall.create( imaState.strURL_s_chain, rpcCallOpts, async function( joCall, err ) { if( err ) { console.log( cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain failed" ) ); + if( joCall ) + await joCall.disconnect(); process.exit( 156 ); } await joCall.call( { @@ -1395,6 +1400,7 @@ imaCLI.parse( { }, async function( joIn, joOut, err ) { if( err ) { console.log( cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain failed, error: " ) + cc.warning( err ) ); + await joCall.disconnect(); process.exit( 157 ); } log.write( strLogPrefix + cc.normal( "S-Chain network information: " ) + cc.j( joOut.result ) + "\n" ); @@ -1413,6 +1419,7 @@ imaCLI.parse( { await rpcCall.create( strNodeURL, rpcCallOpts, async function( joCall, err ) { if( err ) { console.log( cc.fatal( "CRITICAL ERROR:" ) + cc.error( " JSON RPC call to S-Chain failed" ) ); + await joCall.disconnect(); process.exit( 158 ); } await joCall.call( { @@ -1428,6 +1435,7 @@ imaCLI.parse( { } log.write( strLogPrefix + cc.normal( "Node " ) + cc.info( joNode.nodeID ) + cc.normal( " IMA information: " ) + cc.j( joOut.result ) + "\n" ); //process.exit( 0 ); + await joCall.disconnect(); } ); } ); } @@ -1438,6 +1446,7 @@ imaCLI.parse( { process.exit( 0 ); } }, 100 ); + await joCall.disconnect(); } ); } ); return true; @@ -1462,7 +1471,8 @@ imaCLI.parse( { }; const addressFrom = imaState.joAccount_main_net.address( imaState.w3_main_net ); const arr_schains = await skale_observer.load_schains( imaState.w3_main_net, addressFrom, opts ); - log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( "SKALE NETWORK" ) + cc.normal( " information: " ) + cc.j( arr_schains ) + "\n" ); + const cnt = arr_schains.length; + log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( cnt ) + cc.normal( " S-Chains(s) in SKALE NETWORK information: " ) + cc.j( arr_schains ) + "\n" ); return true; } } ); @@ -1485,18 +1495,17 @@ imaCLI.parse( { "bStopNeeded": false }; const addressFrom = imaState.joAccount_main_net.address( imaState.w3_main_net ); - const arr_schains = await skale_observer.load_schains( imaState.w3_main_net, addressFrom, opts ); - await skale_observer.check_connected_schains( + + const arr_schains_cached = await skale_observer.load_schains_connected_only( + imaState.w3_main_net, + imaState.w3_s_chain, imaState.strChainName_s_chain, // strChainNameConnectedTo - arr_schains, addressFrom, opts ); - const arr_schains_cached = await skale_observer.filter_schains_marked_as_connected( - arr_schains, - opts - ); - log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( "connected S-Chains" ) + cc.normal( " information: " ) + cc.j( arr_schains_cached ) + "\n" ); + + const cnt = arr_schains_cached.length; + log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( cnt ) + cc.normal( " onnected S-Chain(s): " ) + cc.j( arr_schains_cached ) + "\n" ); return true; } } ); @@ -1751,8 +1760,11 @@ async function continue_schain_discovery_in_background_if_needed( isSilent ) { return; if( imaState.joSChainDiscovery.repeatIntervalMilliseconds <= 0 ) return; // no S-Chain re-discovery (for debugging only) - g_timer_s_chain_discovery = setInterval( async function() { + const fn_async_handler = async function() { + if( g_b_in_s_chain_discovery ) + return; if( g_b_in_s_chain_discovery ) { + isInsideAsyncHandler = false; if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) log.write( cc.warning( "Notice: long S-Chain discovery is in progress" ) + "\n" ); return; @@ -1819,6 +1831,11 @@ async function continue_schain_discovery_in_background_if_needed( isSilent ) { } ); } catch ( err ) { } g_b_in_s_chain_discovery = false; + }; + g_timer_s_chain_discovery = setInterval( function() { + if( g_b_in_s_chain_discovery ) + return; + fn_async_handler(); }, imaState.joSChainDiscovery.repeatIntervalMilliseconds ); } @@ -1842,6 +1859,8 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI ); } fnAfter( err, null ); + if( joCall ) + await joCall.disconnect(); return; } await joCall.call( { @@ -1859,6 +1878,7 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI ); } fnAfter( err, null ); + await joCall.disconnect(); return; } if( ( !isSilent ) && IMA.verbose_get() >= IMA.RV_VERBOSE.trace ) @@ -1877,6 +1897,7 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI ); } fnAfter( err2, null ); + await joCall.disconnect(); return; } const jarrNodes = joSChainNetworkInfo.network; @@ -1932,6 +1953,8 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI } // fnAfter( err, null ); ++ cntFailed; + if( joCall ) + await joCall.disconnect(); return; } joCall.call( { @@ -2062,6 +2085,7 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI ); } }, nWaitStepMilliseconds ); + await joCall.disconnect(); } ); } ); } catch ( err ) { @@ -2084,7 +2108,7 @@ async function discover_s_chain_network( fnAfter, isSilent, joPrevSChainNetworkI let g_ws_server_monitoring = null; if( imaState.nMonitoringPort > 0 ) { - const strLogPrefix = cc.attention( "Monitoring" ) + " " + cc.sunny( ">>" ) + " "; + const strLogPrefix = cc.attention( "Monitoring:" ) + " "; if( IMA.verbose_get() >= IMA.RV_VERBOSE.trace ) log.write( strLogPrefix + cc.normal( "Will start monitoring WS server on port " ) + cc.info( imaState.nMonitoringPort ) + "\n" ); g_ws_server_monitoring = new ws.Server( { port: 0 + imaState.nMonitoringPort } ); @@ -2101,7 +2125,7 @@ if( imaState.nMonitoringPort > 0 ) { try { const joMessage = JSON.parse( message ); if( IMA.verbose_get() >= IMA.RV_VERBOSE.trace ) - log.write( strLogPrefix + cc.normal( "Message from " ) + cc.info( ip ) + cc.normal( ": " ) + cc.j( joMessage ) + "\n" ); + log.write( strLogPrefix + cc.sunny( "<<<" ) + " " + cc.normal( "message from " ) + cc.info( ip ) + cc.normal( ": " ) + cc.j( joMessage ) + "\n" ); if( ! ( "method" in joMessage ) ) throw new Error( "\"method\" field was not specified" ); joAnswer.method = joMessage.method; @@ -2175,8 +2199,8 @@ if( imaState.nMonitoringPort > 0 ) { } break; case "get_last_transfer_errors": // call: { "id": 1, "method": "get_last_transfer_errors" } - // answer: { "id": 1, "method": "get_last_transfer_errors", "error": null, "last_transfer_errors": [ { ts: ..., textLog: ... }, ... ] } - joAnswer.last_transfer_errors = IMA.get_last_transfer_errors(); + // answer: { "id": 1, "method": "get_last_transfer_errors", "isIncludeTextLog": true, "error": null, "last_transfer_errors": [ { ts: ..., textLog: ... }, ... ] } + joAnswer.last_transfer_errors = IMA.get_last_transfer_errors( ( ( "isIncludeTextLog" in joMessage ) && joMessage.isIncludeTextLog ) ? true : false ); joAnswer.last_error_categories = IMA.get_last_error_categories(); break; default: @@ -2192,7 +2216,7 @@ if( imaState.nMonitoringPort > 0 ) { } try { if( IMA.verbose_get() >= IMA.RV_VERBOSE.trace ) - log.write( strLogPrefix + cc.normal( "Answer to " ) + cc.info( ip ) + cc.normal( ": " ) + cc.j( joAnswer ) + "\n" ); + log.write( strLogPrefix + cc.sunny( ">>>" ) + " " + cc.normal( "answer to " ) + cc.info( ip ) + cc.normal( ": " ) + cc.j( joAnswer ) + "\n" ); ws_peer.send( JSON.stringify( joAnswer ) ); } catch ( err ) { if( IMA.verbose_get() >= IMA.RV_VERBOSE.error ) { diff --git a/agent/package.json b/agent/package.json index a6ce83b34..401151436 100644 --- a/agent/package.json +++ b/agent/package.json @@ -7,12 +7,14 @@ "postinstall": "echo \"----- installing in OWASP\n\" && cd ../npms/skale-owasp && yarn install && cd ../../agent && echo \"----- installing in IMA CORE\n\" && cd ../npms/skale-ima && yarn install && cd ../../agent && echo \"----- installing in IMA OBSERVER\n\" && cd ../npms/skale-observer && yarn install && cd ../../agent" }, "dependencies": { + "js-sha3": "^0.8.0", + "number-to-bn": "^1.7.0", "ethereumjs-tx": "2.1.2", "ethereumjs-wallet": "^1.0.2", - "ethereumjs-util": "^7.1.3", + "ethereumjs-util": "^7.1.4", "web3": "^1.6.1", "uuid": "8.3.2", - "ws": "^8.4.0", + "ws": "^8.6.0", "urllib": "2.38.0", "sha3": "2.1.4", "shelljs": "^0.8.5" diff --git a/agent/rpc-call.js b/agent/rpc-call.js index f6bcfe98d..dd1aa81d1 100644 --- a/agent/rpc-call.js +++ b/agent/rpc-call.js @@ -29,9 +29,17 @@ const net = require( "net" ); const g_nConnectionTimeoutSeconds = 60; +function rpc_call_init() { + owaspUtils.owaspAddUsageRef(); +} + +function validateURL( x ) { + return owaspUtils.validateURL( x ); +} + function is_http_url( strURL ) { try { - if( !owaspUtils.validateURL( strURL ) ) + if( !validateURL( strURL ) ) return false; const u = new URL( strURL ); if( u.protocol == "http:" || u.protocol == "https:" ) @@ -43,7 +51,7 @@ function is_http_url( strURL ) { function is_ws_url( strURL ) { try { - if( !owaspUtils.validateURL( strURL ) ) + if( !validateURL( strURL ) ) return false; const u = new URL( strURL ); if( u.protocol == "ws:" || u.protocol == "wss:" ) @@ -53,16 +61,17 @@ function is_ws_url( strURL ) { return false; } -function rpc_call_init() { - owaspUtils.owaspAddUsageRef(); -} - async function wait_web_socket_is_open( socket, fnDone, fnStep ) { fnDone = fnDone || async function( nStep ) {}; fnDone = fnStep || async function( nStep ) { return true; }; - const nStep = 0; + let nStep = 0; const promiseComplete = new Promise( function( resolve, reject ) { - const iv = setInterval( async function() { + let isInsideAsyncHandler = false; + const fn_async_handler = async function() { + if( isInsideAsyncHandler ) + return; + isInsideAsyncHandler = true; + ++ nStep; if( socket.readyState === 1 ) { // console.log( "Connection is made" ) clearInterval( iv ); @@ -74,6 +83,15 @@ async function wait_web_socket_is_open( socket, fnDone, fnStep ) { reject( new Error( "web socket wait timout by callback on step " + nStep ) ); } } + isInsideAsyncHandler = false; + }; + const iv = setInterval( function() { + if( isInsideAsyncHandler ) + return; + fn_async_handler() + .then( () => { + } ).catch( () => { + } ); }, 1000 ); // 1 second } ); await Promise.all( [ promiseComplete ] ); @@ -82,7 +100,7 @@ async function wait_web_socket_is_open( socket, fnDone, fnStep ) { async function do_connect( joCall, opts, fn ) { try { fn = fn || async function() {}; - if( !owaspUtils.validateURL( joCall.url ) ) + if( !validateURL( joCall.url ) ) throw new Error( "JSON RPC CALLER cannot connect web socket to invalid URL: " + joCall.url ); if( is_ws_url( joCall.url ) ) { let strWsError = null; @@ -92,15 +110,23 @@ async function do_connect( joCall, opts, fn ) { } ); joCall.wsConn.on( "close", async function() { strWsError = "web socket was closed, please check provided URL is valid and accessible"; - joCall.wsConn = 0; + joCall.wsConn = null; } ); joCall.wsConn.on( "error", async function( err ) { strWsError = err.toString() || "internal web socket error"; log.write( cc.u( joCall.url ) + cc.error( " web socket error: " ) + cc.warning( err.toString() ) + "\n" ); + const wsConn = joCall.wsConn; + joCall.wsConn = null; + wsConn.close(); + do_reconnect_ws_step( joCall, opts ); } ); joCall.wsConn.on( "fail", async function( err ) { strWsError = err.toString() || "internal web socket failure"; log.write( cc.u( joCall.url ) + cc.error( " web socket fail: " ) + cc.warning( err.toString() ) + "\n" ); + const wsConn = joCall.wsConn; + joCall.wsConn = null; + wsConn.close(); + do_reconnect_ws_step( joCall, opts ); } ); joCall.wsConn.on( "message", async function incoming( data ) { // log.write( cc.info( "WS message " ) + cc.attention( data ) + "\n" ); @@ -108,6 +134,10 @@ async function do_connect( joCall, opts, fn ) { if( joOut.id in joCall.mapPendingByCallID ) { const entry = joCall.mapPendingByCallID[joOut.id]; delete joCall.mapPendingByCallID[joOut.id]; + if( entry.iv ) { + clearTimeout( entry.iv ); + entry.iv = null; + } clearTimeout( entry.out ); await entry.fn( entry.joIn, joOut, null ); } @@ -123,6 +153,10 @@ async function do_connect( joCall, opts, fn ) { if( nStep >= g_nConnectionTimeoutSeconds ) { strWsError = "wait timeout, web socket is connecting too long"; log.write( cc.u( joCall.url ) + cc.error( " web socket wait timeout detected" ) + "\n" ); + const wsConn = joCall.wsConn; + joCall.wsConn = null; + wsConn.close(); + do_reconnect_ws_step( joCall, opts ); return false; // stop waiting } return true; // continue waiting @@ -138,12 +172,13 @@ async function do_connect( joCall, opts, fn ) { joCall.wsConn = null; await fn( joCall, err ); } + return joCall; } async function do_connect_if_needed( joCall, opts, fn ) { try { fn = fn || async function() {}; - if( !owaspUtils.validateURL( joCall.url ) ) + if( !validateURL( joCall.url ) ) throw new Error( "JSON RPC CALLER cannot connect web socket to invalid URL: " + joCall.url ); if( is_ws_url( joCall.url ) && ( !joCall.wsConn ) ) { await joCall.reconnect( fn ); @@ -153,9 +188,43 @@ async function do_connect_if_needed( joCall, opts, fn ) { } catch ( err ) { await fn( joCall, err ); } + return joCall; } -const impl_sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; +async function do_reconnect_ws_step( joCall, opts, fn ) { + if( ! joCall.isAutoReconnect ) + return; + if( joCall.isDisconnectMode ) + return; + fn = fn || async function() {}; + do_connect( joCall, opts, async function( joCall, err ) { + if( err ) { + do_reconnect_ws_step( joCall, opts ); + return; + } + await fn( joCall, null ); + } ); +} + +async function do_disconnect( joCall, fn ) { + fn = fn || async function() {}; + try { + joCall.isDisconnectMode = true; + const wsConn = joCall.wsConn ? joCall.wsConn : null; + joCall.wsConn = null; + if( wsConn ) + wsConn.close(); + joCall.isDisconnectMode = false; + try { + await fn( joCall, null ); + } catch ( err ) { + } + } catch ( err ) { + await await fn( joCall, err ); + } +} + +const do_sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; async function do_call( joCall, joIn, fn ) { // console.log( "--- --- --- initial joIn is", joIn ); @@ -169,13 +238,15 @@ async function do_call( joCall, joIn, fn ) { out: null }; joCall.mapPendingByCallID[joIn.id] = entry; - entry.out = setTimeout( function() { + entry.iv = setTimeout( function() { + clearTimeout( entry.iv ); + entry.iv = null; delete joCall.mapPendingByCallID[joIn.id]; - }, 20 * 1000 ); + }, 200 * 1000 ); joCall.wsConn.send( JSON.stringify( joIn ) ); } else { // console.log( "--- --- --- call URL is", joCall.url ); - if( !owaspUtils.validateURL( joCall.url ) ) { + if( !validateURL( joCall.url ) ) { // throw new Error( "JSON RPC CALLER cannot do query post to invalid URL: " + joCall.url ); await fn( joIn, null, "JSON RPC CALLER cannot do query post to invalid URL: " + joCall.url ); return; @@ -223,17 +294,17 @@ async function do_call( joCall, joIn, fn ) { } ); for( let idxWait = 0; ! bCompleteFlag; ++ idxWait ) { if( idxWait < 50 ) - await impl_sleep( 5 ); + await do_sleep( 5 ); else if( idxWait < 100 ) - await impl_sleep( 10 ); + await do_sleep( 10 ); else if( idxWait < 1000 ) - await impl_sleep( 100 ); + await do_sleep( 100 ); else { const nLastWaitPeriod = 200; if( ( idxWait - 1000 ) * nLastWaitPeriod > g_nConnectionTimeoutSeconds ) bCompleteFlag = true; else - await impl_sleep( nLastWaitPeriod ); + await do_sleep( nLastWaitPeriod ); } } // for( let idxWait = 0; ! bCompleteFlag; ++ idxWait ) try { @@ -244,7 +315,7 @@ async function do_call( joCall, joIn, fn ) { } async function rpc_call_create( strURL, opts, fn ) { - if( !owaspUtils.validateURL( strURL ) ) + if( !validateURL( strURL ) ) throw new Error( "JSON RPC CALLER cannot create a call object invalid URL: " + strURL ); fn = fn || async function() {}; if( !( strURL && typeof strURL == "string" && strURL.length > 0 ) ) @@ -254,6 +325,8 @@ async function rpc_call_create( strURL, opts, fn ) { "joRpcOptions": opts ? opts : null, "mapPendingByCallID": { }, "wsConn": null, + "isAutoReconnect": ( opts && "isAutoReconnect" in opts && opts.isAutoReconnect ) ? true : false, + "isDisconnectMode": false, "reconnect": async function( fnAfter ) { await do_connect( joCall, fnAfter ); }, @@ -269,9 +342,13 @@ async function rpc_call_create( strURL, opts, fn ) { } await do_call( joCall, joIn, fnAfter ); } ); + }, + "disconnect": async function( fnAfter ) { + await do_disconnect( joCall, fnAfter ); } }; await do_connect( joCall, opts, fn ); + return joCall; } function generate_random_integer_in_range( min, max ) { @@ -426,5 +503,6 @@ module.exports = { get_valid_host_and_port: get_valid_host_and_port, check_tcp_promise: check_tcp_promise, check_tcp: check_tcp, - check_url: check_url + check_url: check_url, + sleep: do_sleep }; // module.exports diff --git a/agent/run.sh b/agent/run.sh index 77646efc8..205af234d 100644 --- a/agent/run.sh +++ b/agent/run.sh @@ -78,7 +78,6 @@ BASE_OPTIONS="--gas-price-multiplier=$GAS_PRICE_MULTIPLIER \ --cid-s-chain=$CID_SCHAIN \ --abi-main-net=$MAINNET_PROXY_PATH \ --abi-s-chain=$SCHAIN_PROXY_PATH \ ---state-file=$STATE_FILE \ --sgx-url-s-chain=$SGX_URL \ --sgx-ecdsa-key-s-chain=$ECDSA_KEY_NAME \ --sgx-ssl-key-s-chain=$SGX_SSL_KEY_PATH \ @@ -86,7 +85,9 @@ BASE_OPTIONS="--gas-price-multiplier=$GAS_PRICE_MULTIPLIER \ --address-main-net=$NODE_ADDRESS \ --address-s-chain=$NODE_ADDRESS \ --sign-messages \ +--gathered \ --expose \ +--no-expose-security-info \ --skip-dry-run \ --bls-glue=/ima/bls_binaries/bls_glue \ --hash-g1=/ima/bls_binaries/hash_g1 \ diff --git a/agent/yarn.lock b/agent/yarn.lock index 0e786c078..6fcdc58d7 100644 --- a/agent/yarn.lock +++ b/agent/yarn.lock @@ -233,11 +233,23 @@ dependencies: "@types/node" "*" +"@types/connect@^3.4.33": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/node@*": version "16.10.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.1.tgz#f3647623199ca920960006b3dccf633ea905f243" integrity sha512-4/Z9DMPKFexZj/Gn3LylFgamNKHm4K3QDi0gz9B26Uk0c8izYf97B5fxfpspMNkWlFupblKM/nV8+NA9Ffvr+w== +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + "@types/node@^12.12.6": version "12.20.27" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.27.tgz#4141fcad57c332a120591de883e26fe4bb14aaea" @@ -257,6 +269,21 @@ dependencies: "@types/node" "*" +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -270,6 +297,14 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + acorn-walk@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" @@ -471,6 +506,24 @@ body-parser@1.19.0, body-parser@^1.16.0: raw-body "2.4.0" type-is "~1.6.17" +body-parser@1.20.1, body-parser@^1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -671,6 +724,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -688,6 +746,13 @@ content-disposition@0.5.3: dependencies: safe-buffer "5.1.2" +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + content-hash@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" @@ -712,6 +777,11 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -888,6 +958,11 @@ degenerator@^3.0.1: esprima "^4.0.0" vm2 "^3.9.3" +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -898,6 +973,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -911,6 +991,11 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + destroy@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.1.0.tgz#b77ae22e472d85437141319d32ae40b344dff38a" @@ -1041,6 +1126,18 @@ es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -1192,6 +1289,17 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3: ethereum-cryptography "^0.1.3" rlp "^2.2.4" +ethereumjs-util@^7.1.4: + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + ethereumjs-wallet@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" @@ -1276,6 +1384,43 @@ express@^4.14.0: utils-merge "1.0.1" vary "~1.1.2" +express@^4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + ext@^1.1.2: version "1.6.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" @@ -1305,6 +1450,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1325,6 +1475,19 @@ file-uri-to-path@2: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1672,6 +1835,17 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" @@ -1955,6 +2129,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1968,6 +2147,24 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" +jayson@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.0.0.tgz#145a0ced46f900934c9b307e1332bcb0c7dbdb17" + integrity sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + JSONStream "^1.3.5" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.4.5" + js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -1998,7 +2195,7 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -2010,6 +2207,11 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2098,6 +2300,11 @@ mime-db@1.49.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.32" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" @@ -2105,6 +2312,13 @@ mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.49.0" +mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -2203,7 +2417,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2281,6 +2495,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + netmask@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" @@ -2396,10 +2615,10 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -number-to-bn@1.7.0: +number-to-bn@1.7.0, number-to-bn@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== dependencies: bn.js "4.11.6" strip-hex-prefix "1.0.0" @@ -2441,6 +2660,13 @@ oboe@2.1.5: dependencies: http-https "^1.0.0" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -2635,7 +2861,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -proxy-addr@~2.0.5: +proxy-addr@~2.0.5, proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== @@ -2697,6 +2923,13 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -2753,6 +2986,16 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + raw-body@^2.2.0: version "2.4.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" @@ -2880,7 +3123,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -2943,6 +3186,25 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -2953,6 +3215,16 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + servify@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" @@ -3088,6 +3360,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + "statuses@>= 1.5.0 < 2", statuses@^1.3.1, statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -3229,10 +3506,10 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through@~2.3: +"through@>=2.2.7 <3", through@~2.3: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" @@ -3792,10 +4069,15 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6" - integrity sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ== +ws@^7.4.5: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +ws@^8.6.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" + integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg== xhr-request-promise@^0.1.2: version "0.1.3" diff --git a/npms/skale-cc/cc.js b/npms/skale-cc/cc.js index 10f5dc410..0c86e20a2 100644 --- a/npms/skale-cc/cc.js +++ b/npms/skale-cc/cc.js @@ -31,6 +31,63 @@ function replaceAll( str, find, replace ) { return str.replace( new RegExp( find, "g" ), replace ); } +function validateRadix( value, radix ) { + value = "" + ( value ? value.toString() : "10" ); + value = value.trim(); + radix = ( radix == null || radix == undefined ) + ? ( ( value.length > 2 && value[0] == "0" && ( value[1] == "x" || value[1] == "X" ) ) ? 16 : 10 ) + : parseInt( radix, 10 ); + return radix; +} + +function validateInteger( value, radix ) { + try { + value = "" + value; + value = value.trim(); + if( value.length < 1 ) + return false; + radix = validateRadix( value, radix ); + if( ( !isNaN( value ) ) && + ( parseInt( Number( value ), radix ) == value || radix !== 10 ) && + ( !isNaN( parseInt( value, radix ) ) ) + ) + return true; + } catch ( err ) { + } + return false; +} + +function toInteger( value, radix ) { + try { + radix = validateRadix( value, radix ); + if( !validateInteger( value, radix ) ) + return NaN; + return parseInt( value, radix ); + } catch ( err ) { + } + return false; +} + +function validateFloat( value ) { + try { + const f = parseFloat( value ); + if( isNaN( f ) ) + return false; + return true; + } catch ( err ) { + } + return false; +} + +function toFloat( value ) { + try { + const f = parseFloat( value ); + return f; + } catch ( err ) { + } + return false; +} + function toBoolean( value ) { let b = false; try { diff --git a/npms/skale-cool-socket/.eslintrc.js b/npms/skale-cool-socket/.eslintrc.js new file mode 100644 index 000000000..a2a8d690f --- /dev/null +++ b/npms/skale-cool-socket/.eslintrc.js @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file .eslintrc.js + * @copyright SKALE Labs 2019-Present + */ + +module.exports = { + "env": { + "browser": true, + "es6": true + }, + "extends": "standard", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "indent": [ "error", 4 ], + "linebreak-style": [ "error", "unix" ], + "quotes": [ "error", "double" ], + "semi": [ "error", "always" ], + "camelcase": "off", + // "no-unused-vars": "off", + "eqeqeq": "off", + "comma-dangle": [ "error", "never" ], + "comma-style": [ "error", "last" ], + "comma-spacing": "off", + "space-before-function-paren": [ "error", "never" ], + "space-in-parens": [ "error", "always" ], + "keyword-spacing": [ "error", { + "overrides": { + "if": { + "before": false, + "after": false + }, + "else": { + "before": true, + "after": true + }, + "for": { + "before": false, + "after": false + }, + "while": { + "before": false, + "after": false + } + } + } ], + "space-before-blocks": [ "error", "always" ], + "array-bracket-spacing": [ "error", "always" ], + "object-curly-spacing": [ "error", "always" ], + "space-unary-ops": "off", + "spaced-comment": "off", + "curly": [ "error", "multi-or-nest" ], + "nonblock-statement-body-position": [ "error", "below" ], + "one-var": "off", + "no-unneeded-ternary": "off", + "no-cond-assign": [ "error", "always" ], + "no-console": "off", + "new-cap": "off", + "no-tabs": "off", + "no-mixed-spaces-and-tabs": "off", + "no-prototype-builtins": "off", + "quote-props": "off", + "no-undef": "off", + "no-useless-return": "off", + "no-new": "off", + "no-useless-constructor": "off", + "no-lone-blocks": "off", + "no-fallthrough": "off", + "no-useless-catch": "off", + "padded-blocks": "off", + "no-use-before-define": "off", // [ "error", { "variables": false, "functions": false } ], + "lines-between-class-members": [ "error", "never" ], + "no-var": "error", + "no-unused-vars": "error" + } +}; diff --git a/npms/skale-cool-socket/event_dispatcher.js b/npms/skale-cool-socket/event_dispatcher.js new file mode 100644 index 000000000..43e9e5f30 --- /dev/null +++ b/npms/skale-cool-socket/event_dispatcher.js @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file event_dispatcher.js + * @copyright SKALE Labs 2019-Present + */ + +class UniversalDispatcherEvent { + constructor( type, jo ) { + this.type = type; + for( const [ key, value ] of Object.entries( jo ) ) { + if( key in this ) { + console.warn( "UniversalDispatcherEvent will skip", key, "data field" ); + continue; + } + this[key] = value; + } + } +}; + +class EventDispatcher { + // see https://stackoverflow.com/questions/36675693/eventtarget-interface-in-safari + constructor() { + this._listeners = []; + this.isDisposed = false; + this.isDisposing = false; + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.isDisposed = true; + this.dispatchEvent( new UniversalDispatcherEvent( "dispose", { detail: { ref: this } } ) ); + this.removeAllEventListeners(); + } + hasEventListener( type, listener ) { + return this._listeners.some( item => item.type === type && item.listener === listener ); + } + addEventListener( type, listener ) { + if( ! this.hasEventListener( type, listener ) ) { + this._listeners.push( { + type, + listener, + options: { once: false } + } ); + } + // console.log( `${this}-listeners:`,this._listeners ); + return this; + } + removeEventListener( type, listener ) { + while( true ) { + const index = ( listener != undefined ) + ? this._listeners.findIndex( item => item.type === type && item.listener === listener ) + : this._listeners.findIndex( item => item.type === type ); + if( index >= 0 ) { + this._listeners.splice( index, 1 ); + continue; + } + break; + } + // console.log( `${this}-listeners:`, this._listeners ); + return this; + } + removeAllEventListeners() { + this._listeners = []; + return this; + } + on( type, listener ) { + return this.addEventListener( type, listener ); + } + off( type, listener ) { + return this.removeEventListener( type, listener ); + } + offAll() { + return this.removeAllEventListeners(); + } + dispatchEvent( evt ) { + const a = this._listeners.filter( item => item.type === evt.type ); + for( const item of a ) { + const { + type, + listener, + options: { once } + } = item; + listener.call( this, evt ); + if( once === true ) + this.removeEventListener( type, listener ); + } + // console.log( `${this}-listeners:`,this._listeners ); + return this; + } +}; + +module.exports = { + UniversalDispatcherEvent: UniversalDispatcherEvent, + EventDispatcher: EventDispatcher +}; diff --git a/npms/skale-cool-socket/package.json b/npms/skale-cool-socket/package.json new file mode 100644 index 000000000..e05e2f54a --- /dev/null +++ b/npms/skale-cool-socket/package.json @@ -0,0 +1,35 @@ +{ + "name": "skale-cool-socket", + "version": "1.2.3", + "description": "Cool socket implementation for direct, local, worker thread, web socket, web RTC connections", + "main": "test.js", + "license": "AGPL-3.0", + "author": "SKALE Labs and contributors", + "scripts": { + "lint-check": "eslint *.js", + "lint-fix": "eslint ./*.js --fix", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "cool", + "socket", + "worker", + "thread", + "ws", + "wss", + "webrtc" + ], + "dependencies": { + "connect": "^3.7.0", + "serve-static": "^1.14.1", + "ws": "^8.6.0" + }, + "devDependencies": { + "eslint": "^6.8.0", + "eslint-config-standard": "^14.1.1", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1" + } +} diff --git a/npms/skale-cool-socket/server.js b/npms/skale-cool-socket/server.js new file mode 100644 index 000000000..d4335a472 --- /dev/null +++ b/npms/skale-cool-socket/server.js @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file server.js + * @copyright SKALE Labs 2019-Present + */ + +const { EventDispatcher, UniversalDispatcherEvent } = require( "./event_dispatcher.js" ); +const utils = require( "./utils.js" ); + +class Server extends EventDispatcher { + constructor( acceptor ) { + super(); + if( acceptor == null || acceptor == undefined || typeof acceptor != "object" ) + throw new Error( "Cannot create server on bad acceptor" ); + const self = this; + self.log = console.log; + self.acceptor = acceptor; + self.mapApiHandlers = {}; + self.mapAcceptedPipes = { }; + self.isLogAcceptedSocket = false; + self.isLogSocketErrors = true; + self.isLogSocketTraffic = false; + self.isLogSocketTrafficRaw = false; + acceptor.on( "connection", function( eventData ) { + const socket = eventData.socket; + if( ( ! ( "remoteAddress" in eventData ) ) || eventData.remoteAddress == null || eventData.remoteAddress == undefined ) + socket.strSavedRemoteAddress = socket.constructor.name; + else + socket.strSavedRemoteAddress = "" + eventData.remoteAddress; + if( self.isLogAcceptedSocket ) + self.log( "New server connection \"" + socket.strSavedRemoteAddress + "\"" ); + self.mapAcceptedPipes[socket] = { }; + let _offAllPipeEventListeners = null; + let _onPipeClose = function() { + if( self.isLogAcceptedSocket ) + self.log( "Accepted socket closed \"" + socket.strSavedRemoteAddress + "\"" ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + delete self.mapAcceptedPipes[socket]; + }; + let _onPipeError = function( eventData ) { + if( self.isLogSocketErrors ) + self.log( "Socket error \"" + socket.strSavedRemoteAddress + "\"" ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + delete self.mapAcceptedPipes[socket]; + }; + let _onPipeMessage = function( eventData ) { + if( self.isLogSocketTrafficRaw ) + self.log( "Accepted socket \"" + socket.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( self.isLogAcceptedSocket ) + self.log( "Accepted socket \"" + socket.strSavedRemoteAddress + "\" message", joMessage ); + let joAnswer = null; + let isFlush = false; + try { + if( joMessage.method in self.mapApiHandlers ) { + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer = self.mapApiHandlers[joMessage.method]( joMessage, joAnswer, eventData, socket ); + if( joAnswer ) + isFlush = true; + } else { + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.error = "Unhandled message"; + joAnswer.joMessage = joMessage; // send it back )) + if( self.isLogSocketTraffic ) + self.log( "Accepted socket \"" + socket.strSavedRemoteAddress + "\" unhandled message", joMessage ); + isFlush = true; + } + } catch ( err ) { + if( self.isLogSocketErrors ) + self.log( "Server method", joMessage.method, "RPC exception:", err ); + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.error = "" + err.toString(); + } + // + // + if( joAnswer != null && joAnswer != undefined ) { + if( typeof joAnswer.error == "string" && joAnswer.error.length > 0 ) { + if( self.isLogSocketErrors ) + self.log( "Accepted socket \"" + socket.strSavedRemoteAddress + "\" error answer", joAnswer ); + } else { + if( self.isLogSocketTraffic ) + self.log( "Accepted socket \"" + socket.strSavedRemoteAddress + " answer", joAnswer ); + } + socket.send( joAnswer, isFlush ); + } + }; + _offAllPipeEventListeners = function() { + if( _onPipeClose ) { + socket.off( "close", _onPipeClose ); + _onPipeClose = null; + } + if( _onPipeError ) { + socket.off( "error", _onPipeError ); + _onPipeError = null; + } + if( _onPipeMessage ) { + socket.off( "message", _onPipeMessage ); + _onPipeMessage = null; + } + socket.disposeImpersonatedEntries(); + }; + socket.on( "close", _onPipeClose ); + socket.on( "error", _onPipeError ); + socket.on( "message", _onPipeMessage ); + } ); + this.dispatchEvent( new UniversalDispatcherEvent( "initialized", { detail: { ref: this } } ) ); + } + dispose() { + this.isDisposing = true; + super.dispose(); + } +}; + +module.exports = { + Server: Server +}; diff --git a/npms/skale-cool-socket/settings.js b/npms/skale-cool-socket/settings.js new file mode 100644 index 000000000..ca1e6215c --- /dev/null +++ b/npms/skale-cool-socket/settings.js @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file settings.js + * @copyright SKALE Labs 2019-Present + */ + +const settings = { + rtcSpace: { + defaultSpaceName: "default space", + defaultSpaceCategory: "default category" + }, + net: { + hostname: "localhost", + secure: false, + ports: { + http: 8080, // 80, 443, 8080 + ws: 17171, + signaling: 17172 + }, + pipe: { + maxAccumulatedMessagesCount: 30 + }, + ws: { + client: { + reconnectAfterMilliseconds: 100 + } + }, + rtc: { + arrKnownIceServers: [ + // see: https://gist.github.com/mondain/b0ec1cf5f60ae726202e and https://gist.github.com/zziuni/3741933 + // see: https://stackoverflow.com/questions/20068944/webrtc-stun-stun-l-google-com19302 + // see: https://gist.github.com/yetithefoot/7592580 + // even more to see: https://gist.github.com/sagivo/3a4b2f2c7ac6e1b5267c2f1f59ac6c6b + "stun:stun.1.google.com:19302", + "stun:stun.2.google.com:19302", + "stun:stun.3.google.com:19302", + "stun:stun.4.google.com:19302", + "stun:stun.5.google.com:19302", // where is the end? + "stun:stun.l.google.com:19302", + "stun:stun1.l.google.com:19302", + "stun:stun2.l.google.com:19302", + "stun:stun3.l.google.com:19302", + "stun:stun4.l.google.com:19302", + "stun:stun5.l.google.com:19302", // where is the end? + "stun:stun.gmx.net", + "stun:stun.sipgate.net", + "stun:stun.sipgate.net:10000", + "stun:stun.phoneserve.com", + "stun:stun.counterpath.net", + "stun:stun.12connect.com:3478", + "stun:stun.xten.com", + "stun:stun01.sipphone.com", + "stun:stun.ekiga.net", + "stun:stun.fwdnet.net", + "stun:stun.ideasip.com", + "stun:stun.iptel.org", + "stun:stun.schlund.de", + "stun:stun.voiparound.com", + "stun:stun.voipbuster.com", + "stun:stun.voipstunt.com", + "stun:stun.voxgratia.org" + ] , + peerConfiguration: { + iceServers: [ + // { urls: "stun:192.168.88.220:3478", username: "webrtc", credential: "qwerty" } + // { urls: "turn:192.168.88.220:3478", username: "webrtc", credential: "qwerty" } + { urls: "stun:127.0.0.1:3478", username: "webrtc", credential: "qwerty" } + // { urls: "turn:127.0.0.1:3478", username: "webrtc", credential: "qwerty" } + ] + // , iceTransportPolicy: "all" + // , iceCandidatePoolSize: "0" // efault value is 0 (meaning no candidate pre-fetching will occur). + }, + peerAdditionalOptions: { + optional: [ { DtlsSrtpKeyAgreement: true } ] + }, + dataChannel: { + label: "genericDataChannel", + opts: { reliable: true, ordered: true } + }, + maxActiveOfferCount: 10, + isAutoCloseSignalingPipeOnDataChannelOpen: true, // network_layer.WebRTCClientPipe only + timeToPublishMilliseconds: 0, // 0 - no timeout, 300000 = 5 minutes, 60000 = 1 minute + timeToSignalingNegotiationMilliseconds: 0, // 0 - no timeout, 10000 = 10 seconds to identify by WebRTC + offerDiscovery: { + periodMilliseconds: 1000, + stepCount: 20 + }, + fastPublishMode: { + serverPeer: true, + joiner: true + } + } + }, + logging: { + net: { + socket: { + flush: false, + flushOne: false, + flushBlock: false, + flushCount: false, + flushMethodStats: false, + accumulate: false, + send: false, + receive: false, + receiveBlock: false, + receiveCount: false, + receiveMethodStats: false + }, + signaling: { + generic: false, + connect: true, + disconnect: true, + error: true, + rawMessage: false, + message: false, + impersonate: false, + publishOffer: false, + objectLifetime: true, + offer: false, + answer: false, + localDescription: false, + remoteDescription: false, + candidate: false, + candidateWalk: false, + publishTimeout: true, + signalingNegotiationTimeout: true, + offerDiscoveryStepFail: true, + offerRegister: false, + offerUnregister: false, + offerSkipPublishedAnswer: false, + creatorImpersonationComplete: false + }, + rtc: { + generic: false, + error: true, + closePeer: true, + closeDataChannel: true, + iceConnectionStateChange: false, + iceConnectionStateName: false, + iceGatheringStateChange: false, + iceGatheringStateName: false, + iceIceIdentifyResult: false, + iceSignalingStateChange: false, + iceNegotiationNeeded: false + }, + server: { + connect: true, + disconnect: true, + error: true, + rawMessage: false, + message: false, + impersonate: true, + weaponShot: false, + collisionDetection: true + }, + client: { + space: { attach: true, detach: true }, + connect: true, + disconnect: true, + error: true, + rawMessage: false, + message: false, + impersonate: true + }, + relay: { + connect: true, + disconnect: true, + error: true, + rawMessage: false, + message: false + } + } + } +}; + +module.exports = { + settings: settings +}; diff --git a/npms/skale-cool-socket/socket.js b/npms/skale-cool-socket/socket.js new file mode 100644 index 000000000..6b2df9dd7 --- /dev/null +++ b/npms/skale-cool-socket/socket.js @@ -0,0 +1,2703 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file socket.js + * @copyright SKALE Labs 2019-Present + */ + +const { UniversalDispatcherEvent, EventDispatcher } = require( "./event_dispatcher.js" ); +const { settings } = require( "./settings.js" ); +const utils = require( "./utils.js" ); + +let https_mod = null; // server side only +let ws_mod = null; // server side only +let wrtc_mod = null; // server side only + +// if( typeof window == "undefined" ) { +// try { +// https_mod = require( "https" ); +// console.log( "Using pre-loaded HTTPS API in socket.js" ); +// } catch ( err ) { +// } +// try { +// ws_mod = WebSocket; +// console.log( "Using pre-loaded WebSocket API in socket.js" ); +// } catch ( err ) { +// } +// } else { +// try { +// wrtc_mod = window; +// console.log( "Using pre-loaded WebSocket API in socket.js" ); +// } catch ( err ) { +// } +// } + +// needed to init from outside: import * as https_loaded_mod from "https"; +// const https_mod = https_loaded_mod.default; +// needed to init from outside: import * as ws_loaded_mod from "ws"; +// const ws_mod = ws_loaded_mod.default; + +function set_https_mod( mod ) { + https_mod = mod ? mod : null; +} +function set_ws_mod( mod ) { + ws_mod = mod ? mod : null; +} +function set_wrtc_mod( mod ) { + wrtc_mod = mod ? mod : null; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const g_mapLocalServers = { }; // used both for local and in-worker servers + +const socket_sent_data_marshall = function( data ) { + const s = data + ? ( ( typeof data == "string" ) + ? data + : ( ( typeof data == "object" ) ? JSON.stringify( data ) : data.toString() ) + ) + : ""; + return s; +}; +const socket_received_data_reverse_marshall = function( data ) { + try { + const jo = data + ? ( ( typeof data == "object" ) + ? data + : ( ( typeof data == "string" ) ? JSON.parse( data ) : data ) + ) + : { }; + return jo; + } catch ( err ) { + return { + error: true, + message: "data un-marshal error", + data: data + }; + } +}; + +const update_socket_data_stats_for_message = function( joMessage, joStats ) { + let strMethod = "_N/A_"; + if( "method" in joMessage && + joMessage.method && + typeof joMessage.method == "string" + ) + strMethod = "" + joMessage.method; + if( strMethod in joStats ) + joStats[strMethod] ++; + else + joStats[strMethod] = 1; +}; +const generate_socket_data_stats_JSON = function( jo ) { + const joStats = {}; + //let cnt = 1; + if( "arr_packed_messages" in jo && + jo.arr_packed_messages && + typeof jo.arr_packed_messages == "object" + ) { + //cnt = jo.arr_packed_messages.length; + for( const joMessage of jo.arr_packed_messages ) + update_socket_data_stats_for_message( joMessage, joStats ); + + } else + update_socket_data_stats_for_message( jo, joStats ); + //joStats["_cnt_"] = cnt; + return joStats; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class BasicServerAcceptor extends EventDispatcher { + constructor() { + super(); + this.socketType = "BasicAcceptor"; + this.socketSubtype = "acceptor"; + this.isListening = false; + this.strEndPoint = null; + this.nextClientNumber = 1; + this.mapClients = { }; + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.nextClientNumber = 1; + this.isListening = false; + this.disposeNotifyClients(); + super.dispose(); + } + disposeNotifyClients() { + for( const [ /*key*/, entry ] of Object.entries( this.mapClients ) ) { + if( ( "serverPipe" in entry ) && ( "clientPipe" in entry ) ) { + const pair = entry; + pair.serverPipe.handleServerDisposed(); + pair.clientPipe.handleServerDisposed(); + pair.serverPipe = null; + pair.clientPipe = null; + } else { + const pipe = entry; + pipe.handleServerDisposed(); + } + } + this.mapClients = { }; + } + unregisterClientByKey( key ) { + if( key in this.mapClients ) { + const entry = this.mapClients[key]; + if( entry ) { + if( ( "serverPipe" in entry ) && ( "clientPipe" in entry ) ) { + const pair = entry; + pair.serverPipe = null; + pair.clientPipe = null; + } + delete this.mapClients[key]; + } + } + } + flush() { + if( this.isDisposing || this.isDisposed ) + return; + for( const [ /*key*/, entry ] of Object.entries( this.mapClients ) ) { + if( ( "serverPipe" in entry ) && ( "clientPipe" in entry ) ) { + const pair = entry; + pair.serverPipe.flush(); + } else { + const pipe = entry; + pipe.flush(); + } + } + } + newDirectConnection() { + if( this.isDisposing || this.isDisposed ) + return null; + if( !this.isListening ) + return null; + const clientPipe = new DirectPipe( null, false ); + const serverPipe = new DirectPipe( clientPipe, false ); + serverPipe.acceptor = this; + this.mapClients["" + serverPipe.clientPort] = serverPipe; + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + serverPipe.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: serverPipe } ) ); + self.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: serverPipe, remoteAddress: "" + self.url } ) ); + clientPipe.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: clientPipe } ) ); + }, 0 ); + return clientPipe; + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class BasicSocketPipe extends EventDispatcher { + constructor() { + super(); + this.socketType = "N/A"; + this.socketSubtype = "N/A"; + this.url = "N/A"; + this.isConnected = true; + this.arr_accumulated_messages = []; + this.maxAccumulatedMessagesCount = 0 + settings.net.pipe.maxAccumulatedMessagesCount; + this.relayClientSocket = null; // for relay only + this.mapImpersonatedEntries = { }; // for external in-app usage only + } + dispose() { + if( this.relayClientSocket ) { + this.relayClientSocket.dispose(); + this.relayClientSocket = null; + } + this.disposeImpersonatedEntries(); // for external in-app usage only + this.disconnect(); + this.arr_accumulated_messages = []; + super.dispose(); + } + disposeImpersonatedEntries() { // for external in-app usage only + for( const [ /*key*/, entry ] of Object.entries( this.mapImpersonatedEntries ) ) { + try { + if( entry && "dispose" in entry && typeof entry.dispose == "function" ) + entry.dispose(); + } catch ( err ) { + } + } + this.mapImpersonatedEntries = { }; // for app usage + } + impl_send( data ) { + throw new Error( "BasicSocketPipe.impl_send() must be overridden but calling it was attempted" ); + } + is_auto_flush() { + if( this.maxAccumulatedMessagesCount <= 1 ) + return true; + const cnt = this.arr_accumulated_messages.length; + if( cnt == 0 || cnt < this.maxAccumulatedMessagesCount ) + return false; + return true; + } + socketDescription() { + return "" + + // + this.socketType + // + " " + // + this.socketSubtype + // + " " + this.url; + } + socketLoggingTextPrefix( strLogEventName ) { + return "" + strLogEventName + " " + this.socketDescription() + " -"; + } + send( data, isFlush ) { + if( this.isDisposed || ( !this.isConnected ) ) + return; + if( this.is_auto_flush() ) { + if( settings.logging.net.socket.send || settings.logging.net.socket.flush ) + console.log( this.socketLoggingTextPrefix( "send+flush" ), data ); + this.impl_send( data ); + return; + } + isFlush = ( isFlush == undefined || isFlush == null ) ? true : ( isFlush ? true : false ); + const jo = socket_received_data_reverse_marshall( data ); + if( settings.logging.net.socket.accumulate ) + console.log( this.socketLoggingTextPrefix( "accumulate" ), data ); + this.arr_accumulated_messages.push( jo ); + if( isFlush ) + this.flush(); + } + flush() { + if( this.isDisposed || ( !this.isConnected ) ) + return; + const cnt = this.arr_accumulated_messages.length; + if( cnt == 0 ) + return; + if( settings.logging.net.socket.flushCount ) + console.log( this.socketLoggingTextPrefix( "flush-count(" + cnt + ")" ) ); + let joSend = null; + if( cnt == 1 ) { + joSend = this.arr_accumulated_messages[0]; + if( settings.logging.net.socket.flushOne || settings.logging.net.socket.flush ) + console.log( this.socketLoggingTextPrefix( "flush-one" ), joSend ); + } else { + joSend = { arr_packed_messages: this.arr_accumulated_messages }; + if( settings.logging.net.socket.flushBlock || settings.logging.net.socket.flush ) + console.log( this.socketLoggingTextPrefix( "flush-block(" + cnt + ")" ), joSend ); + } + if( settings.logging.net.socket.flushMethodStats ) + console.log( this.socketLoggingTextPrefix( "flush-method-stats(" + cnt + ")" ), generate_socket_data_stats_JSON( joSend ) ); + this.impl_send( joSend ); + this.arr_accumulated_messages = []; + if( this.relayClientSocket ) + this.relayClientSocket.flush(); + } + impl_receive( data ) { + const jo = socket_received_data_reverse_marshall( data ); + this.dispatchEvent( new UniversalDispatcherEvent( "message", { socket: this, message: jo } ) ); + } + receive( data ) { + if( settings.logging.net.socket.receiveBlock ) + console.log( this.socketLoggingTextPrefix( "receive-block" ), data ); + const jo = socket_received_data_reverse_marshall( data ); + if( "arr_packed_messages" in jo && + jo.arr_packed_messages && + typeof jo.arr_packed_messages == "object" + ) { + const cnt = jo.arr_packed_messages.length; + if( settings.logging.net.socket.receiveCount ) + console.log( this.socketLoggingTextPrefix( "receive-count(" + cnt + ")" ) ); + if( settings.logging.net.socket.receiveMethodStats ) + console.log( this.socketLoggingTextPrefix( "receive-method-stats(" + cnt + ")" ), generate_socket_data_stats_JSON( jo ) ); + for( let i = 0; i < cnt; ++ i ) { + const joMessage = jo.arr_packed_messages[i]; + if( settings.logging.net.socket.receive ) + console.log( this.socketLoggingTextPrefix( "receive" ), joMessage ); + this.impl_receive( joMessage ); + } + return; + } + if( settings.logging.net.socket.receiveCount ) + console.log( this.socketLoggingTextPrefix( "receive-count(" + 1 + ")" ) ); + if( settings.logging.net.socket.receiveMethodStats ) + console.log( this.socketLoggingTextPrefix( "receive-method-stats(" + 1 + ")" ), generate_socket_data_stats_JSON( jo ) ); + if( settings.logging.net.socket.receive ) + console.log( this.socketLoggingTextPrefix( "receive" ), jo ); + this.impl_receive( jo ); + } + disconnect() { + this.isConnected = false; + // if( this.relayClientSocket ) { + // this.relayClientSocket.disconnect(); + // this.relayClientSocket = null; + // } + } + reconnect() { + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class NullSocketPipe extends BasicSocketPipe { + constructor() { + super(); + this.socketType = "NULL"; + this.socketSubtype = "pipe"; + this.url = "NullUrl"; + this.isConnected = true; + } + dispose() { + this.isConnected = false; + super.dispose(); + } + impl_send( data ) { + } + impl_receive( data ) { + } + send( data ) { + } + receive( data ) { + } + flush() { + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const is_running_in_worker = function() { + if( self.document === undefined ) + return true; + return false; +}; + +const g_map_awaiting_in_worker_clients = { }; // in-worker clients in connecting state +const g_map_connected_in_worker_clients = { }; // in-worker clients in connecting state + +const out_of_worker_apis = { + on_message: function( worker, data ) { + const jo = socket_received_data_reverse_marshall( data ); + if( ! ( "worker_message_type" in jo ) || typeof jo.worker_message_type != "string" || jo.worker_message_type.length == 0 ) + return false; // not a socket message + if( ! ( "worker_endpoint" in jo ) || typeof jo.worker_endpoint != "string" || jo.worker_endpoint.length == 0 ) + return false; // TO-DO: send error answer and return true + if( ! ( "worker_uuid" in jo ) || typeof jo.worker_uuid != "string" || jo.worker_uuid.length == 0 ) + return false; // TO-DO: send error answer and return true + switch ( jo.worker_message_type ) { + case "in_worker_connect": { + if( !( jo.worker_uuid in g_map_awaiting_in_worker_clients ) ) + return false; + const pipe = g_map_awaiting_in_worker_clients[jo.worker_uuid]; + pipe.performSuccessfulConnection(); + } return true; + case "in_worker_disconnect": { + if( !( jo.worker_uuid in g_map_connected_in_worker_clients ) ) + return false; + const pipe = g_map_connected_in_worker_clients[jo.worker_uuid]; + pipe.performDisconnect(); + } return true; + case "in_worker_message": { + if( !( jo.worker_uuid in g_map_connected_in_worker_clients ) ) + return false; + const pipe = g_map_connected_in_worker_clients[jo.worker_uuid]; + pipe.receive( jo.data ); + } return true; + default: + return false; // TO-DO: send error answer and return true + } // switch( jo.worker_message_type ) + }, + on_send_message: function( worker, type, endpoint, worker_uuid, data ) { + const jo = socket_received_data_reverse_marshall( data ); + const joSend = { + worker_message_type: ( type && typeof type == "string" && type.length > 0 ) ? type : "in_worker_message", + worker_endpoint: endpoint, + worker_uuid: worker_uuid, + data: jo + }; + //worker.postMessage( socket_received_data_reverse_marshall( joSend ) ); + worker.postMessage( socket_sent_data_marshall( joSend ) ); + } +}; +const in_worker_apis = { + on_message: function( data ) { + const jo = socket_received_data_reverse_marshall( data ); + if( ! ( "worker_message_type" in jo ) || typeof jo.worker_message_type != "string" || jo.worker_message_type.length == 0 ) + return false; // not a socket message + if( ! ( "worker_endpoint" in jo ) || typeof jo.worker_endpoint != "string" || jo.worker_endpoint.length == 0 ) + return false; // TO-DO: send error answer and return true + if( ! ( "worker_uuid" in jo ) || typeof jo.worker_uuid != "string" || jo.worker_uuid.length == 0 ) + return false; // TO-DO: send error answer and return true + if( ! ( jo.worker_endpoint in g_mapLocalServers ) ) + return false; // TO-DO: send error answer and return true + const acceptor = g_mapLocalServers[jo.worker_endpoint]; + switch ( jo.worker_message_type ) { + case "in_worker_connect": + return acceptor.performAccept( jo ); + case "in_worker_disconnect": + return acceptor.performDisconnect( jo ); + case "in_worker_message": + return acceptor.receiveForClientPort( jo.worker_uuid, jo.data ); + default: + return false; // TO-DO: send error answer and return true + } // switch( jo.worker_message_type ) + }, + on_send_message: function( type, endpoint, worker_uuid, data ) { + const jo = socket_received_data_reverse_marshall( data ); + const joSend = { + worker_message_type: ( type && typeof type == "string" && type.length > 0 ) ? type : "in_worker_message", + worker_endpoint: endpoint, + worker_uuid: worker_uuid, + data: jo + }; + //postMessage( socket_received_data_reverse_marshall( joSend ) ); + postMessage( socket_sent_data_marshall( joSend ) ); + } +}; + +class InWorkerServerPipe extends BasicSocketPipe { + constructor( acceptor, clientPort, fnSend ) { + super(); + this.socketType = "InWorker"; + this.socketSubtype = "server"; + this.isConnected = true; + this.acceptor = acceptor; + this.clientPort = "" + clientPort; + this.fnSend = fnSend || in_worker_apis.on_send_message; + this.url = "in_worker_server_pipe://" + acceptor.strEndPoint + ":" + clientPort; + this.acceptor.mapClients[this.clientPort] = this; + this.fnSend( "in_worker_connect", this.acceptor.strEndPoint, this.clientPort, {} ); + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + self.acceptor.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: self, remoteAddress: "" + self.url } ) ); + }, 0 ); + } + dispose() { + this.performDisconnect(); + super.dispose(); + } + handleServerDisposed() { + this.performDisconnect(); + this.isConnected = false; + this.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: this } ) ); + this.acceptor = null; + this.fnSend = null; + this.url = ""; + this.dispose(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.fnSend( "in_worker_disconnect", this.acceptor.strEndPoint, this.clientPort, {} ); + this.isConnected = false; + if( this.acceptor ) + this.acceptor.unregisterClientByKey( this.clientPort ); + this.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: this } ) ); + this.acceptor = null; + this.fnSend = null; + this.url = ""; + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.fnSend ) || typeof this.fnSend != "function" ) { + const s = "Cannot send messages to disconnected in-worker server pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + const jo = socket_received_data_reverse_marshall( data ); + this.fnSend( "in_worker_message", this.acceptor.strEndPoint, this.clientPort, jo ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } +}; + +class InWorkerSocketServerAcceptor extends BasicServerAcceptor { + constructor( strEndPoint, fnSend ) { + super(); + this.socketType = "InWorker"; + this.strEndPoint = ( strEndPoint && typeof strEndPoint == "string" && strEndPoint.length > 0 ) ? strEndPoint : "default_local_endpoint"; + if( this.strEndPoint in g_mapLocalServers ) { + const s = "Cannot start in-worker socket server on already listening \"" + this.strEndPoint + "\" endpoint"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + g_mapLocalServers[this.strEndPoint] = this; + this.fnSend = fnSend || in_worker_apis.on_send_message; + this.isListening = true; + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + }, 0 ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.disposeNotifyClients(); + if( this.strEndPoint && typeof this.strEndPoint == "string" && this.strEndPoint.length > 0 ) { + if( this.strEndPoint in g_mapLocalServers ) + delete g_mapLocalServers[this.strEndPoint]; + } + super.dispose(); + } + performAccept( jo ) { + if( jo.worker_uuid in this.mapClients ) + return false; // TO-DO: send error answer and return true + // const pipe = + new InWorkerServerPipe( this, "" + jo.worker_uuid, this.fnSend ); + return true; + } + performDisconnect( jo ) { + if( ! ( jo.worker_uuid in this.mapClients ) ) + return false; // TO-DO: send error answer and return true + const pipe = this.mapClients[jo.worker_uuid]; + pipe.performDisconnect(); + return true; + } + receiveForClientPort( clientPort, jo ) { + if( ! ( clientPort in this.mapClients ) ) + return false; // TO-DO: send error answer and return true + const pipe = this.mapClients[clientPort]; + pipe.receive( jo ); + return true; + } +}; + +class OutOfWorkerSocketClientPipe extends BasicSocketPipe { + constructor( strEndPoint, worker, fnSend ) { + super(); + this.socketType = "InWorker"; + this.socketSubtype = "client"; + this.isConnected = false; + this.worker = worker; + this.clientPort = utils.uuid_v4(); + this.strEndPoint = ( strEndPoint && typeof strEndPoint == "string" && strEndPoint.length > 0 ) ? strEndPoint : "default_in_worker_endpoint"; + this.url = "out_of_worker_client_pipe://" + this.strEndPoint + ":" + this.clientPort; + this.fnSend = fnSend || out_of_worker_apis.on_send_message; + this.fnSend( this.worker, "in_worker_connect", this.strEndPoint, this.clientPort, {} ); + g_map_awaiting_in_worker_clients["" + this.clientPort] = this; + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.performDisconnect(); + if( this.clientPort in g_map_awaiting_in_worker_clients ) + delete g_map_awaiting_in_worker_clients[this.clientPort]; + super.dispose(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.isConnected = false; + delete g_map_connected_in_worker_clients["" + this.clientPort]; + this.fnSend( this.worker, "in_worker_disconnect", this.strEndPoint, this.clientPort, {} ); + this.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: this } ) ); + this.worker = null; + this.clientPort = ""; + this.strEndPoint = ""; + this.url = ""; + } + performSuccessfulConnection() { + delete g_map_awaiting_in_worker_clients[this.clientPort]; + g_map_connected_in_worker_clients["" + this.clientPort] = this; + this.isConnected = true; + this.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: this } ) ); + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.worker ) || ( !this.fnSend ) || typeof this.fnSend != "function" ) { + const s = "Cannot send messages to disconnected in-worker client pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + const jo = socket_received_data_reverse_marshall( data ); + this.fnSend( this.worker, "in_worker_message", this.strEndPoint, this.clientPort, jo ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class OutOfWorkerRelay extends EventDispatcher { + constructor( strRelayName, acceptor, fnCreateClient, isAutoFlushIncoming, isAutoFlushOutgoing ) { + super(); + const self = this; + self.strRelayName = ( strRelayName != null && strRelayName != undefined && typeof strRelayName == "string" && strRelayName.length > 0 ) ? ( "" + strRelayName ) : "unnamed"; + self.isAutoFlushIncoming = ( isAutoFlushIncoming == null || isAutoFlushIncoming == undefined ) ? true : ( isAutoFlushIncoming ? true : false ); + self.isAutoFlushOutgoing = ( isAutoFlushOutgoing == null || isAutoFlushOutgoing == undefined ) ? true : ( isAutoFlushOutgoing ? true : false ); + if( ! acceptor ) + throw new Error( "OutOfWorkerRelay \"" + self.strRelayName + "\" needs acceptor for normal functionality" ); + if( typeof fnCreateClient != "function" ) + throw new Error( "OutOfWorkerRelay \"" + self.strRelayName + "\" needs callback to create connections to target server" ); + self.acceptor = acceptor; + self.fnCreateClient = fnCreateClient; + self.onConnection_ = function( eventData ) { + const pipeIncoming = eventData.socket; + let pipeOutgoing = null; + if( ( ! ( "remoteAddress" in eventData ) ) || eventData.remoteAddress == null || eventData.remoteAddress == undefined ) + pipeIncoming.strSavedRemoteAddress = pipeIncoming.constructor.name; + else + pipeIncoming.strSavedRemoteAddress = "" + eventData.remoteAddress; + if( settings.logging.net.relay.connect ) + console.log( "Relay \"" + self.strRelayName + "\" got new external-client connection \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "connection", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress } ) ); + // + // 1) configure incoming pipe + // + let _offAllPipeEventListeners = null; + let _onExternalPipeClose = function() { + if( settings.logging.net.relay.disconnect ) + console.warn( "Relay \"" + self.strRelayName + "\" external-client socket closed \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "close", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onRelayPipeClose = function() { + if( settings.logging.net.relay.disconnect ) + console.warn( "Relay \"" + self.strRelayName + "\" relay-client socket closed \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "close", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onExternalPipeError = function( eventData ) { + if( settings.logging.net.relay.error ) + console.warn( "Relay client \"" + self.strRelayName + "\" external-client socket error \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "error", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onRelayPipeError = function( eventData ) { + if( settings.logging.net.relay.error ) + console.warn( "Relay client \"" + self.strRelayName + "\" relay-client socket error \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "error", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onExternalPipeMessage = function( eventData ) { + if( settings.logging.net.relay.rawMessage ) + console.log( "Relay \"" + self.strRelayName + "\" external-client socket \"" + eventData.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.relay.message ) + console.log( "Relay \"" + self.strRelayName + "\" external-client socket \"" + pipeIncoming.strSavedRemoteAddress + "\" message ", joMessage ); + if( ! pipeOutgoing ) + throw new Error( "Relay \"" + self.strRelayName + "\" is not completely initialized and cannot transfer messages" ); + self.dispatchEvent( new UniversalDispatcherEvent( "message", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true, message: joMessage } ) ); + pipeOutgoing.send( joMessage ); + if( self.isAutoFlushIncoming ) + pipeOutgoing.flush(); + }; + let _onRelayPipeMessage = function( eventData ) { + if( settings.logging.net.relay.rawMessage ) + console.log( "Relay \"" + self.strRelayName + "\" relay-client socket \"" + eventData.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.relay.message ) + console.log( "Relay \"" + self.strRelayName + "\" relay-client socket \"" + pipeIncoming.strSavedRemoteAddress + "\" message ", joMessage ); + if( ! pipeOutgoing ) + throw new Error( "Relay \"" + self.strRelayName + "\" is not completely initialized and cannot transfer messages" ); + self.dispatchEvent( new UniversalDispatcherEvent( "message", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false, message: joMessage } ) ); + pipeOutgoing.send( joMessage ); + if( self.isAutoFlushOutgoing ) + pipeOutgoing.flush(); + }; + _offAllPipeEventListeners = function() { + if( _onExternalPipeClose ) { + pipeIncoming.off( "close", _onExternalPipeClose ); + _onExternalPipeClose = null; + } + if( _onExternalPipeError ) { + pipeIncoming.off( "error", _onExternalPipeError ); + _onExternalPipeError = null; + } + if( _onExternalPipeMessage ) { + pipeIncoming.off( "message", _onExternalPipeMessage ); + _onExternalPipeMessage = null; + } + if( pipeOutgoing.relayClientSocket ) { + if( _onRelayPipeClose ) { + pipeOutgoing.off( "close", _onRelayPipeClose ); + _onRelayPipeClose = null; + } + if( _onRelayPipeError ) { + pipeOutgoing.off( "error", _onRelayPipeError ); + _onRelayPipeError = null; + } + if( _onRelayPipeMessage ) { + pipeOutgoing.off( "message", _onRelayPipeMessage ); + _onRelayPipeMessage = null; + } + pipeOutgoing.disconnect(); + pipeOutgoing.dispose(); + } + pipeIncoming.disconnect(); + pipeIncoming.dispose(); + }; + pipeIncoming.on( "close", _onExternalPipeClose ); + pipeIncoming.on( "error", _onExternalPipeError ); + pipeIncoming.on( "message", _onExternalPipeMessage ); + // + // 2) configure outgoing relay client pipe + // + pipeOutgoing = pipeIncoming.relayClientSocket = self.fnCreateClient(); + if( ! pipeOutgoing ) { + pipeIncoming.dispose(); + throw new Error( "Relay \"" + self.strRelayName + "\" failed to initialize relay-client socket to target server" ); + } + pipeOutgoing.on( "close", _onRelayPipeClose ); + pipeOutgoing.on( "error", _onRelayPipeError ); + pipeOutgoing.on( "message", _onRelayPipeMessage ); + }; + self.acceptor.on( "connection", self.onConnection_ ); + } + dispose() { + this.isDisposing = true; + if( this.acceptor ) + this.acceptor.off( "connection", this.onConnection_ ); + this.onConnection_ = null; + super.dispose(); + } + flush() { + if( this.acceptor ) + this.acceptor.flush(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class OneToOneRelay extends EventDispatcher { + constructor( strRelayName, pipeIncoming, pipeOutgoing, isAutoFlushIncoming, isAutoFlushOutgoing ) { + super(); + const self = this; + self.strRelayName = ( strRelayName != null && strRelayName != undefined && typeof strRelayName == "string" && strRelayName.length > 0 ) ? ( "" + strRelayName ) : "unnamed"; + self.isAutoFlushIncoming = ( isAutoFlushIncoming == null || isAutoFlushIncoming == undefined ) ? true : ( isAutoFlushIncoming ? true : false ); + self.isAutoFlushOutgoing = ( isAutoFlushOutgoing == null || isAutoFlushOutgoing == undefined ) ? true : ( isAutoFlushOutgoing ? true : false ); + self.pipeIncoming = pipeIncoming; + self.pipeOutgoing = pipeOutgoing; + if( ( !( "strSavedRemoteAddress" in pipeIncoming ) ) || pipeIncoming.strSavedRemoteAddress == null || pipeIncoming.strSavedRemoteAddress == undefined ) + pipeIncoming.strSavedRemoteAddress = "" + pipeIncoming.constructor.name; + if( ( !( "strSavedRemoteAddress" in pipeOutgoing ) ) || pipeOutgoing.strSavedRemoteAddress == null || pipeOutgoing.strSavedRemoteAddress == undefined ) + pipeOutgoing.strSavedRemoteAddress = "" + pipeOutgoing.constructor.name; + // + // 1) configure incoming pipe + // + let _offAllPipeEventListeners = null; + let _onIncomingPipeClose = function() { + if( settings.logging.net.relay.disconnect ) + console.warn( "Relay \"" + self.strRelayName + "\" incoming-client socket closed \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "close", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onOutgoingPipeClose = function() { + if( settings.logging.net.relay.disconnect ) + console.warn( "Relay \"" + self.strRelayName + "\" outgoing-client socket closed \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "close", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onIncomingPipeError = function( eventData ) { + if( settings.logging.net.relay.error ) + console.warn( "Relay client \"" + self.strRelayName + "\" incoming-client socket error \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "error", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onOutgoingPipeError = function( eventData ) { + if( settings.logging.net.relay.error ) + console.warn( "Relay client \"" + self.strRelayName + "\" outgoing-client socket error \"" + pipeIncoming.strSavedRemoteAddress + "\"" ); + self.dispatchEvent( new UniversalDispatcherEvent( "error", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false } ) ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + }; + let _onIncomingPipeMessage = function( eventData ) { + if( settings.logging.net.relay.rawMessage ) + console.log( "Relay \"" + self.strRelayName + "\" incoming-client socket \"" + eventData.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.relay.message ) + console.log( "Relay \"" + self.strRelayName + "\" incoming-client socket \"" + pipeIncoming.strSavedRemoteAddress + "\" message ", joMessage ); + if( ! pipeOutgoing ) + throw new Error( "Relay \"" + self.strRelayName + "\" is not completely initialized and cannot transfer messages" ); + self.dispatchEvent( new UniversalDispatcherEvent( "message", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: true, message: joMessage } ) ); + pipeOutgoing.send( joMessage ); + if( self.isAutoFlushIncoming ) + pipeOutgoing.flush(); + }; + let _onOutgoingPipeMessage = function( eventData ) { + if( settings.logging.net.relay.rawMessage ) + console.log( "Relay \"" + self.strRelayName + "\" outgoing-client socket \"" + eventData.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.relay.message ) + console.log( "Relay \"" + self.strRelayName + "\" outgoing-client socket \"" + pipeIncoming.strSavedRemoteAddress + "\" message ", joMessage ); + if( ! pipeOutgoing ) + throw new Error( "Relay \"" + self.strRelayName + "\" is not completely initialized and cannot transfer messages" ); + self.dispatchEvent( new UniversalDispatcherEvent( "message", { relay: self, socket: pipeIncoming, remoteAddress: "" + pipeIncoming.strSavedRemoteAddress, isExternalSocket: false, message: joMessage } ) ); + pipeIncoming.send( joMessage ); + if( self.isAutoFlushOutgoing ) + pipeIncoming.flush(); + }; + _offAllPipeEventListeners = function() { + if( _onIncomingPipeClose ) { + pipeIncoming.off( "close", _onIncomingPipeClose ); + _onIncomingPipeClose = null; + } + if( _onIncomingPipeError ) { + pipeIncoming.off( "error", _onIncomingPipeError ); + _onIncomingPipeError = null; + } + if( _onIncomingPipeMessage ) { + pipeIncoming.off( "message", _onIncomingPipeMessage ); + _onIncomingPipeMessage = null; + } + if( pipeOutgoing.relayClientSocket ) { + if( _onOutgoingPipeClose ) { + pipeOutgoing.off( "close", _onOutgoingPipeClose ); + _onOutgoingPipeClose = null; + } + if( _onOutgoingPipeError ) { + pipeOutgoing.off( "error", _onOutgoingPipeError ); + _onOutgoingPipeError = null; + } + if( _onOutgoingPipeMessage ) { + pipeOutgoing.off( "message", _onOutgoingPipeMessage ); + _onOutgoingPipeMessage = null; + } + pipeOutgoing.disconnect(); + pipeOutgoing.dispose(); + } + pipeIncoming.disconnect(); + pipeIncoming.dispose(); + }; + pipeIncoming.on( "close", _onIncomingPipeClose ); + pipeIncoming.on( "error", _onIncomingPipeError ); + pipeIncoming.on( "message", _onIncomingPipeMessage ); + // + // 2) configure outgoing relay client pipe + // + pipeOutgoing.on( "close", _onOutgoingPipeClose ); + pipeOutgoing.on( "error", _onOutgoingPipeError ); + pipeOutgoing.on( "message", _onOutgoingPipeMessage ); + } + dispose() { + this.isDisposing = true; + super.dispose(); + } + flush() { + if( this.pipeIncoming ) + this.pipeIncoming.flush(); + if( this.pipeOutgoing ) + this.pipeOutgoing.flush(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class DirectPipe extends BasicSocketPipe { + constructor( counterPipe, isBroadcastOpenEvents ) { + super(); + isBroadcastOpenEvents = isBroadcastOpenEvents ? true : false; + this.socketType = "Direct"; + this.socketSubtype = "direct.not.initialized.yet"; + this.isConnected = false; + this.acceptor = null; + this.counterPipe = ( counterPipe != null && counterPipe != undefined ) ? counterPipe : null; // set outside after this constructor call + this.strEndPoint = this.counterPipe ? ( "2-" + this.counterPipe.strEndPoint ) : ( "1-" + utils.randomDirectPipeID() ); + this.clientPort = this.counterPipe ? 2 : 1; + this.socketSubtype = "direct." + this.clientPort; + this.url = "direct_pipe://" + this.strEndPoint + ":" + this.clientPort; + if( this.counterPipe ) { + this.counterPipe.counterPipe = this; + this.isConnected = true; + this.counterPipe.isConnected = true; + if( isBroadcastOpenEvents ) { + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + // self.acceptor.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: serverPipe, remoteAddress: "" + self.url } ) ); + self.counterPipe.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self.counterPipe } ) ); + }, 0 ); + } + } + } + dispose() { + this.performDisconnect(); + super.dispose(); + } + handleServerDisposed() { // this method is for using in local client/server pipe pairs + this.performDisconnect(); + this.isConnected = false; + this.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: this } ) ); + this.acceptor = null; + this.counterPipe = null; + this.clientPort = 0; + this.url = ""; + this.dispose(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.isConnected = false; + if( this.acceptor ) + this.acceptor.unregisterClientByKey( this.clientPort ); + this.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: this } ) ); + this.counterPipe.performDisconnect(); + this.acceptor = null; + this.counterPipe = null; + this.clientPort = 0; + this.url = ""; + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.counterPipe ) || ( !this.counterPipe.isConnected ) ) { + const s = "Cannot send messages to disconnected local server pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + const s = socket_sent_data_marshall( data ); + const jo = socket_received_data_reverse_marshall( s ); + this.counterPipe.receive( jo ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class LocalSocketServerPipe extends DirectPipe { + constructor( counterPipe, acceptor, clientPort ) { + super( counterPipe, false ); + this.socketType = "Local"; + this.socketSubtype = "server"; + this.isConnected = true; + this.acceptor = acceptor; + this.clientPort = 0 + parseInt( clientPort, 10 ); + this.url = "local_server_pipe://" + acceptor.strEndPoint + ":" + clientPort; + this.acceptor.mapClients["" + clientPort] = this; + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + }, 0 ); + } + dispose() { + super.dispose(); + } +}; + +class LocalSocketServerAcceptor extends BasicServerAcceptor { + constructor( strEndPoint ) { + super(); + this.socketType = "Local"; + this.nextClientPort = 1; + this.strEndPoint = ( strEndPoint && typeof strEndPoint == "string" && strEndPoint.length > 0 ) ? strEndPoint : "default_local_endpoint"; + if( this.strEndPoint in g_mapLocalServers ) { + const s = "Cannot start local socket server on already listening \"" + this.strEndPoint + "\" endpoint"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + g_mapLocalServers[this.strEndPoint] = this; + this.isListening = true; + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + }, 0 ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.disposeNotifyClients(); + if( this.strEndPoint && typeof this.strEndPoint == "string" && this.strEndPoint.length > 0 ) { + if( this.strEndPoint in g_mapLocalServers ) + delete g_mapLocalServers[this.strEndPoint]; + } + super.dispose(); + } +}; + +class LocalSocketClientPipe extends DirectPipe { + constructor( strEndPoint ) { + super( null, false ); + this.socketType = "Local"; + this.socketSubtype = "client"; + this.isConnected = false; + this.clientPort = 0; + this.acceptor = null; + this.counterPipe = null; + this.strEndPoint = ( strEndPoint && typeof strEndPoint == "string" && strEndPoint.length > 0 ) ? strEndPoint : "default_local_endpoint"; + if( !( this.strEndPoint in g_mapLocalServers ) ) { + const s = "Cannot connect to local socket server \"" + this.strEndPoint + "\" endpoint, no such server"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + this.acceptor = g_mapLocalServers[this.strEndPoint]; + this.clientPort = 0 + this.acceptor.nextClientPort; + ++ this.acceptor.nextClientPort; + this.url = "local_client_pipe://" + this.strEndPoint + ":" + this.clientPort; + this.isConnected = true; + const serverPipe = new LocalSocketServerPipe( this, this.acceptor, 0 + this.clientPort ); + serverPipe.counterPipe = this; + this.counterPipe = serverPipe; + this.acceptor.mapClients[0 + this.clientPort] = { + serverPipe: serverPipe, + clientPipe: this + }; + const self = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + self.acceptor.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: serverPipe, remoteAddress: "" + self.url } ) ); + }, 0 ); + } + dispose() { + super.dispose(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class WebSocketServerPipe extends BasicSocketPipe { + constructor( acceptor, ws_conn, remoteAddress ) { + super(); + this.socketType = "WS"; + this.socketSubtype = "server"; + const self = this; + this.isConnected = true; + this.acceptor = acceptor; + this.clientNumber = 0 + acceptor.nextClientNumber; + this.clientPort = 0 + this.clientNumber; + ++ acceptor.nextClientNumber; + this.ws_conn = ws_conn; + this.remoteAddress = "" + remoteAddress; + this.url = "ws_server_pipe(" + this.clientNumber + ")://" + remoteAddress; + this._onWsClose = function() { + self.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: self } ) ); + }; + this._onWsError = function( event ) { + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: event } ) ); + }; + this._onWsMessage = function( event ) { + self.receive( event.data ); + }; + this._removeWsEventListeners = function() { + if( self._onWsClose ) { + ws_conn.removeEventListener( "close", self._onWsClose ); + self._onWsClose = null; + } + if( self._onWsError ) { + ws_conn.removeEventListener( "error", self._onWsError ); + self._onWsError = null; + } + if( self._onWsMessage ) { + ws_conn.removeEventListener( "message", self._onWsMessage ); + self._onWsMessage = null; + } + }; + ws_conn.addEventListener( "close", this._onWsClose ); + ws_conn.addEventListener( "error", this._onWsError ); + ws_conn.addEventListener( "message", this._onWsMessage ); + this.acceptor.mapClients["" + this.clientPort] = this; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + self.acceptor.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: self, remoteAddress: "" + remoteAddress } ) ); + }, 0 ); + } + dispose() { + this.performDisconnect(); + super.dispose(); + } + handleServerDisposed() { + this.isConnected = false; + this.clientNumber = 0; + this.acceptor = null; + this.ws_conn = null; + this.url = ""; + this.remoteAddress = ""; + this.dispose(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.isConnected = false; + if( this._removeWsEventListeners ) { + this._removeWsEventListeners(); + this._removeWsEventListeners = null; + } + if( this.ws_conn ) { + try { + this.ws_conn.terminate(); + } catch ( err ) { + console.warn( "Web socket server pipe termination error", err ); + } + this.ws_conn = null; + } + if( this.acceptor ) + this.acceptor.unregisterClientByKey( this.clientPort ); + this.clientNumber = 0; + this.acceptor = null; + this.url = ""; + this.remoteAddress = ""; + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.ws_conn ) ) { + const s = "Cannot send messages to disconnected web socket server pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + const s = socket_sent_data_marshall( data ); + this.ws_conn.send( s ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } + impl_receive( data ) { + const jo = socket_received_data_reverse_marshall( data ); + this.dispatchEvent( new UniversalDispatcherEvent( "message", { socket: this, message: jo } ) ); + } +}; + +class WebSocketServerAcceptor extends BasicServerAcceptor { + constructor( nTcpPort, key, cert ) { + super(); + this.socketType = "WS"; + this.ws_srv = null; + if( key != null && key != undefined && typeof key == "string" && key.length > 0 && + cert != null && cert != undefined && typeof cert == "string" && cert.length > 0 + ) { + const server = https_mod.createServer( { + key: "" + key, + cert: "" + cert + // , ca: ... + } ); + server.listen( nTcpPort ); + this.ws_srv = new ws_mod.Server( { server } ); + } else + this.ws_srv = new ws_mod.Server( { port: nTcpPort } ); + + const self = this; + self.ws_srv.on( "connection", function( ws_conn, req ) { + ws_conn.strSavedRemoteAddress = "" + req.connection.remoteAddress; + ws_conn.serverPipe = new WebSocketServerPipe( self, ws_conn, req.connection.remoteAddress ); + } ); + this.isListening = true; + const iv = setTimeout( function() { + clearTimeout( iv ); + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + }, 0 ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.disposeNotifyClients(); + super.dispose(); + } +}; + +class WebSocketClientPipe extends BasicSocketPipe { + constructor( url ) { + super(); + this.socketType = "WS"; + this.socketSubtype = "client"; + this.isConnected = false; + this.ws_conn = null; + this._onWsOpen = null; + this._onWsClose = null; + this._onWsError = null; + this._onWsMessage = null; + this.ws_url = "" + ( ( url != null && url != undefined && typeof url == "string" ) ? url : "" ); + this.url = "ws_client_pipe-" + this.ws_url; + this.reconnect(); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.performDisconnect(); + this.ws_url = null; + super.dispose(); + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.ws_conn ) ) { + const s = "Cannot send messages to disconnected web socket client pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + const s = socket_sent_data_marshall( data ); + this.ws_conn.send( s ); + } + reconnect() { + this.performDisconnect(); + this.ws_connect( "" + this.ws_url ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.ws_disconnect(); + } + ws_connect_attempt( url, reconnectAfterMilliseconds, iv ) { + const self = this; + try { + if( this.isConnected || this.ws_conn ) + this.ws_disconnect(); + this.ws_conn = ws_mod + ? new ws_mod( url, { tlsOptions: { rejectUnauthorized: false } } ) // server side + : new WebSocket( url ); // client side + this.url = "" + url; + this._onWsOpen = function() { + self.isConnected = true; + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + }; + this._onWsClose = function( event ) { + // alert( JSON.stringify( event ) ); + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: self, message: event } ) ); + }; + this._onWsError = function( event ) { + // alert( JSON.stringify( event ) ); + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: event } ) ); + }; + this._onWsMessage = function( event ) { + self.receive( event.data ); + }; + this._removeWsEventListeners = function() { + if( self._onWsOpen ) { + self.ws_conn.removeEventListener( "open", self._onWsOpen ); + self._onWsOpen = null; + } + if( self._onWsClose ) { + self.ws_conn.removeEventListener( "close", self._onWsClose ); + self._onWsClose = null; + } + if( self._onWsError ) { + self.ws_conn.removeEventListener( "error", self._onWsError ); + self._onWsError = null; + } + if( self._onWsMessage ) { + self.ws_conn.removeEventListener( "message", self._onWsMessage ); + self._onWsMessage = null; + } + }; + this.ws_conn.addEventListener( "open", this._onWsOpen ); + this.ws_conn.addEventListener( "close", this._onWsClose ); + this.ws_conn.addEventListener( "error", this._onWsError ); + this.ws_conn.addEventListener( "message", this._onWsMessage ); + if( iv ) + clearTimeout( iv ); + return true; + } catch ( err ) { + console.warn( "WS client connect error:", err ); + } + if( reconnectAfterMilliseconds != null && reconnectAfterMilliseconds != undefined ) { + reconnectAfterMilliseconds = parseInt( reconnectAfterMilliseconds, 10 ); + if( reconnectAfterMilliseconds > 0 && ( !iv ) ) { + const iv = setTimeout( function() { + try { + if( self.ws_connect_attempt( url, reconnectAfterMilliseconds, iv ) ) + clearTimeout( iv ); + } catch ( err ) { + } + }, reconnectAfterMilliseconds ); + } + } + return false; + } + ws_connect( url ) { + if( url.length == 0 ) { + const s = "Cannot connect web socket server \"" + url + "\", bad url"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s } ) ); + throw new Error( s ); + } + this.ws_connect_attempt( url, settings.net.ws.client.reconnectAfterMilliseconds, null ); + } + ws_disconnect() { + if( this._removeWsEventListeners ) { + this._removeWsEventListeners(); + this._removeWsEventListeners = null; + } + if( this.ws_conn ) { + //try { this.ws_conn.close( 1000, "Good bye!" ); } catch( err ) { } // see codes here: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes + let bPass = false, anyError = null; + try { + this.ws_conn.close(); + bPass = true; + } catch ( err ) { + anyError = err; + } + if( ! bPass ) { + try { + this.ws_conn.terminate(); + bPass = true; + } catch ( err ) { + anyError = err; + } + } + if( ! bPass ) + console.warn( "Web socket client pipe termination error", anyError ); + this.ws_conn = null; + } + this.isConnected = false; + this.url = ""; + } + impl_receive( data ) { + const jo = socket_received_data_reverse_marshall( data ); + this.dispatchEvent( new UniversalDispatcherEvent( "message", { socket: this, message: jo } ) ); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class RTCConnection extends EventDispatcher { + constructor( strSignalingServerURL, idRtcParticipant ) { + super(); + this.strSignalingServerURL = utils.makeValidSignalingServerURL( strSignalingServerURL ); + this.idRtcParticipant = "" + ( ( idRtcParticipant != null && idRtcParticipant != undefined && typeof idRtcParticipant == "string" && idRtcParticipant.length > 0 ) ? idRtcParticipant : utils.uuid_v4() ); + this.wasIdentified = false; + this.iceComplete = false; + this.pc = null; + this.dc = null; + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.closeDataChannel(); + this.closePeer(); + this.dc = null; + this.wasIdentified = false; + this.iceComplete = false; + this.idRtcParticipant = null; + super.dispose(); + } + describe( strInstanceType, arrAdditionalProps ) { + let strInstanceDescription = ( strInstanceType == null || strInstanceType == undefined || ( typeof strInstanceType != "string" ) || strInstanceType.length == 0 ) + ? "participant" + : ( "" + strInstanceType ); + if( typeof this.idRtcParticipant == "string" && this.idRtcParticipant.length > 0 ) + strInstanceDescription += " " + this.idRtcParticipant; + const arrProps = []; + if( this.isDisposed ) + arrProps.push( "disposed" ); + if( this.wasIdentified ) + arrProps.push( "identified" ); + if( this.pc ) + arrProps.push( "pc" ); + if( this.dc ) + arrProps.push( "dc" ); + if( arrAdditionalProps != null && arrAdditionalProps != undefined && arrAdditionalProps.length > 0 ) { + for( let i = 0; i < arrAdditionalProps.length; ++ i ) + arrProps.push( arrAdditionalProps[i] ); + } + if( arrProps.length > 0 ) + strInstanceDescription += "(" + arrProps.join( ", " ) + ")"; + return strInstanceDescription; + } + closeDataChannel() { + if( this.dc ) { + try { + this.dc.ondatachannel = null; + this.dc.close(); + if( settings.logging.net.rtc.closeDataChannel ) + console.warn( this.describe() + " did closed RTC data channel" ); + } catch ( err ) { + if( settings.logging.net.rtc.error ) + console.warn( this.describe() + " error closing RTC data channel:", err ); + } + this.dc = null; + this.dispatchEvent( new UniversalDispatcherEvent( "dataChannelClose", { detail: { actor: this } } ) ); + } + } + closePeer() { + if( this.pc ) { + try { + this.pc.onicecandidate = null; + this.pc.oniceconnectionstatechange = null; + this.pc.close(); + if( settings.logging.net.rtc.closePeer ) + console.warn( this.describe() + " did closed RTC peer" ); + } catch ( err ) { + if( settings.logging.net.rtc.error ) + console.warn( this.describe() + " error closing RTC peer:", err ); + } + this.dispatchEvent( new UniversalDispatcherEvent( "peerClose", { detail: { actor: this } } ) ); + this.pc = null; + } + } + onError( err ) { + this.dispatchEvent( new UniversalDispatcherEvent( "rtcParticipantError", { detail: { actor: this, error: err } } ) ); + if( settings.logging.net.rtc.error ) + console.warn( " !!! " + this.describe() + " error:", err ); + this.closeDataChannel(); + this.closePeer(); + } + send( data ) { + const s = socket_sent_data_marshall( data ); + if( ! this.dc ) { + this.onError( "Attempt to send message to uninitialized RTC data channel: " + s ); + return; + } + try { + this.dc.send( s ); + } catch ( err ) { + this.onError( "Failed to send message to RTC data channel: " + err.toString() ); + } + } + onDataChannelOpen( event ) { + this.dispatchEvent( new UniversalDispatcherEvent( "dataChannelOpen", { detail: { actor: this } } ) ); + } + onDataChannelClose( event ) { + this.dispatchEvent( new UniversalDispatcherEvent( "dataChannelClose", { detail: { actor: this } } ) ); + // this.onError( "Data channel closed" ); + } + onDataChannelError( event ) { + this.dispatchEvent( new UniversalDispatcherEvent( "dataChannelError", { detail: { actor: this } } ) ); + this.onError( "Data channel error " + event.toString() ); + } + onDataChannelMessage( event ) { + if( event.data.size ) { + // fileReceiver.receive( event.data, { } ); + if( settings.logging.net.rtc.error ) + console.warn( this.describe() + " will ignore file transfer message of size", event.data.size ); + } else { + if( event.data.charCodeAt( 0 ) == 2 ) + return; + const data = JSON.parse( event.data ); + if( data.type === "file" ) { + // fileReceiver.receive( event.data, { } ); + if( settings.logging.net.rtc.error ) + console.warn( this.describe() + " will ignore file transfer message" ); + } else + this.dispatchEvent( new UniversalDispatcherEvent( "dataChannelMessage", { detail: { actor: this, data: data } } ) ); + } + } + onIceComplete( event ) { + } + onIceConnectionStateChange( event ) { // handler for self.pc.oniceconnectionstatechange, see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/oniceconnectionstatechange + if( settings.logging.net.rtc.iceConnectionStateChange ) + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE connection state changed to \"" + this.pc.iceConnectionState + "\", event is:", event ); + else if( settings.logging.net.rtc.iceConnectionStateName ) // similar to previous but prints only connection state name + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE connection state changed to \"" + this.pc.iceConnectionState + "\"" ); + if( this.pc.iceConnectionState === "failed" || + this.pc.iceConnectionState === "closed" || + this.pc.iceConnectionState === "disconnected" + ) + this.onError( "ICE connection state(oniceconnectionstatechange) changed to " + this.pc.iceConnectionState ); + } + onIceGatheringStateChange( event ) { // handler for self.pc.onicegatheringstatechange - this is recommended to handle in a same way as oniceconnectionstatechange, see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onicegatheringstatechange + if( ! this.pc ) { + console.log( "WARNING: Participant \"" + this.idRtcParticipant + "\" ICE gathering state changed event with no pc\", event is:", event ); + return; + } + if( settings.logging.net.rtc.iceGatheringStateChange ) + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE gathering state changed to \"" + this.pc.iceGatheringState + "\", event is:", event ); + else if( settings.logging.net.rtc.iceGatheringStateName ) // similar to previous but prints only gathering state name + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE gathering state changed to \"" + this.pc.iceGatheringState + "\"" ); + if( this.pc.iceConnectionState === "failed" || + this.pc.iceConnectionState === "closed" || + this.pc.iceConnectionState === "disconnected" + ) + this.onError( "ICE connection state(onicegatheringstatechange) changed to " + this.pc.iceConnectionState ); + } + onIceIdentifyResult( event ) { // handler for self.pc.onidentityresult, see https://developer.mozilla.org/en-US/docs/Web/API/RTCIdentityEvent + if( settings.logging.net.rtc.iceIceIdentifyResult ) { + if( "assertion" in event ) + console.warn( "Participant \"" + this.idRtcParticipant + "\" ICE identify result event with new identity assertion (blob: '" + event.assertion + "') has been generated." ); + else + console.warn( "Participant \"" + this.idRtcParticipant + "\" ICE identify result event is:", event ); + } + } + onIceSignalingStateChange( event ) { // handler for self.pc.onsignalingstatechange, see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onsignalingstatechange + if( settings.logging.net.rtc.iceSignalingStateChange ) { + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE signaling state changed to \"" + + ( ( this.pc && "signalingState" in this.pc ) ? this.pc.signalingState : "N/A" ) + + "\", event is:", event ); + } + } + onIceNegotiationNeeded( event ) { // handler for self.pc.onnegotiationneeded, see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/onnegotiationneeded + // TO-DO: improve this + if( settings.logging.net.rtc.iceNegotiationNeeded ) + console.log( "Participant \"" + this.idRtcParticipant + "\" ICE negotiation needed event is:", event ); + } +}; + +class RTCActor extends RTCConnection { + constructor( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions ) { + super( strSignalingServerURL, idRtcParticipant ); + this.isDisposed = false; + this.idSomebodyCreator = null; + this.bWasImpersonated = false; + this.isCreator = false; + this.isJoiner = false; + // + this.offerOptions = { + optional: [], + offerToReceiveAudio: false, // offer to the remote peer the opportunity to try to send audio + offerToReceiveVideo: false, // offer to the remote peer the opportunity to try to send video + voiceActivityDetection: false, + iceRestart: false + }; + if( offerOptions ) { + this.offerOptions.offerToReceiveAudio = ( "offerToReceiveAudio" in offerOptions && offerOptions.offerToReceiveAudio ) ? true : false; + this.offerOptions.offerToReceiveVideo = ( "offerToReceiveVideo" in offerOptions && offerOptions.offerToReceiveVideo ) ? true : false; + this.offerOptions.voiceActivityDetection = ( "voiceActivityDetection" in offerOptions && offerOptions.voiceActivityDetection ) ? true : false; + this.offerOptions.iceRestart = ( "iceRestart" in offerOptions && offerOptions.iceRestart ) ? true : false; + } + // + this.signalingOptions = { + idCategory: "" + settings.rtcSpace.defaultSpaceCategory, + idSpace: "" + settings.rtcSpace.defaultSpaceName + }; + if( signalingOptions ) { + if( "idCategory" in signalingOptions && typeof signalingOptions.idCategory == "string" && signalingOptions.idCategory.length > 0 ) + this.signalingOptions.idCategory = "" + signalingOptions.idCategory; + if( "idSpace" in signalingOptions && typeof signalingOptions.idSpace == "string" && signalingOptions.idSpace.length > 0 ) + this.signalingOptions.idSpace = "" + signalingOptions.idSpace; + } + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.signalingPipeClose(); + this.idSomebodyCreator = null; + this.strSignalingServerURL = null; + this.bWasImpersonated = false; + super.dispose(); + } + describe( strInstanceType, arrAdditionalProps ) { + strInstanceType = ( strInstanceType == null || strInstanceType == undefined || ( typeof strInstanceType != "string" ) || strInstanceType.length == 0 ) + ? ( this.isCreator ? "creator" : ( this.isJoiner ? "joiner" : "actor" ) ) + : strInstanceType; + // arrAdditionalProps = arrAdditionalProps || []; + return super.describe( strInstanceType, arrAdditionalProps ); + } + onError( err ) { + super.onError( err ); + } + signalingPipeOpen() { + try { + const self = this; + self.signalingPipeClose(); + self.dispatchEvent( new UniversalDispatcherEvent( "signalingWillStart", { detail: { actor: this } } ) ); + self.signalingPipe = new WebSocketClientPipe( self.strSignalingServerURL ); + self.signalingPipe.on( "open", function( eventData ) { self.signalingPipeOnOpen( eventData ); } ); + self.signalingPipe.on( "close", function( eventData ) { self.signalingPipeOnClose( eventData ); } ); + self.signalingPipe.on( "error", function( eventData ) { self.signalingPipeOnError( eventData ); } ); + self.signalingPipe.on( "message", function( eventData ) { self.signalingPipeOnRawMessage( eventData ); } ); + self.dispatchEvent( new UniversalDispatcherEvent( "signalingDidStarted", { detail: { actor: this } } ) ); + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( this.describe() + " error starting signaling pipe:", err ); + this.onError( err ); + } + } + signalingPipeClose() { + if( this.signalingPipe ) { + try { + if( settings.logging.net.signaling.disconnect ) + console.warn( this.describe() + " will close signaling pipe" ); + this.signalingPipe.offAll(); + this.signalingPipe.disconnect(); + if( settings.logging.net.signaling.disconnect ) + console.warn( this.describe() + " did closed signaling pipe" ); + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( this.describe() + " error closing signaling pipe:", err ); + } + this.signalingPipe = null; + this.dispatchEvent( new UniversalDispatcherEvent( "signalingClosed", { detail: { actor: this } } ) ); + } + } + signalingPipeOnOpen( eventData ) { + try { + this.dispatchEvent( new UniversalDispatcherEvent( "signalingOpened", { detail: { actor: this } } ) ); + if( settings.logging.net.signaling.connect ) + console.log( "+++ " + this.describe() + " did connected to " + this.strSignalingServerURL ); + const joImpersonateMessage = { + id: utils.randomCallID(), + method: "signalingImpersonate", + idCategory: "" + this.signalingOptions.idCategory, + idSpace: "" + this.signalingOptions.idSpace, + idRtcParticipant: "" + this.idRtcParticipant, + role: this.isCreator ? "creator" : "joiner" + }; + if( settings.logging.net.signaling.message ) + console.log( " <<< " + this.describe() + " message out", joImpersonateMessage ); + this.signalingPipe.send( joImpersonateMessage ); + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( this.describe() + " error sending impersonation to signaling pipe:", err ); + this.onError( err ); + } + } + signalingPipeOnClose( eventData ) { + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPipeClose", { detail: { actor: this } } ) ); + if( settings.logging.net.signaling.disconnect ) + console.warn( " !!! " + this.describe() + " signaling pipe closed for " + this.strSignalingServerURL ); + this.signalingPipeClose(); + } + signalingPipeOnError( eventData ) { + // alert( JSON.stringify( eventData ) ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPipeError", { detail: { actor: this, error: eventData } } ) ); + if( settings.logging.net.signaling.error ) + console.warn( " !!! " + this.describe() + " signaling pipe error for " + this.strSignalingServerURL + ", error is:", eventData ); + this.onError( eventData ); + this.signalingPipeClose(); + } + signalingPipeOnRawMessage( eventData ) { + try { + if( settings.logging.net.signaling.rawMessage ) + console.log( " >>> " + this.describe() + " raw signaling message received", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.signaling.message ) + console.log( " >>> " + this.describe() + " signaling message received", joMessage ); + this.signalingPipeOnMessage( joMessage ); + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( "Error handling raw message in " + this.describe() + ":", err ); + this.onError( err ); + } + } + signalingPipeOnMessage( joMessage ) { + switch ( joMessage.method ) { + case "signalingImpersonate": { + if( joMessage.error == null ) { + // OKay, impersonated + this.bWasImpersonated = true; + if( settings.logging.net.signaling.generic ) + console.log( "Success, " + this.describe() + " impersonated on signaling server" ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPassedImpersonation", { detail: { actor: this } } ) ); + this.onImpersonationComplete(); + } else { + if( settings.logging.net.signaling.error ) + console.warn( " >>> " + this.describe() + " signaling impersonation error", joMessage.error ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingFailedImpersonation", { detail: { actor: this, error: joMessage.error } } ) ); + this.onError( joMessage.error ); + } + } break; + default: + if( settings.logging.net.signaling.error ) + console.warn( " >>> " + this.describe() + " unhandled signaling message", joMessage ); + break; + } // switch( joMessage.method ) + } + onImpersonationComplete() { } + onOtherSideIdentified( idSomebodyOtherSide, idOffer ) { } // generic implementation should never be called +}; + +class RTCServerPeer extends RTCConnection { + constructor( rtcCreator, timeToPublishMilliseconds, timeToSignalingNegotiationMilliseconds, peerConfiguration, peerAdditionalOptions, localMediaStream ) { + super(); + this.rtcCreator = rtcCreator; + this.idSomebodyOtherSide = null; + this.idOffer = this.rtcCreator.idOfferNext ++; + this.tsOfferCreated = null; + if( settings.logging.net.signaling.offerRegister ) + console.log( "Register offer", this.idOffer, "(RTCServerPeer constructor)" ); + this.rtcCreator.map_server_offers[0 + this.idOffer] = this; + this.isPublishing = false; + this.isSignalingNegotiation = false; + this.isPublishTimeout = false; + this.isSignalingNegotiationTimeout = false; + this.timerPublishing = null; + this.timerSignalingNegotiation = null; + this.timeToPublishMilliseconds = timeToPublishMilliseconds + ? parseInt( timeToPublishMilliseconds, 10 ) + : settings.net.rtc.timeToPublishMilliseconds; + this.timeToSignalingNegotiationMilliseconds = timeToSignalingNegotiationMilliseconds + ? parseInt( timeToSignalingNegotiationMilliseconds, 10 ) + : settings.net.rtc.timeToSignalingNegotiationMilliseconds; + this.peerConfiguration = ( peerConfiguration && typeof peerConfiguration == "object" ) ? peerConfiguration : settings.net.rtc.peerConfiguration; + this.peerAdditionalOptions = ( peerAdditionalOptions && typeof peerAdditionalOptions == "object" ) ? peerAdditionalOptions : settings.net.rtc.peerAdditionalOptions; + this.localMediaStream = ( localMediaStream != null && localMediaStream != undefined && typeof localMediaStream == "object" ) ? localMediaStream : null; + this.isOfferPublishedOnSignalingServer = false; + this.initPeer(); + this.publish(); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.publishCancel(); + this.signalingNegotiationCancel(); + if( this.rtcCreator ) { + if( this.idOffer in this.rtcCreator.map_server_offers ) { + if( settings.logging.net.signaling.offerUnregister ) + console.log( "Unregister offer", this.idOffer, "(RTCServerPeer dispose)" ); + delete this.rtcCreator.map_server_offers[this.idOffer]; + } + this.idOffer = 0; + } + this.idOffer = 0; + if( this.idSomebodyOtherSide != null ) { + if( this.idSomebodyOtherSide in this.rtcCreator.map_server_peers ) + delete this.rtcCreator.map_server_peers[this.idSomebodyOtherSide]; + + this.idSomebodyOtherSide = null; + } + this.rtcCreator = null; + this.tsOfferCreated = null; + super.dispose(); + } + describe( strInstanceType, arrAdditionalProps ) { + strInstanceType = ( strInstanceType == null || strInstanceType == undefined || ( typeof strInstanceType != "string" ) || strInstanceType.length == 0 ) + ? "server-peer" + : strInstanceType; + // arrAdditionalProps = arrAdditionalProps || []; + return super.describe( strInstanceType, arrAdditionalProps ); + } + initPeer() { + if( this.isDisposed ) + return; + const self = this; + if( self.pc ) + return; + self.pc = new wrtc_mod.RTCPeerConnection( self.peerConfiguration, self.peerAdditionalOptions ); + if( self.localMediaStream ) { + for( const track of self.localMediaStream.getTracks() ) + self.pc.addTrack( track, self.localMediaStream ); + } else { + self.dc = self.pc.createDataChannel( settings.net.rtc.dataChannel.label, settings.net.rtc.dataChannel.opts ); + self.dc.addEventListener( "open", function( event ) { self.onDataChannelOpen( event ); } ); + self.dc.addEventListener( "close", function( event ) { self.onDataChannelClose( event ); } ); + self.dc.addEventListener( "error", function( event ) { self.onDataChannelError( event ); } ); + self.dc.addEventListener( "message", function( event ) { self.onDataChannelMessage( event ); } ); + } + } + publishCancel() { + if( ! this.isPublishing ) + return; + this.isOfferPublishedOnSignalingServer = false; + this.isPublishing = false; + if( this.timerPublishing ) { + clearTimeout( this.timerPublishing ); + this.timerPublishing = null; + } + this.signalingNegotiationCancel(); // mutual cancel + } + signalingNegotiationCancel() { + if( ! this.isSignalingNegotiation ) + return; + this.isSignalingNegotiation = false; + if( this.timerSignalingNegotiation ) { + clearTimeout( this.timerSignalingNegotiation ); + this.timerSignalingNegotiation = null; + } + this.publishCancel(); // mutual cancel + } + publish() { + if( this.isDisposed || this.isPublishing || this.isSignalingNegotiation || ( !this.rtcCreator ) || ( !this.rtcCreator.signalingPipe ) ) + return; + const self = this; + self.isPublishing = true; + if( self.timeToPublishMilliseconds > 0 ) { + self.isSignalingNegotiation = false; + self.timerPublishing = setTimeout( function() { + self.publishCancel(); + self.signalingNegotiationCancel(); + self.isPublishTimeout = true; + if( settings.logging.net.signaling.publishTimeout ) + console.warn( " !!! " + self.describe() + " offer publish timeout " + self.timeToPublishMilliseconds + " milliseconds reached" ); + self.dispatchEvent( new UniversalDispatcherEvent( "publishTimeout", { detail: { participant: self } } ) ); + if( self.rtcCreator ) + self.rtcCreator.dispatchEvent( new UniversalDispatcherEvent( "publishTimeout", { detail: { participant: self } } ) ); + }, self.timeToPublishMilliseconds ); + } // if( self.timeToPublishMilliseconds > 0 ) + self.dispatchEvent( new UniversalDispatcherEvent( "publishStart", { detail: { participant: self } } ) ); + self.pc.oniceconnectionstatechange = function( event ) { self.onIceConnectionStateChange( event ); }; + self.pc.onicegatheringstatechange = function( event ) { self.onIceGatheringStateChange( event ); }; + self.pc.onidentityresult = function( event ) { self.onIceIdentifyResult( event ); }; + self.pc.onsignalingstatechange = function( event ) { self.onIceSignalingStateChange( event ); }; + self.pc.onnegotiationneeded = function( event ) { self.onIceNegotiationNeeded( event ); }; + self.pc.createOffer( self.offerOptions ).then( + function( offerDescription ) { + // success + self.tsOfferCreated = new Date(); + if( settings.logging.net.signaling.offer ) + console.log( " <<< " + self.describe() + " offer created at " + utils.format_date_time( self.tsOfferCreated ) + " with description:", offerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "offerCreated", { detail: { participant: self } } ) ); + self.pc.setLocalDescription( offerDescription ).then( + function() { + // success + if( settings.logging.net.signaling.localDescription ) + console.log( " <<< " + self.describe() + " local description set:", offerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "localDescriptionSet", { detail: { participant: self } } ) ); + self.pc.onicecandidate = function( event ) { + self.iceComplete = true; + self.onIceComplete( event ); + }; // onicecandidate + }, function( err ) { + // error of setLocalDescription + self.publishCancel(); + self.signalingNegotiationCancel(); + self.onError( "Failed to set local description: " + err.toString() ); + } ); + }, function() { + self.publishCancel(); + self.signalingNegotiationCancel(); + // error of createOffer + self.onError( "Failed to create offer:" + err.toString() ); + } ); + } + onOtherSideIdentified( idSomebodyOtherSide ) { + this.publishCancel(); + this.signalingNegotiationCancel(); + this.idSomebodyOtherSide = "" + idSomebodyOtherSide; + this.wasIdentified = true; + this.dispatchEvent( new UniversalDispatcherEvent( "identified", { detail: { participant: this, idSomebodyOtherSide: "" + idSomebodyOtherSide } } ) ); + } + onError( err ) { + if( this.rtcCreator ) { + this.rtcCreator.onRtcPeerError( this, err ); + if( this.idOffer in this.rtcCreator.map_server_offers ) { + if( settings.logging.net.signaling.offerUnregister ) + console.log( "Unregister offer", this.idOffer, "due to RTCServerPeer error:".err ); + delete this.rtcCreator.map_server_offers[this.idOffer]; + } + this.idOffer = 0; + } + if( this.idSomebodyOtherSide != null ) { + if( this.idSomebodyOtherSide in this.rtcCreator.map_server_peers ) + delete this.rtcCreator.map_server_peers[this.idSomebodyOtherSide]; + this.idSomebodyOtherSide = null; + } + super.onError( err ); + } + onImpersonationCompleteForCreator() { // specific for server peer + if( settings.logging.net.signaling.creatorImpersonationComplete ) + console.log( "Creator impersonation complete" ); + } + publishOfferOnSignalingServer() { + const self = this; + try { + if( settings.logging.net.signaling.candidate ) + console.log( " <<< " + self.describe() + " got candidate", event ); + if( settings.logging.net.signaling.candidate ) + console.log( " <<< " + self.describe() + " got candidate", event ); + if( ! self.rtcCreator.signalingPipe ) + throw new Error( "no connection to signaling server" ); + const joPublishOfferMessage = { + id: utils.randomCallID(), + method: "signalingPublishOffer", + offer: self.pc.localDescription, + idSomebodyCreator: "" + self.rtcCreator.idRtcParticipant, + idOffer: 0 + self.idOffer + }; + if( settings.logging.net.signaling.message ) + console.log( " <<< " + self.describe() + " signaling message out", joPublishOfferMessage ); + self.rtcCreator.signalingPipe.send( joPublishOfferMessage ); + self.publishCancel(); + self.dispatchEvent( new UniversalDispatcherEvent( "signalingNegotiationStart", { detail: { participant: self } } ) ); + if( self.timeToSignalingNegotiationMilliseconds > 0 ) { + self.isSignalingNegotiation = true; + self.timerSignalingNegotiation = setTimeout( function() { + self.publishCancel(); + self.signalingNegotiationCancel(); + self.isSignalingNegotiationTimeout = true; + if( settings.logging.net.signaling.signalingNegotiationTimeout ) + console.warn( " !!! " + self.describe() + " signaling negotiation timeout " + self.timeToSignalingNegotiationMilliseconds + " milliseconds reached" ); + self.dispatchEvent( new UniversalDispatcherEvent( "signalingNegotiationTimeout", { detail: { participant: self } } ) ); + if( self.rtcCreator ) + self.rtcCreator.dispatchEvent( new UniversalDispatcherEvent( "signalingNegotiationTimeout", { detail: { participant: self } } ) ); + }, self.timeToSignalingNegotiationMilliseconds ); + } // if( self.timeToSignalingNegotiationMilliseconds > 0 ) + } catch ( err ) { + throw err; + } + } + onIceComplete( event ) { + super.onIceComplete( event ); + const self = this; + try { + if( event.candidate == null || settings.net.rtc.fastPublishMode.serverPeer ) { + if( ! self.isOfferPublishedOnSignalingServer ) { + self.isOfferPublishedOnSignalingServer = true; + self.publishOfferOnSignalingServer(); + } + } + if( event.candidate != null ) { + if( settings.logging.net.signaling.candidateWalk ) + console.log( " <<< " + self.describe() + " got candidate", event ); + } + } catch ( err ) { + self.publishCancel(); + self.signalingNegotiationCancel(); + self.onError( "Failed to process ICE candidate: " + err.toString() ); + } + } +}; + +class RTCCreator extends RTCActor { + constructor( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions ) { + super( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions ); + const self = this; + self.idOfferNext = 1; + self.isCreator = true; + self.map_server_offers = { }; // idOffer -> RTCServerPeer + self.map_server_peers = { }; // idSomebodyOtherSide -> RTCServerPeer + self.signalingPipeOpen(); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + for( const [ idOffer, rtcPeer ] of Object.entries( this.map_server_offers ) ) { + if( settings.logging.net.signaling.offerUnregister ) + console.log( "Unregister offer", idOffer, "(one of all, RTCCreator dispose)" ); + rtcPeer.dispose(); + } + for( const [ /*idSomebodyOtherSide*/, rtcPeer ] of Object.entries( this.map_server_peers ) ) + rtcPeer.dispose(); + this.map_server_offers = { }; + // self.idOfferNext = 0; + super.dispose(); + } + describe( strInstanceType, arrAdditionalProps ) { + strInstanceType = ( strInstanceType == null || strInstanceType == undefined || ( typeof strInstanceType != "string" ) || strInstanceType.length == 0 ) + ? "rtc-creator" + : strInstanceType; + // arrAdditionalProps = arrAdditionalProps || []; + return super.describe( strInstanceType, arrAdditionalProps ); + } + onOtherSideIdentified( idSomebodyOtherSide, idOffer ) { // server peer got result + if( settings.logging.net.signaling.impersonate ) + console.log( this.describe() + " did identified other side RTC joiner \"" + idSomebodyOtherSide + "\" via offer ID " + idOffer.toString() ); + if( ! ( idOffer in this.map_server_offers ) ) { + const strError = "not a registered pending offer(onOtherSideIdentified)"; + if( settings.logging.net.signaling.error ) + console.warn( " >>> " + this.describe() + " came across with incorrect other side identification for *somebody*", idSomebodyOtherSide, "and offer ID", idOffer, ":".strError ); + this.onError( strError ); + return; + } + const rtcPeer = this.map_server_offers[idOffer]; + if( settings.logging.net.signaling.offerUnregister ) + console.log( "Unregister offer", idOffer, "(onOtherSideIdentified in RTCCreator)" ); + delete this.map_server_offers[idOffer]; + this.map_server_peers["" + idSomebodyOtherSide] = rtcPeer; + rtcPeer.onOtherSideIdentified( "" + idSomebodyOtherSide ); + } + onRtcPeerError( rtcPeer, err ) { + if( settings.logging.net.rtc.error ) + console.warn( " !!! " + this.describe() + " rtc peer error", err ); + this.dispatchEvent( new UniversalDispatcherEvent( "rtcPeerError", { detail: { actor: this, peer: rtcPeer, error: err } } ) ); + } + signalingPipeOnMessage( joMessage ) { + const self = this; + switch ( joMessage.method ) { + case "signalingPublishOffer": { + if( joMessage.error == null ) { + // OKay, creator offer published + if( settings.logging.net.signaling.offer ) + console.log( "Success, " + this.describe() + " offer published (step 1)" ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPassedOfferPublish", { detail: { actor: this } } ) ); + } else { + if( settings.logging.net.signaling.error ) + console.warn( " !!! " + this.describe() + " signaling offer publishing (step 1) error", joMessage.error ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingFailedOfferPublish", { detail: { actor: this, error: joMessage.error } } ) ); + this.onError( joMessage.error ); + } + } break; + case "signalingPublishAnswer": { // server peer got result + if( joMessage.error == null ) { + const idSomebodyOtherSide = "" + joMessage.idSomebody_joiner; + const idOffer = 0 + joMessage.idOffer; + if( ! ( idOffer in this.map_server_offers ) ) { + const strError = "not a registered pending offer(signalingPublishAnswer)"; + if( settings.logging.net.signaling.error ) + console.warn( " !!! " + this.describe() + " came across with incorrect signalingPublishAnswer message for *somebody*", idSomebodyOtherSide, "and offer ID", idOffer, ":", strError ); + this.onError( strError ); + return; + } + const rtcPeer = this.map_server_offers[idOffer]; + // OKay, finally got answer from candida + if( settings.logging.net.signaling.generic ) + console.log( "Success, " + this.describe() + " got answer from candidate (step 3)" ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPassedPublishAnswer", { detail: { actor: this, idSomebodyOtherSide: "" + idSomebodyOtherSide, idOffer: 0 + idOffer } } ) ); + const answer = joMessage.answer; + if( settings.logging.net.signaling.offer ) + console.log( " >>> " + self.describe() + " got answer:", answer ); + const answerDescription = new wrtc_mod.RTCSessionDescription( answer ); + if( settings.logging.net.signaling.offer ) + console.log( " >>> " + self.describe() + " got answer description:", answerDescription ); + // console.log( "----- will set remote desc when in state", rtcPeer.pc.signalingState ); + if( rtcPeer.pc.signalingState != "have-local-offer" ) { + if( settings.logging.net.signaling.offerSkipPublishedAnswer ) + console.warn( " >>> " + self.describe() + " in \"" + rtcPeer.pc.signalingState + "\" state will skip setting remote description from answer", answerDescription ); + return; + } + rtcPeer.pc.setRemoteDescription( answerDescription ).then( + function() { + // success + if( settings.logging.net.signaling.remoteDescription ) + console.log( " >>> " + self.describe() + "did set remote description:", answerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "remoteDescriptionSet", { detail: { participant: self } } ) ); + self.onOtherSideIdentified( idSomebodyOtherSide, idOffer ); // server peer got result + }, function( err ) { + // error + self.onError( "Failed to set remote description: " + err.toString() ); + } ); + } else { + if( settings.logging.net.signaling.error ) + console.warn( " !!! " + this.describe() + " error getting candidate answer (step 1) error", joMessage.error ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingFailedPublishAnswer", { detail: { actor: this, error: joMessage.error } } ) ); + this.onError( joMessage.error ); + } + } break; + default: + super.signalingPipeOnMessage( joMessage ); + break; + } // switch( joMessage.method ) + } + send( data ) { // implementation in RTCCreator does send to all + try { + const s = socket_sent_data_marshall( data ); + for( const [ /*idSomebodyOtherSide*/, rtcPeer ] of Object.entries( this.map_server_peers ) ) { + try { + rtcPeer.send( s ); + } catch ( err ) { + this.onRtcPeerError( rtcPeer, err ); + } + } + } catch ( err ) { + this.onError( err ); + } + } + onImpersonationComplete() { + super.onImpersonationComplete(); + for( const [ /*idOffer*/, rtcPeer ] of Object.entries( this.map_server_offers ) ) + rtcPeer.onImpersonationCompleteForCreator(); + for( const [ /*idSomebodyOtherSide*/, rtcPeer ] of Object.entries( this.map_server_peers ) ) + rtcPeer.onImpersonationCompleteForCreator(); + } +}; + +class RTCJoiner extends RTCActor { + constructor( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions, peerConfiguration, peerAdditionalOptions ) { + super( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions ); + this.idSomebodyOtherSide = null; + this.idOffer = 0; + this.isJoiner = true; + this.tsAnswerCreated = null; + this.isAnswerPublishedOnSignalingServer = false; + this.signalingPipeOpen(); + this.peerConfiguration = ( peerConfiguration && typeof peerConfiguration == "object" ) ? peerConfiguration : settings.net.rtc.peerConfiguration; + this.peerAdditionalOptions = ( peerAdditionalOptions && typeof peerAdditionalOptions == "object" ) ? peerAdditionalOptions : settings.net.rtc.peerAdditionalOptions; + // this.initPeer(); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.idSomebodyOtherSide = null; + this.idOffer = 0; + this.tsAnswerCreated = null; + this.isAnswerPublishedOnSignalingServer = false; + super.dispose(); + } + describe( strInstanceType, arrAdditionalProps ) { + strInstanceType = ( strInstanceType == null || strInstanceType == undefined || ( typeof strInstanceType != "string" ) || strInstanceType.length == 0 ) + ? "rtc-joiner" + : strInstanceType; + // arrAdditionalProps = arrAdditionalProps || []; + return super.describe( strInstanceType, arrAdditionalProps ); + } + initPeer() { + if( this.isDisposed ) + return; + const self = this; + if( self.pc ) + return; + self.pc = new wrtc_mod.RTCPeerConnection( self.peerConfiguration, self.peerAdditionalOptions ); + self.pc.addEventListener( "track", function( event ) { + self.dispatchEvent( new UniversalDispatcherEvent( "trackAvailable", { detail: { participant: self, event: event } } ) ); + } ); + self.pc.oniceconnectionstatechange = function( event ) { self.onIceConnectionStateChange( event ); }; + self.pc.onicegatheringstatechange = function( event ) { self.onIceGatheringStateChange( event ); }; + self.pc.onidentityresult = function( event ) { self.onIceIdentifyResult( event ); }; + self.pc.onsignalingstatechange = function( event ) { self.onIceSignalingStateChange( event ); }; + self.pc.onnegotiationneeded = function( event ) { self.onIceNegotiationNeeded( event ); }; + self.pc.ondatachannel = function( event ) { + self.dispatchEvent( new UniversalDispatcherEvent( "dataChannelAvailable", { detail: { participant: self, event: event } } ) ); + const dataChannel = event.channel || event; + self.dc = dataChannel; + self.dc.addEventListener( "open", function( event ) { self.onDataChannelOpen( event ); } ); + self.dc.addEventListener( "close", function( event ) { self.onDataChannelClose( event ); } ); + self.dc.addEventListener( "error", function( event ) { self.onDataChannelError( event ); } ); + self.dc.addEventListener( "message", function( event ) { self.onDataChannelMessage( event ); } ); + }; + self.pc.onicecandidate = function( event ) { + self.iceComplete = true; + self.onIceComplete( event ); + try { + if( ! self.signalingPipe ) { + if( self.dc ) + return; // already connected, ignore (Firefox fix) + // if( self.pc && self.pc.onicecandidate ) + // self.pc.onicecandidate = null; + throw new Error( "no connection to signaling server" ); + } + if( ! self.isAnswerPublishedOnSignalingServer ) { + self.publishSignalingAnswer( event ); + self.iAnswerPublishedOnSignalingServer = true; + } + if( event.candidate != null ) { + if( settings.logging.net.signaling.candidateWalk ) + console.log( " <<< " + self.describe() + " got candidate", event ); + } + } catch ( err ) { + // self.publishCancel(); + // self.signalingNegotiationCancel(); + self.onError( "Failed to process ICE candidate: " + err.toString() ); + } + }; // onicecandidate + } + publishSignalingAnswer( event ) { + const self = this; + try { + if( event.candidate == null || settings.net.rtc.fastPublishMode.joiner ) { + if( settings.logging.net.signaling.candidate ) + console.log( " <<< " + self.describe() + " got candidate", event ); + if( ! self.signalingPipe ) + throw new Error( "no connection to signaling server" ); + const joPublishAnswerMessage = { + id: utils.randomCallID(), + method: "signalingPublishAnswer", + answer: self.pc.localDescription, + idRtcParticipant: "" + self.idRtcParticipant, + idSomebodyCreator: "" + self.idSomebodyCreator, + idOffer: 0 + self.idOffer + }; + if( settings.logging.net.signaling.message ) + console.log( " <<< " + self.describe() + " signaling client message out", joPublishAnswerMessage ); + self.signalingPipe.send( joPublishAnswerMessage ); + } + } catch ( err ) { + throw err; + } + } + delayedInitPeer() { + if( this.bWasImpersonated ) + this.initPeer(); + } + onImpersonationComplete() { + super.onImpersonationComplete(); + const joFetchOfferMessage = { + id: utils.randomCallID(), + method: "signalingFetchOffer" + }; + if( settings.logging.net.signaling.message ) + console.log( " <<< " + this.describe() + " signaling client message out", joFetchOfferMessage ); + this.signalingPipe.send( joFetchOfferMessage ); + } + onIceComplete( event ) { + super.onIceComplete( event ); + } + onOtherSideIdentified( idSomebodyOtherSide, idOffer ) { // client peer got result + if( settings.logging.net.signaling.impersonate ) + console.log( this.describe() + " did identified other side RTC creator \"" + idSomebodyOtherSide + "\" via offer ID " + idOffer.toString() ); + this.idSomebodyOtherSide = "" + idSomebodyOtherSide; + this.idOffer = 0 + idOffer; + this.wasIdentified = true; + this.dispatchEvent( new UniversalDispatcherEvent( "identified", { detail: { participant: this, idSomebodyOtherSide: "" + idSomebodyOtherSide } } ) ); + } + signalingPipeOnMessage( joMessage ) { + const self = this; + switch ( joMessage.method ) { + case "signalingFetchOffer": { + if( joMessage.error == null ) { + // OKay, fetched offer from creator + this.delayedInitPeer(); + this.idSomebodyCreator = "" + joMessage.idSomebodyCreator; + const idSomebodyOtherSide = "" + joMessage.idSomebodyCreator; + const idOffer = 0 + joMessage.idOffer; + if( settings.logging.net.signaling.generic ) + console.log( "Success, " + this.describe() + " fetched offer from creator (step 2)" ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingPassedFetchOffer", { detail: { actor: this, idSomebodyOtherSide: "" + idSomebodyOtherSide, idOffer: 0 + idOffer } } ) ); + const offer = joMessage.offer; + if( settings.logging.net.signaling.offer ) + console.log( " <<< " + self.describe() + " got offer:", offer ); + const offerDescription = new wrtc_mod.RTCSessionDescription( offer ); + if( settings.logging.net.signaling.offer ) + console.log( " <<< " + self.describe() + " got offer description:", offerDescription ); + this.pc.setRemoteDescription( offerDescription ).then( + function() { + // success + if( settings.logging.net.signaling.remoteDescription ) + console.log( " <<< " + self.describe() + "did set remote description:", offerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "remoteDescriptionSet", { detail: { participant: self } } ) ); + self.pc.createAnswer( self.offerOptions ).then( + function( answerDescription ) { + // success + self.tsAnswerCreated = new Date(); + if( settings.logging.net.signaling.answer ) + console.log( " <<< " + self.describe() + "did created answer at " + utils.format_date_time( self.tsAnswerCreated ) + " with description:", answerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "answerCreated", { detail: { participant: self } } ) ); + self.pc.setLocalDescription( answerDescription ).then( + function() { + // success + if( settings.logging.net.signaling.localDescription ) + console.log( " <<< " + self.describe() + " local description set:", answerDescription ); + self.dispatchEvent( new UniversalDispatcherEvent( "localDescriptionSet", { detail: { participant: self } } ) ); + self.onOtherSideIdentified( idSomebodyOtherSide, idOffer ); // client peer got result + }, function( err ) { + // error of setLocalDescription + self.onError( "Failed to set local description (while fetching offer for \"" + idSomebodyOtherSide + "\"): " + err.toString() ); + } ); + }, function( err ) { + // error of createAnswer + self.onError( "Failed to create answer (while fetching offer for \"" + idSomebodyOtherSide + "\"): " + err.toString() ); + } ); + }, function( err ) { + // error of setLocalDescription + self.onError( "Failed to set remote description: (while fetching offer for \"" + idSomebodyOtherSide + "\"): " + err.toString() ); + } ); + } else { + if( settings.logging.net.signaling.error ) + console.warn( " !!! " + this.describe() + " signaling offer publishing (step 1) error", joMessage.error ); + this.dispatchEvent( new UniversalDispatcherEvent( "signalingFailedFetchOffer", { detail: { actor: this, error: joMessage.error } } ) ); + this.onError( joMessage.error ); + } + } break; + default: + super.signalingPipeOnMessage( joMessage ); + break; + } // switch( joMessage.method ) + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class WebRTCServerPipe extends BasicSocketPipe { + constructor( acceptor, rtcPeer, strSignalingServerURL ) { + super(); + const self = this; + self.socketType = "WebRTC"; + self.socketSubtype = "server"; + self.isConnected = true; + self.acceptor = acceptor; + self.clientNumber = 0 + acceptor.nextClientNumber; + self.clientPort = 0 + self.clientNumber; + ++ acceptor.nextClientNumber; + self.rtcPeer = rtcPeer; + self.strSignalingServerURL = utils.makeValidSignalingServerURL( strSignalingServerURL ); + self.url = "rtc_server_pipe(" + self.clientNumber + ")://" + strSignalingServerURL; + // self.rtcPeer.on( "identified", function( event ) { + // if( settings.logging.net.signaling.generic ) + // console.log( self.describe() + " is now identified peer", event.detail.idSomebodyOtherSide ); + // } ); + self.rtcPeer.on( "dataChannelOpen", function( jo ) { + self.isConnected = true; + self.acceptor.mapClients["" + self.clientPort] = self; + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + self.acceptor.dispatchEvent( new UniversalDispatcherEvent( "connection", { socket: self, strSignalingServerURL: "" + strSignalingServerURL } ) ); + } ); + self.rtcPeer.on( "dataChannelMessage", function( jo ) { + self.receive( jo.detail.data ); + } ); + self.rtcPeer.on( "rtcParticipantError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo } ) ); + } ); + self.rtcPeer.on( "dataChannelError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo } ) ); + } ); + self.rtcPeer.on( "dataChannelClose", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: self, message: jo } ) ); + } ); + self.rtcPeer.on( "peerClose", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: self, message: jo } ) ); + } ); + } + dispose() { + this.performDisconnect(); + super.dispose(); + } + handleServerDisposed() { + this.performDisconnect(); + this.isConnected = false; + this.clientNumber = 0; + this.acceptor = null; + this.rtcPeer = null; + this.url = ""; + this.strSignalingServerURL = ""; + super.handleServerDisposed(); + this.dispose(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.isConnected = false; + if( this.acceptor ) + this.acceptor.unregisterClientByKey( this.clientPort ); + if( this.rtcPeer ) { + this.rtcPeer.offAll(); + this.rtcPeer = null; + } + this.clientNumber = 0; + this.acceptor = null; + this.url = ""; + this.strSignalingServerURL = ""; + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.rtcPeer ) ) { + const err = "Cannot send messages to disconnected WebRTC socket server pipe"; + this.onError( err ); + throw err; + } + const s = socket_sent_data_marshall( data ); + this.rtcPeer.send( s ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } + impl_receive( data ) { + const jo = socket_received_data_reverse_marshall( data ); + this.dispatchEvent( new UniversalDispatcherEvent( "message", { socket: this, message: jo } ) ); + } +}; + +class WebRTCServerAcceptor extends BasicServerAcceptor { + constructor( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions, maxActiveOfferCount, timeToPublishMilliseconds, timeToSignalingNegotiationMilliseconds, peerConfiguration, peerAdditionalOptions ) { + super(); + this.strSignalingServerURL = utils.makeValidSignalingServerURL( strSignalingServerURL ); + this.idRtcParticipant = "" + ( ( idRtcParticipant != null && idRtcParticipant != undefined && typeof idRtcParticipant == "string" && idRtcParticipant.length > 0 ) ? idRtcParticipant : utils.uuid_v4() ); + this.offerOptions = offerOptions ? offerOptions : null; + this.signalingOptions = signalingOptions ? signalingOptions : null; + this.peerConfiguration = ( peerConfiguration && typeof peerConfiguration == "object" ) ? peerConfiguration : settings.net.rtc.peerConfiguration; + this.peerAdditionalOptions = ( peerAdditionalOptions && typeof peerAdditionalOptions == "object" ) ? peerAdditionalOptions : settings.net.rtc.peerAdditionalOptions; + this.socketType = "WebRTC"; + this.maxActiveOfferCount = ( maxActiveOfferCount != null && maxActiveOfferCount != undefined ) ? parseInt( maxActiveOfferCount, 10 ) : settings.net.rtc.maxActiveOfferCount; + if( this.maxActiveOfferCount < 1 ) + this.maxActiveOfferCount = 1; + this.mapPendingOffers = { }; // idOffer -> RTCServerPeer + this.timeToPublishMilliseconds = timeToPublishMilliseconds + ? parseInt( timeToPublishMilliseconds, 10 ) + : settings.net.rtc.timeToPublishMilliseconds; + this.timeToSignalingNegotiationMilliseconds = timeToSignalingNegotiationMilliseconds + ? parseInt( timeToSignalingNegotiationMilliseconds, 10 ) + : settings.net.rtc.timeToSignalingNegotiationMilliseconds; + this.rtcCreator = new RTCCreator( "" + this.strSignalingServerURL, "" + this.idRtcParticipant, this.offerOptions, this.signalingOptions ); + this.isListening = true; + const self = this; + this.rtcCreator.on( "signalingPassedImpersonation", function( eventData ) { + self.updateAllPendingOffers(); + self.dispatchEvent( new UniversalDispatcherEvent( "signalingPassedImpersonation", { detail: { acceptor: self } } ) ); + } ); + this.rtcCreator.on( "signalingFailedImpersonation", function( eventData ) { + self.dispatchEvent( new UniversalDispatcherEvent( "signalingFailedImpersonation", { detail: { acceptor: self } } ) ); + } ); + this.rtcCreator.on( "error", function( eventData ) { + self.dispatchEvent( new UniversalDispatcherEvent( "error", { detail: { acceptor: self, eventData: eventData, errorType: "rtcCreatorError" } } ) ); + } ); + this.rtcCreator.on( "close", function( eventData ) { + self.dispatchEvent( new UniversalDispatcherEvent( "close", { detail: { acceptor: self, eventData: eventData } } ) ); + } ); + self.rtcCreator.on( "signalingPipeError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo, errorType: "signalingPipeError" } ) ); + } ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.removeAllPendingOffers(); + if( this.rtcCreator ) { + this.rtcCreator.dispose(); + this.rtcCreator = null; + } + this.disposeNotifyClients(); + super.dispose(); + } + // flush() { + // if( this.isDisposed ) + // return; + // if( this.rtcCreator ) { + // for( const [ /*idSomebodyOtherSide*/, rtcPeer ] of Object.entries( this.rtcCreator.map_server_peers ) ) { + // const serverPipe = rtcPeer.serverPipe; + // serverPipe.flush(); + // } + // } + // } + addPendingOffer() { + if( this.isDisposed ) + return; + const rtcPeer = new RTCServerPeer( this.rtcCreator, this.timeToPublishMilliseconds, this.timeToSignalingNegotiationMilliseconds, this.peerConfiguration, this.peerAdditionalOptions ); + const self = this; + rtcPeer.on( "identified", function( event ) { + if( rtcPeer.isDisposing || rtcPeer.isDisposed ) + return; + if( settings.logging.net.signaling.generic ) + console.log( self.rtcCreator.describe() + " is now identified peer", event.detail.idSomebodyOtherSide ); + rtcPeer.serverPipe = new WebRTCServerPipe( self, rtcPeer, self.strSignalingServerURL ); + self.detachPendingOffer( rtcPeer.idOffer ); + self.dispatchEvent( new UniversalDispatcherEvent( "identified", { detail: { peer: rtcPeer } } ) ); + self.updateAllPendingOffers(); + } ); + rtcPeer.on( "localDescriptionSet", function( event ) { + self.dispatchEvent( new UniversalDispatcherEvent( "peerLocalDescriptionSet", { detail: { acceptor: self, peerEvent: event } } ) ); + } ); + const onTimeoutHandler = function() { + self.disposePendingOffer( rtcPeer.idOffer ); + self.updateAllPendingOffers(); + }; + rtcPeer.on( "publishTimeout", onTimeoutHandler ); + rtcPeer.on( "signalingNegotiationTimeout", onTimeoutHandler ); + rtcPeer.on( "signalingNegotiationStart", function() { + self.updateAllPendingOffers(); + } ); + + const retranslateError = function( eventData ) { + self.dispatchEvent( new UniversalDispatcherEvent( "error", { detail: { acceptor: self, rtcPeer: rtcPeer, eventData: eventData, errorType: "rtcPeerError" } } ) ); + }; + rtcPeer.on( "error", retranslateError ); + rtcPeer.on( "rtcPeerError", retranslateError ); + + this.mapPendingOffers[rtcPeer.idOffer] = rtcPeer; + } + detachPendingOffer( idOffer ) { + if( idOffer in this.mapPendingOffers ) + delete this.mapPendingOffers[idOffer]; + } + disposePendingOffer( idOffer ) { + if( idOffer in this.mapPendingOffers ) { + const rtcPeer = this.mapPendingOffers[idOffer]; + rtcPeer.dispose(); + delete this.mapPendingOffers[idOffer]; + } + } + removeAllPendingOffers() { + for( const [ /*idOffer*/, rtcPeer ] of Object.entries( this.rtcCreator.map_server_peers ) ) { + const serverPipe = rtcPeer.serverPipe; + serverPipe.dispose(); + } + this.rtcCreator.map_server_peers = { }; + for( const [ /*idOffer*/, rtcPeer ] of Object.entries( this.rtcCreator.mapPendingOffers ) ) + rtcPeer.dispose(); + + this.mapPendingOffers = { }; + } + updateAllPendingOffers() { + if( this.isDisposed ) + return; + for( let n = Object.keys( this.mapPendingOffers ); n < this.maxActiveOfferCount; ++ n ) + this.addPendingOffer(); + } +}; + +class WebRTCClientPipe extends BasicSocketPipe { + constructor( strSignalingServerURL, idRtcParticipant, offerOptions, signalingOptions, peerConfiguration, peerAdditionalOptions ) { + super(); + this.strSignalingServerURL = utils.makeValidSignalingServerURL( strSignalingServerURL ); + this.idRtcParticipant = "" + ( ( idRtcParticipant != null && idRtcParticipant != undefined && typeof idRtcParticipant == "string" && idRtcParticipant.length > 0 ) ? idRtcParticipant : utils.uuid_v4() ); + this.offerOptions = offerOptions ? offerOptions : null; + this.signalingOptions = signalingOptions ? signalingOptions : null; + this.peerConfiguration = ( peerConfiguration && typeof peerConfiguration == "object" ) ? peerConfiguration : settings.net.rtc.peerConfiguration; + this.peerAdditionalOptions = ( peerAdditionalOptions && typeof peerAdditionalOptions == "object" ) ? peerAdditionalOptions : settings.net.rtc.peerAdditionalOptions; + this.socketType = "WebRTC"; + this.socketSubtype = "client"; + this.isConnected = false; + this.rtcPeer = null; + this.isAutoCloseSignalingPipeOnDataChannelOpen = settings.net.rtc.isAutoCloseSignalingPipeOnDataChannelOpen ? true : false; + this.url = "rtc_client_pipe-" + this.strSignalingServerURL; + this.reconnect(); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + this.performDisconnect(); + this.strSignalingServerURL = null; + super.dispose(); + } + impl_send( data ) { + if( ( !this.isConnected ) || ( !this.rtcPeer ) ) { + const s = "Cannot send messages to disconnected WebRTC socket client pipe"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s, errorType: "dataSendError" } ) ); + throw new Error( s ); + } + const s = socket_sent_data_marshall( data ); + this.rtcPeer.send( s ); + } + reconnect() { + this.performDisconnect(); + this.rtc_connect( "" + this.strSignalingServerURL ); + } + disconnect() { + this.performDisconnect(); + super.disconnect(); + } + performDisconnect() { + if( ! this.isConnected ) + return; + this.rtc_disconnect(); + } + rtc_connect( strSignalingServerURL ) { + if( strSignalingServerURL.length == 0 ) { + const s = "Cannot connect signaling server \"" + strSignalingServerURL + "\", bad url"; + this.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: this, message: "" + s, errorType: "badSignalingServerURL" } ) ); + throw new Error( s ); + } + const self = this; + while( true ) { + try { + if( self.isConnected || self.rtcPeer ) + self.rtc_disconnect(); + self.rtcPeer = new RTCJoiner( "" + strSignalingServerURL, "" + self.idRtcParticipant, self.offerOptions, self.signalingOptions, self.peerConfiguration, self.peerAdditionalOptions ); // client side + self.strSignalingServerURL = utils.makeValidSignalingServerURL( strSignalingServerURL ); + self.rtcPeer.on( "identified", function( event ) { + if( settings.logging.net.signaling.generic ) + console.log( self.rtcPeer.describe() + " is now identified peer", event.detail.idSomebodyOtherSide ); + } ); + self.rtcPeer.on( "dataChannelOpen", function( jo ) { + self.isConnected = true; + self.dispatchEvent( new UniversalDispatcherEvent( "open", { socket: self } ) ); + if( self.isAutoCloseSignalingPipeOnDataChannelOpen ) { + if( settings.logging.net.signaling.disconnect ) + console.warn( self.rtcPeer.describe() + " will auto-close signaling pipe(inside socket \"dataChannelOpen\" handler)" ); + self.rtcPeer.signalingPipeClose(); + } + } ); + self.rtcPeer.on( "dataChannelMessage", function( jo ) { + self.receive( jo.detail.data ); + } ); + self.rtcPeer.on( "rtcParticipantError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo, errorType: "rtcParticipantError" } ) ); + } ); + self.rtcPeer.on( "dataChannelError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo, errorType: "dataChannelError" } ) ); + } ); + self.rtcPeer.on( "dataChannelClose", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "close", { socket: self, message: jo } ) ); + } ); + self.rtcPeer.on( "signalingPipeError", function( jo ) { + self.isConnected = false; + self.dispatchEvent( new UniversalDispatcherEvent( "error", { socket: self, message: jo, errorType: "signalingPipeError" } ) ); + } ); + return; + } catch ( err ) { + console.warn( "WebRTC client connect error:", err ); + continue; + } + } // while( true ) + } + rtc_disconnect() { + if( this.rtcPeer ) { + this.rtcPeer.offAll(); + this.rtcPeer.dispose(); + this.rtcPeer = null; + } + this.isConnected = false; + this.url = ""; + } + impl_receive( data ) { + const jo = socket_received_data_reverse_marshall( data ); + this.dispatchEvent( new UniversalDispatcherEvent( "message", { socket: this, message: jo } ) ); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +module.exports = { + https_mod: https_mod, + ws_mod: ws_mod, + wrtc_mod: wrtc_mod, + set_https_mod: set_https_mod, + set_ws_mod: set_ws_mod, + set_wrtc_mod: set_wrtc_mod, + g_mapLocalServers: g_mapLocalServers, + socket_sent_data_marshall: socket_sent_data_marshall, + socket_received_data_reverse_marshall: socket_received_data_reverse_marshall, + update_socket_data_stats_for_message: update_socket_data_stats_for_message, + generate_socket_data_stats_JSON: generate_socket_data_stats_JSON, + BasicServerAcceptor: BasicServerAcceptor, + BasicSocketPipe: BasicSocketPipe, + NullSocketPipe: NullSocketPipe, + is_running_in_worker: is_running_in_worker, + g_map_awaiting_in_worker_clients: g_map_awaiting_in_worker_clients, + g_map_connected_in_worker_clients: g_map_connected_in_worker_clients, + out_of_worker_apis: out_of_worker_apis, + in_worker_apis: in_worker_apis, + InWorkerServerPipe: InWorkerServerPipe, + InWorkerSocketServerAcceptor: InWorkerSocketServerAcceptor, + OutOfWorkerSocketClientPipe: OutOfWorkerSocketClientPipe, + OutOfWorkerRelay: OutOfWorkerRelay, + OneToOneRelay: OneToOneRelay, + DirectPipe: DirectPipe, + LocalSocketServerPipe: LocalSocketServerPipe, + LocalSocketServerAcceptor: LocalSocketServerAcceptor, + LocalSocketClientPipe: LocalSocketClientPipe, + WebSocketServerPipe: WebSocketServerPipe, + WebSocketServerAcceptor: WebSocketServerAcceptor, + WebSocketClientPipe: WebSocketClientPipe, + RTCConnection: RTCConnection, + RTCActor: RTCActor, + RTCServerPeer: RTCServerPeer, + RTCCreator: RTCCreator, + RTCJoiner: RTCJoiner, + WebRTCServerPipe: WebRTCServerPipe, + WebRTCServerAcceptor: WebRTCServerAcceptor, + WebRTCClientPipe: WebRTCClientPipe +}; diff --git a/npms/skale-cool-socket/test.js b/npms/skale-cool-socket/test.js new file mode 100644 index 000000000..dd9183dd2 --- /dev/null +++ b/npms/skale-cool-socket/test.js @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file test.js + * @copyright SKALE Labs 2019-Present + */ + +const network_layer = require( "./socket.js" ); +const { TestServer } = require( "./test_server.js" ); +const { Worker } = require( "worker_threads" ); +const { settings } = require( "./settings.js" ); +const ws = require( "ws" ); +// const wrtc = require( "wrtc" ); + +const joTestMessage = { "method": "echo", "message": "Please echo this message!" }; + +const sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; + +async function test_local() { + console.log( "Local test" ); + const strEndPoint = "local_endpoint"; + const acceptor = new network_layer.LocalSocketServerAcceptor( strEndPoint ); + const server = new TestServer( acceptor ); + const client = new network_layer.LocalSocketClientPipe( strEndPoint ); + client.on( "message", function( eventData ) { + const joMessage = eventData.message; + console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); + client.disconnect(); + console.log( " " ); + } ); + await sleep( 1 ); + console.log( "CLIENT >>>", JSON.stringify( joTestMessage ) ); + client.send( joTestMessage ); + await sleep( 100 ); + const joReturnValue = { + server: server, + client: client + }; + return joReturnValue; +} + +async function test_worker() { + console.log( "Worker test" ); + const url = "local_worker_server"; + const worker = new Worker( "./test_worker.js" ); + console.log( "Will connect to " + url ); + worker.on( "message", jo => { + if( network_layer.out_of_worker_apis.on_message( worker, jo ) ) + return; + } ); + const client = new network_layer.OutOfWorkerSocketClientPipe( url, worker ); + client.on( "message", function( eventData ) { + const joMessage = eventData.message; + console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); + client.disconnect(); + worker.terminate(); + console.log( " " ); + } ); + await sleep( 100 ); + console.log( "CLIENT >>>", JSON.stringify( joTestMessage ) ); + client.send( joTestMessage ); + await sleep( 100 ); + const joReturnValue = { + worker: worker, + client: client + }; + return joReturnValue; +} + +async function test_web_socket() { + console.log( "Web socket test" ); + network_layer.set_ws_mod( ws ); + const nPort = 33123; + const url = ( settings.net.secure ? "wss" : "ws" ) + "://127.0.0.1:" + nPort; + const key = settings.net.secure ? fs.readFileSync( "./self-signed/self-signed-key.pem", "utf8" ) : null; + const cert = settings.net.secure ? fs.readFileSync( "./self-signed/self-signed-cert.pem", "utf8" ) : null; + const acceptor = new network_layer.WebSocketServerAcceptor( nPort, key, cert ); + const server = new TestServer( acceptor ); + const client = new network_layer.WebSocketClientPipe( url ); + client.on( "message", function( eventData ) { + const joMessage = eventData.message; + console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); + client.disconnect(); + console.log( " " ); + } ); + await sleep( 100 ); + console.log( "CLIENT >>>", JSON.stringify( joTestMessage ) ); + client.send( joTestMessage ); + await sleep( 100 ); + const joReturnValue = { + server: server, + client: client + }; + return joReturnValue; +} + +// async function test_wrtc() { +// // +// // Needed in package.json: "wrtc": "^0.4.6", +// // +// // ## Coturn - own STUN and/or TURN server +// // +// // See and see +// // Explanation for Mac OSX is +// // +// // Install via **sudo apt-get install coturn** or **brew install coturn**. +// // Run **sudo nano /etc/turnserver.conf** and specify described in , +// // realm **realm=origin/realm**, **no-tls** and **no-dtls**. Also set **listening-ip** to **0.0.0.0** +// // +// // **STUN** config entry is **{ urls: "stun:127.0.0.1:3478", username: "webrtc", credential: "qwerty" }**. +// // **TURN** config entry is **{ urls: "turn:127.0.0.1:3478", username: "webrtc", credential: "qwerty" }**. +// // +// console.log( "Web RTC test" ); +// network_layer.set_ws_mod( ws ); +// network_layer.set_wrtc_mod( wrtc ); +// const url = null; // null here means url will be got from settings +// const acceptor = new network_layer.WebRTCServerAcceptor( url ); +// const server = new TestServer( acceptor ); +// server.on( "dispose", function() { console.log( "disposed", url ); } ); +// console.log( "Will connect to " + url ); +// const client = new network_layer.WebRTCClientPipe( url ); +// client.on( "message", function( eventData ) { +// const joMessage = eventData.message; +// console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); +// client.disconnect(); +// console.log( " " ); +// } ); +// await sleep( 1000 ); +// console.log( "CLIENT >>>", JSON.stringify( joTestMessage ) ); +// client.send( joTestMessage ); +// await sleep( 1000 ); +// const joReturnValue = { +// server: server, +// client: client +// }; +// return joReturnValue; +// } + +async function test() { + await test_local(); + await test_worker(); + await test_web_socket(); + // await test_wrtc(); + process.exit( 0 ); +} +test(); diff --git a/npms/skale-cool-socket/test_server.js b/npms/skale-cool-socket/test_server.js new file mode 100644 index 000000000..32283918d --- /dev/null +++ b/npms/skale-cool-socket/test_server.js @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file test_server.js + * @copyright SKALE Labs 2019-Present + */ + +const { Server } = require( "./server.js" ); + +class TestServer extends Server { + constructor( acceptor ) { + super( acceptor ); + const self = this; + self.mapApiHandlers.echo = function( joMessage, joAnswer, eventData, socket ) { + console.log( "SERVER <<<", JSON.stringify( joMessage ) ); + joAnswer.message = joMessage.message ? joMessage.message : ""; + console.log( "SERVER >>>", JSON.stringify( joAnswer ) ); + return joAnswer; + }; + } + dispose() { + this.isDisposing = true; + super.dispose(); + } +}; + +module.exports = { + TestServer: TestServer +}; diff --git a/npms/skale-cool-socket/test_signaling_server.js b/npms/skale-cool-socket/test_signaling_server.js new file mode 100644 index 000000000..736839c19 --- /dev/null +++ b/npms/skale-cool-socket/test_signaling_server.js @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file test_signaling_server.js + * @copyright SKALE Labs 2019-Present + */ + +const fs = require( "fs" ); + +const https_loaded_mod = require( "https" ); +const ws_loaded_mod = require( "ws" ); +const wrtc_loaded_mod = require( "wrtc" ); + +const network_layer = require( "./socket.js" ); +const { settings } = require( "./settings.js" ); +const { UniversalDispatcherEvent, EventDispatcher } = require( "./event_dispatcher.js" ); +const utils = require( "./utils.js" ); + +// const connect = connect_loaded_mod; // .default; +// const serveStatic = serveStatic_loaded_mod; // .default; +const https_mod = https_loaded_mod; // .default; +const ws_mod = ws_loaded_mod; // .default; +const wrtc_mod = wrtc_loaded_mod; // .default; + +network_layer.set_https_mod( https_mod ); +network_layer.set_ws_mod( ws_mod ); +network_layer.set_wrtc_mod( wrtc_mod ); + +console.log( "Test signaling server application..." ); +process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SignalingClient extends EventDispatcher { + constructor( idRtcParticipant, strRole, signalingSpace, socket ) { + super(); + this.isDisposed = false; + this.idRtcParticipant = "" + ( ( idRtcParticipant && typeof idRtcParticipant == "string" && idRtcParticipant.length > 0 ) ? idRtcParticipant : "" ); + this.isCreator = ( strRole == "creator" ) ? true : false; + this.isJoiner = ( strRole == "joiner" ) ? true : false; + this.signalingSpace = signalingSpace; + this.socket = socket; + socket.signalingClient = this; + if( this.isCreator ) + this.signalingSpace.idSomebodyCreator = "" + this.idRtcParticipant; + this.signalingSpace.map_clients[this.idRtcParticipant] = this; + this.idSpace = "" + this.signalingSpace.idSpace; + this.idCategory = "" + this.signalingSpace.signalingCategory.idCategory; + this.isFetchingOffer = false; + this.timerFetchingOffer = null; + this.fetchingOfferStepNumber = 0; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "New signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\" using socket " + this.socket.strSavedRemoteAddress ); + this.signalingSpace.dispatchEvent( new UniversalDispatcherEvent( "clientAdded", { detail: { signalingClient: this } } ) ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Disposing signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + this.disconnect(); + if( this.idRtcParticipant ) { + if( this.signalingSpace ) { + this.signalingSpace.dispatchEvent( new UniversalDispatcherEvent( "clientRemoved", { detail: { signalingClient: this } } ) ); + delete this.signalingSpace.map_clients[this.idRtcParticipant]; + } + this.idRtcParticipant = null; + } + if( this.isCreator ) { + if( this.signalingSpace ) + this.signalingSpace.idSomebodyCreator = ""; + } + this.isCreator = false; + this.isJoiner = false; + this.idSpace = null; + this.idCategory = null; + this.signalingSpace.autoDispose(); + this.signalingSpace = null; + super.dispose(); + } + disconnect() { + if( this.isDisposed || ( !this.socket ) ) + return; + this.offerDiscoveryStop(); + let bPass = false, anyError = null; + try { + this.socket.disconnect(); + bPass = true; + } catch ( err ) { + anyError = err; + } + if( ! bPass ) { + if( settings.logging.net.signaling.error ) + console.warn( "Signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\" - web socket signaling pipe termination error", anyError ); + } + // + this.socket.signalingClient = null; + this.socket = null; + if( settings.logging.net.signaling.disconnect ) + console.warn( "Disconnected/force signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + } + onPipeClose( socket ) { + if( this.isDisposed ) + return; + if( settings.logging.net.signaling.disconnect ) + console.warn( "Disconnected/pipe signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + this.offerDiscoveryStop(); + this.dispose(); + } + onPipeError( socket ) { + if( this.isDisposed ) + return; + if( settings.logging.net.signaling.error ) + console.warn( "Disconnected/error signaling client \"" + this.idRtcParticipant + "\" in signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + this.offerDiscoveryStop(); + this.dispose(); + } + offerDiscoveryStop() { + if( ! this.isFetchingOffer ) + return; + if( this.timerFetchingOffer ) { + clearInterval( this.timerFetchingOffer ); + this.timerFetchingOffer = null; + } + this.isFetchingOffer = false; + this.fetchingOfferStepNumber = 0; + } + offerDiscoveryStart( joMessage ) { + if( this.isFetchingOffer ) + return; + this.isFetchingOffer = true; + this.offerDiscoveryStep( joMessage ); + } + offerDiscoveryStep( joMessage ) { + if( ! this.isFetchingOffer ) + return; + let joAnswer = null; + ++ this.fetchingOfferStepNumber; + try { + // let signalingCategory = null; + const signalingSpace = this.signalingSpace; + // if( signalingSpace ) + // signalingCategory = signalingSpace.signalingCategory; + const joOfferInfo = signalingSpace.fetchPublishedOffer(); + if( ! joOfferInfo ) { + if( settings.logging.net.signaling.offerDiscoveryStepFail ) + console.warn( "Signaling client socket \"" + this.socket.strSavedRemoteAddress + "\" did not found offer at step", this.fetchingOfferStepNumber, "of", settings.net.rtc.offerDiscovery.stepCount ); + if( this.fetchingOfferStepNumber >= settings.net.rtc.offerDiscovery.stepCount ) { + this.offerDiscoveryStop(); + throw new Error( "no offer found" ); + } + if( ! this.timerFetchingOffer ) { + const self = this; + this.timerFetchingOffer = setInterval( function() { + self.offerDiscoveryStep( joMessage ); + }, settings.net.rtc.offerDiscovery.periodMilliseconds ); + } + return; + } + if( settings.logging.net.signaling.impersonate ) { + console.log( "Signaling client socket \"" + this.socket.strSavedRemoteAddress + "\" impersonated as \"" + this.idRtcParticipant + + "\" in signaling space \"" + signalingSpace.idSpace + "\" did fetched published offer:", joOfferInfo ); + } + joAnswer = utils.prepareAnswerJSON( joMessage ); // successful answer + joAnswer.offer = joOfferInfo.offer; + joAnswer.idOffer = 0 + joOfferInfo.idOffer; + joAnswer.idSomebodyCreator = joOfferInfo.idSomebodyCreator; // server holder + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( "Server method", joMessage.method, "RPC exception:", err ); + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.error = "" + err.toString(); + } + if( typeof joAnswer.error == "string" && joAnswer.error.length > 0 ) { + if( settings.logging.net.signaling.error ) + console.warn( "Signaling client socket \"" + this.socket.strSavedRemoteAddress + "\" error answer", joAnswer ); + } else if( settings.logging.net.signaling.message ) + console.log( "Signaling client socket \"" + this.socket.strSavedRemoteAddress + " answer", joAnswer ); + this.socket.send( joAnswer, true ); // isFlush=true always in signaling server + this.offerDiscoveryStop(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SignalingSpace extends EventDispatcher { + constructor( idSpace, signalingCategory ) { + super(); + this.isDisposed = false; + this.idSpace = "" + ( ( idSpace && typeof idSpace == "string" && idSpace.length > 0 ) ? idSpace : "" ); + this.idSomebodyCreator = ""; + this.arr_published_offers = []; + this.signalingCategory = signalingCategory; + this.map_clients = {}; + this.signalingCategory.map_spaces[this.idSpace] = this; + this.idCategory = "" + this.signalingCategory.idCategory; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "New signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + this.signalingCategory.dispatchEvent( new UniversalDispatcherEvent( "spaceAdded", { detail: { signalingSpace: this } } ) ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Disposing signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + for( const [ /*idRtcParticipant*/, signalingClient ] of Object.entries( this.map_clients ) ) + signalingClient.dispose(); + if( this.idSpace ) { + if( this.signalingCategory ) { + this.signalingCategory.dispatchEvent( new UniversalDispatcherEvent( "spaceRemoved", { detail: { signalingSpace: this } } ) ); + delete this.signalingCategory.map_spaces[this.idSpace]; + } + this.idSpace = null; + } + this.idCategory = null; + this.signalingCategory.autoDispose(); + this.signalingCategory = null; + this.arr_published_offers = []; + super.dispose(); + } + autoDispose() { + if( this.isDisposed ) + return; + if( this.allSomebodyIDs().length > 0 ) + return; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Auto-dispose signaling space \"" + this.idSpace + "\" in signaling category \"" + this.idCategory + "\"" ); + this.dispose(); + } + allSomebodyIDs() { + if( this.isDisposed ) + return []; + return Object.keys( this.map_clients ); + } + clientGet( idRtcParticipant ) { + if( this.isDisposed ) + return null; + const signalingClient = this.map_clients[idRtcParticipant]; + return signalingClient ? signalingClient : null; + } + clientRemove( idRtcParticipant ) { + if( this.isDisposed ) + return false; + idRtcParticipant = "" + ( idRtcParticipant ? idRtcParticipant.toString() : "" ); + if( idRtcParticipant in this.map_clients ) { + const signalingClient = this.map_clients[idRtcParticipant]; + signalingClient.dispose(); + this.autoDispose(); + return true; + } + return false; + } + fetchPublishedOffer() { + if( this.isDisposed || this.isDisposing ) { + if( settings.logging.net.signaling.offerDiscoveryStepFail ) + console.warn( "Attempt to fetch offer in destroyed signaling space" ); + return null; + } + if( this.idSomebodyCreator == undefined || this.idSomebodyCreator == null || this.idSomebodyCreator == "" ) { + if( settings.logging.net.signaling.offerDiscoveryStepFail ) + console.warn( "Attempt to fetch offer in malformed signaling space" ); + return null; + } + if( this.arr_published_offers.length == 0 ) { + if( settings.logging.net.signaling.offerDiscoveryStepFail ) + console.warn( "Attempt to fetch offer in signaling space with no offers" ); + return null; + } + const joOfferInfo = this.arr_published_offers[0]; + this.arr_published_offers.splice( 0, 1 ); + joOfferInfo.idSomebodyCreator = "" + this.idSomebodyCreator; + return joOfferInfo; + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SignalingCategory extends EventDispatcher { + constructor( idCategory, signalingManager ) { + super(); + this.isDisposed = false; + this.idCategory = "" + ( ( idCategory && typeof idCategory == "string" && idCategory.length > 0 ) ? idCategory : "" ); + this.signalingManager = signalingManager; + this.map_spaces = {}; + this.signalingManager.map_categories[this.idCategory] = this; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "New signaling category \"" + this.idCategory + "\"" ); + this.signalingManager.dispatchEvent( new UniversalDispatcherEvent( "categoryAdded", { detail: { signalingCategory: this } } ) ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Disposing signaling category \"" + this.idCategory + "\"" ); + for( const [ /*idSpace*/, signalingSpace ] of Object.entries( this.map_spaces ) ) + signalingSpace.dispose(); + if( this.signalingManager ) { + delete this.signalingManager.map_categories[this.idCategory]; + this.signalingManager.dispatchEvent( new UniversalDispatcherEvent( "categoryRemoved", { detail: { signalingCategory: this } } ) ); + this.signalingManager = null; + } + this.map_spaces = {}; + this.idCategory = null; + super.dispose(); + } + autoDispose() { + if( this.isDisposed ) + return; + if( this.allCSpaceIDs().length > 0 ) + return; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Auto-dispose signaling category \"" + this.idCategory + "\"" ); + this.dispose(); + } + allCSpaceIDs() { + if( this.isDisposed ) + return []; + return Object.keys( this.map_spaces ); + } + spaceGet( idSpace, isAutoAlloc ) { + if( this.isDisposed ) + return null; + try { + idSpace = "" + ( idSpace ? idSpace.toString() : settings.rtcSpace.defaultSpaceName ); + isAutoAlloc = ( isAutoAlloc == null || isAutoAlloc == undefined ) ? true : ( isAutoAlloc ? true : false ); + let signalingSpace = null; + if( idSpace in this.map_spaces ) + signalingSpace = this.map_spaces[idSpace]; + else if( isAutoAlloc ) + this.map_spaces["" + idSpace] = signalingSpace = new SignalingSpace( "" + idSpace, this ); + return signalingSpace; + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( "Signaling space retrieval error:", err ); + return null; + } + } + spaceRemove( idSpace ) { + if( this.isDisposed ) + return false; + idSpace = "" + ( idSpace ? idSpace.toString() : idSpace.rtcSpace.defaultSpaceName ); + if( idSpace in this.map_spaces ) { + const signalingSpace = this.map_spaces[idSpace]; + signalingSpace.dispose(); + this.autoDispose(); + return true; + } + return false; + } + fetchPublishedOffer() { + if( this.isDisposed ) + return null; + for( const [ /*idSpace*/, signalingSpace ] of Object.entries( this.map_spaces ) ) { + const joOfferInfo = signalingSpace.fetchPublishedOffer(); + if( joOfferInfo ) + return joOfferInfo; + } + return null; + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SignalingManager extends EventDispatcher { + constructor() { + super(); + this.isDisposed = false; + this.map_categories = {}; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "New signaling manager" ); + } + dispose() { + if( this.isDisposed ) + return; + this.isDisposing = true; + if( settings.logging.net.signaling.objectLifetime ) + console.log( "Disposing signaling manager" ); + for( const [ /*idCategory*/, signalingCategory ] of Object.entries( this.map_categories ) ) + signalingCategory.dispose(); + this.map_categories = {}; + super.dispose(); + } + allCategoryIDs() { + return Object.keys( this.map_categories ); + } + categoryGet( idCategory, isAutoAlloc ) { + try { + idCategory = "" + ( idCategory ? idCategory.toString() : settings.rtcSpace.defaultSpaceCategory ); + isAutoAlloc = ( isAutoAlloc == null || isAutoAlloc == undefined ) ? true : ( isAutoAlloc ? true : false ); + let signalingCategory = null; + if( idCategory in this.map_categories ) + signalingCategory = this.map_categories[idCategory]; + else if( isAutoAlloc ) + this.map_categories["" + idCategory] = signalingCategory = new SignalingCategory( "" + idCategory, this ); + return signalingCategory; + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( "Signaling category retrieval error:", err ); + return null; + } + } + categoryRemove( idCategory ) { + idCategory = "" + ( idCategory ? idCategory.toString() : settings.rtcSpace.defaultSpaceName ); + if( idCategory in this.map_categories ) { + const signalingCategory = this.map_categories[idCategory]; + signalingCategory.dispose(); + return true; + } + return false; + } +}; + +const g_default_signaling_manager = new SignalingManager(); + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class SignalingServer extends EventDispatcher { + constructor( acceptor, signalingManager ) { + super(); + if( acceptor == null || acceptor == undefined || typeof acceptor != "object" ) + throw new Error( "Cannot create test server on bad acceptor" ); + this.acceptor = acceptor; + this.signalingManager = signalingManager || g_default_signaling_manager; + const self = this; + acceptor.on( "connection", function( eventData ) { + const socket = eventData.socket; + if( ( ! ( "remoteAddress" in eventData ) ) || eventData.remoteAddress == null || eventData.remoteAddress == undefined ) + socket.strSavedRemoteAddress = socket.constructor.name; + else + socket.strSavedRemoteAddress = "" + eventData.remoteAddress; + socket.signalingClient = null; // not impersonated yet + if( settings.logging.net.signaling.connect ) + console.log( "New signaling server connection \"" + socket.strSavedRemoteAddress + "\"" ); + socket.signalingAuthInfo = { + isAuthorized: false, + idCategory: null, + idSpaceSpace: null, + idRtcParticipant: null + }; + let _offAllPipeEventListeners = null; + let _onPipeClose = function() { + if( settings.logging.net.signaling.disconnect ) + console.warn( "Signaling client socket closed \"" + socket.strSavedRemoteAddress + "\"" ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + if( socket.signalingClient ) { + socket.signalingClient.onPipeClose( socket ); + socket.signalingClient = null; + } + }; + let _onPipeError = function( eventData ) { + if( settings.logging.net.signaling.error ) + console.warn( "Socket error \"" + socket.strSavedRemoteAddress + "\"" ); + if( _offAllPipeEventListeners ) { + _offAllPipeEventListeners(); + _offAllPipeEventListeners = null; + } + if( socket.signalingClient ) { + socket.signalingClient.onPipeError( socket ); + socket.signalingClient = null; + } + }; + let _onPipeMessage = function( eventData ) { + if( settings.logging.net.signaling.rawMessage ) + console.log( "Signaling client socket \"" + eventData.strSavedRemoteAddress + "\" raw message", eventData ); + const joMessage = eventData.message; + if( settings.logging.net.signaling.message ) + console.log( "Signaling client socket \"" + socket.strSavedRemoteAddress + "\" message ", joMessage ); + let signalingCategory = null; + let signalingSpace = null; + let signalingClient = socket.signalingClient; + if( signalingClient ) { + signalingSpace = signalingClient.signalingSpace; + if( signalingSpace ) + signalingCategory = signalingSpace.signalingCategory; + } + let joAnswer = null; + let isForceDisconnect = false; + try { + switch ( joMessage.method ) { + case "signalingListSpaces": { + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.arrSpaces = self.gamingSpaceManager.allNames(); + } break; + case "signalingImpersonate": { + const idRtcParticipant = joMessage.idRtcParticipant; + if( ( !idRtcParticipant ) || typeof idRtcParticipant != "string" || idRtcParticipant.length <= 0 ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, no valid signaling *somebody* ID provided" ); + } + // + const strRole = joMessage.role; + if( ( !strRole ) || typeof strRole != "string" || strRole.length <= 0 || ( ! ( strRole == "creator" || strRole == "joiner" ) ) ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, no valid signaling *somebody* role provided" ); + } + // + const idCategory = joMessage.idCategory; + if( ( !idCategory ) || typeof idCategory != "string" || idCategory.length <= 0 ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, no valid signaling space category provided" ); + } + signalingCategory = self.signalingManager.categoryGet( idCategory, true ); + if( ! signalingCategory ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, cannot get/alloc signaling category with \"" + idCategory + "\" name" ); + } + // + const idSpace = joMessage.idSpace; + if( ( !idSpace ) || typeof idSpace != "string" || idSpace.length <= 0 ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, no valid signaling space name provided" ); + } + signalingSpace = signalingCategory.spaceGet( idSpace, true ); + if( ! signalingSpace ) { + isForceDisconnect = true; + throw new Error( "Bad impersonate call data, cannot get/alloc signaling space with \"" + idSpace + "\" name" ); + } + // + if( signalingSpace.clientGet( idRtcParticipant ) != null ) { + isForceDisconnect = true; + throw new Error( "*Somebody* \"" + idRtcParticipant + "\" is already in \"" + idSpace + "\" signaling space" ); + } + // + if( strRole == "creator" && signalingSpace.idSomebodyCreator != "" && signalingSpace.idSomebodyCreator != idRtcParticipant ) + throw new Error( "*Somebody* \"" + idRtcParticipant + "\" is already in \"" + idSpace + "\" attempted to impersonate as creator while other creator already exist" ); + // + signalingClient = new SignalingClient( "" + idRtcParticipant, "" + strRole, signalingSpace, socket ); + if( settings.logging.net.signaling.impersonate ) { + isForceDisconnect = true; + console.log( "Signaling client socket \"" + socket.strSavedRemoteAddress + "\" was impersonated as \"" + idRtcParticipant + + "\" in signaling space \"" + signalingSpace.idSpace + "\"" ); + } + // if( (!( "fnFlushNetwork" in signalingSpace )) || (!signalingSpace.fnFlushNetwork) ) + // //console.log( "Setting up network data flushing in acceptor" ); + // signalingSpace.fnFlushNetwork = function() { + // // TO-DO: improve this + // //console.log( "Flushing data to network via acceptor" ); + // acceptor.flush(); // network + // }; + socket.signalingClient = signalingClient; + socket.signalingAuthInfo.isAuthorized = true; + socket.signalingAuthInfo.idCategory = "" + idCategory; + socket.signalingAuthInfo.idSpaceSpace = "" + idSpace; + socket.signalingAuthInfo.idRtcParticipant = "" + idRtcParticipant; + joAnswer = utils.prepareAnswerJSON( joMessage ); // successful answer + joAnswer.signalingAuthInfo = JSON.parse( JSON.stringify( socket.signalingAuthInfo ) ); + } break; + case "signalingPublishOffer": { + if( ! ( signalingClient && signalingSpace && signalingCategory ) ) + throw new Error( "only connected signaling clients can publish offers" ); + if( ! ( signalingClient.isCreator ) ) + throw new Error( "only creator can publish offers" ); + const joOfferInfo = { + // ts: some time stamp + offer: joMessage.offer, + idOffer: 0 + joMessage.idOffer + }; + signalingSpace.arr_published_offers.push( joOfferInfo ); + if( settings.logging.net.signaling.publishOffer ) { + console.log( "Signaling client socket \"" + socket.strSavedRemoteAddress + "\" impersonated as \"" + signalingClient.idRtcParticipant + + "\" in signaling space \"" + signalingSpace.idSpace + "\" did published creator offer:", joOfferInfo ); + } + joAnswer = utils.prepareAnswerJSON( joMessage ); // successful answer + } break; + case "signalingFetchOffer": { + if( ! ( signalingClient && signalingSpace && signalingCategory ) ) + throw new Error( "only connected signaling clients can fetch published offers" ); + signalingClient.offerDiscoveryStart( joMessage ); + } break; + case "signalingPublishAnswer": { + if( ! ( signalingClient && signalingSpace && signalingCategory ) ) + throw new Error( "only connected signaling clients can publish offer answers" ); + const connectedServerCreator = signalingSpace.clientGet( joMessage.idSomebodyCreator ); + if( ! connectedServerCreator ) + throw new Error( "answer published with invalid server holder reference: " + joMessage.idSomebodyCreator ); + const joForwardMessage = JSON.parse( JSON.stringify( joMessage ) ); + joForwardMessage.idSomebody_joiner = "" + signalingClient.idRtcParticipant; + connectedServerCreator.socket.send( joForwardMessage ); // re-send it to server holder, joiner *somebody* ID is added + // no answer so far(( + } break; + default: { + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.error = "Unhandled message"; + joAnswer.joMessage = joMessage; // send it back )) + if( settings.logging.net.signaling.error ) + console.warn( "Signaling client socket \"" + socket.strSavedRemoteAddress + "\" unhandled message", joMessage ); + } break; + } // switch( joMessage.method ) + } catch ( err ) { + if( settings.logging.net.signaling.error ) + console.warn( "Server method", joMessage.method, "RPC exception:", err ); + joAnswer = utils.prepareAnswerJSON( joMessage ); + joAnswer.error = "" + err.toString(); + } + if( joAnswer != null && joAnswer != undefined ) { + if( typeof joAnswer.error == "string" && joAnswer.error.length > 0 ) { + if( settings.logging.net.signaling.error ) + console.warn( "Signaling client socket \"" + socket.strSavedRemoteAddress + "\" error answer", joAnswer ); + } else if( settings.logging.net.signaling.message ) + console.log( "Signaling client socket \"" + socket.strSavedRemoteAddress + " answer", joAnswer ); + socket.send( joAnswer, true ); // isFlush=true always in signaling server + if( isForceDisconnect ) + socket.disconnect(); + } + if( signalingSpace ) + signalingSpace.autoDispose(); + if( signalingCategory ) + signalingCategory.autoDispose(); + }; + _offAllPipeEventListeners = function() { + if( _onPipeClose ) { + socket.off( "close", _onPipeClose ); + _onPipeClose = null; + } + if( _onPipeError ) { + socket.off( "error", _onPipeError ); + _onPipeError = null; + } + if( _onPipeMessage ) { + socket.off( "message", _onPipeMessage ); + _onPipeMessage = null; + } + let signalingSpace = null; + const signalingClient = socket.signalingClient; + if( signalingClient ) { + signalingSpace = signalingClient.signalingSpace; + if( settings.logging.net.signaling.disconnect ) + console.log( "Handling connection close for signaling client \"" + signalingClient.idRtcParticipant + "\"" ); + if( signalingSpace ) + signalingSpace.clientRemove( signalingClient.idRtcParticipant ); + + signalingClient.dispose(); + } + socket.signalingClient = null; + }; + socket.on( "close", _onPipeClose ); + socket.on( "error", _onPipeError ); + socket.on( "message", _onPipeMessage ); + } ); + this.dispatchEvent( new UniversalDispatcherEvent( "initialized", { detail: { ref: this } } ) ); + } + dispose() { + this.isDisposing = true; + super.dispose(); + } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const protoName = settings.net.secure ? "WSS" : "WS"; +if( settings.logging.net.signaling.generic ) + console.log( protoName + " signaling server will start" ); + +const key = settings.net.secure ? fs.readFileSync( "./self-signed/self-signed-key.pem", "utf8" ) : null; +const cert = settings.net.secure ? fs.readFileSync( "./self-signed/self-signed-cert.pem", "utf8" ) : null; +let acceptor = new network_layer.WebSocketServerAcceptor( settings.net.ports.signaling, key, cert ); +let signalingServer = new SignalingServer( acceptor ); +signalingServer.on( "initialized", function() { + if( settings.logging.net.signaling.generic ) + console.log( protoName + " signaling server did started" ); +} ); +signalingServer.on( "dispose", function() { + if( settings.logging.net.signaling.generic ) + console.log( protoName + " signaling server did stopped" ); +} ); + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +let g_bShouldExit = false, g_bProcessExitRequested = false; +function exit_if_needed() { + if( ! g_bShouldExit ) + return; + if( g_bProcessExitRequested ) + return; + // ensure components stopped here, if needed + g_bProcessExitRequested = true; + console.log( "App will exit" ); + process.exit( 0 ); +} + +process.on( "SIGINT", function() { + console.warn( "\nApp did caught interrupt signal " ); + // stop components here, if needed + if( signalingServer ) { + console.log( "Will stop signaling server" ); + signalingServer.dispose(); + signalingServer = null; + console.log( "Did stopped signaling server" ); + } + if( acceptor ) { + console.log( "Will stop signaling acceptor" ); + acceptor.dispose(); + acceptor = null; + console.log( "Did stopped signaling acceptor" ); + } + g_bShouldExit = true; + // + exit_if_needed(); + g_bShouldExit = true; +} ); + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/npms/skale-cool-socket/test_worker.js b/npms/skale-cool-socket/test_worker.js new file mode 100644 index 000000000..a315cf581 --- /dev/null +++ b/npms/skale-cool-socket/test_worker.js @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file test_worker.js + * @copyright SKALE Labs 2019-Present + */ + +const network_layer = require( "./socket.js" ); +const { TestServer } = require( "./test_server.js" ); +const { + parentPort + //, workerData +} = require( "worker_threads" ); + +parentPort.on( "message", jo => { + if( network_layer.in_worker_apis.on_message( jo ) ) + return; +} ); + +function doSendMessage( type, endpoint, worker_uuid, data ) { + const jo = network_layer.socket_received_data_reverse_marshall( data ); + const joSend = { + worker_message_type: ( type && typeof type == "string" && type.length > 0 ) ? type : "in_worker_message", + worker_endpoint: endpoint, + worker_uuid: worker_uuid, + data: jo + }; + parentPort.postMessage( network_layer.socket_sent_data_marshall( joSend ) ); +} + +const url = "local_worker_server"; +const acceptor = new network_layer.InWorkerSocketServerAcceptor( url, doSendMessage ); +const server = new TestServer( acceptor ); +server.on( "dispose", function() { console.log( "disposed in-worker server" ); } ); diff --git a/npms/skale-cool-socket/utils.js b/npms/skale-cool-socket/utils.js new file mode 100644 index 000000000..270b57c68 --- /dev/null +++ b/npms/skale-cool-socket/utils.js @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE COOL SOCKET + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file utils.js + * @copyright SKALE Labs 2019-Present + */ + +const { settings } = require( "./settings.js" ); + +const uuid_v4 = function() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace( /[xy]/g, function( c ) { + const r = Math.random() * 16 | 0, v = c == "x" ? r : ( r & 0x3 | 0x8 ); + return v.toString( 16 ); + } ); +}; + +const getRandomInt = function( nMax ) { + return parseInt( Math.floor( Math.random() * Math.floor( nMax ) ), 10 ); +}; + +const randomFixedInteger = function( length ) { + return Math.floor( Math.pow( 10, length - 1 ) + Math.random() * ( Math.pow( 10, length ) - Math.pow( 10, length - 1 ) - 1 ) ); +}; + +const randomStringABC = function( length, arrCharacters ) { + length = parseInt( length, 10 ); + if( length <= 0 || arrCharacters.length == 0 ) + return ""; + let s = ""; + for( let i = 0; i < length; ++i ) + s += arrCharacters.charAt( Math.floor( Math.random() * arrCharacters.length ) ); + return s; +}; + +const randomString = function( length, isABC, isDigits, isSpecChr, isPunctuation ) { // by default only isABC=true + length = parseInt( length, 10 ); + if( length <= 0 ) + return ""; + isABC = ( isABC == null || isABC == undefined ) ? true : ( isABC ? true : false ); + isDigits = ( isDigits == null || isDigits == undefined ) ? false : ( isDigits ? true : false ); + isSpecChr = ( isSpecChr == null || isSpecChr == undefined ) ? false : ( isSpecChr ? true : false ); + isPunctuation = ( isPunctuation == null || isPunctuation == undefined ) ? false : ( isPunctuation ? true : false ); + let arrCharacters = ""; + if( isABC ) + arrCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + if( isDigits ) + arrCharacters += "0123456789"; + if( isSpecChr ) + arrCharacters += "(){}[]~!?@#$%^&*_+-='\"/\\"; + if( isPunctuation ) + arrCharacters += ",.:;"; + if( arrCharacters.length == 0 ) + return ""; + return randomStringABC( length, arrCharacters ); +}; + +const randomHexString = function( length ) { // length in characters, not bytes, each byte is 2 characters + const arrCharacters = "0123456789abcdef"; + return randomStringABC( length, arrCharacters ); +}; + +const replaceAll = function( str, find, replace ) { + return str.replace( new RegExp( find, "g" ), replace ); +}; + +const simpleEscapeString = function( s ) { + if( s == null || s == undefined || typeof s != "string" ) + return s; + s = replaceAll( s, "&", "&" ); + s = replaceAll( s, "<", "<" ); + s = replaceAll( s, ">", ">" ); + s = replaceAll( s, " ", " " ); + return s; +}; + +const abstractUniqueID = function() { + const id = replaceAll( uuid_v4(), "-", "" ).toLowerCase(); + return id; +}; + +const isEven = function( n ) { + return n % 2 == 0; +}; +const isOdd = function( n ) { + return Math.abs( n % 2 ) == 1; +}; + +const g_nCallIdDigits = 10; +const randomCallID = function() { + const id = randomHexString( g_nCallIdDigits ); + return id; +}; + +const g_nDirectPipeIdDigits = 10; +const randomDirectPipeID = function() { + const id = randomHexString( g_nDirectPipeIdDigits ); + return id; +}; + +const bind_scope_to_function = function( scope, fn ) { + return function() { + fn.apply( scope, arguments ); + }; +}; + +const prepareAnswerJSON = function( joMessage ) { + const joAnswer = { + id: "" + ( ( joMessage != null && joMessage != undefined && typeof joMessage.id == "string" ) ? joMessage.id : randomCallID() ), + method: "" + ( ( joMessage != null && joMessage != undefined && typeof joMessage.method == "string" ) ? joMessage.method : "" ), + error: null + }; + return joAnswer; +}; + +const makeValidSignalingServerURL = function( strSignalingServerURL ) { + const proto = settings.net.secure ? "wss" : "ws"; + return "" + ( ( strSignalingServerURL != null && strSignalingServerURL != undefined && typeof strSignalingServerURL == "string" && strSignalingServerURL.length > 0 ) + ? "" + strSignalingServerURL + : "" + proto + "://" + settings.net.hostname + ":" + settings.net.ports.signaling + ); +}; + +const zero_padding_left = function( val, cntCharsNeeded ) { + if( val == null || val == undefined ) + return val; + let s = "" + val; + while( s.length < cntCharsNeeded ) + s = "0" + s; + return s; +}; +const zero_padding_right = function( val, cntCharsNeeded ) { + if( val == null || val == undefined ) + return val; + let s = "" + val; + while( s.length < cntCharsNeeded ) + s = s + "0"; + return s; +}; + +const parse_date_time = function( ts ) { + if( ts === null || ts === undefined ) + return ts; + if( typeof ts != "string" ) + return null; + // example: + // 0----|----1----|----2----|---- + // 012345678901234567890123456789 + // "2020/03/19-19:42:55.663" + const year = parseInt( ts.substring( 0, 4 ), 10 ); + const month = parseInt( ts.substring( 5, 7 ), 10 ) + 1; + const day = parseInt( ts.substring( 8, 10 ), 10 ); + const hour = parseInt( ts.substring( 11, 13 ), 10 ); + const minute = parseInt( ts.substring( 14, 16 ), 10 ); + const second = parseInt( ts.substring( 17, 19 ), 10 ); + let millisecond = ts.substring( 20 ); + if( millisecond.length > 3 ) + millisecond = millisecond.substring( 0, 3 ); + else { + while( millisecond.length < 3 ) + millisecond = "0" + millisecond; + } + millisecond = parseInt( millisecond, 10 ); + const u = Date.UTC( year, month, day, hour, minute, second, millisecond ); + const d = new Date( u ); + d.setMilliseconds( millisecond ); + return d; +}; +const format_date_time = function( dt, isDate, isTime, isMilliseconds, sepDate, sepTime, sepBetween, sepMilliseconds ) { + if( dt === null ) + return "null-date-time"; + if( dt === undefined ) + return "undefined-date-time"; + if( ! ( dt instanceof Date ) ) + return "not-a-date-time"; + isDate = ( isDate == null || isDate == undefined ) ? true : ( isDate ? true : false ); + isTime = ( isTime == null || isTime == undefined ) ? true : ( isTime ? true : false ); + if( ( !isDate ) && ( !isTime ) ) + return ""; + let s = ""; + if( isDate ) { + sepDate = ( sepDate == null || sepDate == undefined || ( typeof sepDate != "string" ) ) ? "/" : sepDate; + const strDate = "" + + zero_padding_left( dt.getFullYear(), 4 ) + + sepDate + + zero_padding_left( dt.getMonth() + 1, 2 ) + + sepDate + + zero_padding_left( dt.getDate(), 2 ); + s += strDate; + } + if( isTime ) { + sepTime = ( sepTime == null || sepTime == undefined || ( typeof sepTime != "string" ) ) ? ":" : sepTime; + if( isDate ) { + sepBetween = ( sepBetween == null || sepBetween == undefined || ( typeof sepBetween != "string" ) ) ? "-" : sepBetween; + s += sepBetween; + } + let strTime = "" + + zero_padding_left( dt.getHours(), 2 ) + + sepDate + + zero_padding_left( dt.getMinutes(), 2 ) + + sepDate + + zero_padding_left( dt.getSeconds(), 2 ); + isMilliseconds = ( isMilliseconds == null || isMilliseconds == undefined ) ? true : ( isMilliseconds ? true : false ); + if( isMilliseconds ) { + sepMilliseconds = ( sepMilliseconds == null || sepMilliseconds == undefined || ( typeof sepMilliseconds != "string" ) ) ? "." : sepMilliseconds; + strTime += sepMilliseconds + zero_padding_right( dt.getMilliseconds(), 3 ); + } + s += strTime; + } + return s; +}; + +module.exports = { + uuid_v4: uuid_v4, + getRandomInt: getRandomInt, + randomFixedInteger: randomFixedInteger, + randomStringABC: randomStringABC, + randomString: randomString, + randomHexString: randomHexString, + replaceAll: replaceAll, + simpleEscapeString: simpleEscapeString, + abstractUniqueID: abstractUniqueID, + isEven: isEven, + isOdd: isOdd, + g_nCallIdDigits: g_nCallIdDigits, + randomCallID: randomCallID, + g_nDirectPipeIdDigits: g_nDirectPipeIdDigits, + randomDirectPipeID: randomDirectPipeID, + bind_scope_to_function: bind_scope_to_function, + prepareAnswerJSON: prepareAnswerJSON, + makeValidSignalingServerURL: makeValidSignalingServerURL, + zero_padding_left: zero_padding_left, + zero_padding_right: zero_padding_right, + parse_date_time: parse_date_time, + format_date_time: format_date_time +}; diff --git a/npms/skale-cool-socket/yarn.lock b/npms/skale-cool-socket/yarn.lock new file mode 100644 index 000000000..71b02d8b2 --- /dev/null +++ b/npms/skale-cool-socket/yarn.lock @@ -0,0 +1,1510 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/highlight@^7.16.7": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3" + integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +acorn-jsx@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.0.0, chalk@^2.1.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@2.6.9, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.2.tgz#8f7b696d8f15b167ae3640b4060670f3d054143f" + integrity sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-config-standard@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.3: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-import@^2.20.2: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.3" + has "^1.0.3" + is-core-module "^2.8.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.5" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-promise@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" + integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== + +eslint-plugin-standard@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5" + integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ== + +eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.3" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== + dependencies: + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.17.14, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.10.1, resolve@^1.20.0, resolve@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.1.0, semver@^6.1.2: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@^1.14.1: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23" + integrity sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw== diff --git a/npms/skale-ima/index.js b/npms/skale-ima/index.js index ba0f56434..ef70478aa 100644 --- a/npms/skale-ima/index.js +++ b/npms/skale-ima/index.js @@ -192,7 +192,7 @@ async function get_web3_blockNumber( details, cntAttempts, w3, retValOnFail, thr cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -222,7 +222,7 @@ async function get_web3_blockNumber( details, cntAttempts, w3, retValOnFail, thr cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -257,7 +257,7 @@ async function get_web3_transactionCount( details, cntAttempts, w3, address, par cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -287,7 +287,7 @@ async function get_web3_transactionCount( details, cntAttempts, w3, address, par cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -322,7 +322,7 @@ async function get_web3_transactionReceipt( details, cntAttempts, w3, txHash, re cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -352,7 +352,7 @@ async function get_web3_transactionReceipt( details, cntAttempts, w3, txHash, re cc.error( "Failed call attempt " ) + cc.info( idxAttempt ) + cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } ++ idxAttempt; @@ -393,9 +393,9 @@ async function get_web3_pastEvents( details, w3, cntAttempts, joContract, strEve cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + cc.error( ", from block " ) + cc.warning( nBlockFrom ) + cc.error( ", to block " ) + cc.warning( nBlockTo ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); - if( err.toString().indexOf( strErrorTextAboutNotExistingEvent ) >= 0 ) { + if( owaspUtils.extract_error_message( err ).indexOf( strErrorTextAboutNotExistingEvent ) >= 0 ) { details.write( cc.error( "Did stopped calls to " ) + cc.note( strFnName + "()" ) + cc.error( " because event " ) + cc.notice( strEventName ) + @@ -439,9 +439,9 @@ async function get_web3_pastEvents( details, w3, cntAttempts, joContract, strEve cc.error( " to " ) + cc.note( strFnName + "()" ) + cc.error( " via " ) + cc.u( u ) + cc.error( ", from block " ) + cc.warning( nBlockFrom ) + cc.error( ", to block " ) + cc.warning( nBlockTo ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); - if( err.toString().indexOf( strErrorTextAboutNotExistingEvent ) >= 0 ) { + if( owaspUtils.extract_error_message( err ).indexOf( strErrorTextAboutNotExistingEvent ) >= 0 ) { details.write( cc.error( "Did stopped calls to " ) + cc.note( strFnName + "()" ) + cc.error( " because event " ) + cc.notice( strEventName ) + @@ -552,7 +552,7 @@ async function get_web3_pastEventsIterative( details, w3, attempts, joContract, cc.error( "Got scan error during interative scan of " ) + cc.info( idxBlockSubRangeFrom ) + cc.error( "/" ) + cc.info( idxBlockSubRangeTo ) + cc.error( " block sub-range in " ) + cc.info( nBlockFrom ) + cc.error( "/" ) + cc.info( nBlockTo ) + - cc.error( " block range, error is: " ) + cc.warning( err.toString() ) + "\n" + cc.error( " block range, error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } idxBlockSubRangeFrom = idxBlockSubRangeTo; @@ -599,8 +599,18 @@ function save_transfer_success_all() { g_mapTransferErrorCategories = { }; // clear all transfer error categories, out of time frame } -function get_last_transfer_errors() { - return JSON.parse( JSON.stringify( g_arrLastTransferErrors ) ); +function get_last_transfer_errors( isIncludeTextLog ) { + if( typeof isIncludeTextLog == "undefined" ) + isIncludeTextLog = true; + const jarr = JSON.parse( JSON.stringify( g_arrLastTransferErrors ) ); + if( ! isIncludeTextLog ) { + for( let i = 0; i < jarr.length; ++ i ) { + const jo = jarr[i]; + if( "textLog" in jo ) + delete jo.textLog; + } + } // if( ! isIncludeTextLog ) + return jarr; } function get_last_error_categories() { @@ -1056,8 +1066,8 @@ async function dry_run_call( details, w3, methodWithArguments, joAccount, strDRC details.write( strLogPrefix + cc.fatal( "CRITICAL DRY RUN FAIL" ) + " " + cc.error( " invoking the " ) + cc.info( strMethodName ) + cc.error( " method: " ) + - cc.warning( err.toString() ) + "\n" ); - return "CRITICAL DRY RUN FAIL invoking the \"" + strMethodName + "\" method: " + err.toString(); + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); + return "CRITICAL DRY RUN FAIL invoking the \"" + strMethodName + "\" method: " + owaspUtils.extract_error_message( err ); } } return null; @@ -1238,7 +1248,7 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc const strPrefixLog = cc.debug( "(immediate log)" ) + " "; const sendingCnt = loopTmSendingCnt++; let strMsg = - cc.debug( "Sending transaction with account(" ) + cc.notice( "sending counter" ) + cc.debug( " is " ) + + cc.debug( "Signing(and later, sending) transaction with account(" ) + cc.notice( "sending counter" ) + cc.debug( " is " ) + cc.info( sendingCnt ) + cc.debug( "), raw TX object is " ) + cc.j( rawTx ); details.write( strPrefixDetails + strMsg + "\n" ); log.write( strPrefixLog + strMsg + "\n" ); @@ -1247,6 +1257,9 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc tx: null, txHashSent: null }; + strMsg = cc.debug( "Signing(and later, sending) transaction with backend type: " ) + cc.bright( joSR.joACI.strType ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); switch ( joSR.joACI.strType ) { case "tm": { /* @@ -1269,6 +1282,8 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc if( verbose_get() >= RV_VERBOSE.error ) log.write( s ); details.write( s ); + if( joCall ) + await joCall.disconnect(); return; } const txAdjusted = JSON.parse( JSON.stringify( rawTx ) ); // tx // rawTx @@ -1290,6 +1305,7 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc if( verbose_get() >= RV_VERBOSE.error ) log.write( s ); details.write( s ); + await joCall.disconnect(); return; } details.write( cc.debug( "Transaction Manager sign-and-send result is: " ) + cc.j( joOut ) + "\n" ); @@ -1302,6 +1318,7 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc details.write( s ); return; } + await joCall.disconnect(); } ); } ); await sleep( 5000 ); @@ -1325,26 +1342,37 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc redis = new Redis( joAccount.strTransactionManagerURL ); const priority = joAccount.tm_priority || 5; try { + strMsg = cc.debug( "Will TM-ensure transaction " ) + cc.j( txAdjusted ) + cc.debug( "..." ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); const [ tx_id, joReceipt ] = await tm_ensure_transaction( details, w3, priority, txAdjusted ); + strMsg = cc.success( "Done TM-ensure transaction, got ID " ) + cc.notice( tx_id ) + cc.success( " and receipt " ) + cc.j( joReceipt ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); joSR.txHashSent = "" + joReceipt.transactionHash; joSR.joReceipt = joReceipt; joSR.tm_tx_id = tx_id; + strMsg = cc.success( "Done, TX was signed with Transaction Manager" ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); } catch ( err ) { strMsg = cc.fatal( "BAD ERROR:" ) + " " + cc.error( "TM - transaction was not sent, underlying error is: " ) + - cc.warning( err.toString() ); + cc.warning( owaspUtils.extract_error_message( err ) ); details.write( strPrefixDetails + strMsg + "\n" ); log.write( strPrefixLog + strMsg + "\n" ); // throw err; } } break; case "sgx": { - details.write( - cc.debug( "Will sign with SGX wallet, transaction is " ) + cc.j( tx ) + - cc.debug( ", raw transaction is " ) + cc.j( rawTx ) + "\n" - // + cc.debug( " using account " ) + cc.j( joAccount ) + "\n" - ); + strMsg = + cc.debug( "Will sign with SGX Wallet, transaction is " ) + cc.j( tx ) + + cc.debug( ", raw transaction is " ) + cc.j( rawTx ) + // + cc.debug( " using account " ) + cc.j( joAccount ) + ; + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); let rpcCallOpts = null; if( "strPathSslKey" in joAccount && typeof joAccount.strPathSslKey == "string" && joAccount.strPathSslKey.length > 0 && "strPathSslCert" in joAccount && typeof joAccount.strPathSslCert == "string" && joAccount.strPathSslCert.length > 0 @@ -1361,6 +1389,8 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc if( verbose_get() >= RV_VERBOSE.error ) log.write( s ); details.write( s ); + if( joCall ) + await joCall.disconnect(); return; } const msgHash = tx.hash( false ); @@ -1374,16 +1404,20 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc "base": 16 // 10 } }; - details.write( cc.debug( "Calling SGX to sign using ECDSA key with " ) + cc.info( joIn.method ) + cc.debug( "..." ) + "\n" ); + strMsg = cc.debug( "Calling SGX to sign using ECDSA key with " ) + cc.info( joIn.method ) + cc.debug( "..." ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); await joCall.call( joIn, async function( joIn, joOut, err ) { if( err ) { - const s = cc.fatal( "CRITICAL TRANSACTION SIGNING ERROR:" ) + cc.error( " JSON RPC call to SGX wallet failed, error: " ) + cc.warning( err ) + "\n"; - if( verbose_get() >= RV_VERBOSE.error ) - log.write( s ); - details.write( s ); + strMsg = cc.fatal( "CRITICAL TRANSACTION SIGNING ERROR:" ) + cc.error( " JSON RPC call to SGX wallet failed, error: " ) + cc.warning( err ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); + await joCall.disconnect(); return; } - details.write( cc.debug( "SGX wallet ECDSA sign result is: " ) + cc.j( joOut ) + "\n" ); + strMsg = cc.debug( "SGX wallet ECDSA sign result is: " ) + cc.j( joOut ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); const joNeededResult = { // "v": Buffer.from( parseIntOrHex( joOut.result.signature_v ).toString( "hex" ), "utf8" ), // "r": Buffer.from( "" + joOut.result.signature_r, "utf8" ), @@ -1392,7 +1426,9 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc "r": "" + joOut.result.signature_r, "s": "" + joOut.result.signature_s }; - details.write( cc.debug( "Sign result to assign into transaction is: " ) + cc.j( joNeededResult ) + "\n" ); + strMsg = cc.debug( "SGX Wallet sign result to assign into transaction is: " ) + cc.j( joNeededResult ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); // // if( "_chainId" in tx && tx._chainId != null && tx._chainId != undefined ) // tx.v += tx._chainId * 2 + 8; @@ -1418,27 +1454,38 @@ async function safe_sign_transaction_with_account( details, w3, tx, rawTx, joAcc tx.v = joNeededResult.v; tx.r = joNeededResult.r; tx.s = joNeededResult.s; - details.write( cc.debug( "Resulting adjusted transaction is: " ) + cc.j( tx ) + "\n" ); + strMsg = cc.debug( "Resulting adjusted transaction is: " ) + cc.j( tx ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); + await joCall.disconnect(); + strMsg = cc.success( "Done, TX was signed with SGX Wallet" ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); } ); } ); await sleep( 3000 ); } break; case "direct": { - details.write( + strMsg = cc.debug( "Will sign with private key, transaction is " ) + cc.notice( JSON.stringify( tx ) ) + - cc.debug( ", raw transaction is " ) + cc.notice( JSON.stringify( rawTx ) ) + "\n" - // + cc.debug( " using account " ) + cc.j( joAccount ) + "\n" - ); + cc.debug( ", raw transaction is " ) + cc.notice( JSON.stringify( rawTx ) ) + // + cc.debug( " using account " ) + cc.j( joAccount ) + ; + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); const key = Buffer.from( joAccount.privateKey, "hex" ); // convert private key to buffer tx.sign( key ); // arg is privateKey as buffer + strMsg = cc.success( "Done, TX was signed with private key" ); + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); } break; default: { - const s = cc.fatal( "CRITICAL TRANSACTION SIGNING ERROR:" ) + - cc.error( " bad credentials information specified, no explicit SGX and no explicit private key found" ) + + strMsg = cc.fatal( "CRITICAL TRANSACTION SIGNING ERROR:" ) + + cc.error( " bad credentials information specified, no explicit SGX and no explicit private key found" ) // + cc.error( ", account is: " ) + cc.j( joAccount ) - "\n"; - details.write( s ); - log.write( s ); + ; + details.write( strPrefixDetails + strMsg + "\n" ); + log.write( strPrefixLog + strMsg + "\n" ); if( isExitIfEmpty ) { details.exposeDetailsTo( log, "safe_sign_transaction_with_account", false ); details.close(); @@ -1465,7 +1512,7 @@ async function safe_send_signed_transaction( details, w3, serializedTx, strActio details.write( strPrefixDetails + strMsg + "\n" ); log.write( strPrefixLog + strMsg + "\n" ); const strTX = "0x" + serializedTx.toString( "hex" ); // strTX is string starting from "0x" - details.write( strLogPrefix + cc.debug( "....signed raw TX is " ) + cc.j( strTX ) + "\n" ); + details.write( strLogPrefix + cc.debug( "....signed raw TX is " ) + cc.attention( strTX ) + "\n" ); let joReceipt = null; let bHaveReceipt = false; try { @@ -5323,7 +5370,6 @@ async function do_transfer( savedBlockNumberForOptimizations: joValues.savedBlockNumberForOptimizations }; jarrMessages.push( joMessage ); - } // for( let idxInBlock = 0; nIdxCurrentMsg < nOutMsgCnt && idxInBlock < nTransactionsCountInBlock; ++ nIdxCurrentMsg, ++ idxInBlock, ++cntAccumulatedForBlock ) if( cntAccumulatedForBlock == 0 ) break; @@ -5506,14 +5552,15 @@ async function do_transfer( cc.debug( " using URL " ) + cc.info( jo_node.http_endpoint_ip ) + cc.debug( "..." ) + "\n" ); try { - const w3_node = getWeb3FromURL( jo_node.http_endpoint_ip ); + const w3_node = getWeb3FromURL( jo_node.http_endpoint_ip, details ); const jo_message_proxy_node = new w3_node.eth.Contract( imaState.joAbiPublishResult_s_chain.message_proxy_chain_abi, imaState.joAbiPublishResult_s_chain.message_proxy_chain_address ); + const strEventName = "OutgoingMessage"; const node_r = await get_web3_pastEventsProgressive( details, w3_node, 10, jo_message_proxy_node, - "OutgoingMessage", + strEventName, joMessage.savedBlockNumberForOptimizations, // 0, // nBlockFrom joMessage.savedBlockNumberForOptimizations, // "latest", // nBlockTo { @@ -5523,7 +5570,7 @@ async function do_transfer( ); const cntEvents = node_r.length; details.write( strLogPrefix + - cc.debug( "Got " ) + cc.info( cntEvents ) + cc.debug( " events on node " ) + + cc.debug( "Got " ) + cc.info( cntEvents ) + cc.debug( " event(s) (" ) + cc.info( strEventName ) + cc.debug( ") on node " ) + cc.info( jo_node.name ) + cc.debug( " with data: " ) + cc.j( node_r ) + "\n" ); for( let idxEvent = 0; idxEvent < cntEvents; ++ idxEvent ) { const joEvent = node_r[idxEvent]; @@ -5540,7 +5587,7 @@ async function do_transfer( ++ cntFailedNodes; const strError = strLogPrefix + cc.fatal( strDirection + " message analysis error:" ) + " " + cc.error( "Failed to scan events on node " ) + cc.info( jo_node.name ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + + cc.error( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + cc.error( ", detailed node description is: " ) + cc.j( jo_node ) + "\n"; details.write( strError ); @@ -5583,7 +5630,7 @@ async function do_transfer( cc.error( "Failed to process events for " ) + cc.sunny( strDirection ) + cc.error( " message " ) + cc.info( idxMessage + 1 ) + cc.error( " on node " ) + cc.info( jo_node.name ) + cc.success( " using URL " ) + cc.info( jo_node.http_endpoint_ip ) + - cc.debug( ", error is: " ) + cc.warning( err.toString() ) + "\n"; + cc.debug( ", error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; details.write( strError ); if( verbose_get() >= RV_VERBOSE.fatal ) log.write( strError ); @@ -5915,7 +5962,7 @@ async function do_s2s_all( // s-chain --> s-chain for( let idxSChain = 0; idxSChain < cntSChains; ++ idxSChain ) { const jo_schain = arr_schains_cached[idxSChain]; const url_src = skale_observer.pick_random_schain_w3_url( jo_schain ); - const w3_src = getWeb3FromURL( url_src ); + const w3_src = getWeb3FromURL( url_src, log ); const joAccountSrc = joAccountDst; // ??? const chain_id_src = "" + jo_schain.data.name; const cid_src = "" + jo_schain.data.computed.chainId; diff --git a/npms/skale-ima/package.json b/npms/skale-ima/package.json index 05aacded4..f425aa5d4 100644 --- a/npms/skale-ima/package.json +++ b/npms/skale-ima/package.json @@ -33,7 +33,7 @@ "dependencies": { "ethereumjs-tx": "1.3.7", "ethereumjs-wallet": "^1.0.2", - "ethereumjs-util": "^7.1.3", + "ethereumjs-util": "^7.1.4", "web3": "^1.6.1", "ioredis": "^4.28.2" }, diff --git a/npms/skale-ima/yarn.lock b/npms/skale-ima/yarn.lock index 053271b48..677be220b 100644 --- a/npms/skale-ima/yarn.lock +++ b/npms/skale-ima/yarn.lock @@ -1087,6 +1087,17 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.3: ethereum-cryptography "^0.1.3" rlp "^2.2.4" +ethereumjs-util@^7.1.4: + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + ethereumjs-wallet@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js index d22107216..59e6cc27a 100644 --- a/npms/skale-observer/observer.js +++ b/npms/skale-observer/observer.js @@ -24,12 +24,58 @@ * @copyright SKALE Labs 2019-Present */ +const network_layer = require( "../skale-cool-socket/socket.js" ); +const { Worker } = require( "worker_threads" ); +const path = require( "path" ); + const owaspUtils = require( "../skale-owasp/owasp-util.js" ); -const { getWeb3FromURL } = require( "../../agent/cli.js" ); const cc = owaspUtils.cc; +const w3mod = require( "web3" ); +// const ethereumjs_tx = require( "ethereumjs-tx" ); +// const ethereumjs_wallet = require( "ethereumjs-wallet" ); +// const ethereumjs_util = require( "ethereumjs-util" ); + const PORTS_PER_SCHAIN = 64; +function getWeb3FromURL( strURL, log ) { + let w3 = null; + log = log || { write: console.log }; + try { + const u = cc.safeURL( strURL ); + const strProtocol = u.protocol.trim().toLowerCase().replace( ":", "" ).replace( "/", "" ); + if( strProtocol == "ws" || strProtocol == "wss" ) { + const w3ws = new w3mod.providers.WebsocketProvider( strURL, { + // see: https://github.com/ChainSafe/web3.js/tree/1.x/packages/web3-providers-ws#usage + clientConfig: { + // // if requests are large: + // maxReceivedFrameSize: 100000000, // bytes - default: 1MiB + // maxReceivedMessageSize: 100000000, // bytes - default: 8MiB + // keep a connection alive + keepalive: true, + keepaliveInterval: 200000 // ms + }, + reconnect: { // enable auto reconnection + auto: true, + delay: 5000, // ms + maxAttempts: 10000000, // 10 million times + onTimeout: false + } + } ); + w3 = new w3mod( w3ws ); + } else { + const w3http = new w3mod.providers.HttpProvider( strURL ); + w3 = new w3mod( w3http ); + } + } catch ( err ) { + log.write( cc.fatal( "CRITICAL ERROR:" ) + cc.error( " Failed to create " ) + + cc.attention( "Web3" ) + cc.error( " connection to " ) + cc.info( strURL ) + + cc.error( ": " ) + cc.warning( owaspUtils.extract_error_message( err ) ) ); + w3 = null; + } + return w3; +} + function get_schain_index_in_node( schain_id, schains_ids_on_node ) { let i = 0; for( const schain_id_on_node of schains_ids_on_node ) { @@ -55,6 +101,7 @@ function compose_endpoints( jo_schain, node_dict, endpoint_type ) { node_dict["ws_endpoint_" + endpoint_type] = "ws://" + node_dict[endpoint_type] + ":" + jo_schain.data.computed.ports.wsRpcPort; node_dict["wss_endpoint_" + endpoint_type] = "wss://" + node_dict[endpoint_type] + ":" + jo_schain.data.computed.ports.wssRpcPort; node_dict["info_http_endpoint_" + endpoint_type] = "http://" + node_dict[endpoint_type] + ":" + jo_schain.data.computed.ports.infoHttpRpcPort; + node_dict["ima_agent_endpoint_" + endpoint_type] = "http://" + node_dict[endpoint_type] + ":" + jo_schain.data.computed.ports.imaAgentRpcPort; } const SkaledPorts = { @@ -67,7 +114,8 @@ const SkaledPorts = { IMA_MONITORING: 6, WSS_JSON: 7, HTTPS_JSON: 8, - INFO_HTTP_JSON: 9 + INFO_HTTP_JSON: 9, + IMA_AGENT_JSON: 10 }; function calc_ports( jo_schain, schain_base_port ) { @@ -77,7 +125,8 @@ function calc_ports( jo_schain, schain_base_port ) { httpsRpcPort: schain_base_port + SkaledPorts.HTTPS_JSON, wsRpcPort: schain_base_port + SkaledPorts.WS_JSON, wssRpcPort: schain_base_port + SkaledPorts.WSS_JSON, - infoHttpRpcPort: schain_base_port + SkaledPorts.INFO_HTTP_JSON + infoHttpRpcPort: schain_base_port + SkaledPorts.INFO_HTTP_JSON, + imaAgentRpcPort: schain_base_port + SkaledPorts.IMA_AGENT_JSON }; } @@ -137,12 +186,12 @@ function remove_schain_desc_data_num_keys( jo_schain ) { } } -async function load_schain( w3, addressFrom, idxSChain, cntSChains, opts ) { +async function load_schain( w3, addressFrom, idxSChain, hash, cntSChains, opts ) { if( ! opts.imaState ) throw new Error( "Cannot load S-Chain description in observer, no imaState is provided" ); if( opts && opts.details ) opts.details.write( cc.debug( "Loading S-Chain " ) + cc.notice( "#" ) + cc.info( idxSChain + 1 ) + cc.debug( " of " ) + cc.info( cntSChains ) + cc.debug( "..." ) + "\n" ); - const hash = await opts.imaState.jo_schains_internal.methods.schainsAtSystem( idxSChain ).call( { from: addressFrom } ); + hash = hash || await opts.imaState.jo_schains_internal.methods.schainsAtSystem( idxSChain ).call( { from: addressFrom } ); if( opts && opts.details ) opts.details.write( cc.debug( " Hash " ) + cc.attention( hash ) + "\n" ); if( opts && opts.bStopNeeded ) @@ -172,7 +221,7 @@ async function load_schains( w3, addressFrom, opts ) { for( let idxSChain = 0; idxSChain < cntSChains; ++ idxSChain ) { if( opts && opts.bStopNeeded ) break; - const jo_schain = await load_schain( w3, addressFrom, idxSChain, cntSChains, opts ); + const jo_schain = await load_schain( w3, addressFrom, idxSChain, null, cntSChains, opts ); if( ! jo_schain ) break; arr_schains.push( jo_schain ); @@ -186,6 +235,87 @@ async function load_schains( w3, addressFrom, opts ) { return arr_schains; } +async function load_cached_schains_simplified( w3, addressFrom, opts ) { + if( ! opts.imaState ) + throw new Error( "Cannot load S-Chains in observer, no imaState is provided" ); + if( opts && opts.details ) + opts.details.write( cc.debug( "Will request all S-Chain(s) hashes..." ) + "\n" ); + const arrSChainHashes = await opts.imaState.jo_schains_internal.methods.getSchains().call( { from: addressFrom } ); + const cntSChains = arrSChainHashes.length; + if( opts && opts.details ) + opts.details.write( cc.debug( "Have all " ) + cc.info( cntSChains ) + cc.debug( " S-Chain(s) hashes: " ) + cc.j( arrSChainHashes ) + "\n" ); + const arr_schains = []; + for( let idxSChain = 0; idxSChain < cntSChains; ++ idxSChain ) { + if( opts && opts.bStopNeeded ) + break; + const strSChainHash = arrSChainHashes[idxSChain]; + const strSChainName = await opts.imaState.jo_schains_internal.methods.getSchainName( strSChainHash ).call( { from: addressFrom } ); + if( opts && opts.details ) + opts.details.write( cc.debug( "S-Chain " ) + cc.notice( idxSChain ) + cc.debug( " hash " ) + cc.notice( strSChainHash ) + cc.debug( " corresponds to S-Chain name " ) + cc.notice( strSChainName ) + "\n" ); + if( opts && opts.bStopNeeded ) + break; + const jo_schain = await load_schain( w3, addressFrom, idxSChain, strSChainHash, cntSChains, opts ); + if( ! jo_schain ) + break; + arr_schains.push( jo_schain ); + } + return arr_schains; +} + +async function load_schains_connected_only( w3_main_net, w3_s_chain, strChainNameConnectedTo, addressFrom, opts ) { + if( ! opts.imaState ) + throw new Error( "Cannot load S-Chains in observer, no imaState is provided" ); + if( opts && opts.details ) + opts.details.write( cc.debug( "Will request all S-Chain(s) hashes..." ) + "\n" ); + const arrSChainHashes = await opts.imaState.jo_schains_internal.methods.getSchains().call( { from: addressFrom } ); + const cntSChains = arrSChainHashes.length; + if( opts && opts.details ) + opts.details.write( cc.debug( "Have all " ) + cc.info( cntSChains ) + cc.debug( " S-Chain(s) hashes: " ) + cc.j( arrSChainHashes ) + "\n" ); + const jo_message_proxy_s_chain = + new w3_s_chain.eth.Contract( + opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_abi, + opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_address + ); + const arr_schains = []; + for( let idxSChain = 0; idxSChain < cntSChains; ++ idxSChain ) { + try { + if( opts && opts.bStopNeeded ) + break; + const strSChainHash = arrSChainHashes[idxSChain]; + const strSChainName = await opts.imaState.jo_schains_internal.methods.getSchainName( strSChainHash ).call( { from: addressFrom } ); + if( opts && opts.details ) + opts.details.write( cc.debug( "S-Chain " ) + cc.notice( idxSChain ) + cc.debug( " hash " ) + cc.notice( strSChainHash ) + cc.debug( " corresponds to S-Chain name " ) + cc.notice( strSChainName ) + "\n" ); + if( opts && opts.bStopNeeded ) + break; + // + if( strChainNameConnectedTo == strSChainName ) { + if( opts && opts.details ) + opts.details.write( cc.debug( "Skip this S-Chain " ) + cc.info( strSChainName ) + cc.debug( " connected status check" ) + "\n" ); + continue; + } + if( opts && opts.details ) { + opts.details.write( + cc.debug( "Querying connected status between S-Chain " ) + cc.info( strSChainName ) + cc.debug( " and S-Chain " ) + + cc.info( strChainNameConnectedTo ) + cc.debug( "..." ) + "\n" ); + } + const isConnected = await jo_message_proxy_s_chain.methods.isConnectedChain( strSChainName ).call( { from: addressFrom } ); + if( opts && opts.details ) + opts.details.write( cc.debug( "Got S-Chain " ) + cc.info( strSChainName ) + cc.debug( " connected status: " ) + cc.yn( isConnected ) + "\n" ); + if( ! isConnected ) + continue; + const jo_schain = await load_schain( w3_main_net, addressFrom, idxSChain, strSChainHash, cntSChains, opts ); + if( ! jo_schain ) + break; + jo_schain.isConnected = true; + arr_schains.push( jo_schain ); + } catch ( err ) { + if( opts && opts.details ) + opts.details.write( cc.error( "Got error: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); + } + } + return arr_schains; +} + async function check_connected_schains( strChainNameConnectedTo, arr_schains, addressFrom, opts ) { if( ! opts.imaState ) throw new Error( "Cannot load S-Chains in observer, no imaState is provided" ); @@ -198,7 +328,6 @@ async function check_connected_schains( strChainNameConnectedTo, arr_schains, ad if( jo_schain.data.name == strChainNameConnectedTo ) continue; try { - //jo_schain.isConnected = await opts.imaState.jo_message_proxy_s_chain.methods.isConnectedChain( strChainNameConnectedTo ).call( { from: addressFrom } ); const url = pick_random_schain_w3_url( jo_schain ); if( opts && opts.details ) { opts.details.write( @@ -206,8 +335,8 @@ async function check_connected_schains( strChainNameConnectedTo, arr_schains, ad cc.info( jo_schain.data.name ) + cc.debug( " whether it's connected to S-Chain " ) + cc.info( strChainNameConnectedTo ) + cc.debug( "..." ) + "\n" ); } - const w3 = getWeb3FromURL( url ); - const jo_message_proxy_s_chain = new w3.eth.Contract( imaState.joAbiPublishResult_s_chain.message_proxy_chain_abi, imaState.joAbiPublishResult_s_chain.message_proxy_chain_address ); + const w3 = getWeb3FromURL( url, opts.details ); + const jo_message_proxy_s_chain = new w3.eth.Contract( opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_abi, opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_address ); jo_schain.isConnected = await jo_message_proxy_s_chain.methods.isConnectedChain( strChainNameConnectedTo ).call( { from: addressFrom } ); if( opts && opts.details ) { opts.details.write( @@ -215,7 +344,7 @@ async function check_connected_schains( strChainNameConnectedTo, arr_schains, ad } } catch ( err ) { if( opts && opts.details ) - opts.details.write( cc.error( "Got error: " ) + cc.warning( err.toString() ) + "\n" ); + opts.details.write( cc.error( "Got error: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" ); } } return arr_schains; @@ -298,40 +427,41 @@ function merge_schains_array_from_to( arrSrc, arrDst, arrNew, arrOld, opts ) { opts.details.write( cc.success( "Finally, have " ) + cc.info( arrDst.length ) + cc.success( " S-Chain(s)" ) + "\n" ); } -let g_arr_schains_cached = null; +let g_arr_schains_cached = []; -async function cache_schains( strChainNameConnectedTo, w3, addressFrom, opts ) { +async function cache_schains( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ) { let strError = null; try { - const arr_schains = await load_schains( w3, addressFrom, opts ); + let arr_schains = []; if( strChainNameConnectedTo && ( typeof strChainNameConnectedTo == "string" ) && strChainNameConnectedTo.length > 0 ) { - await check_connected_schains( + arr_schains = await load_schains_connected_only( + w3_main_net, + w3_s_chain, strChainNameConnectedTo, - arr_schains, addressFrom, opts ); - g_arr_schains_cached = await filter_schains_marked_as_connected( - arr_schains, - opts - ); } else - g_arr_schains_cached = arr_schains; + arr_schains = await load_schains( w3_main_net, addressFrom, opts ); + + g_arr_schains_cached = arr_schains; + if( opts && opts.details ) { opts.details.write( - cc.debug( "Connected " ) + cc.attention( "S-Chains" ) + cc.debug( " cache was updated: " ) + + cc.debug( "Connected " ) + cc.attention( "S-Chains" ) + cc.debug( " cache was updated in this thread: " ) + cc.j( g_arr_schains_cached ) + "\n" ); } if( opts.fn_chache_changed ) opts.fn_chache_changed( g_arr_schains_cached, null ); // null - no error } catch ( err ) { - strError = err.toString(); + strError = owaspUtils.extract_error_message( err ); if( ! strError ) strError = "unknown exception during S-Chains download"; if( opts.fn_chache_changed ) opts.fn_chache_changed( g_arr_schains_cached, strError ); if( opts && opts.details ) opts.details.write( cc.fatal( "ERROR:" ) + cc.error( " Failed to cache: " ) + cc.error( err ) + "\n" ); + } return strError; // null on success } @@ -340,33 +470,123 @@ function get_last_cached_schains() { return JSON.parse( JSON.stringify( g_arr_schains_cached ) ); } -let g_intervalPeriodicSchainsCaching = null; -let g_bIsPeriodicCachingStepInProgress = false; - -async function periodic_caching_start( strChainNameConnectedTo, w3, addressFrom, opts ) { - await periodic_caching_stop(); - if( ! ( "secondsToReDiscoverSkaleNetwork" in opts ) ) - return false; - const secondsToReDiscoverSkaleNetwork = parseInt( opts.secondsToReDiscoverSkaleNetwork ); - if( secondsToReDiscoverSkaleNetwork <= 0 ) - return false; - g_intervalPeriodicSchainsCaching = setInterval( async function() { - if( g_bIsPeriodicCachingStepInProgress ) +const impl_sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; + +let g_worker = null; +let g_client = null; + +async function ensure_have_worker( opts ) { + if( g_worker ) + return g_worker; + const url = "skale_observer_worker_server"; + g_worker = new Worker( path.join( __dirname, "observer_worker.js" ) ); + // console.log( "Will connect to " + url ); + g_worker.on( "message", jo => { + if( network_layer.out_of_worker_apis.on_message( g_worker, jo ) ) return; - g_bIsPeriodicCachingStepInProgress = true; - // const strError = - await cache_schains( strChainNameConnectedTo, w3, addressFrom, opts ); - g_bIsPeriodicCachingStepInProgress = false; - }, secondsToReDiscoverSkaleNetwork * 1000 ); - return true; + } ); + g_client = new network_layer.OutOfWorkerSocketClientPipe( url, g_worker ); + g_client.on( "message", function( eventData ) { + const joMessage = eventData.message; + // console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); + switch ( joMessage.method ) { + case "periodic_caching_do_now": + g_arr_schains_cached = joMessage.message; + if( opts && opts.details ) { + opts.details.write( + cc.debug( "Connected " ) + cc.attention( "S-Chains" ) + + cc.debug( " cache was updated using data arrived from SNB worker: " ) + + cc.j( g_arr_schains_cached ) + "\n" ); + } + break; + case "log": + log.write( cc.attention( "SNB WORKER" ) + " " + joMessage.message ); + break; + } // switch ( joMessage.method ) + } ); + await impl_sleep( 1000 ); + const jo = { + method: "init", + message: { + opts: { + imaState: { + "joAbiPublishResult_skale_manager": opts.imaState.joAbiPublishResult_skale_manager, + "joAbiPublishResult_main_net": opts.imaState.joAbiPublishResult_main_net, + "joAbiPublishResult_s_chain": opts.imaState.joAbiPublishResult_s_chain, + "bHaveSkaleManagerABI": opts.imaState.bHaveSkaleManagerABI, + "bHaveImaAbiMainNet": opts.imaState.bHaveImaAbiMainNet, + "bNoWaitSChainStarted": opts.imaState.bNoWaitSChainStarted, + "nMaxWaitSChainAttempts": opts.imaState.nMaxWaitSChainAttempts, + "strURL_main_net": opts.imaState.strURL_main_net, + "strChainName_main_net": opts.imaState.strChainName_main_net, + "cid_main_net": opts.imaState.cid_main_net, + "strURL_s_chain": opts.imaState.strURL_s_chain, + "strChainName_s_chain": opts.imaState.strChainName_s_chain, + "cid_s_chain": opts.imaState.cid_s_chain, + "nNodeNumber": opts.imaState.nNodeNumber, // S-Chain node number(zero based) + "nNodesCount": opts.imaState.nNodesCount, + "nTimeFrameSeconds": opts.imaState.nTimeFrameSeconds, // 0-disable, 60-recommended + "nNextFrameGap": opts.imaState.nNextFrameGap, + "joAccount_main_net": { + "privateKey": opts.imaState.joAccount_main_net.privateKey, + // "address": IMA.owaspUtils.fn_address_impl_, + "strTransactionManagerURL": opts.imaState.joAccount_main_net.strTransactionManagerURL, + "tm_priority": opts.imaState.joAccount_main_net.tm_priority, + "strSgxURL": opts.imaState.joAccount_main_net.strSgxURL, + "strSgxKeyName": opts.imaState.joAccount_main_net.strSgxKeyName, + "strPathSslKey": opts.imaState.joAccount_main_net.strPathSslKey, + "strPathSslCert": opts.imaState.joAccount_main_net.strPathSslCert, + "strBlsKeyName": opts.imaState.joAccount_main_net.strBlsKeyName + }, + "joAccount_s_chain": { + "privateKey": opts.imaState.joAccount_s_chain.privateKey, + // "address": IMA.owaspUtils.fn_address_impl_, + "strTransactionManagerURL": opts.imaState.joAccount_s_chain.strTransactionManagerURL, + "tm_priority": opts.imaState.joAccount_s_chain.tm_priority, + "strSgxURL": opts.imaState.joAccount_s_chain.strSgxURL, + "strSgxKeyName": opts.imaState.joAccount_s_chain.strSgxKeyName, + "strPathSslKey": opts.imaState.joAccount_s_chain.strPathSslKey, + "strPathSslCert": opts.imaState.joAccount_s_chain.strPathSslCert, + "strBlsKeyName": opts.imaState.joAccount_s_chain.strBlsKeyName + }, + // "tc_main_net": IMA.tc_main_net, + // "tc_s_chain": IMA.tc_s_chain, + // "doEnableDryRun": function( isEnable ) { return IMA.dry_run_enable( isEnable ); }, + // "doIgnoreDryRun": function( isIgnore ) { return IMA.dry_run_ignore( isIgnore ); }, + "joSChainDiscovery": { + "isSilentReDiscovery": opts.imaState.joSChainDiscovery.isSilentReDiscovery, + "repeatIntervalMilliseconds": opts.imaState.joSChainDiscovery.repeatIntervalMilliseconds // zero to disable (for debugging only) + } + } + }, + "cc": { + "isEnabled": cc.isEnabled() + } + } + }; + g_client.send( jo ); +} + +async function periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ) { + await ensure_have_worker( opts ); + const jo = { + method: "periodic_caching_start", + message: { + secondsToReDiscoverSkaleNetwork: parseInt( opts.secondsToReDiscoverSkaleNetwork ), + strChainNameConnectedTo: strChainNameConnectedTo, + addressFrom: addressFrom + } + }; + g_client.send( jo ); } async function periodic_caching_stop() { - if( ! g_intervalPeriodicSchainsCaching ) - return false; - clearInterval( g_intervalPeriodicSchainsCaching ); - g_intervalPeriodicSchainsCaching = null; - g_bIsPeriodicCachingStepInProgress = false; - return true; + await ensure_have_worker( opts ); + const jo = { + method: "periodic_caching_stop", + message: { + } + }; + g_client.send( jo ); } function pick_random_schain_node_index( jo_schain ) { @@ -391,7 +611,9 @@ async function discover_chain_id( strURL ) { const rpcCallOpts = null; await rpcCall.create( strURL, rpcCallOpts, async function( joCall, err ) { if( err ) { - //ret = "Failed to create RPC (" + strURL + ") call: " + err.toString(); + //ret = "Failed to create RPC (" + strURL + ") call: " + owaspUtils.extract_error_message( err ); + if( joCall ) + await joCall.disconnect(); return; } await joCall.call( { @@ -399,24 +621,31 @@ async function discover_chain_id( strURL ) { "params": [] }, async function( joIn, joOut, err ) { if( err ) { - //ret = "Failed to query RPC (" + strURL + ") for chain ID: " + err.toString(); + //ret = "Failed to query RPC (" + strURL + ") for chain ID: " + owaspUtils.extract_error_message( err ); + await joCall.disconnect(); return; } if( ! ( "result" in joOut && joOut.result ) ) { //ret = "Failed to query RPC (" + strURL + ") for chain ID, got bad result: " + JSON.stringify( joOut ); + await joCall.disconnect(); return; } ret = joOut.result; + await joCall.disconnect(); } ); // joCall.call ... } ); // rpcCall.create ... return ret; } +module.exports.w3mod = w3mod; +module.exports.getWeb3FromURL = getWeb3FromURL; module.exports.owaspUtils = owaspUtils; module.exports.cc = cc; module.exports.get_schains_count = get_schains_count; module.exports.load_schain = load_schain; module.exports.load_schains = load_schains; +module.exports.load_cached_schains_simplified = load_cached_schains_simplified; +module.exports.load_schains_connected_only = load_schains_connected_only; module.exports.check_connected_schains = check_connected_schains; module.exports.filter_schains_marked_as_connected = filter_schains_marked_as_connected; module.exports.find_schain_index_in_array_by_name = find_schain_index_in_array_by_name; diff --git a/npms/skale-observer/observer_worker.js b/npms/skale-observer/observer_worker.js new file mode 100644 index 000000000..3180fc071 --- /dev/null +++ b/npms/skale-observer/observer_worker.js @@ -0,0 +1,210 @@ + +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * @license + * SKALE IMA + * + * SKALE IMA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SKALE IMA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with SKALE IMA. If not, see . + */ + +/** + * @file observer_worker.js + * @copyright SKALE Labs 2019-Present + */ + +const { + parentPort + //, workerData +} = require( "worker_threads" ); +const network_layer = require( "../skale-cool-socket/socket.js" ); +const { Server } = require( "../skale-cool-socket/server.js" ); +const owaspUtils = require( "../skale-owasp/owasp-util.js" ); +const cc = owaspUtils.cc; + +const skale_observer = require( "./observer.js" ); + +const g_url = "skale_observer_worker_server"; + +parentPort.on( "message", jo => { + if( network_layer.in_worker_apis.on_message( jo ) ) + return; +} ); + +function doSendMessage( type, endpoint, worker_uuid, data ) { + const jo = network_layer.socket_received_data_reverse_marshall( data ); + const joSend = { + worker_message_type: ( type && typeof type == "string" && type.length > 0 ) ? type : "in_worker_message", + worker_endpoint: endpoint, + worker_uuid: worker_uuid, + data: jo + }; + parentPort.postMessage( network_layer.socket_sent_data_marshall( joSend ) ); +} + +class ObserverServer extends Server { + constructor( acceptor ) { + super( acceptor ); + const self = this; + self.opts = null; + self.intervalPeriodicSchainsCaching = null; + self.bIsPeriodicCachingStepInProgress = false; + self.mapApiHandlers.init = function( joMessage, joAnswer, eventData, socket ) { + self.log = function() { + const args = Array.prototype.slice.call( arguments ); + const jo = { + method: "log", + error: null, + message: args.join( " " ) + }; + const isFlush = true; + socket.send( jo, isFlush ); + }; + self.opts = JSON.parse( JSON.stringify( joMessage.message.opts ) ); + self.opts.details = { + write: self.log + }; + // self.log( cc.debug( "Initialized in-worker options:" ) + " " + cc.j( self.opts ) + "\n" ); + // + self.opts.imaState.joAccount_main_net.address = owaspUtils.fn_address_impl_; + self.opts.imaState.joAccount_s_chain.address = owaspUtils.fn_address_impl_; + // + if( self.opts.imaState.strURL_main_net && typeof self.opts.imaState.strURL_main_net == "string" && self.opts.imaState.strURL_main_net.length > 0 ) { + const u = self.opts.imaState.strURL_main_net; + self.opts.imaState.w3_main_net = skale_observer.getWeb3FromURL( u, self.log ); + } else { + self.log( + cc.error( "WARNING:" ) + cc.warning( " No " ) + cc.note( "Main-net" ) + + cc.warning( " URL specified in command line arguments" ) + + cc.debug( "(needed for particular operations only)" ) + + "\n" ); + } + // + if( self.opts.imaState.strURL_s_chain && typeof self.opts.imaState.strURL_s_chain == "string" && self.opts.imaState.strURL_s_chain.length > 0 ) { + const u = self.opts.imaState.strURL_s_chain; + self.opts.imaState.w3_s_chain = skale_observer.getWeb3FromURL( u, self.log ); + } else { + self.log( + cc.error( "WARNING:" ) + cc.warning( " No " ) + cc.note( "Main-net" ) + + cc.warning( " URL specified in command line arguments" ) + + cc.debug( "(needed for particular operations only)" ) + + "\n" ); + } + // + self.opts.imaState.jo_nodes = new self.opts.imaState.w3_main_net.eth.Contract( self.opts.imaState.joAbiPublishResult_skale_manager.nodes_abi, self.opts.imaState.joAbiPublishResult_skale_manager.nodes_address ); + self.opts.imaState.jo_schains = new self.opts.imaState.w3_main_net.eth.Contract( self.opts.imaState.joAbiPublishResult_skale_manager.schains_abi, self.opts.imaState.joAbiPublishResult_skale_manager.schains_address ); + self.opts.imaState.jo_schains_internal = new self.opts.imaState.w3_main_net.eth.Contract( self.opts.imaState.joAbiPublishResult_skale_manager.schains_internal_abi, self.opts.imaState.joAbiPublishResult_skale_manager.schains_internal_address ); + // + self.opts.imaState.jo_message_proxy_s_chain = new self.opts.imaState.w3_s_chain.eth.Contract( self.opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_abi, self.opts.imaState.joAbiPublishResult_s_chain.message_proxy_chain_address ); + // + cc.enable( joMessage.message.cc.isEnabled ); + joAnswer.message = { + method: "" + joMessage.method, + error: null + }; + self.log( cc.debug( "Full init compete for in-worker SNB server" ) + " " + cc.notice( g_url ) + "\n" ); + return joAnswer; + }; + self.mapApiHandlers.periodic_caching_start = function( joMessage, joAnswer, eventData, socket ) { + self.periodic_caching_start( + socket, + joMessage.message.secondsToReDiscoverSkaleNetwork, + joMessage.message.strChainNameConnectedTo, + joMessage.message.addressFrom + ); + joAnswer.message = { + method: "" + joMessage.method, + error: null + }; + return joAnswer; + }; + self.mapApiHandlers.periodic_caching_stop = function( joMessage, joAnswer, eventData, socket ) { + self.periodic_caching_stop(); + joAnswer.message = { + method: "" + joMessage.method, + error: null + }; + return joAnswer; + }; + self.log( cc.debug( "Initialized in-worker SNB server" ) + " " + cc.notice( g_url ) + "\n" ); + } + dispose() { + const self = this; + self.isDisposing = true; + if( self.intervalPeriodicSchainsCaching ) { + clearInterval( self.intervalPeriodicSchainsCaching ); + self.intervalPeriodicSchainsCaching = null; + } + super.dispose(); + } + async periodic_caching_do_now( socket, secondsToReDiscoverSkaleNetwork, strChainNameConnectedTo, addressFrom ) { + const self = this; + if( self.bIsPeriodicCachingStepInProgress ) + return; + self.bIsPeriodicCachingStepInProgress = true; + // const strError = + await skale_observer.cache_schains( + strChainNameConnectedTo, + self.opts.imaState.w3_main_net, + self.opts.imaState.w3_s_chain, + addressFrom, + self.opts + ); + self.bIsPeriodicCachingStepInProgress = false; + const arr_schains = skale_observer.get_last_cached_schains(); + // self.log( cc.normal( "Got " ) + cc.info( "SKALE NETWORK" ) + cc.normal( " information in worker: " ) + cc.j( arr_schains ) + "\n" ); + const jo = { + method: "periodic_caching_do_now", + error: null, + message: arr_schains + }; + const isFlush = true; + socket.send( jo, isFlush ); + } + async periodic_caching_start( socket, secondsToReDiscoverSkaleNetwork, strChainNameConnectedTo, addressFrom ) { + const self = this; + await self.periodic_caching_stop(); + if( secondsToReDiscoverSkaleNetwork <= 0 ) + return false; + const fn_async_handler = async function() { + await self.periodic_caching_do_now( socket, secondsToReDiscoverSkaleNetwork, strChainNameConnectedTo, addressFrom ); + }; + self.intervalPeriodicSchainsCaching = setInterval( function() { + if( self.bIsPeriodicCachingStepInProgress ) + return; + fn_async_handler() + .then( () => { + } ).catch( () => { + } ); + }, secondsToReDiscoverSkaleNetwork * 1000 ); + fn_async_handler(); // initial async call + return true; + } + async periodic_caching_stop() { + const self = this; + if( ! self.intervalPeriodicSchainsCaching ) + return false; + clearInterval( self.intervalPeriodicSchainsCaching ); + self.intervalPeriodicSchainsCaching = null; + self.bIsPeriodicCachingStepInProgress = false; + return true; + } +}; + +const acceptor = new network_layer.InWorkerSocketServerAcceptor( g_url, doSendMessage ); +const server = new ObserverServer( acceptor ); +server.on( "dispose", function() { + const self = server; + self.log( cc.debug( "Disposed in-worker SNB server" ) + " " + cc.notice( g_url ) + "\n" ); +} ); diff --git a/npms/skale-observer/package.json b/npms/skale-observer/package.json index c3575b4e1..6aff75501 100644 --- a/npms/skale-observer/package.json +++ b/npms/skale-observer/package.json @@ -5,9 +5,9 @@ "author": "SKALE Labs and contributors", "scripts": {}, "dependencies": { - "ethereumjs-tx": "1.3.7", - "ethereumjs-wallet": "0.6.3", - "ethereumjs-util": "6.1.0", + "ethereumjs-tx": "2.1.2", + "ethereumjs-wallet": "^1.0.2", + "ethereumjs-util": "^7.1.4", "web3": "^1.6.1", "uuid": "3.3.3", "sha3": "2.1.4" diff --git a/npms/skale-observer/yarn.lock b/npms/skale-observer/yarn.lock index a0ba805e4..e04aa5e45 100644 --- a/npms/skale-observer/yarn.lock +++ b/npms/skale-observer/yarn.lock @@ -257,7 +257,7 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -aes-js@^3.1.1: +aes-js@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== @@ -376,20 +376,6 @@ bignumber.js@^9.0.0: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== -bindings@^1.2.1, bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bip66@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" - integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI= - dependencies: - safe-buffer "^5.0.1" - blakejs@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" @@ -412,7 +398,7 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -451,7 +437,7 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6, browserify-aes@^1.2.0: +browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -858,15 +844,6 @@ dom-walk@^0.1.0: resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== -drbg.js@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" - integrity sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs= - dependencies: - browserify-aes "^1.0.6" - create-hash "^1.1.2" - create-hmac "^1.1.4" - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -1022,11 +999,6 @@ ethereum-bloom-filters@^1.0.6: dependencies: js-sha3 "^0.8.0" -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha1-L9w1dvIykDNYl26znaeDIT/5Uj8= - ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -1048,39 +1020,18 @@ ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereumjs-tx@1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-util@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz#e9c51e5549e8ebd757a339cc00f5380507e799c8" - integrity sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - ethjs-util "0.1.6" - keccak "^1.0.2" - rlp "^2.0.0" - safe-buffer "^5.1.1" - secp256k1 "^3.0.1" +ethereumjs-common@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" + integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== -ethereumjs-util@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== +ethereumjs-tx@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" + integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.0.0" ethereumjs-util@^6.0.0: version "6.2.1" @@ -1106,20 +1057,30 @@ ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.3: ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethereumjs-wallet@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.3.tgz#b0eae6f327637c2aeb9ccb9047b982ac542e6ab1" - integrity sha512-qiXPiZOsStem+Dj/CQHbn5qex+FVkuPmGH7SvSnA9F3tdRDt8dLMyvIj3+U05QzVZNPYh4HXEdnzoYI4dZkr9w== +ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.4: + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethereumjs-wallet@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz#2c000504b4c71e8f3782dabe1113d192522e99b6" + integrity sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA== dependencies: - aes-js "^3.1.1" + aes-js "^3.1.2" bs58check "^2.1.2" - ethereumjs-util "^6.0.0" - hdkey "^1.1.0" - randombytes "^2.0.6" - safe-buffer "^5.1.2" - scrypt.js "^0.3.0" + ethereum-cryptography "^0.1.3" + ethereumjs-util "^7.1.2" + randombytes "^2.1.0" + scrypt-js "^3.0.1" utf8 "^3.0.0" - uuid "^3.3.2" + uuid "^8.3.2" ethjs-unit@0.1.6: version "0.1.6" @@ -1129,7 +1090,7 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3: +ethjs-util@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== @@ -1223,11 +1184,6 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1496,15 +1452,6 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hdkey@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-1.1.2.tgz#c60f9cf6f90fbf24a8a52ea06893f36a0108cd3e" - integrity sha512-PTQ4VKu0oRnCrYfLp04iQZ7T2Cxz0UsEXYauk2j8eh6PJXCpbXuCFhOmtIFtbET0i3PMWmHN9J11gU8LEgUljQ== - dependencies: - bs58check "^2.1.2" - safe-buffer "^5.1.1" - secp256k1 "^3.0.1" - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -1823,16 +1770,6 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -keccak@^1.0.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" - integrity sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw== - dependencies: - bindings "^1.2.1" - inherits "^2.0.3" - nan "^2.2.1" - safe-buffer "^5.1.0" - keccak@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" @@ -2031,7 +1968,7 @@ multihashes@^0.4.15, multihashes@~0.4.15: multibase "^0.7.0" varint "^5.0.0" -nan@^2.14.0, nan@^2.2.1: +nan@^2.14.0: version "2.15.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== @@ -2398,7 +2335,7 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== @@ -2508,7 +2445,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.3, rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -2540,41 +2477,11 @@ scrypt-js@^3.0.0, scrypt-js@^3.0.1: resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -scrypt.js@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.3.0.tgz#6c62d61728ad533c8c376a2e5e3e86d41a95c4c0" - integrity sha512-42LTc1nyFsyv/o0gcHtDztrn+aqpkaCNt5Qh7ATBZfhEZU7IC/0oT/qbBH+uRNoAPvs2fwiOId68FDEoSRA8/A== - dependencies: - scryptsy "^1.2.1" - optionalDependencies: - scrypt "^6.0.2" - -scrypt@^6.0.2, "scrypt@file:../scrypt/node-scrypt": +"scrypt@file:../scrypt/node-scrypt": version "6.0.3" dependencies: nan "^2.14.0" -scryptsy@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" - integrity sha1-oyJfpLJST4AnAHYeKFW987LZIWM= - dependencies: - pbkdf2 "^3.0.3" - -secp256k1@^3.0.1: - version "3.8.0" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.8.0.tgz#28f59f4b01dbee9575f56a47034b7d2e3b3b352d" - integrity sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw== - dependencies: - bindings "^1.5.0" - bip66 "^1.1.5" - bn.js "^4.11.8" - create-hash "^1.2.0" - drbg.js "^1.0.1" - elliptic "^6.5.2" - nan "^2.14.0" - safe-buffer "^5.1.2" - secp256k1@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.2.tgz#15dd57d0f0b9fdb54ac1fa1694f40e5e9a54f4a1" @@ -3005,6 +2912,11 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + varint@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" diff --git a/npms/skale-owasp/owasp-util.js b/npms/skale-owasp/owasp-util.js index c7e51d941..439adfc9d 100644 --- a/npms/skale-owasp/owasp-util.js +++ b/npms/skale-owasp/owasp-util.js @@ -285,12 +285,12 @@ function verifyArgumentIsInteger( joArg ) { } } -function verifyArgumentIsIntegerIpPortNumber( joArg ) { +function verifyArgumentIsIntegerIpPortNumber( joArg, isEnableZero ) { try { verifyArgumentIsInteger( joArg ); if( joArg.value < 0 ) throw new Error( "Port number " + joArg.value + " cannot be negative" ); - if( joArg.value < 1 ) + if( ( !isEnableZero ) && joArg.value < 1 ) throw new Error( "Port number " + joArg.value + " too small" ); if( joArg.value > 65535 ) throw new Error( "Port number " + joArg.value + " too big" ); @@ -625,6 +625,39 @@ function w3_2_url( w3 ) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function extract_error_message( jo, strDefaultErrorText ) { + strDefaultErrorText = strDefaultErrorText || "unknown error or error without a description"; + try { + if( ! jo ) + return strDefaultErrorText; + if( typeof jo != "object" ) + return strDefaultErrorText; + let strStack = ""; + if( "stack" in jo && jo.stack && typeof jo.stack == "object" && "length" in jo.stack && jo.stack.length > 0 ) { + strStack += "\nCall stack from error object:"; + for( let i = 0; i < jo.stack.length; ++ i ) + strStack += "\n" + jo.stack[i].toString(); + } + if( "error" in jo ) { + jo = jo.error; + if( typeof jo == "string" ) + return jo; + if( typeof jo != "object" ) + return strDefaultErrorText + "(" + jo.toString() + ")" + strStack; + } + if( "message" in jo ) { + jo = jo.message; + if( typeof jo == "string" ) + return jo + strStack; + } + strDefaultErrorText += "(" + jo.toString() + ")" + strStack; + } catch ( err ) { + } + return strDefaultErrorText; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// module.exports = { cc: cc, w3mod: w3mod, @@ -667,5 +700,6 @@ module.exports = { fn_address_impl_: fn_address_impl_, compute_chain_id_from_schain_name: compute_chain_id_from_schain_name, w3provider_2_url: w3provider_2_url, - w3_2_url: w3_2_url + w3_2_url: w3_2_url, + extract_error_message: extract_error_message }; // module.exports From aae520c67b7d0cb316fdaa188ea782ed0cbda7cc Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 1 Dec 2022 15:04:09 +0200 Subject: [PATCH 22/62] Update mainnet.json --- proxy/.openzeppelin/mainnet.json | 1761 +++++++++++++++++++++++++++++- proxy/package.json | 2 +- proxy/yarn.lock | 8 +- 3 files changed, 1758 insertions(+), 13 deletions(-) diff --git a/proxy/.openzeppelin/mainnet.json b/proxy/.openzeppelin/mainnet.json index 964bddbc9..51864d871 100644 --- a/proxy/.openzeppelin/mainnet.json +++ b/proxy/.openzeppelin/mainnet.json @@ -5903,7 +5903,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -6121,7 +6121,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -6307,7 +6307,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -6487,7 +6487,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -6679,7 +6679,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -6877,7 +6877,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -7075,7 +7075,7 @@ { "contract": "Initializable", "label": "_initialized", - "type": "t_bool", + "type": "t_uint8", "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:21" }, { @@ -7273,6 +7273,1751 @@ } } } + }, + "3622da58837ec6a715bb7177e0e4abd52b6f06ccae45304744665adce6974a38": { + "address": "0xC261084Dc6475d4980548Bd8C323FF825b3D0C38", + "txHash": "0xedeaefffa86911da5334b4c8a231fa8f70c6be9007de26306eae9b4ed1d8ad78", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "MessageProxy", + "label": "connectedChains", + "type": "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11079_storage)", + "src": "contracts/MessageProxy.sol:58" + }, + { + "contract": "MessageProxy", + "label": "deprecatedRegistryContracts", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/MessageProxy.sol:61" + }, + { + "contract": "MessageProxy", + "label": "gasLimit", + "type": "t_uint256", + "src": "contracts/MessageProxy.sol:63" + }, + { + "contract": "MessageProxyForMainnet", + "label": "communityPool", + "type": "t_contract(ICommunityPool)9651", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:72" + }, + { + "contract": "MessageProxyForMainnet", + "label": "headerMessageGasCost", + "type": "t_uint256", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:74" + }, + { + "contract": "MessageProxyForMainnet", + "label": "messageGasCost", + "type": "t_uint256", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:75" + }, + { + "contract": "MessageProxyForMainnet", + "label": "_registryContracts", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:80" + }, + { + "contract": "MessageProxyForMainnet", + "label": "version", + "type": "t_string_storage", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:81" + }, + { + "contract": "MessageProxyForMainnet", + "label": "messageInProgress", + "type": "t_bool", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:82" + }, + { + "contract": "MessageProxyForMainnet", + "label": "pauseInfo", + "type": "t_mapping(t_bytes32,t_struct(Pause)19381_storage)", + "src": "contracts/mainnet/MessageProxyForMainnet.sol:85" + } + ], + "types": { + "t_contract(ICommunityPool)9651": { + "label": "contract ICommunityPool" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_string_storage": { + "label": "string" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_struct(Pause)19381_storage)": { + "label": "mapping(bytes32 => struct MessageProxyForMainnet.Pause)" + }, + "t_struct(Pause)19381_storage": { + "label": "struct MessageProxyForMainnet.Pause", + "members": [ + { + "label": "paused", + "type": "t_bool" + } + ] + }, + "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11079_storage)": { + "label": "mapping(bytes32 => struct MessageProxy.ConnectedChainInfo)" + }, + "t_struct(ConnectedChainInfo)11079_storage": { + "label": "struct MessageProxy.ConnectedChainInfo", + "members": [ + { + "label": "incomingMessageCounter", + "type": "t_uint256" + }, + { + "label": "outgoingMessageCounter", + "type": "t_uint256" + }, + { + "label": "inited", + "type": "t_bool" + } + ] + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "be5f43ef1b09eacc8934bd9644f84fd79173f4ea3ed4c8c212649f0c2576eeca": { + "address": "0xEde996A9899b570dE70eaDE06Fa69621cE1470Be", + "txHash": "0x02b7cf351a60df17afb174d1912991f9f36d34ab5f22d4c819d84b386a0c78fe", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "Linker", + "label": "_mainnetContracts", + "type": "t_struct(AddressSet)8661_storage", + "src": "contracts/mainnet/Linker.sol:44" + }, + { + "contract": "Linker", + "label": "_interchainConnections", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/Linker.sol:47" + }, + { + "contract": "Linker", + "label": "statuses", + "type": "t_mapping(t_bytes32,t_enum(KillProcess)18966)", + "src": "contracts/mainnet/Linker.sol:51" + } + ], + "types": { + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_enum(KillProcess)18966)": { + "label": "mapping(bytes32 => enum Linker.KillProcess)" + }, + "t_enum(KillProcess)18966": { + "label": "enum Linker.KillProcess", + "members": [ + "NotKilled", + "PartiallyKilledBySchainOwner", + "PartiallyKilledByContractOwner", + "Killed" + ] + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_address": { + "label": "address" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "5e36dd460ee62e62cfe850c673b47ca31f1a405d93f219217e0f4a627a8048a2": { + "address": "0xAC1861ed87595E0AfF6C2bB9f8742D3308f48ba0", + "txHash": "0xc9155c27d61c3aa21cf792b0e22ce4b30792391ff7460f363697fa344b6bd6bf", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)1612_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)2390", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)2263", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "CommunityPool", + "label": "_userWallets", + "type": "t_mapping(t_address,t_mapping(t_bytes32,t_uint256))", + "src": "contracts/mainnet/CommunityPool.sol:44" + }, + { + "contract": "CommunityPool", + "label": "activeUsers", + "type": "t_mapping(t_address,t_mapping(t_bytes32,t_bool))", + "src": "contracts/mainnet/CommunityPool.sol:47" + }, + { + "contract": "CommunityPool", + "label": "minTransactionGas", + "type": "t_uint256", + "src": "contracts/mainnet/CommunityPool.sol:49" + }, + { + "contract": "CommunityPool", + "label": "multiplierNumerator", + "type": "t_uint256", + "src": "contracts/mainnet/CommunityPool.sol:51" + }, + { + "contract": "CommunityPool", + "label": "multiplierDivider", + "type": "t_uint256", + "src": "contracts/mainnet/CommunityPool.sol:52" + } + ], + "types": { + "t_mapping(t_address,t_mapping(t_bytes32,t_uint256))": { + "label": "mapping(address => mapping(bytes32 => uint256))" + }, + "t_address": { + "label": "address" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_address,t_mapping(t_bytes32,t_bool))": { + "label": "mapping(address => mapping(bytes32 => bool))" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_bool": { + "label": "bool" + }, + "t_contract(IMessageProxyForMainnet)2263": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)2390": { + "label": "contract IContractManager" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)1612_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)1612_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)1311_storage" + } + ] + }, + "t_struct(Set)1311_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "39a9414e6c3405f4b73d2c4bde389d583146d93c02e5ed4461d0da6d4980863c": { + "address": "0x998D6AA8CaC99f1557b65E680fc4FDCD94Be70ca", + "txHash": "0xc666170c9ada0cec01b9fa0d440ee5a83a9bf62ddde5b56c37bdbaa7d914adc1", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9750", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxEth", + "label": "approveTransfers", + "type": "t_mapping(t_address,t_uint256)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:39" + }, + { + "contract": "DepositBoxEth", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_uint256)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:41" + }, + { + "contract": "DepositBoxEth", + "label": "activeEthTransfers", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:43" + } + ], + "types": { + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)" + }, + "t_address": { + "label": "address" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_bool": { + "label": "bool" + }, + "t_contract(ILinker)9750": { + "label": "contract ILinker" + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "10b740355b58700c23bb43bffc6103dff368b689c2d205faac2fc9fe0aaea2de": { + "address": "0x4B4192649E9450f329dD36F56a81C08aD0c12c02", + "txHash": "0xa3d60753d4655bb28a64b70674335588fe0db268b9cd22b33c35e578c01a2d92", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9750", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC20", + "label": "_deprecatedSchainToERC20", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:84" + }, + { + "contract": "DepositBoxERC20", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_uint256))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:85" + }, + { + "contract": "DepositBoxERC20", + "label": "_schainToERC20", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:86" + }, + { + "contract": "DepositBoxERC20", + "label": "_delayConfig", + "type": "t_mapping(t_bytes32,t_struct(DelayConfig)15776_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:90" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfersSize", + "type": "t_uint256", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:92" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfers", + "type": "t_mapping(t_uint256,t_struct(DelayedTransfer)15764_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:94" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfersByReceiver", + "type": "t_mapping(t_address,t_struct(Bytes32Deque)8027_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:96" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_uint256))": { + "label": "mapping(bytes32 => mapping(address => uint256))" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_mapping(t_bytes32,t_struct(DelayConfig)15776_storage)": { + "label": "mapping(bytes32 => struct DepositBoxERC20.DelayConfig)" + }, + "t_struct(DelayConfig)15776_storage": { + "label": "struct DepositBoxERC20.DelayConfig", + "members": [ + { + "label": "bigTransferThreshold", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "label": "trustedReceivers", + "type": "t_struct(AddressSet)8661_storage" + }, + { + "label": "transferDelay", + "type": "t_uint256" + }, + { + "label": "arbitrageDuration", + "type": "t_uint256" + } + ] + }, + "t_mapping(t_uint256,t_struct(DelayedTransfer)15764_storage)": { + "label": "mapping(uint256 => struct DepositBoxERC20.DelayedTransfer)" + }, + "t_struct(DelayedTransfer)15764_storage": { + "label": "struct DepositBoxERC20.DelayedTransfer", + "members": [ + { + "label": "receiver", + "type": "t_address" + }, + { + "label": "schainHash", + "type": "t_bytes32" + }, + { + "label": "token", + "type": "t_address" + }, + { + "label": "amount", + "type": "t_uint256" + }, + { + "label": "untilTimestamp", + "type": "t_uint256" + }, + { + "label": "status", + "type": "t_enum(DelayedTransferStatus)15750" + } + ] + }, + "t_enum(DelayedTransferStatus)15750": { + "label": "enum DepositBoxERC20.DelayedTransferStatus", + "members": [ + "DELAYED", + "ARBITRAGE", + "COMPLETED" + ] + }, + "t_mapping(t_address,t_struct(Bytes32Deque)8027_storage)": { + "label": "mapping(address => struct DoubleEndedQueueUpgradeable.Bytes32Deque)" + }, + "t_struct(Bytes32Deque)8027_storage": { + "label": "struct DoubleEndedQueueUpgradeable.Bytes32Deque", + "members": [ + { + "label": "_begin", + "type": "t_int128" + }, + { + "label": "_end", + "type": "t_int128" + }, + { + "label": "_data", + "type": "t_mapping(t_int128,t_bytes32)" + } + ] + }, + "t_int128": { + "label": "int128" + }, + "t_mapping(t_int128,t_bytes32)": { + "label": "mapping(int128 => bytes32)" + }, + "t_contract(ILinker)9750": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "74a3adbddb234aaf28561dae38c6e0cad571c7b9f8c2b7853db06ab9b9ec35c0": { + "address": "0x205fDFa8BB5b035152d9aca24cA32377A98838b8", + "txHash": "0x1897f89e94608ea48e711ef88a7daa0ba38ae3c01a6205e14ecf92c26bd70288", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9750", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC721", + "label": "_deprecatedSchainToERC721", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:46" + }, + { + "contract": "DepositBoxERC721", + "label": "transferredAmount", + "type": "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:47" + }, + { + "contract": "DepositBoxERC721", + "label": "_schainToERC721", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:48" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))": { + "label": "mapping(address => mapping(uint256 => bytes32))" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_contract(ILinker)9750": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "59a902dda9624a6536c254f82d8d63a88e20e802815828aecdf3c89b25190c5c": { + "address": "0xBc03C79991f6a6486B5187ad91853626c9686bF2", + "txHash": "0x86d04f1be9820d868e2ee679a6219dd23b2bb277ed7c87433b5d0a01552e735f", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9750", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "ERC1155ReceiverUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155ReceiverUpgradeable.sol:31" + }, + { + "contract": "DepositBoxERC1155", + "label": "_deprecatedSchainToERC1155", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:49" + }, + { + "contract": "DepositBoxERC1155", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_uint256,t_uint256)))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:50" + }, + { + "contract": "DepositBoxERC1155", + "label": "_schainToERC1155", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:51" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_uint256,t_uint256)))": { + "label": "mapping(bytes32 => mapping(address => mapping(uint256 => uint256)))" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_uint256))": { + "label": "mapping(address => mapping(uint256 => uint256))" + }, + "t_mapping(t_uint256,t_uint256)": { + "label": "mapping(uint256 => uint256)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_contract(ILinker)9750": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "1a9001822d60ba0c7aa9c80d35572bb16c40a7103cc7352818334cbdb96df86b": { + "address": "0xCe4ceF453a2D7071B845e36a2E1bf096fba6eEeA", + "txHash": "0x3b4f7db78d229b2dcd260802f653628f207f7bfd8738994b66ae119c15f67696", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10382", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9795", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9750", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC721", + "label": "_deprecatedSchainToERC721", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:46" + }, + { + "contract": "DepositBoxERC721", + "label": "transferredAmount", + "type": "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:47" + }, + { + "contract": "DepositBoxERC721", + "label": "_schainToERC721", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:48" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))": { + "label": "mapping(address => mapping(uint256 => bytes32))" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_contract(ILinker)9750": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9795": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10382": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } } } -} \ No newline at end of file +} diff --git a/proxy/package.json b/proxy/package.json index 37a01e933..b66d2b073 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "^1.0.0-withdrawals-blocking.1", + "@skalenetwork/ima-interfaces": "1.1.0", "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index e82a8e181..3659aa8cc 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@^1.0.0-withdrawals-blocking.1": - version "1.0.0-withdrawals-blocking.1" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-withdrawals-blocking.1.tgz#f973c63a74fa0bca3ee72a967d7e2aa80680fa4a" - integrity sha512-pETNThx9NDGdmbdUVXmrf58Fw883SglWak1cmo+FIhKzDrQm+cTxZhX9xdrBoWy2WDmNk37ZmseMx0v454ozCg== +"@skalenetwork/ima-interfaces@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.1.0.tgz#d7d1a698a7d2a31a4f9bd966abcb21a7bd0e5d1d" + integrity sha512-eB9/m/1pA2VCGKTJPcKJUZKeLEHKlcla0lRjd3rWxFAEqzTX8b1yX88rAkwqW0ngVxaqJ+GY/VLdiuMxkBuHMw== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From d55997f6bd43e406b68f005440e962e37307f4b1 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 1 Dec 2022 17:21:59 +0200 Subject: [PATCH 23/62] Add DepositBoxERC721WithMetadata --- proxy/migrations/deployMainnet.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/proxy/migrations/deployMainnet.ts b/proxy/migrations/deployMainnet.ts index f9cf83f33..46238ae28 100644 --- a/proxy/migrations/deployMainnet.ts +++ b/proxy/migrations/deployMainnet.ts @@ -100,9 +100,8 @@ export const contracts = [ "DepositBoxEth", "DepositBoxERC20", "DepositBoxERC721", - "DepositBoxERC1155" - - // "DepositBoxERC721WithMetadata" + "DepositBoxERC1155", + "DepositBoxERC721WithMetadata" ] async function main() { From ad28da33f0f03ae807096900b3dee47b496703f4 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Mon, 5 Dec 2022 11:40:55 +0000 Subject: [PATCH 24/62] task-569/improve-SNB-functionality --- npms/skale-observer/README.md | 2 +- npms/skale-observer/observer.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/npms/skale-observer/README.md b/npms/skale-observer/README.md index 19c60cc3a..8d3b81db8 100644 --- a/npms/skale-observer/README.md +++ b/npms/skale-observer/README.md @@ -12,7 +12,7 @@ First SKALE network scan is performed by **SNB** on IMA startup. Next network de ## Implementation details -The `SchainsInternal.numberOfSchains` contract call returns number of created S-Chains to load from **SKALE Mananger**. For each of S-Chains we need to get its hash by index what is done `SchainsInternal.schainsAtSystem` contract call. Then contract call to `SchainsInternal.schains` returns basic S-Chain description by hash. Obtained basic S-Chain description does not describe nodes and they must be loaded via set of contract calls. The `SchainsInternal.getNodesInGroup` contract call returns array of node identifiers for all S-Chain nodes. The `Nodes.nodes` contract call returns node description by node id. Returned node description includes IP adderess, domain name and, base port of a node, maintanance state flag. Then call to `SchainsInternal.getSchainIdsForNode` contract call allows to find effective node base port and compute per-protocol ports (`http`, `https`, `ws`, `wss`). +The `SchainsInternal.numberOfSchains` contract call returns number of created S-Chains to load from **SKALE Mananger**. For each of S-Chains we need to get its hash by index what is done `SchainsInternal.schainsAtSystem` contract call. Then contract call to `SchainsInternal.schains` returns basic S-Chain description by hash. Obtained basic S-Chain description does not describe nodes and they must be loaded via set of contract calls. The `SchainsInternal.getNodesInGroup` contract call returns array of node identifiers for all S-Chain nodes. The `Nodes.nodes` contract call returns node description by node id. Returned node description includes IP adderess, domain name and, base port of a node, maintanance state flag. Then call to `SchainsInternal.getSchainHashesForNode` contract call allows to find effective node base port and compute per-protocol ports (`http`, `https`, `ws`, `wss`). Cache of S-Chain descriptions is result of download process described above. When new S-Chain descriptions are downloaded, they replace old ones. By default this is performed once in an hour. diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js index 59e6cc27a..82b3db9ee 100644 --- a/npms/skale-observer/observer.js +++ b/npms/skale-observer/observer.js @@ -153,7 +153,10 @@ async function load_schain_parts( w3, jo_schain, addressFrom, opts ) { }; if( opts && opts.bStopNeeded ) return; - const schain_ids = await opts.imaState.jo_schains_internal.methods.getSchainHashesForNode( node_id ).call( { from: addressFrom } ); + const schain_ids = + ( "getSchainHashesForNode" in opts.imaState.jo_schains_internal.methods ) + ? await opts.imaState.jo_schains_internal.methods.getSchainHashesForNode( node_id ).call( { from: addressFrom } ) + : await opts.imaState.jo_schains_internal.methods.getSchainIdsForNode( node_id ).call( { from: addressFrom } ); node_dict.schain_base_port = get_schain_base_port_on_node( schain_id, schain_ids, node_dict.base_port ); calc_ports( jo_schain, node_dict.schain_base_port ); compose_endpoints( jo_schain, node_dict, "ip" ); From bf2cb369b8e2b5f0742bd52ae76824d5aa210a56 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Mon, 12 Dec 2022 17:30:54 +0000 Subject: [PATCH 25/62] getSchainHashesForNode is used by default --- agent/yarn.lock | 281 +------------------------------- npms/skale-observer/observer.js | 5 +- 2 files changed, 6 insertions(+), 280 deletions(-) diff --git a/agent/yarn.lock b/agent/yarn.lock index 6fcdc58d7..756364277 100644 --- a/agent/yarn.lock +++ b/agent/yarn.lock @@ -233,23 +233,11 @@ dependencies: "@types/node" "*" -"@types/connect@^3.4.33": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== - dependencies: - "@types/node" "*" - "@types/node@*": version "16.10.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.1.tgz#f3647623199ca920960006b3dccf633ea905f243" integrity sha512-4/Z9DMPKFexZj/Gn3LylFgamNKHm4K3QDi0gz9B26Uk0c8izYf97B5fxfpspMNkWlFupblKM/nV8+NA9Ffvr+w== -"@types/node@^12.12.54": - version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - "@types/node@^12.12.6": version "12.20.27" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.27.tgz#4141fcad57c332a120591de883e26fe4bb14aaea" @@ -269,21 +257,6 @@ dependencies: "@types/node" "*" -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -297,14 +270,6 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - acorn-walk@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" @@ -506,24 +471,6 @@ body-parser@1.19.0, body-parser@^1.16.0: raw-body "2.4.0" type-is "~1.6.17" -body-parser@1.20.1, body-parser@^1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -724,11 +671,6 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.20.3: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -746,13 +688,6 @@ content-disposition@0.5.3: dependencies: safe-buffer "5.1.2" -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - content-hash@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" @@ -777,11 +712,6 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -958,11 +888,6 @@ degenerator@^3.0.1: esprima "^4.0.0" vm2 "^3.9.3" -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -973,11 +898,6 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -991,11 +911,6 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - destroy@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.1.0.tgz#b77ae22e472d85437141319d32ae40b344dff38a" @@ -1126,18 +1041,6 @@ es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== - dependencies: - es6-promise "^4.0.3" - es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -1384,43 +1287,6 @@ express@^4.14.0: utils-merge "1.0.1" vary "~1.1.2" -express@^4.18.2: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - ext@^1.1.2: version "1.6.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" @@ -1450,11 +1316,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== - fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1475,19 +1336,6 @@ file-uri-to-path@2: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1835,17 +1683,6 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" @@ -2129,11 +1966,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -2147,24 +1979,6 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -jayson@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.0.0.tgz#145a0ced46f900934c9b307e1332bcb0c7dbdb17" - integrity sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA== - dependencies: - "@types/connect" "^3.4.33" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - JSONStream "^1.3.5" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - uuid "^8.3.2" - ws "^7.4.5" - js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -2195,7 +2009,7 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -2207,11 +2021,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2300,11 +2109,6 @@ mime-db@1.49.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.32" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" @@ -2312,13 +2116,6 @@ mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.49.0" -mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -2417,7 +2214,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2495,11 +2292,6 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - netmask@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" @@ -2660,13 +2452,6 @@ oboe@2.1.5: dependencies: http-https "^1.0.0" -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -2861,7 +2646,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -proxy-addr@~2.0.5, proxy-addr@~2.0.7: +proxy-addr@~2.0.5: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== @@ -2923,13 +2708,6 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -2986,16 +2764,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - raw-body@^2.2.0: version "2.4.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" @@ -3123,7 +2891,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -3186,25 +2954,6 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -3215,16 +2964,6 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - servify@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" @@ -3360,11 +3099,6 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - "statuses@>= 1.5.0 < 2", statuses@^1.3.1, statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -3506,7 +3240,7 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -"through@>=2.2.7 <3", through@~2.3: +through@~2.3: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -4069,11 +3803,6 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^7.4.5: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - ws@^8.6.0: version "8.9.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js index 82b3db9ee..59e6cc27a 100644 --- a/npms/skale-observer/observer.js +++ b/npms/skale-observer/observer.js @@ -153,10 +153,7 @@ async function load_schain_parts( w3, jo_schain, addressFrom, opts ) { }; if( opts && opts.bStopNeeded ) return; - const schain_ids = - ( "getSchainHashesForNode" in opts.imaState.jo_schains_internal.methods ) - ? await opts.imaState.jo_schains_internal.methods.getSchainHashesForNode( node_id ).call( { from: addressFrom } ) - : await opts.imaState.jo_schains_internal.methods.getSchainIdsForNode( node_id ).call( { from: addressFrom } ); + const schain_ids = await opts.imaState.jo_schains_internal.methods.getSchainHashesForNode( node_id ).call( { from: addressFrom } ); node_dict.schain_base_port = get_schain_base_port_on_node( schain_id, schain_ids, node_dict.base_port ); calc_ports( jo_schain, node_dict.schain_base_port ); compose_endpoints( jo_schain, node_dict, "ip" ); From 2d905fcb87d761407623014a6cff47675ad2c605 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 15 Dec 2022 16:30:35 +0200 Subject: [PATCH 26/62] Add comments --- proxy/contracts/MessageProxy.sol | 3 +++ proxy/contracts/schain/MessageProxyForSchain.sol | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/proxy/contracts/MessageProxy.sol b/proxy/contracts/MessageProxy.sol index 30b067316..1a67e3133 100644 --- a/proxy/contracts/MessageProxy.sol +++ b/proxy/contracts/MessageProxy.sol @@ -143,6 +143,9 @@ abstract contract MessageProxy is AccessControlEnumerableUpgradeable, IMessagePr _; } + /** + * @dev Modifier to make a function callable only if caller is granted with {DEFAULT_ADMIN_ROLE}. + */ modifier onlyOwner() { require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "DEFAULT_ADMIN_ROLE is required"); _; diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index 2f7339a97..b4f7ab164 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -107,6 +107,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { */ uint256 public minimumReceiverBalance; + /** + * @dev the event is emitted when value of receiver's minimum balance is changed + */ event MinimumReceiverBalanceChanged ( uint256 oldValue, uint256 newValue @@ -231,11 +234,18 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { version = newVersion; } + /** + * @dev Sets a minimum balance of a receiver. + * If the balance is lower IMA tries to send sFuel to top up it. + */ function setMinimumReceiverBalance(uint256 balance) external override onlyConstantSetter { emit MinimumReceiverBalanceChanged(minimumReceiverBalance, balance); minimumReceiverBalance = balance; } + /** + * @dev Sends sFuel to the `receiver` address to satisfy a minimum balance + */ function topUpReceiverBalance(address payable receiver) external override { require(isContractRegistered(bytes32(0), msg.sender), "Sender is not registered"); uint256 balance = receiver.balance; @@ -399,7 +409,7 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } /** - * @dev Move skETH from Etherbase if the sender balance is too low + * @dev Move SFuel from Etherbase if the sender balance is too low */ function _topUpSenderBalance() private { uint balance = msg.sender.balance + gasleft() * tx.gasprice; From 3adc504f287c0d770aa9d36d670911d20cdeed80 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 15 Dec 2022 16:42:36 +0200 Subject: [PATCH 27/62] Remove unused imports --- proxy/contracts/schain/DefaultAddresses.sol | 2 +- proxy/contracts/schain/MessageProxyForSchain.sol | 3 +++ proxy/test/MessageProxy.ts | 7 ++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/proxy/contracts/schain/DefaultAddresses.sol b/proxy/contracts/schain/DefaultAddresses.sol index 213eb059c..e467be99d 100644 --- a/proxy/contracts/schain/DefaultAddresses.sol +++ b/proxy/contracts/schain/DefaultAddresses.sol @@ -2,7 +2,7 @@ /** * DefaultAddresses.sol - SKALE Interchain Messaging Agent - * Copyright (C) 2021-Present SKALE Labs + * Copyright (C) 2022-Present SKALE Labs * @author Dmytro Stebaiev * * SKALE IMA is free software: you can redistribute it and/or modify diff --git a/proxy/contracts/schain/MessageProxyForSchain.sol b/proxy/contracts/schain/MessageProxyForSchain.sol index b4f7ab164..625ccf1c4 100644 --- a/proxy/contracts/schain/MessageProxyForSchain.sol +++ b/proxy/contracts/schain/MessageProxyForSchain.sol @@ -418,6 +418,9 @@ contract MessageProxyForSchain is MessageProxy, IMessageProxyForSchain { } } + /** + * @dev Move SFuel from Etherbase to `target` address + */ function _transferFromEtherbase(address payable target, uint256 value) private { IEtherbaseUpgradeable etherbase = _getEtherbase(); if (address(etherbase).isContract() diff --git a/proxy/test/MessageProxy.ts b/proxy/test/MessageProxy.ts index f6f678ea4..2ac1670b4 100644 --- a/proxy/test/MessageProxy.ts +++ b/proxy/test/MessageProxy.ts @@ -41,7 +41,6 @@ import { SchainsInternal } from "../typechain/"; import { stringToHex, getPublicKey } from "./utils/helper"; -import ABIReceiverMock = require("../artifacts/contracts/test/ReceiverMock.sol/ReceiverMock.json"); import { deployLinker } from "./utils/deploy/mainnet/linker"; import { deployMessageProxyForMainnet } from "./utils/deploy/mainnet/messageProxyForMainnet"; import { deployDepositBoxEth } from "./utils/deploy/mainnet/depositBoxEth"; @@ -52,16 +51,14 @@ import { setCommonPublicKey } from "./utils/skale-manager-utils/keyStorage"; import { deployMessageProxyCaller } from "./utils/deploy/test/messageProxyCaller"; import { deployMessages } from "./utils/deploy/messages"; import { deployKeyStorageMock } from "./utils/deploy/test/keyStorageMock"; -import { ethers, web3 } from "hardhat"; +import { ethers } from "hardhat"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signer-with-address"; import { BigNumber, Wallet } from "ethers"; -import { assert, expect } from "chai"; +import { expect } from "chai"; import { MessageProxyForSchainTester } from "../typechain/MessageProxyForSchainTester"; import { deployMessageProxyForSchainTester } from "./utils/deploy/test/messageProxyForSchainTester"; import { deployCommunityPool } from "./utils/deploy/mainnet/communityPool"; import { createNode } from "./utils/skale-manager-utils/nodes"; -import { skipTime } from "./utils/time"; -import { deployTokenManagerLinker } from "./utils/deploy/schain/tokenManagerLinker"; chai.should(); chai.use((chaiAsPromised)); From 9f375e4dd167cfc9ed0b9f175ce6a24b411d8f68 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 22 Dec 2022 13:29:36 +0200 Subject: [PATCH 28/62] Revert files after a merge --- agent/cli.js | 24 +-- agent/main.js | 35 ++-- agent/oracle.js | 199 --------------------- agent/package.json | 2 +- agent/run.sh | 4 +- agent/yarn.lock | 281 ++++++++++++++++++++++++++++- npms/skale-ima/index.js | 373 ++++++++++++++------------------------- test/agent-test.js | 3 - test/tools/blockchain.py | 2 +- 9 files changed, 444 insertions(+), 479 deletions(-) delete mode 100644 agent/oracle.js diff --git a/agent/cli.js b/agent/cli.js index f87da67e8..9188a5173 100644 --- a/agent/cli.js +++ b/agent/cli.js @@ -390,6 +390,9 @@ function parse( joExternalHandlers, argv ) { console.log( soi + cc.debug( "--" ) + cc.bright( "ptx-ignore2" ) + cc.debug( "..................." ) + cc.error( "Ignore" ) + cc.notice( " secondary result of " ) + cc.attention( "pending transaction analysis" ) + cc.notice( "." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "no-ptx-ignore2" ) + cc.debug( "................" ) + cc.success( "Do not ignore" ) + cc.notice( " secondary result of " ) + cc.attention( "pending transaction analysis" ) + cc.notice( ". Transfer loop will be delayed until " ) + cc.attention( "pending transactions disappear" ) + cc.notice( "." ) ); // + console.log( cc.sunny( "IMA STATE" ) + cc.info( " options:" ) ); + console.log( soi + cc.debug( "--" ) + cc.bright( "state-file" ) + cc.sunny( "=" ) + cc.info( "path" ) + cc.debug( "..............." ) + cc.notice( "Specifies path to IMA state file for optimized logs searches." ) ); + // console.log( cc.sunny( "MESSAGE SIGNING" ) + cc.info( " options:" ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "sign-messages" ) + cc.debug( "................." ) + cc.notice( "Sign transferred messages." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "bls-glue" ) + cc.sunny( "=" ) + cc.note( "path" ) + cc.debug( "................." ) + cc.notice( "Specifies path to " ) + cc.note( "bls_glue" ) + cc.notice( " application." ) ); @@ -412,9 +415,8 @@ function parse( joExternalHandlers, argv ) { console.log( soi + cc.debug( "--" ) + cc.bright( "bs-progressive-enable" ) + cc.debug( "........." ) + cc.success( "Enables" ) + " " + cc.attention( "progressive block scan" ) + cc.notice( " to search past events." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "bs-progressive-disable" ) + cc.debug( "........" ) + cc.error( "Disables" ) + " " + cc.attention( "progressive block scan" ) + cc.notice( " to search past events." ) ); // - console.log( cc.sunny( "ORACLE BASED GAS REIMBURSEMENT" ) + cc.info( " options:" ) ); - console.log( soi + cc.debug( "--" ) + cc.bright( "enable-oracle" ) + cc.debug( "................." ) + cc.success( "Enable" ) + cc.notice( " call to " ) + cc.note( "Oracle" ) + cc.notice( " to compute " ) + cc.note( "gas price" ) + cc.notice( " for " ) + cc.attention( "gas reimbursement" ) + cc.notice( ". " ) + cc.debug( "Default mode" ) + cc.notice( "." ) ); - console.log( soi + cc.debug( "--" ) + cc.bright( "disable-oracle" ) + cc.debug( "................" ) + cc.error( "Disable" ) + cc.notice( " call to " ) + cc.note( "Oracle" ) + cc.notice( " to compute " ) + cc.note( "gas price" ) + cc.notice( " for " ) + cc.attention( "gas reimbursement" ) + cc.notice( "." ) ); + console.log( cc.sunny( "ORACLE GAS PRICE MANAGEMENT" ) + cc.info( " options:" ) ); + console.log( soi + cc.debug( "--" ) + cc.bright( "ogp-mode" ) + cc.sunny( "=" ) + cc.note( "number" ) + cc.debug( "..............." ) + cc.notice( "Oracle gas price mode: " ) + cc.sunny( "0" ) + cc.notice( " - " ) + cc.error( "disable" ) + cc.debug( "(default)" ) + cc.notice( ", " ) + cc.sunny( "1" ) + cc.notice( " - " ) + cc.success( "enable" ) + cc.notice( " and invoke before message transfer loop." ) ); // console.log( cc.sunny( "TEST" ) + cc.info( " options:" ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "browse-s-chain" ) + cc.debug( "................" ) + cc.notice( "Download own " ) + cc.note( "S-Chain" ) + cc.notice( " network information." ) ); @@ -1087,6 +1089,11 @@ function parse( joExternalHandlers, argv ) { imaState.optsPendingTxAnalysis.isIgnore2 = false; continue; } + if( joArg.name == "state-file" ) { + imaState.optsStateFile.isEnabled = true; + imaState.optsStateFile.path = joArg.value; + continue; + } if( joArg.name == "log-size" ) { owaspUtils.verifyArgumentIsInteger( joArg ); imaState.nLogMaxSizeBeforeRotation = owaspUtils.toInteger( joArg.value ); @@ -1188,12 +1195,9 @@ function parse( joExternalHandlers, argv ) { IMA.setEnabledProgressiveEventsScan( false ); continue; } - if( joArg.name == "enable-oracle" ) { - IMA.setEnabledOracle( true ); - continue; - } - if( joArg.name == "disable-oracle" ) { - IMA.setEnabledOracle( false ); + if( joArg.name == "ogp-mode" ) { + owaspUtils.verifyArgumentIsInteger( joArg ); + IMA.setOracleGasPriceMode( owaspUtils.toInteger( joArg.value ) ); continue; } if( joArg.name == "s2s-forward" ) { @@ -2253,7 +2257,7 @@ function ima_common_init() { log.write( cc.info( "Pending transaction analysis 2nd attempt after" ) + cc.debug( "......." ) + cc.bright( imaState.optsPendingTxAnalysis.nTimeoutSecondsBeforeSecondAttempt ) + "\n" ); log.write( cc.info( "Ignore result of PTX is" ) + cc.debug( ".............................." ) + ( imaState.optsPendingTxAnalysis.isIgnore ? cc.success( "yes" ) : cc.error( "no" ) ) + "\n" ); log.write( cc.info( "Ignore secondary result of PTX is" ) + cc.debug( "...................." ) + ( imaState.optsPendingTxAnalysis.isIgnore2 ? cc.success( "yes" ) : cc.error( "no" ) ) + "\n" ); - log.write( cc.info( "Oracle based gas reimbursement is" ) + cc.debug( "...................." ) + ( IMA.getEnabledOracle() ? cc.success( "enabled" ) : cc.error( "disabled" ) ) + "\n" ); + log.write( cc.info( "Oracle gas price mode is" ) + cc.debug( "............................." ) + cc.info( IMA.getOracleGasPriceMode() ) + "\n" ); log.write( cc.info( "S-Chain to S-Chain transferring is" ) + cc.debug( "..................." ) + ( imaState.s2s_opts.isEnabled ? cc.success( "enabled" ) : cc.error( "disabled" ) ) + "\n" ); log.write( cc.info( "SKALE network re-discovery interval is" ) + cc.debug( "..............." ) + ( imaState.s2s_opts.secondsToReDiscoverSkaleNetwork ? cc.info( imaState.s2s_opts.secondsToReDiscoverSkaleNetwork.toString() ) : cc.error( "disabled" ) ) + "\n" ); log.write( cc.info( "S<->S transfer mode is" ) + cc.debug( "..............................." ) + IMA.get_S2S_transfer_mode_description_colorized() + "\n" ); diff --git a/agent/main.js b/agent/main.js index e884af003..63b93918b 100644 --- a/agent/main.js +++ b/agent/main.js @@ -47,8 +47,6 @@ global.imaBLS = require( "./bls.js" ); global.rpcCall = require( "./rpc-call.js" ); global.skale_observer = require( "../npms/skale-observer/observer.js" ); global.rpcCall.init(); -global.imaOracle = require( "./oracle.js" ); -global.imaOracle.init(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -120,7 +118,6 @@ global.imaState = { "strChainName_main_net": ( process.env.CHAIN_NAME_ETHEREUM || "Mainnet" ).toString().trim(), "strChainName_s_chain": ( process.env.CHAIN_NAME_SCHAIN || "id-S-chain" ).toString().trim(), - "strChainName_origin_chain": ( process.env.CHAIN_NAME_SCHAIN_ORIGIN || "Mainnet" ).toString().trim(), "strChainName_t_chain": ( process.env.CHAIN_NAME_SCHAIN_TARGET || "id-T-chain" ).toString().trim(), "cid_main_net": owaspUtils.toInteger( process.env.CID_ETHEREUM ) || -4, "cid_s_chain": owaspUtils.toInteger( process.env.CID_SCHAIN ) || -4, @@ -258,11 +255,16 @@ global.imaState = { "optsPendingTxAnalysis": { "isEnabled": false, // disable bv default - "nTimeoutSecondsBeforeSecondAttempt": 3, // 0 - disable 2nd attempt + "nTimeoutSecondsBeforeSecondAttempt": 30, // 0 - disable 2nd attempt "isIgnore": false, // ignore PTX result "isIgnore2": true // ignore secondary PTX result }, + "optsStateFile": { + "isEnabled": false, // true + "path": "./ima.state.json" + }, + "nMonitoringPort": 0, // 0 - default, means monitoring server is disabled "strReimbursementChain": "", @@ -1266,7 +1268,8 @@ imaCLI.parse( { imaBLS.do_sign_messages_m2s, // fn_sign_messages null, // joExtraSignOpts imaState.tc_s_chain, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + imaState.optsStateFile ); } } ); @@ -1300,7 +1303,8 @@ imaCLI.parse( { imaBLS.do_sign_messages_s2m, // fn_sign_messages null, // joExtraSignOpts imaState.tc_main_net, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + imaState.optsStateFile ); } } ); @@ -1330,7 +1334,8 @@ imaCLI.parse( { imaState.nBlockAgeM2S, imaBLS.do_sign_messages_m2s, // fn_sign_messages imaState.tc_s_chain, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + null // imaState.optsStateFile ); } } ); @@ -1653,7 +1658,7 @@ if( haveReimbursementCommands ) { } if( imaState.nReimbursementRange >= 0 ) { imaState.arrActions.push( { - "name": "Gas Reimbursement - Set Minimal time interval from S2M and S2S transfers", + "name": "Gas Reimbursement - Set Minimal time interval from S2M transfers", "fn": async function() { await IMA.reimbursement_set_range( imaState.w3_s_chain, @@ -1662,7 +1667,6 @@ if( imaState.nReimbursementRange >= 0 ) { imaState.strChainName_s_chain, imaState.cid_s_chain, imaState.tc_s_chain, - imaState.strChainName_origin_chain, imaState.nReimbursementRange ); return true; @@ -2466,9 +2470,7 @@ async function single_transfer_loop() { if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) log.write( strLogPrefix + cc.debug( "Will invoke Oracle gas price setup..." ) + "\n" ); let b0 = true; - if( IMA.getEnabledOracle() ) { - if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) - log.write( strLogPrefix + cc.debug( "Will invoke Oracle gas price setup..." ) + "\n" ); + if( IMA.getOracleGasPriceMode() == 1 ) { b0 = IMA.do_oracle_gas_price_setup( imaState.w3_main_net, imaState.w3_s_chain, @@ -2509,7 +2511,8 @@ async function single_transfer_loop() { imaBLS.do_sign_messages_m2s, // fn_sign_messages null, // joExtraSignOpts imaState.tc_s_chain, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + imaState.optsStateFile ); if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) log.write( strLogPrefix + cc.debug( "M2S transfer done: " ) + cc.tf( b1 ) + "\n" ); @@ -2539,7 +2542,8 @@ async function single_transfer_loop() { imaBLS.do_sign_messages_s2m, // fn_sign_messages null, // joExtraSignOpts imaState.tc_main_net, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + imaState.optsStateFile ); if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) log.write( strLogPrefix + cc.debug( "S2M transfer done: " ) + cc.tf( b2 ) + "\n" ); @@ -2564,7 +2568,8 @@ async function single_transfer_loop() { imaState.nBlockAgeM2S, imaBLS.do_sign_messages_s2s, // fn_sign_messages imaState.tc_s_chain, - imaState.optsPendingTxAnalysis + imaState.optsPendingTxAnalysis, + null // imaState.optsStateFile ); if( IMA.verbose_get() >= IMA.RV_VERBOSE.information ) log.write( strLogPrefix + cc.debug( "All S2S transfers done: " ) + cc.tf( b3 ) + "\n" ); diff --git a/agent/oracle.js b/agent/oracle.js deleted file mode 100644 index a1fd223af..000000000 --- a/agent/oracle.js +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only - -/** - * @license - * SKALE IMA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -/** - * @file oracle.js - * @copyright SKALE Labs 2019-Present - */ - -const numberToBN = require( "number-to-bn" ); -const { keccak256 } = require( "js-sha3" ); - -const MIN_POW_RESULT = 10000; -const MAX_POW_NUMBER = 100000; - -const g_bnMIN_POW_RESULT = numberToBN( MIN_POW_RESULT ); -const g_bn1 = numberToBN( 1 ); -const g_bn2 = numberToBN( 2 ); -const g_bn256 = numberToBN( 256 ); -const g_bnUpperPart = g_bn2.pow( g_bn256 ).sub( g_bn1 ); -// log.write( cc.debug( "using " ) + cc.info( "2**256-1" ) + cc.debug( "=" ) + cc.info( "0x" + g_bnUpperPart.toString( 16 ) ) + cc.debug( "=" ) + cc.info( g_bnUpperPart.toString() ) + "\n" ); - -const sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; - -function oracle_init() { -} - -function get_utc_timestamp_string( d ) { - d = d || new Date(); // use now time if d is not specified - const nUtcUnixTimeStampWithMilliseconds = d.getTime(); - const t = "" + nUtcUnixTimeStampWithMilliseconds; - // const t = "" + parseInt( nUtcUnixTimeStampWithMilliseconds / 1000, 10 ) + "000"; - return t; -} - -function find_pow_number( strRequestPart, details, isVerbose ) { - details = details || log; - if( isVerbose ) - details.write( cc.debug( "source part of request to find " ) + cc.sunny( "PoW number" ) + cc.debug( " is " ) + cc.notice( strRequestPart ) + "\n" ); - const t = get_utc_timestamp_string(); - let i = 0, n = 0, s = ""; - if( isVerbose ) - details.write( cc.debug( "source " ) + cc.sunny( "t" ) + cc.debug( "=" ) + cc.info( t ) + cc.debug( ", this is " ) + cc.sunny( "UTC timestamp" ) + "\n" ); - for( ; i < MAX_POW_NUMBER; ++ i ) { - n = "" + i; - s = "{" + strRequestPart + ",\"time\":" + t + ",\"pow\":" + n + "}"; - const f = numberToBN( "0x" + keccak256( s ) ); - const r = g_bnUpperPart.div( f ); // r = ( 2 ** 256 - 1 ) / f; - if( r.gt( g_bnMIN_POW_RESULT ) ) { // if( r > MIN_POW_RESULT ) - if( isVerbose ) { - details.write( cc.debug( "computed " ) + cc.sunny( "n" ) + cc.debug( "=" ) + cc.info( i ) + cc.debug( ", this is resulting " ) + cc.sunny( "PoW number" ) + "\n" ); - details.write( cc.debug( "computed " ) + cc.sunny( "f" ) + cc.debug( "=" ) + cc.info( f.toString() ) + cc.debug( "=" ) + cc.info( "0x" + f.toString( 16 ) ) + "\n" ); - details.write( cc.debug( "computed " ) + cc.sunny( "r" ) + cc.debug( "=" ) + cc.info( "(2**256-1)/f" ) + cc.debug( "=" ) + cc.info( r.toString() ) + cc.debug( "=" ) + cc.info( "0x" + r.toString( 16 ) ) + "\n" ); - details.write( cc.debug( "computed " ) + cc.sunny( "s" ) + cc.debug( "=" ) + cc.info( s ) + "\n" ); - } - break; - } - } - return s; -} - -function oracle_get_gas_price( oracleOpts, details ) { - details = details || log; - const promise_complete = new Promise( ( resolve, reject ) => { - try { - const url = oracleOpts.url; - const isVerbose = "isVerbose" in oracleOpts ? oracleOpts.isVerbose : false; - const isVerboseTraceDetails = "isVerboseTraceDetails" in oracleOpts ? oracleOpts.isVerboseTraceDetails : false; - const callOpts = "callOpts" in oracleOpts ? oracleOpts.callOpts : { }; - const nMillisecondsSleepBefore = "nMillisecondsSleepBefore" in oracleOpts ? oracleOpts.nMillisecondsSleepBefore : 1000; - const nMillisecondsSleepPeriod = "nMillisecondsSleepPeriod" in oracleOpts ? oracleOpts.nMillisecondsSleepPeriod : 3000; - let cntAttempts = "cntAttempts" in oracleOpts ? oracleOpts.cntAttempts : 40; - if( cntAttempts < 1 ) - cntAttempts = 1; - rpcCall.create( url, callOpts || { }, async function( joCall, err ) { - if( err ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " RPC connection problem for url " ) + cc.u( url ) + cc.error( ", error description: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - reject( new Error( "CRITICAL ORACLE CALL ERROR: RPC connection problem for url \"" + url + "\", error description: " + err.toString() ) ); - return; - } - try { - const s = find_pow_number( - "\"cid\":1000,\"uri\":\"geth://\",\"jsps\":[\"/result\"],\"post\":\"{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"eth_gasPrice\\\",\\\"params\\\":[],\\\"id\\\":1}\"", - details, - isVerbose - ); - const joIn = { - method: "oracle_submitRequest", - params: [ s ] - }; - if( isVerboseTraceDetails ) - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_submitRequest" ) + cc.normal( ")" ) + cc.debug( " is " ) + cc.j( joIn ) + "\n" ); - await joCall.call( joIn, async function( joIn, joOut, err ) { - if( err ) { - if( isVerboseTraceDetails ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " JSON RPC call" ) + cc.debug( "(" ) + cc.attention( "oracle_submitRequest" ) + cc.normal( ")" ) + cc.error( " failed, error: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - } - reject( new Error( "CRITICAL ORACLE CALL ERROR: JSON RPC call(oracle_submitRequest) failed, error: " + err.toString() ) ); - return; - } - if( isVerboseTraceDetails ) - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_submitRequest" ) + cc.normal( ")" ) + cc.debug( " result is: " ) + cc.j( joOut ) + "\n" ); - if( !( "result" in joOut && typeof joOut.result == "string" && joOut.result.length > 0 ) ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " bad unexpecected result" ) + cc.normal( "(" ) + cc.attention( "oracle_submitRequest" ) + cc.normal( ")" ) + "\n" ); - details.write( err.stack + "\n" ); - reject( new Error( "CRITICAL ORACLE CALL ERROR: bad unexpecected result(oracle_submitRequest)" ) ); - return; - } - for( let idxAttempt = 0; idxAttempt < cntAttempts; ++idxAttempt ) { - const nMillisecondsToSleep = ( ! idxAttempt ) ? nMillisecondsSleepBefore : nMillisecondsSleepPeriod; - if( nMillisecondsToSleep > 0 ) - await sleep( nMillisecondsToSleep ); - try { - joIn = { - method: "oracle_checkResult", - params: [ joOut.result ] - }; - if( isVerboseTraceDetails ) { - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.debug( " attempt " ) + cc.info( idxAttempt ) + cc.debug( " of " ) + cc.info( cntAttempts ) + cc.debug( "..." ) + "\n" ); - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.debug( " is " ) + cc.j( joIn ) + "\n" ); - } - await joCall.call( joIn, async function( joIn, joOut, err ) { - if( err ) { - if( isVerboseTraceDetails ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " JSON RPC call" ) + cc.debug( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.error( " failed, error: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - } - //reject( new Error( "CRITICAL ORACLE CALL ERROR: JSON RPC call(oracle_checkResult) failed, error: " + err.toString() ) ); - return; - } - if( isVerboseTraceDetails ) - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.debug( " result is: " ) + cc.j( joOut ) + "\n" ); - if( !( "result" in joOut && typeof joOut.result == "string" && joOut.result.length > 0 ) ) { - if( isVerboseTraceDetails ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " bad unexpecected result" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + "\n" ); - details.write( err.stack + "\n" ); - } - // reject( new Error( "CRITICAL ORACLE CALL ERROR: bad unexpecected result(oracle_checkResult)" ) ); - return; - } - const joResult = JSON.parse( joOut.result ); - if( isVerboseTraceDetails ) - details.write( cc.debug( "RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.debug( " parsed " ) + cc.sunny( "result" ) + cc.debug( " field is: " ) + cc.j( joResult ) + "\n" ); - const gp = numberToBN( joResult.rslts[0] ); - if( isVerbose ) - details.write( cc.success( "success, computed " ) + cc.sunny( "Gas Price" ) + cc.success( "=" ) + cc.info( gp.toString() ) + cc.success( "=" ) + cc.info( "0x" + gp.toString( 16 ) ) + "\n" ); - resolve( gp ); - return; - } ); - } catch ( err ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.error( " exception is: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - reject( err ); - return; - } - } // for( let idxAttempt = 0; idxAttempt < cntAttempts; ++idxAttempt ) - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_checkResult" ) + cc.normal( ")" ) + cc.error( " all attempts timed out" ) + "\n" ); - reject( new Error( "RPC call(oracle_checkResult) all attempts timed out" ) ); - return; - } ); - } catch ( err ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " RPC call" ) + cc.normal( "(" ) + cc.attention( "oracle_submitRequest" ) + cc.normal( ")" ) + cc.error( " exception is: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - reject( err ); - return; - } - } ); - } catch ( err ) { - details.write( cc.fatal( "CRITICAL ORACLE CALL ERROR:" ) + cc.error( " RPC call object creation failed, error is: " ) + cc.warning( err.toString() ) + "\n" ); - details.write( err.stack + "\n" ); - reject( err ); - return; - } - } ); - return promise_complete; -} - -module.exports = { - init: oracle_init, - get_gas_price: oracle_get_gas_price -}; // module.exports diff --git a/agent/package.json b/agent/package.json index c0f40499b..401151436 100644 --- a/agent/package.json +++ b/agent/package.json @@ -4,7 +4,7 @@ "license": "AGPL-3.0", "author": "SKALE Labs and contributors", "scripts": { - "postinstall": "echo \"----- installing in OWASP\n\" && cd ../npms/skale-owasp && yarn install && cd ../../agent && echo \"----- installing in IMA CORE\n\" && cd ../npms/skale-ima && yarn install && cd ../../agent && echo \"----- installing in IMA OBSERVER\n\" && cd ../npms/skale-observer && yarn install && cd ../../agent && echo \"----- installing in SKALE COOL SOCKET\n\" && cd ../npms/skale-cool-socket && yarn install && cd ../../agent" + "postinstall": "echo \"----- installing in OWASP\n\" && cd ../npms/skale-owasp && yarn install && cd ../../agent && echo \"----- installing in IMA CORE\n\" && cd ../npms/skale-ima && yarn install && cd ../../agent && echo \"----- installing in IMA OBSERVER\n\" && cd ../npms/skale-observer && yarn install && cd ../../agent" }, "dependencies": { "js-sha3": "^0.8.0", diff --git a/agent/run.sh b/agent/run.sh index e239002a8..205af234d 100644 --- a/agent/run.sh +++ b/agent/run.sh @@ -110,9 +110,7 @@ BASE_OPTIONS="--gas-price-multiplier=$GAS_PRICE_MULTIPLIER \ --time-framing=$TIME_FRAMING \ --tm-url-main-net=$TM_URL_MAIN_NET \ --time-gap=$TIME_GAP \ ---monitoring-port=$MONITORING_PORT \ ---ptx \ ---ptx-attempt=3 " +--monitoring-port=$MONITORING_PORT" #echo "Base options:" #echo "$BASE_OPTIONS" diff --git a/agent/yarn.lock b/agent/yarn.lock index 756364277..6fcdc58d7 100644 --- a/agent/yarn.lock +++ b/agent/yarn.lock @@ -233,11 +233,23 @@ dependencies: "@types/node" "*" +"@types/connect@^3.4.33": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/node@*": version "16.10.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.1.tgz#f3647623199ca920960006b3dccf633ea905f243" integrity sha512-4/Z9DMPKFexZj/Gn3LylFgamNKHm4K3QDi0gz9B26Uk0c8izYf97B5fxfpspMNkWlFupblKM/nV8+NA9Ffvr+w== +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + "@types/node@^12.12.6": version "12.20.27" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.27.tgz#4141fcad57c332a120591de883e26fe4bb14aaea" @@ -257,6 +269,21 @@ dependencies: "@types/node" "*" +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -270,6 +297,14 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + acorn-walk@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" @@ -471,6 +506,24 @@ body-parser@1.19.0, body-parser@^1.16.0: raw-body "2.4.0" type-is "~1.6.17" +body-parser@1.20.1, body-parser@^1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -671,6 +724,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -688,6 +746,13 @@ content-disposition@0.5.3: dependencies: safe-buffer "5.1.2" +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + content-hash@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" @@ -712,6 +777,11 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + cookiejar@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" @@ -888,6 +958,11 @@ degenerator@^3.0.1: esprima "^4.0.0" vm2 "^3.9.3" +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -898,6 +973,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -911,6 +991,11 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + destroy@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.1.0.tgz#b77ae22e472d85437141319d32ae40b344dff38a" @@ -1041,6 +1126,18 @@ es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" @@ -1287,6 +1384,43 @@ express@^4.14.0: utils-merge "1.0.1" vary "~1.1.2" +express@^4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + ext@^1.1.2: version "1.6.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" @@ -1316,6 +1450,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1336,6 +1475,19 @@ file-uri-to-path@2: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1683,6 +1835,17 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" @@ -1966,6 +2129,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1979,6 +2147,24 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" +jayson@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.0.0.tgz#145a0ced46f900934c9b307e1332bcb0c7dbdb17" + integrity sha512-v2RNpDCMu45fnLzSk47vx7I+QUaOsox6f5X0CUlabAFwxoP+8MfAY0NQRFwOEYXIxm8Ih5y6OaEa5KYiQMkyAA== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + JSONStream "^1.3.5" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.4.5" + js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -2009,7 +2195,7 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -2021,6 +2207,11 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2109,6 +2300,11 @@ mime-db@1.49.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.32" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" @@ -2116,6 +2312,13 @@ mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.49.0" +mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -2214,7 +2417,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2292,6 +2495,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + netmask@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" @@ -2452,6 +2660,13 @@ oboe@2.1.5: dependencies: http-https "^1.0.0" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -2646,7 +2861,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -proxy-addr@~2.0.5: +proxy-addr@~2.0.5, proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== @@ -2708,6 +2923,13 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -2764,6 +2986,16 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + raw-body@^2.2.0: version "2.4.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" @@ -2891,7 +3123,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -2954,6 +3186,25 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -2964,6 +3215,16 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + servify@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" @@ -3099,6 +3360,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + "statuses@>= 1.5.0 < 2", statuses@^1.3.1, statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -3240,7 +3506,7 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through@~2.3: +"through@>=2.2.7 <3", through@~2.3: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -3803,6 +4069,11 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" +ws@^7.4.5: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + ws@^8.6.0: version "8.9.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" diff --git a/npms/skale-ima/index.js b/npms/skale-ima/index.js index e899caee4..ef70478aa 100644 --- a/npms/skale-ima/index.js +++ b/npms/skale-ima/index.js @@ -632,14 +632,13 @@ function setEnabledProgressiveEventsScan( isEnabled ) { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -let g_bIsEnabledOracle = false; +let g_nOracleGasPriceMode = 0; -function getEnabledOracle( isEnabled ) { - return g_bIsEnabledOracle ? true : false; +function getOracleGasPriceMode() { + return 0 + g_nOracleGasPriceMode; } - -function setEnabledOracle( isEnabled ) { - g_bIsEnabledOracle = isEnabled ? true : false; +function setOracleGasPriceMode( mode ) { + g_nOracleGasPriceMode = 0 + parseInt( mode ? mode.toString() : "0" ); } async function do_oracle_gas_price_setup( @@ -653,7 +652,7 @@ async function do_oracle_gas_price_setup( fn_sign_o_msg, optsPendingTxAnalysis ) { - if( ! getEnabledOracle() ) + if( getOracleGasPriceMode() == 0 ) return; const details = log.createMemoryStream(); const jarrReceipts = []; @@ -671,91 +670,15 @@ async function do_oracle_gas_price_setup( strActionName = "do_oracle_gas_price_setup.latestBlockNumber()"; const latestBlockNumber = await w3_main_net.eth.getBlockNumber(); details.write( cc.debug( "Latest block on Main Net is " ) + cc.info( latestBlockNumber ) + "\n" ); - strActionName = "do_oracle_gas_price_setup.bnTimestampOfBlock()"; + strActionName = "do_oracle_gas_price_setup.timestampOfBlock()"; const latestBlock = await w3_main_net.eth.getBlock( latestBlockNumber ); - let bnTimestampOfBlock = w3_main_net.utils.toBN( latestBlock.timestamp ); - details.write( - cc.debug( "Local timestamp on Main Net is " ) + cc.info( bnTimestampOfBlock.toString() ) + cc.debug( "=" ) + - cc.info( "0x" + bnTimestampOfBlock.toString( 16 ) ) + cc.debug( " (original)" ) + - "\n" ); - const bnTimeZoneOffset = w3_main_net.utils.toBN( parseInt( new Date( parseInt( bnTimestampOfBlock.toString(), 10 ) ).getTimezoneOffset(), 10 ) ); - details.write( - cc.debug( "Local time zone offset is " ) + cc.info( bnTimeZoneOffset.toString() ) + cc.debug( "=" ) + - cc.info( "0x" + bnTimeZoneOffset.toString( 16 ) ) + cc.debug( " (original)" ) + - "\n" ); - bnTimestampOfBlock = bnTimestampOfBlock.add( bnTimeZoneOffset ); - details.write( - cc.debug( "UTC timestamp on Main Net is " ) + cc.info( bnTimestampOfBlock.toString() ) + cc.debug( "=" ) + - cc.info( "0x" + bnTimestampOfBlock.toString( 16 ) ) + cc.debug( " (original)" ) + - "\n" ); - const bnValueToSubtractFromTimestamp = w3_main_net.utils.toBN( 60 ); - details.write( - cc.debug( "Value to subtract from timestamp is " ) + cc.info( bnValueToSubtractFromTimestamp ) + cc.debug( "=" ) + - cc.info( "0x" + bnValueToSubtractFromTimestamp.toString( 16 ) ) + cc.debug( " (to adjust it to past a bit)" ) + "\n" ); - bnTimestampOfBlock = bnTimestampOfBlock.sub( bnValueToSubtractFromTimestamp ); - details.write( - cc.debug( "Timestamp on Main Net is " ) + cc.info( bnTimestampOfBlock.toString() ) + cc.debug( "=" ) + - cc.info( "0x" + bnTimestampOfBlock.toString( 16 ) ) + cc.debug( " (adjusted to past a bit)" ) + - "\n" ); + let timestampOfBlock = "0x" + w3_main_net.utils.toBN( latestBlock.timestamp ).toString( 16 ); + details.write( cc.debug( "Timestamp on Main Net is " ) + cc.info( timestampOfBlock ) + cc.debug( " (original)" ) + "\n" ); + timestampOfBlock -= 10; + details.write( cc.debug( "Timestamp on Main Net is " ) + cc.info( timestampOfBlock ) + cc.debug( " (adjusted to past a bit)" ) + "\n" ); strActionName = "do_oracle_gas_price_setup.getGasPrice()"; - let gasPriceOnMainNet = null; - if( IMA.getEnabledOracle() ) { - const oracleOpts = { - url: owaspUtils.w3_2_url( w3_schain ), - callOpts: { }, - nMillisecondsSleepBefore: 1000, - nMillisecondsSleepPeriod: 3000, - cntAttempts: 40, - isVerbose: ( verbose_get() >= RV_VERBOSE.information ) ? true : false, - isVerboseTraceDetails: ( verbose_get() >= RV_VERBOSE.trace ) ? true : false - }; - details.write( - cc.debug( "Will fetch " ) + cc.info( "Main Net gas price" ) + - cc.debug( " via call to " ) + cc.info( "Oracle" ) + - cc.debug( " with options " ) + cc.j( oracleOpts ) + - cc.debug( "..." ) + "\n" ); - try { - gasPriceOnMainNet = owaspUtils.ensure_starts_with_0x( ( await imaOracle.get_gas_price( oracleOpts, details ) ).toString( 16 ) ); - } catch ( err ) { - gasPriceOnMainNet = null; - details.write( - cc.error( "Failed to fetch " ) + cc.info( "Main Net gas price" ) + - cc.error( " via call to " ) + cc.info( "Oracle" ) + - cc.error( ", error is: " ) + cc.warning( err.toString() ) + "\n" ); - } - } - if( gasPriceOnMainNet === null ) { - details.write( - cc.debug( "Will fetch " ) + cc.info( "Main Net gas price" ) + - cc.debug( " directly..." ) + "\n" ); - gasPriceOnMainNet = "0x" + w3_main_net.utils.toBN( await w3_main_net.eth.getGasPrice() ).toString( 16 ); - } - details.write( - cc.success( "Done, " ) + cc.info( "Oracle" ) + cc.success( " did computed new " ) + cc.info( "Main Net gas price" ) + - cc.success( "=" ) + cc.bright( w3_main_net.utils.toBN( gasPriceOnMainNet ).toString() ) + - cc.success( "=" ) + cc.bright( gasPriceOnMainNet ) + - "\n" ); - // - const joGasPriceOnMainNetOld = - await jo_community_locker.methods.mainnetGasPrice().call( { - from: joAccountSC.address( w3_schain ) - } ); - const bnGasPriceOnMainNetOld = w3_schain.utils.toBN( joGasPriceOnMainNetOld ); - details.write( - cc.debug( "Previous " ) + cc.info( "Main Net gas price" ) + cc.debug( " saved and kept in " ) + cc.info( "CommunityLocker" ) + - cc.debug( "=" ) + cc.bright( bnGasPriceOnMainNetOld.toString() ) + - cc.debug( "=" ) + cc.bright( bnGasPriceOnMainNetOld.toString( 16 ) ) + - "\n" ); - if( bnGasPriceOnMainNetOld.eq( w3_schain.utils.toBN( gasPriceOnMainNet ) ) ) { - details.write( - cc.debug( "Previous " ) + cc.info( "Main Net gas price" ) + - cc.debug( " is equal to new one, will skip setting it in " ) + cc.info( "CommunityLocker" ) + - "\n" ); - if( expose_details_get() ) - details.exposeDetailsTo( log, "do_oracle_gas_price_setup", true ); - details.close(); - return; - } + const gasPriceOnMainNet = "0x" + w3_main_net.utils.toBN( await w3_main_net.eth.getGasPrice() ).toString( 16 ); + details.write( cc.info( "Main Net gas price" ) + cc.debug( " is " ) + cc.bright( gasPriceOnMainNet ) + "\n" ); // strActionName = "do_oracle_gas_price_setup.fn_sign_o_msg()"; await fn_sign_o_msg( gasPriceOnMainNet, details, async function( strError, u256, joGlueResult ) { @@ -790,7 +713,7 @@ async function do_oracle_gas_price_setup( const methodWithArguments_setGasPrice = jo_community_locker.methods.setGasPrice( // call params u256, - "0x" + bnTimestampOfBlock.toString( 16 ), + timestampOfBlock, sign // bls signature components ); const dataTx_setGasPrice = methodWithArguments_setGasPrice.encodeABI(); // the encoded ABI of the method @@ -838,9 +761,11 @@ async function do_oracle_gas_price_setup( const tx_setGasPrice = compose_tx_instance( details, strLogPrefix, raw_tx_setGasPrice ); const joSetGasPriceSR = await safe_sign_transaction_with_account( details, w3_schain, tx_setGasPrice, raw_tx_setGasPrice, joAccountSC ); let joReceipt = null; - if( joSetGasPriceSR.joACI.isAutoSend ) + if( joSetGasPriceSR.joACI.isAutoSend ) { + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3_schain, w3_main_net, chain_id_schain, chain_id_mainnet, "" + joSetGasPriceSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3_schain, joSetGasPriceSR.txHashSent ); - else { + } else { const serializedTx_setGasPrice = tx_setGasPrice.serialize(); strActionName = "w3_schain.eth.sendSignedTransaction()"; // let joReceipt = await w3_schain.eth.sendSignedTransaction( "0x" + serializedTx_setGasPrice.toString( "hex" ) ); @@ -853,8 +778,8 @@ async function do_oracle_gas_price_setup( "receipt": joReceipt } ); print_gas_usage_report_from_array( "(intermediate result) ORACLE GAS PRICE SETUP ", jarrReceipts ); - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_complete( details, w3_schain, w3_main_net, chain_id_schain, chain_id_mainnet, "" + joReceipt.transactionHash ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_complete( details, w3_schain, w3_main_net, chain_id_schain, chain_id_mainnet, "" + joReceipt.transactionHash ); } save_transfer_success( "oracle" ); } ); @@ -2128,7 +2053,6 @@ async function reimbursement_set_range( strChainName_s_chain, cid_s_chain, tc_s_chain, - strChainName_origin_chain, nReimbursementRange ) { const details = log.createMemoryStream(); @@ -2148,7 +2072,6 @@ async function reimbursement_set_range( // const methodWithArguments = jo_community_locker.methods.setTimeLimitPerMessage( // call params, last is destination account on S-chain - strChainName_origin_chain, "0x" + w3_s_chain.utils.toBN( nReimbursementRange ).toString( 16 ) ); const dataTx = methodWithArguments.encodeABI(); // the encoded ABI of the method @@ -5059,99 +4982,33 @@ async function async_pending_tx_scanner( details, w3, w3_opposite, chain_id, cha ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -async function find_out_reference_log_record( details, w3, jo_message_proxy, nBlockId, nMessageNumberToFind, isVerbose ) { - const strLogPrefix = ""; - const bnMessageNumberToFind = w3.utils.toBN( nMessageNumberToFind.toString() ); - const strEventName = "PreviousMessageReference"; - const arrLogRecords = await get_web3_pastEventsProgressive( - details, - w3, - 10, - jo_message_proxy, - strEventName, - nBlockId, // nBlockFrom - nBlockId, // nBlockTo - { } // filter - ); - const cntLogRecord = arrLogRecords.length; - if( isVerbose ) { - details.write( strLogPrefix + - cc.debug( "Got " ) + cc.info( cntLogRecord ) + cc.debug( " log record(s) (" ) + cc.info( strEventName ) + - cc.debug( ") with data: " ) + cc.j( arrLogRecords ) + "\n" ); - } - for( let idxLogRecord = 0; idxLogRecord < cntLogRecord; ++ idxLogRecord ) { - const joEvent = arrLogRecords[idxLogRecord]; - const joReferenceLogRecord = { // joEvent.returnValues; - currentMessage: joEvent.returnValues.currentMessage, - previousOutgoingMessageBlockId: joEvent.returnValues.previousOutgoingMessageBlockId, - currentBlockId: owaspUtils.toInteger( nBlockId.toString() ) // added field - }; - const bnCurrentMessage = w3.utils.toBN( joReferenceLogRecord.currentMessage.toString() ); - if( bnCurrentMessage.eq( bnMessageNumberToFind ) ) { - if( isVerbose ) { - details.write( strLogPrefix + - cc.success( "Found " ) + cc.info( strEventName ) + cc.success( " log record " ) + - cc.j( joReferenceLogRecord ) + cc.success( " for message " ) + cc.info( nMessageNumberToFind ) + "\n" ); - } - return joReferenceLogRecord; - } - } // for( let idxLogRecord = 0; idxLogRecord < cntLogRecord; ++ idxLogRecord ) - if( isVerbose ) { - details.write( strLogPrefix + - cc.error( "Failed to find " ) + cc.info( strEventName ) + cc.error( " log record for message " ) + - cc.info( nMessageNumberToFind ) + "\n" ); - } - return null; -} - -async function find_out_all_reference_log_records( details, w3, jo_message_proxy, nBlockId, nIncMsgCnt, nOutMsgCnt, isVerbose ) { - const strLogPrefix = ""; - if( isVerbose ) { - details.write( strLogPrefix + - cc.debug( "Optimized IMA message search algorithm will start at block " ) + cc.info( nBlockId.toString() ) + - cc.debug( ", will search for ougoing message counter " ) + cc.info( nOutMsgCnt.toString() ) + - cc.debug( " and approach down to incoming message counter " ) + cc.info( nIncMsgCnt.toString() ) + - "\n" ); - } - const arrLogRecordReferences = []; - const cntExpected = nOutMsgCnt - nIncMsgCnt; - if( cntExpected <= 0 ) { - if( isVerbose ) { - details.write( strLogPrefix + - cc.success( "Optimized IMA message search algorithm success, nothing to search, result is empty" ) + "\n" ); - } - return arrLogRecordReferences; // nothing to searcharrLogRecordReferences - } - let nWalkMsgNumber = nOutMsgCnt - 1; - let nWalkBlockId = nBlockId; - for( ; nWalkMsgNumber >= nIncMsgCnt; -- nWalkMsgNumber ) { - const joReferenceLogRecord = await find_out_reference_log_record( details, w3, jo_message_proxy, nWalkBlockId, nWalkMsgNumber, isVerbose ); - if( joReferenceLogRecord == null ) - break; - nWalkBlockId = owaspUtils.toInteger( joReferenceLogRecord.previousOutgoingMessageBlockId.toString() ); - arrLogRecordReferences.unshift( joReferenceLogRecord ); - } // for( ; nWalkMsgNumber >= nIncMsgCnt; -- nWalkMsgNumber ) - const cntFound = arrLogRecordReferences.length; - if( cntFound != cntExpected ) { - if( isVerbose ) { - details.write( strLogPrefix + - cc.error( "Optimized IMA message search algorithm fail, found " ) + cc.info( cntFound ) + - cc.error( " log record(s), expected " ) + cc.info( cntExpected ) + cc.error( " log record(s), found records are: " ) + - cc.j( arrLogRecordReferences ) + "\n" ); - } - } else { - if( isVerbose ) { - details.write( strLogPrefix + - cc.success( "Optimized IMA message search algorithm success, found all " ) + - cc.info( cntFound ) + cc.success( " log record(s): " ) + cc.j( arrLogRecordReferences ) + "\n" ); - } +async function init_ima_state_file( details, w3, strDirection, optsStateFile ) { + if( strDirection != "M2S" ) + return; + if( ! ( optsStateFile && optsStateFile.isEnabled && "path" in optsStateFile && typeof optsStateFile.path == "string" && optsStateFile.path.length > 0 ) ) + return; + let isFileExist = false; + try { + if( fs.existsSync( optsStateFile.path ) ) + isFileExist = true; + } catch ( err ) { } + if( isFileExist ) + return; + let nBlockFrom = 0; + try { + nBlockFrom = await w3.eth.getBlockNumber(); + } catch ( err ) { } + const strKeyName = ( strDirection == "M2S" ) ? "lastSearchedStartBlockM2S" : "lastSearchedStartBlockS2M"; + try { + const joStateForLogsSearch = {}; + details.write( strLogPrefix + cc.normal( "(FIRST TIME) Saving next forecasted block number for logs search value " ) + cc.info( blockNumberNextForecast ) + "\n" ); + joStateForLogsSearch[strKeyName] = nBlockFrom; + const s = JSON.stringify( joStateForLogsSearch, null, 4 ); + fs.writeFileSync( optsStateFile.path, s ); + } catch ( err ) { } - return arrLogRecordReferences; } -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - let g_nTransferLoopCounter = 0; // @@ -5199,7 +5056,8 @@ async function do_transfer( // tc_dst, // - optsPendingTxAnalysis + optsPendingTxAnalysis, + optsStateFile ) { const nTransferLoopCounter = g_nTransferLoopCounter; ++ g_nTransferLoopCounter; @@ -5214,6 +5072,7 @@ async function do_transfer( const details = log.createMemoryStream( true ); const jarrReceipts = []; let bErrorInSigningMessages = false; + await init_ima_state_file( details, w3_src, strDirection, optsStateFile ); const strLogPrefix = cc.bright( strDirection ) + cc.info( " transfer from " ) + cc.notice( chain_id_src ) + cc.info( " to " ) + cc.notice( chain_id_dst ) + cc.info( ":" ) + " "; if( fn_sign_messages == null || fn_sign_messages == undefined ) { details.write( strLogPrefix + cc.debug( "Using internal signing stub function" ) + "\n" ); @@ -5238,12 +5097,14 @@ async function do_transfer( let nIdxCurrentMsg = 0; let nOutMsgCnt = 0; let nIncMsgCnt = 0; + let idxLastToPopNotIncluding = 0; try { + let nPossibleIntegerValue = 0; details.write( cc.info( "SRC " ) + cc.sunny( "MessageProxy" ) + cc.info( " address is....." ) + cc.bright( jo_message_proxy_src.options.address ) + "\n" ); details.write( cc.info( "DST " ) + cc.sunny( "MessageProxy" ) + cc.info( " address is....." ) + cc.bright( jo_message_proxy_dst.options.address ) + "\n" ); strActionName = "src-chain.MessageProxy.getOutgoingMessagesCounter()"; details.write( strLogPrefix + cc.debug( "Will call " ) + cc.notice( strActionName ) + cc.debug( "..." ) + "\n" ); - let nPossibleIntegerValue = await jo_message_proxy_src.methods.getOutgoingMessagesCounter( chain_id_dst ).call( { + nPossibleIntegerValue = await jo_message_proxy_src.methods.getOutgoingMessagesCounter( chain_id_dst ).call( { from: joAccountSrc.address( w3_src ) } ); if( !owaspUtils.validateInteger( nPossibleIntegerValue ) ) @@ -5267,31 +5128,9 @@ async function do_transfer( } ); if( !owaspUtils.validateInteger( nPossibleIntegerValue ) ) throw new Error( "DST chain " + chain_id_dst + " returned incoming message counter " + nPossibleIntegerValue + " which is not a valid integer" ); - const idxLastToPopNotIncluding = owaspUtils.toInteger( nPossibleIntegerValue ); + idxLastToPopNotIncluding = owaspUtils.toInteger( nPossibleIntegerValue ); details.write( strLogPrefix + cc.debug( "Result of " ) + cc.notice( strActionName ) + cc.debug( " call: " ) + cc.info( idxLastToPopNotIncluding ) + "\n" ); - - // - // optimized scanner - // - const nBlockId = await jo_message_proxy_src.methods.getLastOutgoingMessageBlockId( chain_id_dst ).call( { - from: joAccountSrc.address( w3_src ) - } ); - // const joReferenceLogRecord = await find_out_reference_log_record( details, w3_src, jo_message_proxy_src, nBlockId, nOutMsgCnt - 1, true ); - let arrLogRecordReferences = []; - try { - arrLogRecordReferences = await find_out_all_reference_log_records( details, w3_src, jo_message_proxy_src, nBlockId, nIncMsgCnt, nOutMsgCnt, true ); - if( arrLogRecordReferences.length <= 0 ) - throw new Error( "Nothing was found by optimized IMA messages search algorithm" ); - } catch ( err ) { - arrLogRecordReferences = []; - details.write( - strLogPrefix + cc.warning( "Optimized log search is " ) + cc.error( "off" ) + - cc.warning( ". Running old IMA smart contracts?" ) + cc.success( " Please upgrade, if possible." ) + - "\n" ); - } - // - // classic scanner with optional usage of optimizamed IMA messages search algorithm // outer loop is block former/creator, then transfer // nIdxCurrentMsg = nIncMsgCnt; @@ -5318,19 +5157,46 @@ async function do_transfer( // // inner loop wil create block of transactions // - let cntAccumulatedForBlock = 0; + let cntAccumulatedForBlock = 0, blockNumberNextForecast = 0; + let nBlockFrom = 0; + const nBlockTo = "latest"; + let joStateForLogsSearch = {}; + // const nLatestBlockNumber = await get_web3_blockNumber( details, 10, w3_src ); + if( optsStateFile && optsStateFile.isEnabled && "path" in optsStateFile && typeof optsStateFile.path == "string" && optsStateFile.path.length > 0 ) { + const strKeyName = ( strDirection == "M2S" ) ? "lastSearchedStartBlockM2S" : "lastSearchedStartBlockS2M"; + try { + const s = fs.readFileSync( optsStateFile.path ); + joStateForLogsSearch = JSON.parse( s ); + if( strKeyName in joStateForLogsSearch && typeof joStateForLogsSearch[strKeyName] == "string" ) { + nBlockFrom = "0x" + w3_src.utils.toBN( joStateForLogsSearch[strKeyName] ).toString( 16 ); + details.write( strLogPrefix + + cc.normal( "Loaded nearest previously forecasted " ) + + cc.bright( strDirection ) + cc.debug( "/" ) + cc.attention( strKeyName ) + + cc.normal( " block number for logs search value " ) + + cc.info( nBlockFrom ) + "\n" ); + } else { + details.write( strLogPrefix + + cc.normal( "Was not found nearest previously forecasted " ) + + cc.bright( strDirection ) + cc.debug( "/" ) + cc.attention( strKeyName ) + + cc.normal( " block number for logs search value " ) + + cc.info( nBlockFrom ) + "\n" ); + } + } catch ( err ) { + nBlockFrom = 0; + details.write( strLogPrefix + + cc.error( "Was reset nearest previously forecasted " ) + + cc.bright( strDirection ) + cc.debug( "/" ) + cc.attention( strKeyName ) + + cc.error( " block number for logs search value " ) + + cc.error( nBlockFrom ) + cc.error( " due to error: " ) + cc.warning( err ) + "\n" ); + } + } + // blockNumberNextForecast = nBlockFrom; + for( let idxInBlock = 0; nIdxCurrentMsg < nOutMsgCnt && idxInBlock < nTransactionsCountInBlock; ++nIdxCurrentMsg, ++idxInBlock, ++cntAccumulatedForBlock ) { const idxProcessing = cntProcessed + idxInBlock; if( idxProcessing > nMaxTransactionsCount ) break; // - let nBlockFrom = 0; - let nBlockTo = "latest"; - if( arrLogRecordReferences.length > 0 ) { - const joReferenceLogRecord = arrLogRecordReferences.shift(); - nBlockFrom = joReferenceLogRecord.currentBlockId; - nBlockTo = joReferenceLogRecord.currentBlockId; - } // strActionName = "src-chain->MessageProxy->scan-past-events()"; details.write( @@ -5372,6 +5238,16 @@ async function do_transfer( cc.success( "accepted for processing, found event values are " ) + cc.j( joValues ) + cc.success( ", found block number is " ) + cc.info( joValues.savedBlockNumberForOptimizations ) + "\n" ); + if( blockNumberNextForecast === 0 ) + blockNumberNextForecast = w3mod.utils.toHex( r[i].blockNumber ); + else { + const oldBN = w3_src.utils.toBN( blockNumberNextForecast ); + const newBN = w3_src.utils.toBN( r[i].blockNumber ); + if( newBN.lt( oldBN ) ) { + blockNumberNextForecast = "0x" + newBN.toString( 16 ); + details.write( strLogPrefix + cc.normal( "Narrowing next forecasted block number for logs search is " ) + cc.info( blockNumberNextForecast ) + "\n" ); + } + } break; } else { details.write( strLogPrefix + @@ -5380,6 +5256,7 @@ async function do_transfer( "\n" ); } } + details.write( strLogPrefix + cc.normal( "Next forecasted block number for logs search is " ) + cc.info( blockNumberNextForecast ) + "\n" ); if( joValues == "" ) { const strError = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + " " + cc.error( "Can't get events from MessageProxy" ); log.write( strError + "\n" ); @@ -5929,9 +5806,6 @@ async function do_transfer( const joPostIncomingMessagesSR = await safe_sign_transaction_with_account( detailsB, w3_dst, tx_postIncomingMessages, raw_tx_postIncomingMessages, joAccountDst ); let joReceipt = null; if( joPostIncomingMessagesSR.joACI.isAutoSend ) { - // - // NOTICE: async_pending_tx_start()/ async_pending_tx_complete() must be called only in do_transfer() - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) await async_pending_tx_start( detailsB, w3_dst, w3_src, chain_id_dst, chain_id_src, "" + joPostIncomingMessagesSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( detailsB, 10, w3_dst, joPostIncomingMessagesSR.txHashSent ); @@ -5949,9 +5823,6 @@ async function do_transfer( "receipt": joReceipt } ); print_gas_usage_report_from_array( "(intermediate result) TRANSFER " + chain_id_src + " -> " + chain_id_dst, jarrReceipts ); - // - // NOTICE: async_pending_tx_start()/ async_pending_tx_complete() must be called only in do_transfer() - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) await async_pending_tx_complete( detailsB, w3_dst, w3_src, chain_id_dst, chain_id_src, "" + joReceipt.transactionHash ); } @@ -5988,6 +5859,22 @@ async function do_transfer( detailsB.write( strLogPrefix + cc.error( "WARNING:" ) + " " + cc.warn( "Cannot validate transfer to Main Net via MessageProxy error absence on Main Net, no MessageProxy provided" ) + "\n" ); } // if( chain_id_dst == "Mainnet" ) + if( optsStateFile && optsStateFile.isEnabled && "path" in optsStateFile && typeof optsStateFile.path == "string" && optsStateFile.path.length > 0 ) { + if( blockNumberNextForecast !== nBlockFrom ) { + const strKeyName = ( strDirection == "M2S" ) ? "lastSearchedStartBlockM2S" : "lastSearchedStartBlockS2M"; + try { + detailsB.write( strLogPrefix + + cc.normal( "Saving next forecasted " + + cc.bright( strDirection ) + cc.debug( "/" ) + cc.attention( strKeyName ) + + " block number for logs search value " ) + + cc.info( blockNumberNextForecast ) + "\n" ); + joStateForLogsSearch[strKeyName] = blockNumberNextForecast; + const s = JSON.stringify( joStateForLogsSearch, null, 4 ); + fs.writeFileSync( optsStateFile.path, s ); + } catch ( err ) { + } + } + } } ).catch( ( err ) => { // callback fn as argument of fn_sign_messages bErrorInSigningMessages = true; if( verbose_get() >= RV_VERBOSE.fatal ) { @@ -6065,7 +5952,8 @@ async function do_s2s_all( // s-chain --> s-chain // tc_dst, // - optsPendingTxAnalysis + optsPendingTxAnalysis, + optsStateFile ) { let cntOK = 0, cntFail = 0; const strDirection = "S2S"; @@ -6123,7 +6011,8 @@ async function do_s2s_all( // s-chain --> s-chain // tc_dst, // - optsPendingTxAnalysis + optsPendingTxAnalysis, + optsStateFile ); } catch ( err ) { bOK = false; @@ -6446,8 +6335,8 @@ async function mintERC20( const joSR = await safe_sign_transaction_with_account( details, w3, tx_mint, raw_tx_mint, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_mint = tx_mint.serialize(); @@ -6542,8 +6431,8 @@ async function mintERC721( const joSR = await safe_sign_transaction_with_account( details, w3, tx_mint, raw_tx_mint, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_mint = tx_mint.serialize(); @@ -6641,8 +6530,8 @@ async function mintERC1155( const joSR = await safe_sign_transaction_with_account( details, w3, tx_mint, raw_tx_mint, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_mint = tx_mint.serialize(); @@ -6737,8 +6626,8 @@ async function burnERC20( const joSR = await safe_sign_transaction_with_account( details, w3, tx_burn, raw_tx_burn, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_burn = tx_burn.serialize(); @@ -6833,8 +6722,8 @@ async function burnERC721( const joSR = await safe_sign_transaction_with_account( details, w3, tx_burn, raw_tx_burn, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_burn = tx_burn.serialize(); @@ -6931,8 +6820,8 @@ async function burnERC1155( const joSR = await safe_sign_transaction_with_account( details, w3, tx_burn, raw_tx_burn, joAccount ); let joReceipt = null; if( joSR.joACI.isAutoSend ) { - // if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) - // await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); + if( optsPendingTxAnalysis && "isEnabled" in optsPendingTxAnalysis && optsPendingTxAnalysis.isEnabled ) + await async_pending_tx_start( details, w3, w3, cid, cid, "" + joSR.txHashSent ); joReceipt = await get_web3_transactionReceipt( details, 10, w3, joSR.txHashSent ); } else { const serializedTx_burn = tx_burn.serialize(); @@ -7057,8 +6946,8 @@ module.exports.getMaxIterationsInAllRangeEventsScan = getMaxIterationsInAllRange module.exports.setMaxIterationsInAllRangeEventsScan = setMaxIterationsInAllRangeEventsScan; module.exports.getEnabledProgressiveEventsScan = getEnabledProgressiveEventsScan; module.exports.setEnabledProgressiveEventsScan = setEnabledProgressiveEventsScan; -module.exports.getEnabledOracle = getEnabledOracle; -module.exports.setEnabledOracle = setEnabledOracle; +module.exports.getOracleGasPriceMode = getOracleGasPriceMode; +module.exports.setOracleGasPriceMode = setOracleGasPriceMode; module.exports.do_oracle_gas_price_setup = do_oracle_gas_price_setup; module.exports.get_S2S_transfer_mode_description = get_S2S_transfer_mode_description; diff --git a/test/agent-test.js b/test/agent-test.js index 2ff55e927..cb06ad64f 100644 --- a/test/agent-test.js +++ b/test/agent-test.js @@ -56,7 +56,6 @@ global.imaState = { "nLogMaxSizeBeforeRotation": -1, "nLogMaxFilesCount": -1, "isPrintGathered": true, - "isPrintSecurityValues": true, "bIsNeededCommonInit": true, "bSignMessages": false, // use BLS message signing, turned on with --sign-messages @@ -117,7 +116,6 @@ global.imaState = { "strChainName_main_net": ( process.env.CHAIN_NAME_ETHEREUM || "Mainnet" ).toString().trim(), "strChainName_s_chain": ( process.env.CHAIN_NAME_SCHAIN || "Bob" ).toString().trim(), - "strChainName_origin_chain": ( process.env.CHAIN_NAME_ETHEREUM || "Mainnet" ).toString().trim(), "strChainName_t_chain": ( process.env.CHAIN_NAME_SCHAIN_TARGET || "Alice" ).toString().trim(), "cid_main_net": owaspUtils.toInteger( process.env.CID_ETHEREUM ) || -4, "cid_s_chain": owaspUtils.toInteger( process.env.CID_SCHAIN ) || -4, @@ -662,7 +660,6 @@ describe( "CLI", function() { "--url-s-chain=" + imaState.strURL_s_chain, "--id-main-net=" + imaState.strChainName_main_net, "--id-s-chain=" + imaState.strChainName_s_chain, - "--id-origin-chain=" + imaState.strChainName_origin_chain, "--cid-main-net=" + imaState.cid_main_net, "--cid-s-chain=" + imaState.cid_s_chain, "--address-main-net=" + imaState.joAccount_main_net.address(), diff --git a/test/tools/blockchain.py b/test/tools/blockchain.py index 16f7c2147..bb00268aa 100644 --- a/test/tools/blockchain.py +++ b/test/tools/blockchain.py @@ -250,7 +250,7 @@ def recharge_user_wallet(self, from_key, schainName, amount_wei): def set_time_limit_per_message(self, from_key, time_limit): sender_address = self.key_to_address(from_key) community_locker = self._get_contract_on_schain('community_locker') - time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=["Mainnet", time_limit]) + time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=[time_limit]) signed_txn = self.web3_schain.eth.account.signTransaction(dict( nonce=self.web3_schain.eth.getTransactionCount(sender_address), gasPrice=self.web3_schain.eth.gasPrice, From 725c7dce2d186e51870196d942cd3f9ce1a6f457 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 28 Dec 2022 17:26:15 +0200 Subject: [PATCH 29/62] Add schain name to setTimeLimitPerMessage in integration tests --- .../load_send_ether_from_mainnet_to_schain_and_back.py | 2 +- test/tools/blockchain.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py b/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py index 92d57d664..3ad37e36a 100644 --- a/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py +++ b/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py @@ -52,7 +52,7 @@ def _execute(self): # 60 finney back because when we send on mainnet we should be able to cover gas fee on gasPrice 200 Gwei amount_from_schain = 7 * 10 ** 16 # - self.blockchain.set_time_limit_per_message(self.config.schain_key, 0) + self.blockchain.set_time_limit_per_message(self.config.schain_key, self.config.schain_name, 0) for x in range(range_int): # transfer to schain self.agent.transfer_eth_from_mainnet_to_schain(self.config.mainnet_key, diff --git a/test/tools/blockchain.py b/test/tools/blockchain.py index bb00268aa..f280c02a7 100644 --- a/test/tools/blockchain.py +++ b/test/tools/blockchain.py @@ -247,10 +247,10 @@ def recharge_user_wallet(self, from_key, schainName, amount_wei): from_key) self.web3_mainnet.eth.sendRawTransaction(signed_txn.rawTransaction) - def set_time_limit_per_message(self, from_key, time_limit): + def set_time_limit_per_message(self, from_key, schainName, time_limit): sender_address = self.key_to_address(from_key) community_locker = self._get_contract_on_schain('community_locker') - time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=[time_limit]) + time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=[schainName, time_limit]) signed_txn = self.web3_schain.eth.account.signTransaction(dict( nonce=self.web3_schain.eth.getTransactionCount(sender_address), gasPrice=self.web3_schain.eth.gasPrice, From 160b2c6910c04ab6cbc5fadb131387fb56c1bec1 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 28 Dec 2022 17:50:50 +0200 Subject: [PATCH 30/62] Remove time limit for messages from mainnet in tests --- .../load_send_ether_from_mainnet_to_schain_and_back.py | 2 +- test/tools/blockchain.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py b/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py index 3ad37e36a..92d57d664 100644 --- a/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py +++ b/test/test_cases/load_send_ether_from_mainnet_to_schain_and_back.py @@ -52,7 +52,7 @@ def _execute(self): # 60 finney back because when we send on mainnet we should be able to cover gas fee on gasPrice 200 Gwei amount_from_schain = 7 * 10 ** 16 # - self.blockchain.set_time_limit_per_message(self.config.schain_key, self.config.schain_name, 0) + self.blockchain.set_time_limit_per_message(self.config.schain_key, 0) for x in range(range_int): # transfer to schain self.agent.transfer_eth_from_mainnet_to_schain(self.config.mainnet_key, diff --git a/test/tools/blockchain.py b/test/tools/blockchain.py index f280c02a7..16f7c2147 100644 --- a/test/tools/blockchain.py +++ b/test/tools/blockchain.py @@ -247,10 +247,10 @@ def recharge_user_wallet(self, from_key, schainName, amount_wei): from_key) self.web3_mainnet.eth.sendRawTransaction(signed_txn.rawTransaction) - def set_time_limit_per_message(self, from_key, schainName, time_limit): + def set_time_limit_per_message(self, from_key, time_limit): sender_address = self.key_to_address(from_key) community_locker = self._get_contract_on_schain('community_locker') - time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=[schainName, time_limit]) + time_limit_abi = community_locker.encodeABI(fn_name="setTimeLimitPerMessage", args=["Mainnet", time_limit]) signed_txn = self.web3_schain.eth.account.signTransaction(dict( nonce=self.web3_schain.eth.getTransactionCount(sender_address), gasPrice=self.web3_schain.eth.gasPrice, From 22622667276c4f7bb8e7465b8ba31854ebf076a4 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Tue, 27 Sep 2022 20:48:21 +0100 Subject: [PATCH 31/62] Add DepositBoxes changes --- .../DepositBoxes/DepositBoxERC1155.sol | 50 ++++++++++++++----- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 24 ++++++--- .../mainnet/DepositBoxes/DepositBoxERC721.sol | 24 ++++++--- .../mainnet/DepositBoxes/DepositBoxEth.sol | 18 +++++-- 4 files changed, 87 insertions(+), 29 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol index 2b5a2f49d..e5a5a09c1 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol @@ -61,6 +61,18 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo */ event ERC1155TokenReady(address indexed contractOnMainnet, uint256[] ids, uint256[] amounts); + function depositERC1155( + string calldata schainName, + address erc1155OnMainnet, + uint256 id, + uint256 amount + ) + external + override + { + depositERC1155Direct(schainName, erc1155OnMainnet, id, amount, msg.sender); + } + /** * @dev Allows `msg.sender` to send ERC1155 token from mainnet to schain. * @@ -69,15 +81,16 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. */ - function depositERC1155( + function depositERC1155Direct( string calldata schainName, address erc1155OnMainnet, uint256 id, - uint256 amount + uint256 amount, + address receiver ) - external - override - rightTransaction(schainName, msg.sender) + public + // override + rightTransaction(schainName, receiver) whenNotKilled(keccak256(abi.encodePacked(schainName))) { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); @@ -90,7 +103,7 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo bytes memory data = _receiveERC1155( schainName, erc1155OnMainnet, - msg.sender, + receiver, id, amount ); @@ -103,6 +116,18 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo ); } + function depositERC1155Batch( + string calldata schainName, + address erc1155OnMainnet, + uint256[] calldata ids, + uint256[] calldata amounts + ) + external + override + { + depositERC1155BatchDirect(schainName, erc1155OnMainnet, ids, amounts, msg.sender); + } + /** * @dev Allows `msg.sender` to send batch of ERC1155 tokens from mainnet to schain. * @@ -111,15 +136,16 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. */ - function depositERC1155Batch( + function depositERC1155BatchDirect( string calldata schainName, address erc1155OnMainnet, uint256[] calldata ids, - uint256[] calldata amounts + uint256[] calldata amounts, + address receiver ) - external - override - rightTransaction(schainName, msg.sender) + public + // override + rightTransaction(schainName, receiver) whenNotKilled(keccak256(abi.encodePacked(schainName))) { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); @@ -132,7 +158,7 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo bytes memory data = _receiveERC1155Batch( schainName, erc1155OnMainnet, - msg.sender, + receiver, ids, amounts ); diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 4f25abadf..14beffe58 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -110,6 +110,17 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { event Escalated(uint256 id); + function depositERC20( + string calldata schainName, + address erc20OnMainnet, + uint256 amount + ) + external + override + { + depositERC20Direct(schainName, erc20OnMainnet, amount, msg.sender); + } + /** * @dev Emitted when token transfer is skipped due to internal token error */ @@ -154,14 +165,15 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC20 address. */ - function depositERC20( + function depositERC20Direct( string calldata schainName, address erc20OnMainnet, - uint256 amount + uint256 amount, + address receiver ) - external - override - rightTransaction(schainName, msg.sender) + public + // override + rightTransaction(schainName, receiver) whenNotKilled(_schainHash(schainName)) { bytes32 schainHash = _schainHash(schainName); @@ -174,7 +186,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes memory data = _receiveERC20( schainName, erc20OnMainnet, - msg.sender, + receiver, amount ); _saveTransferredAmount(schainHash, erc20OnMainnet, amount); diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol index b6674f9ad..5efe1657a 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol @@ -58,6 +58,17 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { */ event ERC721TokenReady(address indexed contractOnMainnet, uint256 tokenId); + function depositERC721( + string calldata schainName, + address erc721OnMainnet, + uint256 tokenId + ) + external + override + { + depositERC721Direct(schainName, erc721OnMainnet, tokenId, msg.sender); + } + /** * @dev Allows `msg.sender` to send ERC721 token from mainnet to schain. * @@ -66,14 +77,15 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { * - Receiver contract should be defined. * - `msg.sender` should approve their token for DepositBoxERC721 address. */ - function depositERC721( + function depositERC721Direct( string calldata schainName, address erc721OnMainnet, - uint256 tokenId + uint256 tokenId, + address receiver ) - external - override - rightTransaction(schainName, msg.sender) + public + // override + rightTransaction(schainName, receiver) whenNotKilled(keccak256(abi.encodePacked(schainName))) { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); @@ -86,7 +98,7 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { bytes memory data = _receiveERC721( schainName, erc721OnMainnet, - msg.sender, + receiver, tokenId ); _saveTransferredAmount(schainHash, erc721OnMainnet, tokenId); diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol index 9fa310437..e9a91707f 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol @@ -48,6 +48,14 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { revert("Use deposit function"); } + function deposit(string memory schainName) + external + payable + override + { + depositDirect(schainName, msg.sender); + } + /** * @dev Allows `msg.sender` to send ETH from mainnet to schain. * @@ -57,11 +65,11 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { * - Receiver contract should be added as twin contract on schain. * - Schain that receives tokens should not be killed. */ - function deposit(string memory schainName) - external + function depositDirect(string memory schainName, address receiver) + public payable - override - rightTransaction(schainName, msg.sender) + // override + rightTransaction(schainName, receiver) whenNotKilled(keccak256(abi.encodePacked(schainName))) { bytes32 schainHash = keccak256(abi.encodePacked(schainName)); @@ -71,7 +79,7 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { messageProxy.postOutgoingMessage( schainHash, contractReceiver, - Messages.encodeTransferEthMessage(msg.sender, msg.value) + Messages.encodeTransferEthMessage(receiver, msg.value) ); } From 217b08ea0f8dfc8b9f390c5c4be6acd468ca9fd6 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Fri, 30 Sep 2022 13:54:42 +0100 Subject: [PATCH 32/62] Add changes --- .../DepositBoxes/DepositBoxERC1155.sol | 172 ++++++++++-------- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 87 +++++---- .../mainnet/DepositBoxes/DepositBoxERC721.sol | 84 +++++---- .../mainnet/DepositBoxes/DepositBoxEth.sol | 53 +++--- proxy/package.json | 2 +- proxy/yarn.lock | 8 +- 6 files changed, 225 insertions(+), 181 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol index e5a5a09c1..c91d98548 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol @@ -61,18 +61,6 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo */ event ERC1155TokenReady(address indexed contractOnMainnet, uint256[] ids, uint256[] amounts); - function depositERC1155( - string calldata schainName, - address erc1155OnMainnet, - uint256 id, - uint256 amount - ) - external - override - { - depositERC1155Direct(schainName, erc1155OnMainnet, id, amount, msg.sender); - } - /** * @dev Allows `msg.sender` to send ERC1155 token from mainnet to schain. * @@ -81,51 +69,16 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. */ - function depositERC1155Direct( + function depositERC1155( string calldata schainName, address erc1155OnMainnet, uint256 id, - uint256 amount, - address receiver - ) - public - // override - rightTransaction(schainName, receiver) - whenNotKilled(keccak256(abi.encodePacked(schainName))) - { - bytes32 schainHash = keccak256(abi.encodePacked(schainName)); - address contractReceiver = schainLinks[schainHash]; - require(contractReceiver != address(0), "Unconnected chain"); - require( - IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)), - "DepositBox was not approved for ERC1155 token" - ); - bytes memory data = _receiveERC1155( - schainName, - erc1155OnMainnet, - receiver, - id, - amount - ); - _saveTransferredAmount(schainHash, erc1155OnMainnet, _asSingletonArray(id), _asSingletonArray(amount)); - IERC1155Upgradeable(erc1155OnMainnet).safeTransferFrom(msg.sender, address(this), id, amount, ""); - messageProxy.postOutgoingMessage( - schainHash, - contractReceiver, - data - ); - } - - function depositERC1155Batch( - string calldata schainName, - address erc1155OnMainnet, - uint256[] calldata ids, - uint256[] calldata amounts + uint256 amount ) external override { - depositERC1155BatchDirect(schainName, erc1155OnMainnet, ids, amounts, msg.sender); + depositERC1155Direct(schainName, erc1155OnMainnet, id, amount, msg.sender); } /** @@ -136,39 +89,16 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. */ - function depositERC1155BatchDirect( + function depositERC1155Batch( string calldata schainName, address erc1155OnMainnet, uint256[] calldata ids, - uint256[] calldata amounts, - address receiver + uint256[] calldata amounts ) - public - // override - rightTransaction(schainName, receiver) - whenNotKilled(keccak256(abi.encodePacked(schainName))) + external + override { - bytes32 schainHash = keccak256(abi.encodePacked(schainName)); - address contractReceiver = schainLinks[schainHash]; - require(contractReceiver != address(0), "Unconnected chain"); - require( - IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)), - "DepositBox was not approved for ERC1155 token Batch" - ); - bytes memory data = _receiveERC1155Batch( - schainName, - erc1155OnMainnet, - receiver, - ids, - amounts - ); - _saveTransferredAmount(schainHash, erc1155OnMainnet, ids, amounts); - IERC1155Upgradeable(erc1155OnMainnet).safeBatchTransferFrom(msg.sender, address(this), ids, amounts, ""); - messageProxy.postOutgoingMessage( - schainHash, - contractReceiver, - data - ); + depositERC1155BatchDirect(schainName, erc1155OnMainnet, ids, amounts, msg.sender); } /** @@ -415,6 +345,92 @@ contract DepositBoxERC1155 is DepositBox, ERC1155ReceiverUpgradeable, IDepositBo __ERC1155Receiver_init(); } + /** + * @dev Allows `msg.sender` to send ERC1155 token from mainnet to schain to specified receiver. + * + * Requirements: + * + * - Receiver contract should be defined. + * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. + */ + function depositERC1155Direct( + string calldata schainName, + address erc1155OnMainnet, + uint256 id, + uint256 amount, + address receiver + ) + public + override + rightTransaction(schainName, receiver) + whenNotKilled(keccak256(abi.encodePacked(schainName))) + { + bytes32 schainHash = keccak256(abi.encodePacked(schainName)); + address contractReceiver = schainLinks[schainHash]; + require(contractReceiver != address(0), "Unconnected chain"); + require( + IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)), + "DepositBox was not approved for ERC1155 token" + ); + bytes memory data = _receiveERC1155( + schainName, + erc1155OnMainnet, + receiver, + id, + amount + ); + _saveTransferredAmount(schainHash, erc1155OnMainnet, _asSingletonArray(id), _asSingletonArray(amount)); + IERC1155Upgradeable(erc1155OnMainnet).safeTransferFrom(msg.sender, address(this), id, amount, ""); + messageProxy.postOutgoingMessage( + schainHash, + contractReceiver, + data + ); + } + + /** + * @dev Allows `msg.sender` to send batch of ERC1155 tokens from mainnet to schain to specified receiver. + * + * Requirements: + * + * - Receiver contract should be defined. + * - `msg.sender` should approve their tokens for DepositBoxERC1155 address. + */ + function depositERC1155BatchDirect( + string calldata schainName, + address erc1155OnMainnet, + uint256[] calldata ids, + uint256[] calldata amounts, + address receiver + ) + public + override + rightTransaction(schainName, receiver) + whenNotKilled(keccak256(abi.encodePacked(schainName))) + { + bytes32 schainHash = keccak256(abi.encodePacked(schainName)); + address contractReceiver = schainLinks[schainHash]; + require(contractReceiver != address(0), "Unconnected chain"); + require( + IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)), + "DepositBox was not approved for ERC1155 token Batch" + ); + bytes memory data = _receiveERC1155Batch( + schainName, + erc1155OnMainnet, + receiver, + ids, + amounts + ); + _saveTransferredAmount(schainHash, erc1155OnMainnet, ids, amounts); + IERC1155Upgradeable(erc1155OnMainnet).safeBatchTransferFrom(msg.sender, address(this), ids, amounts, ""); + messageProxy.postOutgoingMessage( + schainHash, + contractReceiver, + data + ); + } + /** * @dev Checks whether contract supports such interface (first 4 bytes of method name and its params). */ diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 14beffe58..50640a254 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -110,17 +110,6 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { event Escalated(uint256 id); - function depositERC20( - string calldata schainName, - address erc20OnMainnet, - uint256 amount - ) - external - override - { - depositERC20Direct(schainName, erc20OnMainnet, amount, msg.sender); - } - /** * @dev Emitted when token transfer is skipped due to internal token error */ @@ -165,37 +154,15 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * - Receiver contract should be defined. * - `msg.sender` should approve their tokens for DepositBoxERC20 address. */ - function depositERC20Direct( + function depositERC20( string calldata schainName, address erc20OnMainnet, - uint256 amount, - address receiver + uint256 amount ) - public - // override - rightTransaction(schainName, receiver) - whenNotKilled(_schainHash(schainName)) + external + override { - bytes32 schainHash = _schainHash(schainName); - address contractReceiver = schainLinks[schainHash]; - require(contractReceiver != address(0), "Unconnected chain"); - require( - IERC20MetadataUpgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, - "DepositBox was not approved for ERC20 token" - ); - bytes memory data = _receiveERC20( - schainName, - erc20OnMainnet, - receiver, - amount - ); - _saveTransferredAmount(schainHash, erc20OnMainnet, amount); - IERC20MetadataUpgradeable(erc20OnMainnet).safeTransferFrom(msg.sender, address(this), amount); - messageProxy.postOutgoingMessage( - schainHash, - contractReceiver, - data - ); + depositERC20Direct(schainName, erc20OnMainnet, amount, msg.sender); } /** @@ -697,6 +664,50 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { DepositBox.initialize(contractManagerOfSkaleManagerValue, linkerValue, messageProxyValue); } + /** + * @dev Allows `msg.sender` to send ERC20 token from mainnet to schain to specified receiver. + * + * Requirements: + * + * - Schain name must not be `Mainnet`. + * - Receiver account on schain cannot be null. + * - Schain that receives tokens should not be killed. + * - Receiver contract should be defined. + * - `msg.sender` should approve their tokens for DepositBoxERC20 address. + */ + function depositERC20Direct( + string calldata schainName, + address erc20OnMainnet, + uint256 amount, + address receiver + ) + public + override + rightTransaction(schainName, receiver) + whenNotKilled(_schainHash(schainName)) + { + bytes32 schainHash = _schainHash(schainName); + address contractReceiver = schainLinks[schainHash]; + require(contractReceiver != address(0), "Unconnected chain"); + require( + ERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, + "DepositBox was not approved for ERC20 token" + ); + bytes memory data = _receiveERC20( + schainName, + erc20OnMainnet, + receiver, + amount + ); + _saveTransferredAmount(schainHash, erc20OnMainnet, amount); + IERC20MetadataUpgradeable(erc20OnMainnet).safeTransferFrom(msg.sender, address(this), amount); + messageProxy.postOutgoingMessage( + schainHash, + contractReceiver, + data + ); + } + /** * @dev Check if the receiver is in the delay whitelist */ diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol index 5efe1657a..163e3af99 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC721.sol @@ -58,17 +58,6 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { */ event ERC721TokenReady(address indexed contractOnMainnet, uint256 tokenId); - function depositERC721( - string calldata schainName, - address erc721OnMainnet, - uint256 tokenId - ) - external - override - { - depositERC721Direct(schainName, erc721OnMainnet, tokenId, msg.sender); - } - /** * @dev Allows `msg.sender` to send ERC721 token from mainnet to schain. * @@ -77,37 +66,15 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { * - Receiver contract should be defined. * - `msg.sender` should approve their token for DepositBoxERC721 address. */ - function depositERC721Direct( + function depositERC721( string calldata schainName, address erc721OnMainnet, - uint256 tokenId, - address receiver + uint256 tokenId ) - public - // override - rightTransaction(schainName, receiver) - whenNotKilled(keccak256(abi.encodePacked(schainName))) + external + override { - bytes32 schainHash = keccak256(abi.encodePacked(schainName)); - address contractReceiver = schainLinks[schainHash]; - require(contractReceiver != address(0), "Unconnected chain"); - require( - IERC721Upgradeable(erc721OnMainnet).getApproved(tokenId) == address(this), - "DepositBox was not approved for ERC721 token" - ); - bytes memory data = _receiveERC721( - schainName, - erc721OnMainnet, - receiver, - tokenId - ); - _saveTransferredAmount(schainHash, erc721OnMainnet, tokenId); - IERC721Upgradeable(erc721OnMainnet).transferFrom(msg.sender, address(this), tokenId); - messageProxy.postOutgoingMessage( - schainHash, - contractReceiver, - data - ); + depositERC721Direct(schainName, erc721OnMainnet, tokenId, msg.sender); } /** @@ -250,6 +217,47 @@ contract DepositBoxERC721 is DepositBox, IDepositBoxERC721 { DepositBox.initialize(contractManagerOfSkaleManagerValue, linkerValue, messageProxyValue); } + /** + * @dev Allows `msg.sender` to send ERC721 token from mainnet to schain to specified receiver. + * + * Requirements: + * + * - Receiver contract should be defined. + * - `msg.sender` should approve their token for DepositBoxERC721 address. + */ + function depositERC721Direct( + string calldata schainName, + address erc721OnMainnet, + uint256 tokenId, + address receiver + ) + public + override + rightTransaction(schainName, receiver) + whenNotKilled(keccak256(abi.encodePacked(schainName))) + { + bytes32 schainHash = keccak256(abi.encodePacked(schainName)); + address contractReceiver = schainLinks[schainHash]; + require(contractReceiver != address(0), "Unconnected chain"); + require( + IERC721Upgradeable(erc721OnMainnet).getApproved(tokenId) == address(this), + "DepositBox was not approved for ERC721 token" + ); + bytes memory data = _receiveERC721( + schainName, + erc721OnMainnet, + receiver, + tokenId + ); + _saveTransferredAmount(schainHash, erc721OnMainnet, tokenId); + IERC721Upgradeable(erc721OnMainnet).transferFrom(msg.sender, address(this), tokenId); + messageProxy.postOutgoingMessage( + schainHash, + contractReceiver, + data + ); + } + /** * @dev Should return true if token was added by Schain owner or * automatically added after sending to schain if whitelist was turned off. diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol index e9a91707f..6d0b34362 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxEth.sol @@ -48,14 +48,6 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { revert("Use deposit function"); } - function deposit(string memory schainName) - external - payable - override - { - depositDirect(schainName, msg.sender); - } - /** * @dev Allows `msg.sender` to send ETH from mainnet to schain. * @@ -65,22 +57,12 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { * - Receiver contract should be added as twin contract on schain. * - Schain that receives tokens should not be killed. */ - function depositDirect(string memory schainName, address receiver) - public + function deposit(string memory schainName) + external payable - // override - rightTransaction(schainName, receiver) - whenNotKilled(keccak256(abi.encodePacked(schainName))) + override { - bytes32 schainHash = keccak256(abi.encodePacked(schainName)); - address contractReceiver = schainLinks[schainHash]; - require(contractReceiver != address(0), "Unconnected chain"); - _saveTransferredAmount(schainHash, msg.value); - messageProxy.postOutgoingMessage( - schainHash, - contractReceiver, - Messages.encodeTransferEthMessage(receiver, msg.value) - ); + depositDirect(schainName, msg.sender); } /** @@ -231,6 +213,33 @@ contract DepositBoxEth is DepositBox, IDepositBoxEth { DepositBox.initialize(contractManagerOfSkaleManagerValue, linkerValue, messageProxyValue); } + /** + * @dev Allows `msg.sender` to send ETH from mainnet to schain to specified receiver. + * + * Requirements: + * + * - Schain name must not be `Mainnet`. + * - Receiver contract should be added as twin contract on schain. + * - Schain that receives tokens should not be killed. + */ + function depositDirect(string memory schainName, address receiver) + public + payable + override + rightTransaction(schainName, receiver) + whenNotKilled(keccak256(abi.encodePacked(schainName))) + { + bytes32 schainHash = keccak256(abi.encodePacked(schainName)); + address contractReceiver = schainLinks[schainHash]; + require(contractReceiver != address(0), "Unconnected chain"); + _saveTransferredAmount(schainHash, msg.value); + messageProxy.postOutgoingMessage( + schainHash, + contractReceiver, + Messages.encodeTransferEthMessage(receiver, msg.value) + ); + } + /** * @dev Saves amount of ETH that was transferred to schain. */ diff --git a/proxy/package.json b/proxy/package.json index b66d2b073..44f0d56f3 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "1.1.0", + "@skalenetwork/ima-interfaces": "1.0.0-add-receiver-field-mainnet-interfaces.1", "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index 3659aa8cc..ceee595b3 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.1.0.tgz#d7d1a698a7d2a31a4f9bd966abcb21a7bd0e5d1d" - integrity sha512-eB9/m/1pA2VCGKTJPcKJUZKeLEHKlcla0lRjd3rWxFAEqzTX8b1yX88rAkwqW0ngVxaqJ+GY/VLdiuMxkBuHMw== +"@skalenetwork/ima-interfaces@1.0.0-add-receiver-field-mainnet-interfaces.1": + version "1.0.0-add-receiver-field-mainnet-interfaces.1" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-add-receiver-field-mainnet-interfaces.1.tgz#02b3893ee9470258f570daf305f1e0a96d507d68" + integrity sha512-+oLcfSotXXdOvb3gFzN8MgePJjF7aK60ad9k2icgXubFDCePPypkCckxDDGDSYZpiQrIqmWkE5qjhsCYdU+a3A== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From a0828bb9c68ab3170a725135ce445e043fead9ee Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Mon, 3 Oct 2022 13:04:40 +0100 Subject: [PATCH 33/62] Add tests --- proxy/test/DepositBoxERC1155.ts | 93 +++++++++++++++++++++- proxy/test/DepositBoxERC20.ts | 30 ++++++- proxy/test/DepositBoxERC721.ts | 44 +++++++++- proxy/test/DepositBoxERC721WithMetadata.ts | 44 +++++++++- proxy/test/DepositBoxEth.ts | 34 ++++++-- 5 files changed, 229 insertions(+), 16 deletions(-) diff --git a/proxy/test/DepositBoxERC1155.ts b/proxy/test/DepositBoxERC1155.ts index 10860cc29..8dcca4e6a 100644 --- a/proxy/test/DepositBoxERC1155.ts +++ b/proxy/test/DepositBoxERC1155.ts @@ -84,8 +84,10 @@ describe("DepositBoxERC1155", () => { let messageProxy: MessageProxyForMainnet; let linker: Linker; let communityPool: CommunityPool; + let messages: MessagesTester; const contractManagerAddress = "0x0000000000000000000000000000000000000000"; const schainName = "Schain"; + const schainHash = stringValue(web3.utils.soliditySha3(schainName)); before(async () => { [deployer, user, user2, richGuy] = await ethers.getSigners(); @@ -105,6 +107,7 @@ describe("DepositBoxERC1155", () => { linker = await deployLinker(contractManager, messageProxy); depositBoxERC1155 = await deployDepositBoxERC1155(contractManager, linker, messageProxy); communityPool = await deployCommunityPool(contractManager, linker, messageProxy); + messages = await deployMessages(); await messageProxy.grantRole(await messageProxy.CHAIN_CONNECTOR_ROLE(), linker.address); await messageProxy.grantRole(await messageProxy.EXTRA_CONTRACT_REGISTRAR_ROLE(), deployer.address); await initializeSchain(contractManager, schainName, user.address, 1, 1); @@ -220,6 +223,45 @@ describe("DepositBoxERC1155", () => { expect(BigNumber.from(await erc1155.balanceOf(depositBoxERC1155.address, id2)).toNumber()).to.equal(amount2); }); + it("should invoke `depositERC1155Direct` without mistakes", async () => { + // preparation + const contractHere = erc1155.address; + const to = user.address; + const id = 5; + const amount = 7; + const id2 = 10; + const amount2 = 3; + // the wei should be MORE than (55000 * 1000000000) + // GAS_AMOUNT_POST_MESSAGE * AVERAGE_TX_PRICE constants in DepositBox.sol + // add schain to avoid the `Unconnected chain` error + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + // transfer tokenId from `deployer` to `depositBoxERC1155` + await erc1155.connect(deployer).setApprovalForAll(depositBoxERC1155.address, true); + // execution + await depositBoxERC1155 + .connect(deployer) + .depositERC1155Direct(schainName, contractHere, id, amount, to).should.be.eventually.rejectedWith("Whitelist is enabled"); + await depositBoxERC1155.connect(user).disableWhitelist(schainName); + const data1 = await messages.encodeTransferErc1155AndTokenInfoMessage(contractHere, to, id, amount, { uri: "New ERC1155 Token" }); + const data2 = await messages.encodeTransferErc1155Message(contractHere, to, id2, amount2); + await depositBoxERC1155 + .connect(deployer) + .depositERC1155Direct(schainName, contractHere, id, amount, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxERC1155.address, deployer.address, data1); + await depositBoxERC1155 + .connect(deployer) + .depositERC1155Direct(schainName, contractHere, id2, amount2, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 1, depositBoxERC1155.address, deployer.address, data2); + // console.log("Gas for depositERC1155:", res.receipt.gasUsed); + // expectation + expect(BigNumber.from(await erc1155.balanceOf(depositBoxERC1155.address, id)).toNumber()).to.equal(amount); + expect(BigNumber.from(await erc1155.balanceOf(depositBoxERC1155.address, id2)).toNumber()).to.equal(amount2); + }); + it("should rejected with `DepositBox was not approved for ERC1155 token Batch`", async () => { // preparation const error = "DepositBox was not approved for ERC1155 token Batch"; @@ -284,6 +326,55 @@ describe("DepositBoxERC1155", () => { expect(balanceIdsNumber).to.deep.equal(amounts); expect(balanceIds2Number).to.deep.equal(amounts2); }); + + it("should invoke `depositERC1155BatchDirect` without mistakes", async () => { + // preparation + const contractHere = erc1155.address; + const to = user.address; + const ids = [1, 2, 3]; + const amounts = [3, 2, 1]; + const ids2 = [5, 4, 99]; + const amounts2 = [9, 77, 888]; + // the wei should be MORE than (55000 * 1000000000) + // GAS_AMOUNT_POST_MESSAGE * AVERAGE_TX_PRICE constants in DepositBox.sol + // add schain to avoid the `Unconnected chain` error + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + // transfer tokenId from `deployer` to `depositBoxERC1155` + await erc1155.connect(deployer).setApprovalForAll(depositBoxERC1155.address, true); + // execution + await depositBoxERC1155 + .connect(deployer) + .depositERC1155BatchDirect(schainName, contractHere, ids, amounts, to).should.be.eventually.rejectedWith("Whitelist is enabled"); + await depositBoxERC1155.connect(user).disableWhitelist(schainName); + const data1 = await messages.encodeTransferErc1155BatchAndTokenInfoMessage(contractHere, to, ids, amounts, { uri: "New ERC1155 Token" }); + const data2 = await messages.encodeTransferErc1155BatchMessage(contractHere, to, ids2, amounts2); + await depositBoxERC1155 + .connect(deployer) + .depositERC1155BatchDirect(schainName, contractHere, ids, amounts, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxERC1155.address, deployer.address, data1); + await depositBoxERC1155 + .connect(deployer) + .depositERC1155BatchDirect(schainName, contractHere, ids2, amounts2, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 1, depositBoxERC1155.address, deployer.address, data2); + // console.log("Gas for depositERC1155:", res.receipt.gasUsed); + // expectation + const balanceIds = await erc1155.balanceOfBatch([depositBoxERC1155.address, depositBoxERC1155.address, depositBoxERC1155.address], ids); + const balanceIds2 = await erc1155.balanceOfBatch([depositBoxERC1155.address, depositBoxERC1155.address, depositBoxERC1155.address], ids2); + const balanceIdsNumber: number[] = []; + const balanceIds2Number: number[] = []; + balanceIds.forEach(element => { + balanceIdsNumber.push(BigNumber.from(element).toNumber()) + }); + balanceIds2.forEach(element => { + balanceIds2Number.push(BigNumber.from(element).toNumber()) + }); + expect(balanceIdsNumber).to.deep.equal(amounts); + expect(balanceIds2Number).to.deep.equal(amounts2); + }); }); it("should get funds after kill", async () => { @@ -322,11 +413,9 @@ describe("DepositBoxERC1155", () => { describe("tests for `postMessage` function", async () => { let erc1155: ERC1155OnChain; - let messages: MessagesTester; beforeEach(async () => { erc1155 = await deployERC1155OnChain("New ERC1155 Token"); - messages = await deployMessages(); }); it("should transfer ERC1155 token", async () => { diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts index 6b37c51ad..54d1fe14f 100644 --- a/proxy/test/DepositBoxERC20.ts +++ b/proxy/test/DepositBoxERC20.ts @@ -85,6 +85,7 @@ describe("DepositBoxERC20", () => { let messageProxy: MessageProxyForMainnet; let linker: Linker; let communityPool: CommunityPool; + let messages: MessagesTester; const contractManagerAddress = "0x0000000000000000000000000000000000000000"; const schainName = "Schain"; const schainHash = ethers.utils.solidityKeccak256(["string"], [schainName]); @@ -125,6 +126,7 @@ describe("DepositBoxERC20", () => { await messageProxy.registerExtraContractForAll(depositBoxERC20.address); await messageProxy.registerExtraContract(schainName, communityPool.address); await messageProxy.registerExtraContract(schainName, linker.address); + messages = await deployMessages(); }); describe("tests with `ERC20`", async () => { @@ -184,6 +186,32 @@ describe("DepositBoxERC20", () => { .depositERC20(schainName, erc20.address, 1); }); + it("should invoke `depositERC20Direct` without mistakes", async () => { + // preparation + // mint some quantity of ERC20 tokens for `deployer` address + const amount = 10; + await erc20.connect(deployer).mint(deployer.address, amount); + await erc20.connect(deployer).approve(depositBoxERC20.address, amount); + // execution + await depositBoxERC20 + .connect(deployer) + .depositERC20Direct(schainName, erc20.address, 1, user.address).should.be.eventually.rejectedWith("Whitelist is enabled"); + await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName); + const data1 = await messages.encodeTransferErc20AndTokenInfoMessage(erc20.address, user.address, 1, amount, { name: "D2-token", symbol: "D2", decimals: 18 }); + const data2 = await messages.encodeTransferErc20AndTotalSupplyMessage(erc20.address, user.address, 1, amount); + await depositBoxERC20 + .connect(deployer) + .depositERC20Direct(schainName, erc20.address, 1, user.address) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxERC20.address, deployer.address, data1); + + await depositBoxERC20 + .connect(deployer) + .depositERC20Direct(schainName, erc20.address, 1, user.address) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 1, depositBoxERC20.address, deployer.address, data2); + }); + it("should rejected with `Amount is incorrect`", async () => { // preparation // mint some quantity of ERC20 tokens for `deployer` address @@ -274,14 +302,12 @@ describe("DepositBoxERC20", () => { let erc20Clone: ERC20OnChain; let eRC721OnChain: ERC721OnChain; let eRC1155OnChain: ERC1155OnChain; - let messages: MessagesTester; beforeEach(async () => { erc20 = await deployERC20OnChain("D2-token", "D2",); erc20Clone = await deployERC20OnChain("Token", "T",); eRC721OnChain = await deployERC721OnChain("ERC721OnChain", "ERC721"); eRC1155OnChain = await deployERC1155OnChain("New ERC1155 Token"); - messages = await deployMessages(); }); it("should transfer ERC20 token", async () => { diff --git a/proxy/test/DepositBoxERC721.ts b/proxy/test/DepositBoxERC721.ts index d7108957a..838b47e50 100644 --- a/proxy/test/DepositBoxERC721.ts +++ b/proxy/test/DepositBoxERC721.ts @@ -84,8 +84,10 @@ describe("DepositBoxERC721", () => { let messageProxy: MessageProxyForMainnet; let linker: Linker; let communityPool: CommunityPool; + let messages: MessagesTester; const contractManagerAddress = "0x0000000000000000000000000000000000000000"; const schainName = "Schain"; + const schainHash = stringValue(web3.utils.soliditySha3(schainName)); before(async () => { [deployer, user, user2, richGuy] = await ethers.getSigners(); @@ -105,6 +107,7 @@ describe("DepositBoxERC721", () => { linker = await deployLinker(contractManager, messageProxy); depositBoxERC721 = await deployDepositBoxERC721(contractManager, linker, messageProxy); communityPool = await deployCommunityPool(contractManager, linker, messageProxy); + messages = await deployMessages(); await messageProxy.grantRole(await messageProxy.CHAIN_CONNECTOR_ROLE(), linker.address); await messageProxy.grantRole(await messageProxy.EXTRA_CONTRACT_REGISTRAR_ROLE(), deployer.address); await initializeSchain(contractManager, schainName, user.address, 1, 1); @@ -204,6 +207,44 @@ describe("DepositBoxERC721", () => { expect(await erc721OnChain.ownerOf(tokenId2)).to.equal(depositBoxERC721.address); }); + it("should invoke `depositERC721Direct` without mistakes", async () => { + // preparation + const contractHere = erc721OnChain.address; + const to = user.address; + const tokenId = 10; + const tokenId2 = 11; + // the wei should be MORE than (55000 * 1000000000) + // GAS_AMOUNT_POST_MESSAGE * AVERAGE_TX_PRICE constants in DepositBox.sol + // add schain to avoid the `Unconnected chain` error + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + // transfer tokenId from `deployer` to `depositBoxERC721` + await erc721OnChain.connect(deployer).approve(depositBoxERC721.address, tokenId); + await erc721OnChain.connect(deployer).approve(depositBoxERC721.address, tokenId2); + // execution + await depositBoxERC721 + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId, to).should.be.eventually.rejectedWith("Whitelist is enabled"); + await depositBoxERC721.connect(user).disableWhitelist(schainName); + const data1 = await messages.encodeTransferErc721AndTokenInfoMessage(contractHere, to, tokenId, { name: "ERC721OnChain", symbol: "ERC721" }); + const data2 = await messages.encodeTransferErc721Message(contractHere, to, tokenId2); + await depositBoxERC721 + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxERC721.address, deployer.address, data1); + await depositBoxERC721 + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId2, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 1, depositBoxERC721.address, deployer.address, data2);; + // console.log("Gas for depositERC721:", res.receipt.gasUsed); + // expectation + expect(await erc721OnChain.ownerOf(tokenId)).to.equal(depositBoxERC721.address); + expect(await erc721OnChain.ownerOf(tokenId2)).to.equal(depositBoxERC721.address); + }); + }); it("should get funds after kill", async () => { @@ -246,7 +287,6 @@ describe("DepositBoxERC721", () => { describe("tests for `postMessage` function", async () => { let erc721: ERC721OnChain; let erc721OnChain: ERC721OnChain; - let messages: MessagesTester; let weiAmount: string; let sign: { blsSignature: [BigNumber, BigNumber], @@ -259,7 +299,6 @@ describe("DepositBoxERC721", () => { weiAmount = 1e18.toString(); erc721 = await deployERC721OnChain("ERC721", "ERC721"); erc721OnChain = await deployERC721OnChain("ERC721OnChain", "ERC721OnChain"); - messages = await deployMessages(); sign = { blsSignature: BlsSignature, @@ -356,7 +395,6 @@ describe("DepositBoxERC721", () => { // preparation const tokenId = 10; const to = user.address; - const schainHash = stringValue(web3.utils.soliditySha3(schainName)); const zeroHash = "0x0000000000000000000000000000000000000000000000000000000000000000"; const senderFromSchain = deployer.address; diff --git a/proxy/test/DepositBoxERC721WithMetadata.ts b/proxy/test/DepositBoxERC721WithMetadata.ts index 98e80989b..afe70c837 100644 --- a/proxy/test/DepositBoxERC721WithMetadata.ts +++ b/proxy/test/DepositBoxERC721WithMetadata.ts @@ -84,8 +84,10 @@ describe("DepositBoxERC721WithMetadata", () => { let messageProxy: MessageProxyForMainnet; let linker: Linker; let communityPool: CommunityPool; + let messages: MessagesTester; const contractManagerAddress = "0x0000000000000000000000000000000000000000"; const schainName = "Schain"; + const schainHash = stringValue(web3.utils.soliditySha3(schainName)); before(async () => { [deployer, user, user2, richGuy] = await ethers.getSigners(); @@ -105,6 +107,7 @@ describe("DepositBoxERC721WithMetadata", () => { linker = await deployLinker(contractManager, messageProxy); depositBoxERC721WithMetadata = await deployDepositBoxERC721WithMetadata(contractManager, linker, messageProxy); communityPool = await deployCommunityPool(contractManager, linker, messageProxy); + messages = await deployMessages(); await messageProxy.grantRole(await messageProxy.CHAIN_CONNECTOR_ROLE(), linker.address); await messageProxy.grantRole(await messageProxy.EXTRA_CONTRACT_REGISTRAR_ROLE(), deployer.address); await initializeSchain(contractManager, schainName, user.address, 1, 1); @@ -208,6 +211,44 @@ describe("DepositBoxERC721WithMetadata", () => { expect(await erc721OnChain.ownerOf(tokenId2)).to.equal(depositBoxERC721WithMetadata.address); }); + it("should invoke `depositERC721Direct` without mistakes", async () => { + // preparation + const contractHere = erc721OnChain.address; + const to = user.address; + const tokenId = 10; + const tokenId2 = 11; + // the wei should be MORE than (55000 * 1000000000) + // GAS_AMOUNT_POST_MESSAGE * AVERAGE_TX_PRICE constants in DepositBox.sol + // add schain to avoid the `Unconnected chain` error + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + // transfer tokenId from `deployer` to `depositBoxERC721` + await erc721OnChain.connect(deployer).approve(depositBoxERC721WithMetadata.address, tokenId); + await erc721OnChain.connect(deployer).approve(depositBoxERC721WithMetadata.address, tokenId2); + // execution + await depositBoxERC721WithMetadata + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId, to).should.be.eventually.rejectedWith("Whitelist is enabled"); + await depositBoxERC721WithMetadata.connect(user).disableWhitelist(schainName); + const data1 = await messages.encodeTransferErc721WithMetadataAndTokenInfoMessage(contractHere, to, tokenId, "Hello10", { name: "ERC721OnChain", symbol: "ERC721" }); + const data2 = await messages.encodeTransferErc721MessageWithMetadata(contractHere, to, tokenId2, "Hello11"); + await depositBoxERC721WithMetadata + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxERC721WithMetadata.address, deployer.address, data1); + await depositBoxERC721WithMetadata + .connect(deployer) + .depositERC721Direct(schainName, contractHere, tokenId2, to) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 1, depositBoxERC721WithMetadata.address, deployer.address, data2);; + // console.log("Gas for depositERC721:", res.receipt.gasUsed); + // expectation + expect(await erc721OnChain.ownerOf(tokenId)).to.equal(depositBoxERC721WithMetadata.address); + expect(await erc721OnChain.ownerOf(tokenId2)).to.equal(depositBoxERC721WithMetadata.address); + }); + }); it("should get funds after kill", async () => { @@ -250,7 +291,6 @@ describe("DepositBoxERC721WithMetadata", () => { describe("tests for `postMessage` function", async () => { let erc721: ERC721OnChain; let erc721OnChain: ERC721OnChain; - let messages: MessagesTester; let weiAmount: string; let sign: { blsSignature: [BigNumber, BigNumber], @@ -263,7 +303,6 @@ describe("DepositBoxERC721WithMetadata", () => { weiAmount = 1e18.toString(); erc721 = await deployERC721OnChain("ERC721", "ERC721"); erc721OnChain = await deployERC721OnChain("ERC721OnChain", "ERC721OnChain"); - messages = await deployMessages(); sign = { blsSignature: BlsSignature, @@ -368,7 +407,6 @@ describe("DepositBoxERC721WithMetadata", () => { const tokenId = 10; const tokenURI = "Hello10"; const to = user.address; - const schainHash = stringValue(web3.utils.soliditySha3(schainName)); const zeroHash = "0x0000000000000000000000000000000000000000000000000000000000000000"; const senderFromSchain = deployer.address; diff --git a/proxy/test/DepositBoxEth.ts b/proxy/test/DepositBoxEth.ts index c94071b76..3a6809eb1 100644 --- a/proxy/test/DepositBoxEth.ts +++ b/proxy/test/DepositBoxEth.ts @@ -114,8 +114,10 @@ describe("DepositBoxEth", () => { let messageProxy: MessageProxyForMainnet; let linker: Linker; let communityPool: CommunityPool; + let messages: MessagesTester; const contractManagerAddress = "0x0000000000000000000000000000000000000000"; const schainName = "Schain"; + const schainHash = stringValue(web3.utils.soliditySha3(schainName)); before(async () => { [deployer, user, user2, richGuy] = await ethers.getSigners(); @@ -135,6 +137,7 @@ describe("DepositBoxEth", () => { linker = await deployLinker(contractManager, messageProxy); depositBoxEth = await deployDepositBoxEth(contractManager, linker, messageProxy); communityPool = await deployCommunityPool(contractManager, linker, messageProxy); + messages = await deployMessages(); await messageProxy.grantRole(await messageProxy.CHAIN_CONNECTOR_ROLE(), linker.address); await messageProxy.grantRole(await messageProxy.EXTRA_CONTRACT_REGISTRAR_ROLE(), deployer.address); await initializeSchain(contractManager, schainName, user.address, 1, 1); @@ -198,6 +201,30 @@ describe("DepositBoxEth", () => { expect(lockAndDataBalance).to.equal(wei); }); + it("should invoke `depositDirect` without mistakes", async () => { + // preparation + // the wei should be MORE than (55000 * 1000000000) + // GAS_AMOUNT_POST_MESSAGE * AVERAGE_TX_PRICE constants in DepositBox.sol + // to avoid the `Not enough money` error + const wei = "20000000000000000"; + // add schain to avoid the `Unconnected chain` error + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + + const data = await messages.encodeTransferEthMessage(user.address, wei); + // execution + await depositBoxEth + .connect(deployer) + .depositDirect(schainName, user.address, { value: wei }) + .should.emit(messageProxy, "OutgoingMessage") + .withArgs(schainHash, 0, depositBoxEth.address, deployer.address, data); + + const lockAndDataBalance = await web3.eth.getBalance(depositBoxEth.address); + // expectation + expect(lockAndDataBalance).to.equal(wei); + }); + it("should revert `Not allowed. in DepositBox`", async () => { // preparation const error = "Use deposit function"; @@ -230,12 +257,10 @@ describe("DepositBoxEth", () => { describe("tests for `postMessage` function", async () => { let erc20: ERC20OnChain; let erc20Clone: ERC20OnChain; - let messages: MessagesTester; beforeEach(async () => { erc20 = await deployERC20OnChain("D2-token", "D2",); erc20Clone = await deployERC20OnChain("Token", "T",); - messages = await deployMessages(); }); it("should rejected with `Sender is not a MessageProxy`", async () => { @@ -295,7 +320,7 @@ describe("DepositBoxEth", () => { }); it("should rejected with message `Not enough money to finish this transaction` when " - + "`sender != ILockAndDataDB(lockAndDataAddress).tokenManagerAddresses(schainHash)`", async () => { + + "`sender != DepositBoxEth.tokenManagerAddresses(schainHash)`", async () => { // preparation const error = "Not enough money to finish this transaction"; const wei = 1e18.toString(); @@ -436,7 +461,6 @@ describe("DepositBoxEth", () => { const senderFromSchain = deployer.address; const wei = "30000000000000000"; const bytesData = await messages.encodeTransferEthMessage(user.address, wei); - const schainHash = stringValue(web3.utils.soliditySha3(schainName)); await setCommonPublicKey(contractManager, schainName); @@ -486,7 +510,6 @@ describe("DepositBoxEth", () => { const senderFromSchain = deployer.address; const wei = "30000000000000000"; const bytesData = await messages.encodeTransferEthMessage(user.address, wei); - const schainHash = stringValue(web3.utils.soliditySha3(schainName)); await setCommonPublicKey(contractManager, schainName); @@ -560,7 +583,6 @@ describe("DepositBoxEth", () => { const senderFromSchain = deployer.address; const wei = "30000000000000000"; - const schainHash = stringValue(web3.utils.soliditySha3(schainName)); const fallbackEthTester = await deployFallbackEthTester(depositBoxEth, communityPool, schainName); const bytesData = await messages.encodeTransferEthMessage(fallbackEthTester.address, wei); From d0c6f44fb642b940e292587ce6631f2254784483 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Fri, 30 Dec 2022 13:31:33 +0000 Subject: [PATCH 34/62] Change interfaces --- proxy/package.json | 2 +- proxy/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proxy/package.json b/proxy/package.json index 44f0d56f3..90074d622 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "1.0.0-add-receiver-field-mainnet-interfaces.1", + "@skalenetwork/ima-interfaces": "1.1.0-ima-interfaces-rc.0", "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index ceee595b3..bdbee34a5 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@1.0.0-add-receiver-field-mainnet-interfaces.1": - version "1.0.0-add-receiver-field-mainnet-interfaces.1" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-add-receiver-field-mainnet-interfaces.1.tgz#02b3893ee9470258f570daf305f1e0a96d507d68" - integrity sha512-+oLcfSotXXdOvb3gFzN8MgePJjF7aK60ad9k2icgXubFDCePPypkCckxDDGDSYZpiQrIqmWkE5qjhsCYdU+a3A== +"@skalenetwork/ima-interfaces@1.1.0-ima-interfaces-rc.0": + version "1.1.0-ima-interfaces-rc.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.1.0-ima-interfaces-rc.0.tgz#9e3cc0f70b4d34a76f1517fb5f0cae20a2520cd4" + integrity sha512-1X64xW4mIMDc6pLrNJqrA7Ac04phWBjieJCUUEOXTlzQlAL+UDo9Vi18zll5j2QKU33RKSXponuF6C3Dyneg3w== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From 76de39e37c82201cfa2dd4ceba2cb56d16acb2c0 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Fri, 30 Dec 2022 13:35:04 +0000 Subject: [PATCH 35/62] Fix ERC20 usage --- proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 50640a254..dea7b077e 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -690,7 +690,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { address contractReceiver = schainLinks[schainHash]; require(contractReceiver != address(0), "Unconnected chain"); require( - ERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, + IERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, "DepositBox was not approved for ERC20 token" ); bytes memory data = _receiveERC20( From cc0e43191370c2831aad109f877b540aa7a562db Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 30 Dec 2022 18:08:04 +0200 Subject: [PATCH 36/62] Add ability to build custom releases --- .github/workflows/publish.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 775ef86e2..b56ccfef4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,6 +8,9 @@ on: - develop - beta - stable + push: + tags: + - 'custom-release-*' jobs: build: @@ -49,7 +52,7 @@ jobs: with: python-version: 3.8 - + - name: Build and publish container run: | export BRANCH=${GITHUB_REF##*/} @@ -92,21 +95,21 @@ jobs: working-directory: ${{env.PROXY_DIR}} env: VERSION: ${{ env.VERSION }} - run: | + run: | ./predeployed/scripts/build_package.sh - name: Publish predeployed pip package working-directory: ${{env.PROXY_DIR}} env: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - run: | + run: | ./predeployed/scripts/publish_package.sh - name: Generate ABIs working-directory: ${{env.PROXY_DIR}}/predeployed env: VERSION: ${{ env.VERSION }} - run: | + run: | python3 -m venv scripts/venv source scripts/venv/bin/activate pip install dist/ima_predeployed-*.whl @@ -123,7 +126,7 @@ jobs: release_name: ${{ env.VERSION }} draft: false prerelease: ${{ env.PRERELEASE }} - + - name: Upload Release Assets id: upload-release-assets uses: dwenegar/upload-release-assets@v1 From a63bdc247bd3952c429eda308c207d3cf9c1197a Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 30 Dec 2022 18:13:12 +0200 Subject: [PATCH 37/62] Remove merged PR requirement --- .github/workflows/publish.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b56ccfef4..aed29645a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,6 @@ on: jobs: build: runs-on: ubuntu-latest - if: github.event.pull_request.merged env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} @@ -52,7 +51,6 @@ jobs: with: python-version: 3.8 - - name: Build and publish container run: | export BRANCH=${GITHUB_REF##*/} From 0f106a467f777588368b7167197ddbd8bcb1ee2d Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Tue, 24 Jan 2023 18:48:51 +0000 Subject: [PATCH 38/62] ticket-1413 SNB does multiple attempts to download S-Chain descriptions(in beta) --- npms/skale-observer/observer_worker.js | 35 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/npms/skale-observer/observer_worker.js b/npms/skale-observer/observer_worker.js index 3180fc071..a03c135d1 100644 --- a/npms/skale-observer/observer_worker.js +++ b/npms/skale-observer/observer_worker.js @@ -42,6 +42,8 @@ parentPort.on( "message", jo => { return; } ); +const sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; + function doSendMessage( type, endpoint, worker_uuid, data ) { const jo = network_layer.socket_received_data_reverse_marshall( data ); const joSend = { @@ -151,17 +153,31 @@ class ObserverServer extends Server { async periodic_caching_do_now( socket, secondsToReDiscoverSkaleNetwork, strChainNameConnectedTo, addressFrom ) { const self = this; if( self.bIsPeriodicCachingStepInProgress ) - return; + return null; + let strError = null; self.bIsPeriodicCachingStepInProgress = true; - // const strError = - await skale_observer.cache_schains( - strChainNameConnectedTo, - self.opts.imaState.w3_main_net, - self.opts.imaState.w3_s_chain, - addressFrom, - self.opts - ); + for( let idxAttempt = 0; idxAttempt < 10; ++ idxAttempt ) { + try { + strError = + await skale_observer.cache_schains( + strChainNameConnectedTo, + self.opts.imaState.w3_main_net, + self.opts.imaState.w3_s_chain, + addressFrom, + self.opts + ); + if( ! strError ) + break; + } catch ( err ) { + strError = owaspUtils.extract_error_message( err ); + if( ! strError ) + strError = "runtime error without description"; + } + await sleep( 5 * 1000 ); + } self.bIsPeriodicCachingStepInProgress = false; + if( strError ) + return strError; const arr_schains = skale_observer.get_last_cached_schains(); // self.log( cc.normal( "Got " ) + cc.info( "SKALE NETWORK" ) + cc.normal( " information in worker: " ) + cc.j( arr_schains ) + "\n" ); const jo = { @@ -171,6 +187,7 @@ class ObserverServer extends Server { }; const isFlush = true; socket.send( jo, isFlush ); + return null; } async periodic_caching_start( socket, secondsToReDiscoverSkaleNetwork, strChainNameConnectedTo, addressFrom ) { const self = this; From f49c05f65fd4fb026ed3d9a834a31c82e67eeabe Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Mon, 13 Feb 2023 10:42:55 +0000 Subject: [PATCH 39/62] Update versions and manifest --- VERSION | 2 +- proxy/.openzeppelin/mainnet.json | 1174 +++++++++++++++++++++++++++- proxy/DEPLOYED | 2 +- proxy/migrations/upgradeMainnet.ts | 69 +- proxy/migrations/upgradeSchain.ts | 2 +- 5 files changed, 1153 insertions(+), 96 deletions(-) diff --git a/VERSION b/VERSION index d0149fef7..347f5833e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.4 +1.4.1 diff --git a/proxy/.openzeppelin/mainnet.json b/proxy/.openzeppelin/mainnet.json index 51864d871..36ebdc5cf 100644 --- a/proxy/.openzeppelin/mainnet.json +++ b/proxy/.openzeppelin/mainnet.json @@ -7330,13 +7330,13 @@ { "contract": "SkaleManagerClient", "label": "contractManagerOfSkaleManager", - "type": "t_contract(IContractManager)10382", + "type": "t_contract(IContractManager)10439", "src": "contracts/mainnet/SkaleManagerClient.sol:37" }, { "contract": "MessageProxy", "label": "connectedChains", - "type": "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11079_storage)", + "type": "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11136_storage)", "src": "contracts/MessageProxy.sol:58" }, { @@ -7354,7 +7354,7 @@ { "contract": "MessageProxyForMainnet", "label": "communityPool", - "type": "t_contract(ICommunityPool)9651", + "type": "t_contract(ICommunityPool)9708", "src": "contracts/mainnet/MessageProxyForMainnet.sol:72" }, { @@ -7390,12 +7390,12 @@ { "contract": "MessageProxyForMainnet", "label": "pauseInfo", - "type": "t_mapping(t_bytes32,t_struct(Pause)19381_storage)", + "type": "t_mapping(t_bytes32,t_struct(Pause)19540_storage)", "src": "contracts/mainnet/MessageProxyForMainnet.sol:85" } ], "types": { - "t_contract(ICommunityPool)9651": { + "t_contract(ICommunityPool)9708": { "label": "contract ICommunityPool" }, "t_uint256": { @@ -7441,10 +7441,10 @@ "t_bool": { "label": "bool" }, - "t_mapping(t_bytes32,t_struct(Pause)19381_storage)": { + "t_mapping(t_bytes32,t_struct(Pause)19540_storage)": { "label": "mapping(bytes32 => struct MessageProxyForMainnet.Pause)" }, - "t_struct(Pause)19381_storage": { + "t_struct(Pause)19540_storage": { "label": "struct MessageProxyForMainnet.Pause", "members": [ { @@ -7453,10 +7453,10 @@ } ] }, - "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11079_storage)": { + "t_mapping(t_bytes32,t_struct(ConnectedChainInfo)11136_storage)": { "label": "mapping(bytes32 => struct MessageProxy.ConnectedChainInfo)" }, - "t_struct(ConnectedChainInfo)11079_storage": { + "t_struct(ConnectedChainInfo)11136_storage": { "label": "struct MessageProxy.ConnectedChainInfo", "members": [ { @@ -7482,7 +7482,7 @@ "t_address": { "label": "address" }, - "t_contract(IContractManager)10382": { + "t_contract(IContractManager)10439": { "label": "contract IContractManager" }, "t_array(t_uint256)49_storage": { @@ -7569,13 +7569,13 @@ { "contract": "SkaleManagerClient", "label": "contractManagerOfSkaleManager", - "type": "t_contract(IContractManager)10382", + "type": "t_contract(IContractManager)10439", "src": "contracts/mainnet/SkaleManagerClient.sol:37" }, { "contract": "Twin", "label": "messageProxy", - "type": "t_contract(IMessageProxyForMainnet)9795", + "type": "t_contract(IMessageProxyForMainnet)9852", "src": "contracts/mainnet/Twin.sol:38" }, { @@ -7599,7 +7599,7 @@ { "contract": "Linker", "label": "statuses", - "type": "t_mapping(t_bytes32,t_enum(KillProcess)18966)", + "type": "t_mapping(t_bytes32,t_enum(KillProcess)19125)", "src": "contracts/mainnet/Linker.sol:51" } ], @@ -7644,10 +7644,10 @@ "t_bool": { "label": "bool" }, - "t_mapping(t_bytes32,t_enum(KillProcess)18966)": { + "t_mapping(t_bytes32,t_enum(KillProcess)19125)": { "label": "mapping(bytes32 => enum Linker.KillProcess)" }, - "t_enum(KillProcess)18966": { + "t_enum(KillProcess)19125": { "label": "enum Linker.KillProcess", "members": [ "NotKilled", @@ -7656,7 +7656,7 @@ "Killed" ] }, - "t_contract(IMessageProxyForMainnet)9795": { + "t_contract(IMessageProxyForMainnet)9852": { "label": "contract IMessageProxyForMainnet" }, "t_mapping(t_bytes32,t_address)": { @@ -7665,7 +7665,7 @@ "t_address": { "label": "address" }, - "t_contract(IContractManager)10382": { + "t_contract(IContractManager)10439": { "label": "contract IContractManager" }, "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { @@ -7746,7 +7746,7 @@ { "contract": "AccessControlEnumerableUpgradeable", "label": "_roleMembers", - "type": "t_mapping(t_bytes32,t_struct(AddressSet)1612_storage)", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" }, { @@ -7758,13 +7758,13 @@ { "contract": "SkaleManagerClient", "label": "contractManagerOfSkaleManager", - "type": "t_contract(IContractManager)2390", + "type": "t_contract(IContractManager)10439", "src": "contracts/mainnet/SkaleManagerClient.sol:37" }, { "contract": "Twin", "label": "messageProxy", - "type": "t_contract(IMessageProxyForMainnet)2263", + "type": "t_contract(IMessageProxyForMainnet)9852", "src": "contracts/mainnet/Twin.sol:38" }, { @@ -7829,28 +7829,28 @@ "t_bool": { "label": "bool" }, - "t_contract(IMessageProxyForMainnet)2263": { + "t_contract(IMessageProxyForMainnet)9852": { "label": "contract IMessageProxyForMainnet" }, "t_mapping(t_bytes32,t_address)": { "label": "mapping(bytes32 => address)" }, - "t_contract(IContractManager)2390": { + "t_contract(IContractManager)10439": { "label": "contract IContractManager" }, - "t_mapping(t_bytes32,t_struct(AddressSet)1612_storage)": { + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" }, - "t_struct(AddressSet)1612_storage": { + "t_struct(AddressSet)8661_storage": { "label": "struct EnumerableSetUpgradeable.AddressSet", "members": [ { "label": "_inner", - "type": "t_struct(Set)1311_storage" + "type": "t_struct(Set)8360_storage" } ] }, - "t_struct(Set)1311_storage": { + "t_struct(Set)8360_storage": { "label": "struct EnumerableSetUpgradeable.Set", "members": [ { @@ -9018,6 +9018,1128 @@ } } } + }, + "6578b5d8690e7ec2ffe9df16ae35a3c78ef74be2bd5b57fe2e6e406e91b2ab42": { + "address": "0xfE6faFAC88150A23D946E53E9e2285aAB98A0d90", + "txHash": "0x387fc8037a21cba5c767786d79d81c7cddfa81b605b120e68a0b8c2dc0971500", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10439", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9852", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9807", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxEth", + "label": "approveTransfers", + "type": "t_mapping(t_address,t_uint256)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:39" + }, + { + "contract": "DepositBoxEth", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_uint256)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:41" + }, + { + "contract": "DepositBoxEth", + "label": "activeEthTransfers", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxEth.sol:43" + } + ], + "types": { + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)" + }, + "t_address": { + "label": "address" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_bool": { + "label": "bool" + }, + "t_contract(ILinker)9807": { + "label": "contract ILinker" + }, + "t_contract(IMessageProxyForMainnet)9852": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10439": { + "label": "contract IContractManager" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "ac3f405ee46c32af859f71eaa5396893b27253503945319ff602239e674db044": { + "address": "0x778B105215e59e4731CcBDcB0A54C367FD3897a1", + "txHash": "0xad9db4211042adf0653460ec29e416aa5f50e3c94fffec70889f552468e6dcf1", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10439", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9852", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9807", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC20", + "label": "_deprecatedSchainToERC20", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:84" + }, + { + "contract": "DepositBoxERC20", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_uint256))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:85" + }, + { + "contract": "DepositBoxERC20", + "label": "_schainToERC20", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:86" + }, + { + "contract": "DepositBoxERC20", + "label": "_delayConfig", + "type": "t_mapping(t_bytes32,t_struct(DelayConfig)15881_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:90" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfersSize", + "type": "t_uint256", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:92" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfers", + "type": "t_mapping(t_uint256,t_struct(DelayedTransfer)15869_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:94" + }, + { + "contract": "DepositBoxERC20", + "label": "delayedTransfersByReceiver", + "type": "t_mapping(t_address,t_struct(Bytes32Deque)8027_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:96" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_uint256))": { + "label": "mapping(bytes32 => mapping(address => uint256))" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_mapping(t_bytes32,t_struct(DelayConfig)15881_storage)": { + "label": "mapping(bytes32 => struct DepositBoxERC20.DelayConfig)" + }, + "t_struct(DelayConfig)15881_storage": { + "label": "struct DepositBoxERC20.DelayConfig", + "members": [ + { + "label": "bigTransferThreshold", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "label": "trustedReceivers", + "type": "t_struct(AddressSet)8661_storage" + }, + { + "label": "transferDelay", + "type": "t_uint256" + }, + { + "label": "arbitrageDuration", + "type": "t_uint256" + } + ] + }, + "t_mapping(t_uint256,t_struct(DelayedTransfer)15869_storage)": { + "label": "mapping(uint256 => struct DepositBoxERC20.DelayedTransfer)" + }, + "t_struct(DelayedTransfer)15869_storage": { + "label": "struct DepositBoxERC20.DelayedTransfer", + "members": [ + { + "label": "receiver", + "type": "t_address" + }, + { + "label": "schainHash", + "type": "t_bytes32" + }, + { + "label": "token", + "type": "t_address" + }, + { + "label": "amount", + "type": "t_uint256" + }, + { + "label": "untilTimestamp", + "type": "t_uint256" + }, + { + "label": "status", + "type": "t_enum(DelayedTransferStatus)15855" + } + ] + }, + "t_enum(DelayedTransferStatus)15855": { + "label": "enum DepositBoxERC20.DelayedTransferStatus", + "members": [ + "DELAYED", + "ARBITRAGE", + "COMPLETED" + ] + }, + "t_mapping(t_address,t_struct(Bytes32Deque)8027_storage)": { + "label": "mapping(address => struct DoubleEndedQueueUpgradeable.Bytes32Deque)" + }, + "t_struct(Bytes32Deque)8027_storage": { + "label": "struct DoubleEndedQueueUpgradeable.Bytes32Deque", + "members": [ + { + "label": "_begin", + "type": "t_int128" + }, + { + "label": "_end", + "type": "t_int128" + }, + { + "label": "_data", + "type": "t_mapping(t_int128,t_bytes32)" + } + ] + }, + "t_int128": { + "label": "int128" + }, + "t_mapping(t_int128,t_bytes32)": { + "label": "mapping(int128 => bytes32)" + }, + "t_contract(ILinker)9807": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9852": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10439": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "2183964d94b999aff896613761eda57f8a060c6cd3c56e052f9a3a419c56181f": { + "address": "0xa66b813b2e32EEb82D4dafB5e784471cdba452E8", + "txHash": "0xb50b79035ad992d65a425e3388ba35c11851843ffb9b08e9ab75d0cc1e62b68d", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10439", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9852", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9807", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC721", + "label": "_deprecatedSchainToERC721", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:46" + }, + { + "contract": "DepositBoxERC721", + "label": "transferredAmount", + "type": "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:47" + }, + { + "contract": "DepositBoxERC721", + "label": "_schainToERC721", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:48" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))": { + "label": "mapping(address => mapping(uint256 => bytes32))" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_contract(ILinker)9807": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9852": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10439": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "b5f72a6b685f6b0ebc2de40214484e89b11304f2e53eaa1e9402498b3cde0b86": { + "address": "0x9429952791A01c35E715826f34727E885A2b2f09", + "txHash": "0x13b38089d2d8378c8dbccf93220b30b802bab74f148f65a1539cd522228b5160", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10439", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9852", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9807", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "ERC1155ReceiverUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155ReceiverUpgradeable.sol:31" + }, + { + "contract": "DepositBoxERC1155", + "label": "_deprecatedSchainToERC1155", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:49" + }, + { + "contract": "DepositBoxERC1155", + "label": "transferredAmount", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_uint256,t_uint256)))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:50" + }, + { + "contract": "DepositBoxERC1155", + "label": "_schainToERC1155", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:51" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_bytes32,t_mapping(t_address,t_mapping(t_uint256,t_uint256)))": { + "label": "mapping(bytes32 => mapping(address => mapping(uint256 => uint256)))" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_uint256))": { + "label": "mapping(address => mapping(uint256 => uint256))" + }, + "t_mapping(t_uint256,t_uint256)": { + "label": "mapping(uint256 => uint256)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_contract(ILinker)9807": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9852": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10439": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_uint8": { + "label": "uint8" + } + } + } + }, + "56782bd2021cf47b65b43729ea88fd9a9e3f1acb67ffd95f65ddcc13a1ae1dfd": { + "address": "0x858b1F991F248Dc150cE2B839d3d0d71597dBF68", + "txHash": "0xcefb865cfc9d422ab8aa3d89fa96dc040131c72445d4e9aa5afdd3e31fd92af7", + "layout": { + "storage": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint8", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "contract": "ContextUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "contract": "ERC165Upgradeable", + "label": "__gap", + "type": "t_array(t_uint256)50_storage", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)179_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "contract": "AccessControlUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "_roleMembers", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:22" + }, + { + "contract": "AccessControlEnumerableUpgradeable", + "label": "__gap", + "type": "t_array(t_uint256)49_storage", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol:76" + }, + { + "contract": "SkaleManagerClient", + "label": "contractManagerOfSkaleManager", + "type": "t_contract(IContractManager)10439", + "src": "contracts/mainnet/SkaleManagerClient.sol:37" + }, + { + "contract": "Twin", + "label": "messageProxy", + "type": "t_contract(IMessageProxyForMainnet)9852", + "src": "contracts/mainnet/Twin.sol:38" + }, + { + "contract": "Twin", + "label": "schainLinks", + "type": "t_mapping(t_bytes32,t_address)", + "src": "contracts/mainnet/Twin.sol:39" + }, + { + "contract": "DepositBox", + "label": "linker", + "type": "t_contract(ILinker)9807", + "src": "contracts/mainnet/DepositBox.sol:36" + }, + { + "contract": "DepositBox", + "label": "_automaticDeploy", + "type": "t_mapping(t_bytes32,t_bool)", + "src": "contracts/mainnet/DepositBox.sol:39" + }, + { + "contract": "DepositBoxERC721", + "label": "_deprecatedSchainToERC721", + "type": "t_mapping(t_bytes32,t_mapping(t_address,t_bool))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:46" + }, + { + "contract": "DepositBoxERC721", + "label": "transferredAmount", + "type": "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:47" + }, + { + "contract": "DepositBoxERC721", + "label": "_schainToERC721", + "type": "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)", + "src": "contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:48" + } + ], + "types": { + "t_mapping(t_bytes32,t_mapping(t_address,t_bool))": { + "label": "mapping(bytes32 => mapping(address => bool))" + }, + "t_bytes32": { + "label": "bytes32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)" + }, + "t_address": { + "label": "address" + }, + "t_bool": { + "label": "bool" + }, + "t_mapping(t_address,t_mapping(t_uint256,t_bytes32))": { + "label": "mapping(address => mapping(uint256 => bytes32))" + }, + "t_mapping(t_uint256,t_bytes32)": { + "label": "mapping(uint256 => bytes32)" + }, + "t_uint256": { + "label": "uint256" + }, + "t_mapping(t_bytes32,t_struct(AddressSet)8661_storage)": { + "label": "mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)" + }, + "t_struct(AddressSet)8661_storage": { + "label": "struct EnumerableSetUpgradeable.AddressSet", + "members": [ + { + "label": "_inner", + "type": "t_struct(Set)8360_storage" + } + ] + }, + "t_struct(Set)8360_storage": { + "label": "struct EnumerableSetUpgradeable.Set", + "members": [ + { + "label": "_values", + "type": "t_array(t_bytes32)dyn_storage" + }, + { + "label": "_indexes", + "type": "t_mapping(t_bytes32,t_uint256)" + } + ] + }, + "t_array(t_bytes32)dyn_storage": { + "label": "bytes32[]" + }, + "t_mapping(t_bytes32,t_uint256)": { + "label": "mapping(bytes32 => uint256)" + }, + "t_contract(ILinker)9807": { + "label": "contract ILinker" + }, + "t_mapping(t_bytes32,t_bool)": { + "label": "mapping(bytes32 => bool)" + }, + "t_contract(IMessageProxyForMainnet)9852": { + "label": "contract IMessageProxyForMainnet" + }, + "t_mapping(t_bytes32,t_address)": { + "label": "mapping(bytes32 => address)" + }, + "t_contract(IContractManager)10439": { + "label": "contract IContractManager" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]" + }, + "t_mapping(t_bytes32,t_struct(RoleData)179_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)" + }, + "t_struct(RoleData)179_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)" + }, + { + "label": "adminRole", + "type": "t_bytes32" + } + ] + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]" + }, + "t_uint8": { + "label": "uint8" + } + } + } } } } diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index a939f53a1..e21e727f9 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.3.2-stable.1 \ No newline at end of file +1.4.0 \ No newline at end of file diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts index 1cdb09380..d5aefbd6a 100644 --- a/proxy/migrations/upgradeMainnet.ts +++ b/proxy/migrations/upgradeMainnet.ts @@ -9,75 +9,10 @@ import hre from "hardhat"; async function main() { await upgrade( - "1.3.2", + "1.4.0", contracts, async (safeTransactions, abi) => undefined, - async (safeTransactions, abi) => { - const proxyAdmin = await getManifestAdmin(hre); - const owner = await proxyAdmin.owner(); - const communityPoolName = "CommunityPool"; - const communityPoolFactory = await ethers.getContractFactory(communityPoolName); - const communityPoolAddress = abi[getContractKeyInAbiFile(communityPoolName) + "_address"]; - let communityPool; - if (communityPoolAddress) { - communityPool = communityPoolFactory.attach(communityPoolAddress) as CommunityPool; - const constantSetterRole = await communityPool.CONSTANT_SETTER_ROLE(); - const isHasRole = await communityPool.hasRole(constantSetterRole, owner); - if (!isHasRole) { - console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner)); - safeTransactions.push(encodeTransaction( - 0, - communityPoolAddress, - 0, - communityPool.interface.encodeFunctionData("grantRole", [constantSetterRole, owner]) - )); - } - console.log(chalk.yellow("Prepare transaction to set multiplier to 3/2")); - safeTransactions.push(encodeTransaction( - 0, - communityPoolAddress, - 0, - communityPool.interface.encodeFunctionData("setMultiplier", [3, 2]) - )); - console.log(chalk.yellow("Prepare transaction to set header message gas cost to 73800")); - } else { - console.log(chalk.red("CommunityPool was not found!")); - console.log(chalk.red("Check your abi!!!")); - process.exit(1); - } - - const messageProxyForMainnet = (await ethers.getContractFactory("MessageProxyForMainnet")) - .attach(abi[getContractKeyInAbiFile("MessageProxyForMainnet") + "_address"]) as MessageProxyForMainnet; - - if (! await messageProxyForMainnet.hasRole(await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner)) { - console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner)); - safeTransactions.push(encodeTransaction( - 0, - messageProxyForMainnet.address, - 0, - messageProxyForMainnet.interface.encodeFunctionData( - "grantRole", - [ await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner ] - ) - )); - } - - const newHeaderMessageGasCost = 92251; - - console.log(chalk.yellow( - "Prepare transaction to set header message gas cost to", - newHeaderMessageGasCost.toString() - )); - safeTransactions.push(encodeTransaction( - 0, - messageProxyForMainnet.address, - 0, - messageProxyForMainnet.interface.encodeFunctionData( - "setNewHeaderMessageGasCost", - [ newHeaderMessageGasCost ] - ) - )); - }, + async (safeTransactions, abi) => undefined, "proxyMainnet" ); } diff --git a/proxy/migrations/upgradeSchain.ts b/proxy/migrations/upgradeSchain.ts index f787263dd..c710758c8 100644 --- a/proxy/migrations/upgradeSchain.ts +++ b/proxy/migrations/upgradeSchain.ts @@ -14,7 +14,7 @@ async function main() { const pathToManifest: string = stringValue(process.env.MANIFEST); await manifestSetup( pathToManifest ); await upgrade( - "1.3.2", + "1.4.0", contracts, async (safeTransactions, abi) => { // deploying of new contracts From 0fde5012963c744433897a5a25c7a5ac3f34998a Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Mon, 13 Feb 2023 11:32:52 +0000 Subject: [PATCH 40/62] Fix versions --- VERSION | 2 +- proxy/DEPLOYED | 2 +- proxy/migrations/upgradeMainnet.ts | 2 +- proxy/migrations/upgradeSchain.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 347f5833e..88c5fb891 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.1 +1.4.0 diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index e21e727f9..8c9698aaf 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.4.0 \ No newline at end of file +1.3.4 \ No newline at end of file diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts index d5aefbd6a..3ca1967c1 100644 --- a/proxy/migrations/upgradeMainnet.ts +++ b/proxy/migrations/upgradeMainnet.ts @@ -9,7 +9,7 @@ import hre from "hardhat"; async function main() { await upgrade( - "1.4.0", + "1.3.4", contracts, async (safeTransactions, abi) => undefined, async (safeTransactions, abi) => undefined, diff --git a/proxy/migrations/upgradeSchain.ts b/proxy/migrations/upgradeSchain.ts index c710758c8..b1cbbd7d8 100644 --- a/proxy/migrations/upgradeSchain.ts +++ b/proxy/migrations/upgradeSchain.ts @@ -14,7 +14,7 @@ async function main() { const pathToManifest: string = stringValue(process.env.MANIFEST); await manifestSetup( pathToManifest ); await upgrade( - "1.4.0", + "1.3.4", contracts, async (safeTransactions, abi) => { // deploying of new contracts From ce7b1d20e1cd46bc851e7ac05428f52d0d850ec1 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Mon, 13 Feb 2023 11:57:18 +0000 Subject: [PATCH 41/62] Fix deployed version --- proxy/DEPLOYED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index 8c9698aaf..10e7a5846 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.3.4 \ No newline at end of file +1.3.4-stable.0 \ No newline at end of file From 124bb33343f073384db7e465076bf2d5c61737be Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 16 Feb 2023 20:28:40 +0200 Subject: [PATCH 42/62] Update upgrade script --- proxy/DEPLOYED | 2 +- proxy/migrations/upgradeMainnet.ts | 2 +- proxy/migrations/upgradeSchain.ts | 21 ++------------------- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index 10e7a5846..f15cad698 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.3.4-stable.0 \ No newline at end of file +1.4.0-stable.0 \ No newline at end of file diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts index 3ca1967c1..d5aefbd6a 100644 --- a/proxy/migrations/upgradeMainnet.ts +++ b/proxy/migrations/upgradeMainnet.ts @@ -9,7 +9,7 @@ import hre from "hardhat"; async function main() { await upgrade( - "1.3.4", + "1.4.0", contracts, async (safeTransactions, abi) => undefined, async (safeTransactions, abi) => undefined, diff --git a/proxy/migrations/upgradeSchain.ts b/proxy/migrations/upgradeSchain.ts index 72ac293fc..7ca359809 100644 --- a/proxy/migrations/upgradeSchain.ts +++ b/proxy/migrations/upgradeSchain.ts @@ -19,30 +19,13 @@ async function main() { const pathToManifest: string = stringValue(process.env.MANIFEST); await manifestSetup( pathToManifest ); await upgrade( - "1.3.4", + "1.4.0", contracts, async (safeTransactions, abi) => { // deploying of new contracts }, async( safeTransactions, abi ) => { - const communityLockerName = "CommunityLocker"; - const communityLockerFactory = await ethers.getContractFactory(communityLockerName); - const communityLockerAddress = abi[getContractKeyInAbiFile(communityLockerName) + "_address"]; - let communityLocker; - if (communityLockerAddress) { - communityLocker = communityLockerFactory.attach(communityLockerAddress) as CommunityLocker; - console.log(chalk.yellow("Prepare transaction to initialize timestamp")); - safeTransactions.push(encodeTransaction( - 0, - communityLockerAddress, - 0, - communityLocker.interface.encodeFunctionData("initializeTimestamp") - )); - } else { - console.log(chalk.red("CommunityLocker was not found!")); - console.log(chalk.red("Check your abi!!!")); - process.exit(1); - } + // do initialization }, "proxySchain" ); From d50265da65ec1f473bff5d5bc28059e664fabb83 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Tue, 7 Mar 2023 08:52:43 +0000 Subject: [PATCH 43/62] improved SNB parallel startup safety, missprint fixes --- Dockerfile | 5 +- agent/CLI.md | 28 ++++---- agent/README.md | 12 ++-- agent/bls.js | 14 ++-- agent/cli.js | 6 +- agent/main.js | 13 ++-- agent/rpc-call.js | 2 +- npms/skale-cc/cc.js | 4 +- npms/skale-ima/index.js | 22 +++---- npms/skale-observer/README.md | 8 +-- npms/skale-observer/observer.js | 113 ++++++++++++++++++++++++++------ 11 files changed, 152 insertions(+), 75 deletions(-) diff --git a/Dockerfile b/Dockerfile index e91b786c6..5bf4a0e0f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,11 +30,14 @@ RUN chmod +x /ima/bls_binaries/verify_bls RUN npm install -g node-gyp RUN which node-gyp RUN node-gyp --version -RUN npms/scrypt/get_scrypt_npm.sh +RUN cd npms/scrypt; ./get_scrypt_npm.sh; cd ../.. RUN cd proxy && yarn install && cd .. +RUN cd npms/skale-cool-socket && yarn install && cd ../.. RUN cd npms/skale-owasp && yarn install && cd ../.. +RUN cd npms/skale-observer && yarn install && cd ../.. RUN cd npms/skale-ima && yarn install && cd ../.. RUN cd agent && yarn install && cd .. +RUN yarn install CMD ["bash", "/ima/agent/run.sh"] diff --git a/agent/CLI.md b/agent/CLI.md index 4a8f572b7..5976881e3 100644 --- a/agent/CLI.md +++ b/agent/CLI.md @@ -16,14 +16,14 @@ In the most of use cases only **Ethereum(Main Net)** and source **S-Chain** are - Run message loop. - Perform **S-Chain** registration and initialization. -- Confiure and change gas reimbursement. +- Configure and change gas reimbursement. - Do **ETH**, **ERC20**, **ERC721**, **ERC1155**, batch **ERC1155** payments between chains. - View amount of **ETH** can be received on Main Net. - Mint **ERC20**, **ERC721**, **ERC1155** tokens. - Show **ETH**, **ERC20**, **ERC721**, **ERC1155** balances. - Browse **SKALE network**. - Download source **S-Chain** information. -- Discover set of **S-Chains** connected to specifed **S-Chains**. +- Discover set of **S-Chains** connected to specified **S-Chains**. - Discover chain ID of specified chain with `--discover-cid`. - Run monitoring service and expose its JSON RPC, the `--monitoring-port=number` option turns on monitoring web socket RPC server on specified port. By default monitoring server is disabled. @@ -47,7 +47,7 @@ Here is list of options running operations described above: --loop..........................Run M<->S and, optionally, S->S transfer loop. --browse-s-chain................Download own S-Chain network information. --browse-skale-network..........Download entire SKALE network description. ---browse-connected-schains......Download S-Chains conected to S-Chain with name specified in id-s-chain command line parameter. +--browse-connected-schains......Download S-Chains connected to S-Chain with name specified in id-s-chain command line parameter. --mint-erc20....................Mint ERC20 tokens. --mint-erc721...................Mint ERC721 tokens. --mint-erc1155..................Mint ERC1155 tokens. @@ -66,13 +66,13 @@ One or more of the following URL, chain name and chain ID parameters are needed --url-t-chain=URL...............S<->S Target S-chain URL. Value is automatically loaded from the URL_W3_S_CHAIN_TARGET environment variable if --id-main-net=number............Main-net Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_ETHEREUM environment variable if not specified. Default value is "Mainnet". --id-s-chain=number.............S-chain Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_SCHAIN environment variable if not specified. Default value is "id-S-chain". ---id-t-chain=number.............S<->S Target S-chain Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_SCHAIN_TARET environment variable if not specified. Default value is "id-T-chain". +--id-t-chain=number.............S<->S Target S-chain Ethereum network name.. Value is automatically loaded from the CHAIN_NAME_SCHAIN_TARGET environment variable if not specified. Default value is "id-T-chain". --cid-main-net=number...........Main-net Ethereum chain ID. Value is automatically loaded from the CID_ETHEREUM environment variable if not specified. Default value is -4. --cid-s-chain=number............S-chain Ethereum chain ID. Value is automatically loaded from the CID_SCHAIN environment variable if not specified. Default value is -4. --cid-t-chain=number............S<->S Target S-chain Ethereum chain ID. Value is automatically loaded from the CID_SCHAIN_TARGET environment variable if not specified. Default value is -4. ``` -For most of operatons, **IMA** needs ABIs of **Skale Manager**, **Ethereum(Main Net)**, **S-Chain(s)**: +For most of operations, **IMA** needs ABIs of **Skale Manager**, **Ethereum(Main Net)**, **S-Chain(s)**: ``` --abi-skale-manager=path........Path to JSON file containing Skale Manager ABI. Optional parameter. It's needed for S-Chain to S-Chain transfers. @@ -81,7 +81,7 @@ For most of operatons, **IMA** needs ABIs of **Skale Manager**, **Ethereum(Main --abi-t-chain=path..............Path to JSON file containing IMA ABI for S<->S Target S-chain. ``` -Token transfer commands require token APIs on approproate chains. +Token transfer commands require token APIs on appropriate chains. **ERC20** options: @@ -120,7 +120,7 @@ Token transfer commands require token APIs on approproate chains. - Using explicitly specified private key - Using wallet address, for read only operations only -The folllowing parameters needed to use **Transaction Manager**: +The following parameters needed to use **Transaction Manager**: ``` --tm-url-main-net=URL...........Transaction Manager server URL for Main-net. Value is automatically loaded from the TRANSACTION_MANAGER_URL_ETHEREUM environment variable if not specified. Example: redis://@127.0.0.1:6379 @@ -131,7 +131,7 @@ The folllowing parameters needed to use **Transaction Manager**: --tm-priority-t-chain=URL.......Transaction Manager priority for S<->S Target S-chain. Value is automatically loaded from the TRANSACTION_MANAGER_PRIORITY_S_CHAIN_TARGET environment variable if not specified. Default is 5. ``` -The folllowing parameters needed to use **SGX wallet**: +The following parameters needed to use **SGX wallet**: ``` --sgx-url-main-net=URL..........SGX server URL for Main-net. Value is automatically loaded from the SGX_URL_ETHEREUM environment variable if not specified. @@ -166,10 +166,10 @@ For read only operations, only wallet address can be specified: Please notice, **IMA** prefer to use transaction manager to sign blockchain transactions if `--tm-url-main-net`/`--tm-url-s-chain` command line values or `TRANSACTION_MANAGER_URL_ETHEREUM`/`TRANSACTION_MANAGER_URL_S_CHAIN` shell variables were specified. Next preferred option is **SGX wallet** which is used if `--sgx-url-main-net`/`--sgx-url-s-chain` command line values or `SGX_URL_ETHEREUM`/`SGX_URL_S_CHAIN` shell variables were specified. SGX signing also needs key name, key and certificate files. Finally, **IMA** attempts to use explicitly provided private key to sign blockchain transactions if `--key-main-net`/`--key-s-chain` command line values or `PRIVATE_KEY_FOR_ETHEREUM`/`PRIVATE_KEY_FOR_SCHAIN` shell variables were specified. -**ETH** transfers operations require amout of **ETH** to be specied with one of the following options: +**ETH** transfers operations require amount of **ETH** to be specified with one of the following options: ``` ---value=numberunitName..........Amount of unitName to transfer, where unitName is well known Ethereum unit name like ether or wei. +--value=numberAndUnitName.......Amount of unitName to transfer, where unitName is well known Ethereum unit name like ether or wei. --wei=number....................Amount of wei to transfer. --babbage=number................Amount of babbage(wei*1000) to transfer. --lovelace=number...............Amount of lovelace(wei*1000*1000) to transfer. @@ -190,7 +190,7 @@ Token transfer operations require token amounts and/or token IDs: --wait-next-block...............Wait for next block between transactions during complex operations. ``` -**Gas reumbursement** can be configure with the following options: +**Gas reimbursement** can be configure with the following options: ``` --reimbursement-chain=name......Specifies chain name. @@ -200,7 +200,7 @@ Token transfer operations require token amounts and/or token IDs: --reimbursement-range=number....Sets minimal time interval between transfers from S-Chain to Main Net. ``` -**Gas reumbursement** can be **Oracle**-based if the following options are specified: +**Gas reimbursement** can be **Oracle**-based if the following options are specified: --enable-oracle.................Enable call to Oracle to compute gas price for gas reimbursement. Default mode. --disable-oracle................Disable call to Oracle to compute gas price for gas reimbursement. @@ -220,7 +220,7 @@ Token transfer operations require token amounts and/or token IDs: --net-rediscover=number.........SKALE NETWORK re-discovery interval(in seconds). Default is 3600 seconds or 1 hour, specify 0 to disable SKALE NETWORK re-discovery. ``` -**IMA** loop can optionally use dry run, group **IMA** messages and supports varuous customizations: +**IMA** loop can optionally use dry run, group **IMA** messages and supports various customizations: ``` --no-wait-s-chain...............Do not wait until S-Chain is started. @@ -285,7 +285,7 @@ Like any command line application, **IMA** produces various command line output --no-expose-security-info.......Do not expose security-related values in log output. Default mode. ``` -Command line output and loggging can be plain or ANSI-colorized: +Command line output and logging can be plain or ANSI-colorized: ``` --colors........................Use ANSI-colorized logging. diff --git a/agent/README.md b/agent/README.md index b1e72a0d4..119c8417c 100644 --- a/agent/README.md +++ b/agent/README.md @@ -712,9 +712,9 @@ reset; node ./main.js --verbose=9 --expose --colors \ --key-main-net=$PRIVATE_KEY_FOR_ETHEREUM \ --key-s-chain=$PRIVATE_KEY_FOR_SCHAIN \ --sign-messages \ - --bls-glue=/Users/l_sergiy/Work/skaled/build/libconsensus/libBLS/bls_glue \ - --hash-g1=/Users/l_sergiy/Work/skaled/build/libconsensus/libBLS/hash_g1 \ - --bls-verify=/Users/l_sergiy/Work/skaled/build/libconsensus/libBLS/verify_bls + --bls-glue...../bls_glue \ + --hash-g1...../hash_g1 \ + --bls-verify...../verify_bls reset; node ./main.js --verbose=9 --expose --colors \ --loop \ @@ -729,9 +729,9 @@ reset; node ./main.js --verbose=9 --expose --colors \ --key-main-net=$PRIVATE_KEY_FOR_ETHEREUM \ --key-s-chain=$PRIVATE_KEY_FOR_SCHAIN \ --sign-messages \ - --bls-glue=/home/serge/Work/skaled/build/libconsensus/libBLS/bls_glue \ - --hash-g1=/home/serge/Work/skaled/build/libconsensus/libBLS/hash_g1 \ - --bls-verify=/home/serge/Work/skaled/build/libconsensus/libBLS/verify_bls + --bls-glue=...../bls_glue \ + --hash-g1=...../hash_g1 \ + --bls-verify=...../verify_bls ``` ### Gas computation and transaction customization diff --git a/agent/bls.js b/agent/bls.js index 4442863d8..52bf47409 100644 --- a/agent/bls.js +++ b/agent/bls.js @@ -736,7 +736,7 @@ async function check_correctness_of_messages_to_sign( details, strLogPrefix, str joAccount = imaState.joAccount_s_chain; joChainName = joExtraSignOpts.chain_id_dst; } else - throw new Error( "CRITICAL ERROR: Failed check_correctness_of_messages_to_sign() with unknown directon \"" + strDirection + "\"" ); + throw new Error( "CRITICAL ERROR: Failed check_correctness_of_messages_to_sign() with unknown direction \"" + strDirection + "\"" ); const strCallerAccountAddress = joAccount.address( w3 ); details.write( strLogPrefix + cc.sunny( strDirection ) + cc.debug( " message correctness validation through call to " ) + @@ -895,7 +895,7 @@ async function do_sign_messages_impl( } const nCountOfBlsPartsToCollect = 0 + nThreshold; // if( nThreshold <= 1 && nParticipants > 1 ) { - // details.write( strLogPrefix + cc.warning( "Minimal BLS parts number for dicovery was increased." ) + "\n" ); + // details.write( strLogPrefix + cc.warning( "Minimal BLS parts number for discovery was increased." ) + "\n" ); // nCountOfBlsPartsToCollect = 2; // } log.write( strLogPrefix + @@ -962,7 +962,7 @@ async function do_sign_messages_impl( // fromChainURL = owaspUtils.w3_2_url( joExtraSignOpts.w3_src ); } else { await joCall.disconnect(); - throw new Error( "CRITICAL ERROR: Failed do_sign_messages_impl() with unknown directon \"" + strDirection + "\"" ); + throw new Error( "CRITICAL ERROR: Failed do_sign_messages_impl() with unknown direction \"" + strDirection + "\"" ); } const joParams = { @@ -1231,7 +1231,7 @@ async function do_sign_messages_impl( if( ! bHaveResultReportCalled ) { bHaveResultReportCalled = true; await fn( - "Failed to gather BLS signatures in " + jarrNodes.length + " node(s), trakcer data is: " + + "Failed to gather BLS signatures in " + jarrNodes.length + " node(s), tracker data is: " + JSON.stringify( joGatheringTracker ) + ", error is: " + errGathering.toString(), jarrMessages, null @@ -1256,7 +1256,7 @@ async function do_sign_messages_impl( log.write( strErrorMessage ); details.write( strErrorMessage ); bHaveResultReportCalled = true; - await fn( "Failed to gather BLS signatures in " + jarrNodes.length + " node(s), trakcer data is: " + JSON.stringify( joGatheringTracker ), jarrMessages, null ).catch( ( err ) => { + await fn( "Failed to gather BLS signatures in " + jarrNodes.length + " node(s), tracker data is: " + JSON.stringify( joGatheringTracker ), jarrMessages, null ).catch( ( err ) => { const strErrorMessage = cc.error( "Problem(6) in BLS sign result handler, not enough successful BLS signature parts(" ) + cc.info( cntSuccess ) + cc.error( ") and timeout reached, error details: " ) + @@ -1277,7 +1277,7 @@ async function do_sign_messages_impl( if( ! bHaveResultReportCalled ) { bHaveResultReportCalled = true; await fn( "Failed BLS sign due to exception: " + owaspUtils.extract_error_message( err ), jarrMessages, null ).catch( ( err ) => { - const strErrorMessage = cc.error( "Failed BLS sign due to error-erporting callback exception: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; + const strErrorMessage = cc.error( "Failed BLS sign due to error-reporting callback exception: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n"; log.write( strErrorMessage ); if( details ) { details.write( strErrorMessage ); @@ -1385,7 +1385,7 @@ async function do_sign_u256( u256, details, fn ) { } const nCountOfBlsPartsToCollect = 0 + nThreshold; // if( nThreshold <= 1 && nParticipants > 1 ) { - // details.write( strLogPrefix + cc.warning( "Minimal BLS parts number for dicovery was increased." ) + "\n" ); + // details.write( strLogPrefix + cc.warning( "Minimal BLS parts number for discovery was increased." ) + "\n" ); // nCountOfBlsPartsToCollect = 2; // } log.write( strLogPrefix + cc.debug( "Will(u256) collect " ) + cc.info( nCountOfBlsPartsToCollect ) + "\n" ); diff --git a/agent/cli.js b/agent/cli.js index 9188a5173..398b13859 100644 --- a/agent/cli.js +++ b/agent/cli.js @@ -206,7 +206,7 @@ function parse( joExternalHandlers, argv ) { console.log( soi + cc.debug( "--" ) + cc.bright( "url-t-chain" ) + cc.sunny( "=" ) + cc.attention( "URL" ) + cc.debug( "..............." ) + cc.note( "S<->S Target S-chain" ) + cc.notice( " URL. Value is automatically loaded from the " ) + cc.warning( "URL_W3_S_CHAIN_TARGET" ) + cc.notice( " environment variable if not specified." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "id-main-net" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............" ) + cc.note( "Main-net" ) + cc.notice( " Ethereum " ) + cc.note( "network name." ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CHAIN_NAME_ETHEREUM" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( "\"Mainnet\"" ) + cc.notice( "." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "id-s-chain" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............." ) + cc.note( "S-chain" ) + cc.notice( " Ethereum " ) + cc.note( "network name." ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CHAIN_NAME_SCHAIN" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( "\"id-S-chain\"" ) + cc.notice( "." ) ); - console.log( soi + cc.debug( "--" ) + cc.bright( "id-t-chain" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............." ) + cc.note( "S<->S Target S-chain" ) + cc.notice( " Ethereum " ) + cc.note( "network name." ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CHAIN_NAME_SCHAIN_TARET" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( "\"id-T-chain\"" ) + cc.notice( "." ) ); + console.log( soi + cc.debug( "--" ) + cc.bright( "id-t-chain" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............." ) + cc.note( "S<->S Target S-chain" ) + cc.notice( " Ethereum " ) + cc.note( "network name." ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CHAIN_NAME_SCHAIN_TARGET" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( "\"id-T-chain\"" ) + cc.notice( "." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "cid-main-net" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "..........." ) + cc.note( "Main-net" ) + cc.notice( " Ethereum " ) + cc.attention( "chain ID" ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CID_ETHEREUM" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( -4 ) + cc.notice( "." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "cid-s-chain" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............" ) + cc.note( "S-chain" ) + cc.notice( " Ethereum " ) + cc.attention( "chain ID" ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CID_SCHAIN" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( -4 ) + cc.notice( "." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "cid-t-chain" ) + cc.sunny( "=" ) + cc.success( "number" ) + cc.debug( "............" ) + cc.note( "S<->S Target S-chain" ) + cc.notice( " Ethereum " ) + cc.attention( "chain ID" ) + cc.notice( ". Value is automatically loaded from the " ) + cc.warning( "CID_SCHAIN_TARGET" ) + cc.notice( " environment variable if not specified. " ) + cc.debug( "Default value is " ) + cc.sunny( -4 ) + cc.notice( "." ) ); @@ -421,7 +421,7 @@ function parse( joExternalHandlers, argv ) { console.log( cc.sunny( "TEST" ) + cc.info( " options:" ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "browse-s-chain" ) + cc.debug( "................" ) + cc.notice( "Download own " ) + cc.note( "S-Chain" ) + cc.notice( " network information." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "browse-skale-network" ) + cc.debug( ".........." ) + cc.notice( "Download entire " ) + cc.note( "SKALE network" ) + cc.notice( " description." ) ); - console.log( soi + cc.debug( "--" ) + cc.bright( "browse-connected-schains" ) + cc.debug( "......" ) + cc.notice( "Download " ) + cc.note( "S-Chains" ) + cc.notice( " conected to " ) + cc.note( "S-Chain" ) + cc.notice( " with name specified in " ) + cc.bright( "id-s-chain" ) + cc.notice( " command line parameter." ) ); + console.log( soi + cc.debug( "--" ) + cc.bright( "browse-connected-schains" ) + cc.debug( "......" ) + cc.notice( "Download " ) + cc.note( "S-Chains" ) + cc.notice( " connected to " ) + cc.note( "S-Chain" ) + cc.notice( " with name specified in " ) + cc.bright( "id-s-chain" ) + cc.notice( " command line parameter." ) ); console.log( soi + cc.debug( "--" ) + cc.bright( "discover-cid" ) + cc.debug( ".................." ) + cc.notice( "Discover " ) + cc.attention( "chains ID(s)" ) + cc.notice( " from provided " ) + cc.note( "URL(s)" ) + cc.notice( "." ) + cc.debug( " This command is not executed automatically at startup" ) + cc.notice( "." ) ); // console.log( cc.sunny( "LOGGING" ) + cc.info( " options:" ) ); @@ -1490,7 +1490,7 @@ function ima_common_init() { // token_manager_erc20_address --> token_manager_erc20_abi // token_manager_erc721_address --> token_manager_erc721_abi // token_manager_erc1155_address --> token_manager_erc1155_abi - // token_manager_erc721_with_metadata_address --> token_manager_erc721_with_metdata_abi + // token_manager_erc721_with_metadata_address --> token_manager_erc721_with_metadata_abi // token_manager_linker_address --> token_manager_linker_abi // message_proxy_mainnet_address --> message_proxy_mainnet_abi // message_proxy_chain_address --> message_proxy_chain_abi diff --git a/agent/main.js b/agent/main.js index 63b93918b..17bb953f4 100644 --- a/agent/main.js +++ b/agent/main.js @@ -280,7 +280,7 @@ global.imaState = { "s2s_opts": { // S-Chain to S-Chain transfer options "isEnabled": true, // is S-Chain to S-Chain transfers enabled - "secondsToReDiscoverSkaleNetwork": 1 * 60 * 60 // seconts to re-discover SKALE network, 0 to disable + "secondsToReDiscoverSkaleNetwork": 1 * 60 * 60 // seconds to re-discover SKALE network, 0 to disable }, "arrActions": [] // array of actions to run @@ -314,10 +314,11 @@ const fnInitActionSkaleNetworkScanForS2S = function() { } log.write( strLogPrefix + cc.debug( "Downloading SKALE network information..." ) + "\n" ); // just print value const opts = { - imaState: imaState, + "imaState": imaState, "details": log, "bStopNeeded": false, - "secondsToReDiscoverSkaleNetwork": imaState.s2s_opts.secondsToReDiscoverSkaleNetwork + "secondsToReDiscoverSkaleNetwork": imaState.s2s_opts.secondsToReDiscoverSkaleNetwork, + "bParallelMode": true }; const addressFrom = imaState.joAccount_main_net.address( imaState.w3_main_net ); // const strError = await skale_observer.cache_schains( @@ -1505,7 +1506,7 @@ imaCLI.parse( { ); const cnt = arr_schains_cached.length; - log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( cnt ) + cc.normal( " onnected S-Chain(s): " ) + cc.j( arr_schains_cached ) + "\n" ); + log.write( strLogPrefix + cc.normal( "Got " ) + cc.info( cnt ) + cc.normal( " connected S-Chain(s): " ) + cc.j( arr_schains_cached ) + "\n" ); return true; } } ); @@ -1540,7 +1541,7 @@ imaCLI.parse( { } if( arr_urls_to_discover.length === 0 ) { console.log( cc.fatal( "CRITICAL ERROR:" ) + - cc.error( " no URLs privided to discover chain IDs, please specify " ) + + cc.error( " no URLs provided to discover chain IDs, please specify " ) + cc.warning( "--url-main-net" ) + cc.error( " and/or " ) + cc.warning( "--url-s-chain" ) + cc.error( " and/or " ) + cc.warning( "--url-t-chain" ) + cc.error( "." ) + @@ -2452,7 +2453,7 @@ async function single_transfer_loop() { try { if( g_is_single_transfer_loop ) { if( IMA.verbose_get() >= IMA.RV_VERBOSE.debug ) - log.write( strLogPrefix + cc.warning( "Skipped due to other single transfer loop is in progress rignt now" ) + "\n" ); + log.write( strLogPrefix + cc.warning( "Skipped due to other single transfer loop is in progress right now" ) + "\n" ); return true; } g_is_single_transfer_loop = true; diff --git a/agent/rpc-call.js b/agent/rpc-call.js index dd1aa81d1..c81407c28 100644 --- a/agent/rpc-call.js +++ b/agent/rpc-call.js @@ -287,7 +287,7 @@ async function do_call( joCall, joIn, fn ) { } catch ( err ) { bCompleteFlag = true; joOut = null; - errCall = "Responce body parse error: " + err.toString(); + errCall = "Response body parse error: " + err.toString(); return; } bCompleteFlag = true; diff --git a/npms/skale-cc/cc.js b/npms/skale-cc/cc.js index 0c86e20a2..a4f74974b 100644 --- a/npms/skale-cc/cc.js +++ b/npms/skale-cc/cc.js @@ -169,7 +169,7 @@ const g_arrRainbowParts = [ g_map_color_definitions.fgMagenta ]; -function raibow_part( s, i ) { +function rainbow_part( s, i ) { if( !g_bEnabled ) return s; const j = i % g_arrRainbowParts.length; @@ -182,7 +182,7 @@ function rainbow( s ) { let res = ""; const cnt = s.length; for( let i = 0; i < cnt; ++ i ) - res = res + raibow_part( s[i], i ); + res = res + rainbow_part( s[i], i ); return res; } diff --git a/npms/skale-ima/index.js b/npms/skale-ima/index.js index ef70478aa..23c2266ea 100644 --- a/npms/skale-ima/index.js +++ b/npms/skale-ima/index.js @@ -197,8 +197,8 @@ async function get_web3_blockNumber( details, cntAttempts, w3, retValOnFail, thr } ++ idxAttempt; while( ret === "" && idxAttempt <= cntAttempts ) { - const isOnlone = rpcCall.check_url( u, nWaitStepMilliseconds ); - if( ! isOnlone ) { + const isOnLine = rpcCall.check_url( u, nWaitStepMilliseconds ); + if( ! isOnLine ) { ret = retValOnFail; if( ! throwIfServerOffline ) return ret; @@ -262,8 +262,8 @@ async function get_web3_transactionCount( details, cntAttempts, w3, address, par } ++ idxAttempt; while( ret === "" && idxAttempt <= cntAttempts ) { - const isOnlone = rpcCall.check_url( u, nWaitStepMilliseconds ); - if( ! isOnlone ) { + const isOnLine = rpcCall.check_url( u, nWaitStepMilliseconds ); + if( ! isOnLine ) { ret = retValOnFail; if( ! throwIfServerOffline ) return ret; @@ -327,8 +327,8 @@ async function get_web3_transactionReceipt( details, cntAttempts, w3, txHash, re } ++ idxAttempt; while( txReceipt === "" && idxAttempt <= cntAttempts ) { - const isOnlone = rpcCall.check_url( u, nWaitStepMilliseconds ); - if( ! isOnlone ) { + const isOnLine = rpcCall.check_url( u, nWaitStepMilliseconds ); + if( ! isOnLine ) { ret = retValOnFail; if( ! throwIfServerOffline ) return ret; @@ -406,8 +406,8 @@ async function get_web3_pastEvents( details, w3, cntAttempts, joContract, strEve } ++ idxAttempt; while( ret === "" && idxAttempt <= cntAttempts ) { - const isOnlone = rpcCall.check_url( u, nWaitStepMilliseconds ); - if( ! isOnlone ) { + const isOnLine = rpcCall.check_url( u, nWaitStepMilliseconds ); + if( ! isOnLine ) { ret = retValOnFail; if( ! throwIfServerOffline ) return ret; @@ -549,7 +549,7 @@ async function get_web3_pastEventsIterative( details, w3, attempts, joContract, } } catch ( err ) { details.write( - cc.error( "Got scan error during interative scan of " ) + + cc.error( "Got scan error during interactive scan of " ) + cc.info( idxBlockSubRangeFrom ) + cc.error( "/" ) + cc.info( idxBlockSubRangeTo ) + cc.error( " block sub-range in " ) + cc.info( nBlockFrom ) + cc.error( "/" ) + cc.info( nBlockTo ) + cc.error( " block range, error is: " ) + cc.warning( owaspUtils.extract_error_message( err ) ) + "\n" @@ -1233,7 +1233,7 @@ async function tm_ensure_transaction( details, w3, priority, txAdjusted, cntAtte cc.error( " transaction has been dropped" ); details.write( strPrefixDetails + strMsg + "\n" ); log.write( strPrefixLog + strMsg + "\n" ); - throw new Error( "TM unseccessful transaction " + txId ); + throw new Error( "TM unsuccessful transaction " + txId ); } strMsg = cc.success( "TM - successful TX " ) + cc.info( txId ) + cc.success( ", sending attempt " ) + cc.info( idxAttempt ) + @@ -5894,7 +5894,7 @@ async function do_transfer( } ); // fn_sign_messages } catch ( err ) { const strError = strLogPrefix + cc.fatal( "CRITICAL ERROR:" ) + - cc.error( " Exception from sigining messages function: " ) + cc.error( err.toString() ); + cc.error( " Exception from signing messages function: " ) + cc.error( err.toString() ); log.write( strError + "\n" ); details.write( strError + "\n" ); if( detailsB ) diff --git a/npms/skale-observer/README.md b/npms/skale-observer/README.md index 8d3b81db8..2af174ce4 100644 --- a/npms/skale-observer/README.md +++ b/npms/skale-observer/README.md @@ -2,7 +2,7 @@ ## General Description -**SKALE Network Browser** (**SNB**) or **SKALE Observer** is part of IMA resposible for providing description of all SKALE chains. This is done via set of calls to **SKALE Mananger**. +**SKALE Network Browser** (**SNB**) or **SKALE Observer** is part of IMA responsible for providing description of all SKALE chains. This is done via set of calls to **SKALE Manager**. **SNB** maintains cache of S-Chain descriptions and refreshes all descriptions periodically. These descriptions and needed for S-Chain to S-Chain IMA message transfers when IMA needs to know how to connect to other S-Chain. @@ -12,7 +12,7 @@ First SKALE network scan is performed by **SNB** on IMA startup. Next network de ## Implementation details -The `SchainsInternal.numberOfSchains` contract call returns number of created S-Chains to load from **SKALE Mananger**. For each of S-Chains we need to get its hash by index what is done `SchainsInternal.schainsAtSystem` contract call. Then contract call to `SchainsInternal.schains` returns basic S-Chain description by hash. Obtained basic S-Chain description does not describe nodes and they must be loaded via set of contract calls. The `SchainsInternal.getNodesInGroup` contract call returns array of node identifiers for all S-Chain nodes. The `Nodes.nodes` contract call returns node description by node id. Returned node description includes IP adderess, domain name and, base port of a node, maintanance state flag. Then call to `SchainsInternal.getSchainHashesForNode` contract call allows to find effective node base port and compute per-protocol ports (`http`, `https`, `ws`, `wss`). +The `SchainsInternal.numberOfSchains` contract call returns number of created S-Chains to load from **SKALE Manager**. For each of S-Chains we need to get its hash by index what is done `SchainsInternal.schainsAtSystem` contract call. Then contract call to `SchainsInternal.schains` returns basic S-Chain description by hash. Obtained basic S-Chain description does not describe nodes and they must be loaded via set of contract calls. The `SchainsInternal.getNodesInGroup` contract call returns array of node identifiers for all S-Chain nodes. The `Nodes.nodes` contract call returns node description by node id. Returned node description includes IP address, domain name and, base port of a node, maintenance state flag. Then call to `SchainsInternal.getSchainHashesForNode` contract call allows to find effective node base port and compute per-protocol ports (`http`, `https`, `ws`, `wss`). Cache of S-Chain descriptions is result of download process described above. When new S-Chain descriptions are downloaded, they replace old ones. By default this is performed once in an hour. @@ -20,7 +20,7 @@ S-Chain descriptions directly affect on S-Chain to S-Chain transfers because the **SNB** can be invoked from command line of IMA agent in one of the following ways - The`--browse-skale-network` command line options invokes download entire SKALE network description, all S-Chains, all `skaled` nodes. - - The `--browse-connected-schains` command line options invokes download of which are S-Chains conected to S-Chain with name specified in `--id-s-chain` command line parameter. + - The `--browse-connected-schains` command line options invokes download of which are S-Chains connected to S-Chain with name specified in `--id-s-chain` command line parameter. Example of **SNB** invocation: @@ -39,7 +39,7 @@ node agent/main.js --colors --browse-skale-network \ --key-s-chain=... ``` -Example of downloaded S-Chains description containg 2 S-Chains named `Bob1000` and `Bob1001`, 2 `skaled` nodes each: +Example of downloaded S-Chains description containing 2 S-Chains named `Bob1000` and `Bob1001`, 2 `skaled` nodes each: ```json [ diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js index 59e6cc27a..53da0c431 100644 --- a/npms/skale-observer/observer.js +++ b/npms/skale-observer/observer.js @@ -36,6 +36,9 @@ const w3mod = require( "web3" ); // const ethereumjs_wallet = require( "ethereumjs-wallet" ); // const ethereumjs_util = require( "ethereumjs-util" ); +let g_interval_periodic_caching = null; +let g_bHaveParallelResult = false; + const PORTS_PER_SCHAIN = 64; function getWeb3FromURL( strURL, log ) { @@ -451,14 +454,14 @@ async function cache_schains( strChainNameConnectedTo, w3_main_net, w3_s_chain, cc.debug( "Connected " ) + cc.attention( "S-Chains" ) + cc.debug( " cache was updated in this thread: " ) + cc.j( g_arr_schains_cached ) + "\n" ); } - if( opts.fn_chache_changed ) - opts.fn_chache_changed( g_arr_schains_cached, null ); // null - no error + if( opts.fn_cache_changed ) + opts.fn_cache_changed( g_arr_schains_cached, null ); // null - no error } catch ( err ) { strError = owaspUtils.extract_error_message( err ); if( ! strError ) strError = "unknown exception during S-Chains download"; - if( opts.fn_chache_changed ) - opts.fn_chache_changed( g_arr_schains_cached, strError ); + if( opts.fn_cache_changed ) + opts.fn_cache_changed( g_arr_schains_cached, strError ); if( opts && opts.details ) opts.details.write( cc.fatal( "ERROR:" ) + cc.error( " Failed to cache: " ) + cc.error( err ) + "\n" ); @@ -492,6 +495,7 @@ async function ensure_have_worker( opts ) { switch ( joMessage.method ) { case "periodic_caching_do_now": g_arr_schains_cached = joMessage.message; + g_bHaveParallelResult = true; if( opts && opts.details ) { opts.details.write( cc.debug( "Connected " ) + cc.attention( "S-Chains" ) + @@ -567,26 +571,95 @@ async function ensure_have_worker( opts ) { g_client.send( jo ); } +async function in_thread_periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ) { + if( g_interval_periodic_caching != null ) + return; + try { + const fn_do_caching_now = async function() { + await cache_schains( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ); + }; + g_interval_periodic_caching = setInterval( fn_do_caching_now, parseInt( opts.secondsToReDiscoverSkaleNetwork ) * 1000 ); + await fn_do_caching_now(); + return true; + } catch ( err ) { + log.write( + cc.error( "Failed to start in-thread periodic SNB refresh, error is: " ) + + cc.warning( owaspUtils.extract_error_message( err ) ) + + cc.error( ", stack is: " ) + "\n" + cc.stack( err.stack ) + + "\n" ); + } + return false; +} + +async function parallel_periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ) { + g_bHaveParallelResult = false; + try { + const nSecondsToWaitParallel = 60; + setTimeout( function() { + if( g_bHaveParallelResult ) + return; + log.write( + cc.error( "Failed to start parallel periodic SNB refresh, error is: " ) + + cc.warning( "timeout of " ) + cc.info( nSecondsToWaitParallel ) + + cc.warning( " reached, will restart periodic SNB refresh in non-parallel mode" ) + + "\n" ); + periodic_caching_stop(); + in_thread_periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ); + }, nSecondsToWaitParallel * 1000 ); + await ensure_have_worker( opts ); + const jo = { + method: "periodic_caching_start", + message: { + secondsToReDiscoverSkaleNetwork: parseInt( opts.secondsToReDiscoverSkaleNetwork ), + strChainNameConnectedTo: strChainNameConnectedTo, + addressFrom: addressFrom + } + }; + g_client.send( jo ); + return true; + } catch ( err ) { + log.write( + cc.error( "Failed to start parallel periodic SNB refresh, error is: " ) + + cc.warning( owaspUtils.extract_error_message( err ) ) + + cc.error( ", stack is: " ) + "\n" + cc.stack( err.stack ) + + "\n" ); + } + return false; +} + async function periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ) { - await ensure_have_worker( opts ); - const jo = { - method: "periodic_caching_start", - message: { - secondsToReDiscoverSkaleNetwork: parseInt( opts.secondsToReDiscoverSkaleNetwork ), - strChainNameConnectedTo: strChainNameConnectedTo, - addressFrom: addressFrom - } - }; - g_client.send( jo ); + g_bHaveParallelResult = false; + const bParallelMode = ( opts && "bParallelMode" in opts && typeof opts.bParallelMode != "undefined" && opts.bParallelMode ) ? true : false; + let wasStarted = false; + if( bParallelMode ) + wasStarted = parallel_periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ); + if( wasStarted ) + return; + in_thread_periodic_caching_start( strChainNameConnectedTo, w3_main_net, w3_s_chain, addressFrom, opts ); } + async function periodic_caching_stop() { - await ensure_have_worker( opts ); - const jo = { - method: "periodic_caching_stop", - message: { + if( g_worker && g_client ) { + const jo = { + method: "periodic_caching_stop", + message: { } + }; + g_client.send( jo ); + } + if( g_interval_periodic_caching ) { + try { + clearInterval( g_interval_periodic_caching ); + g_interval_periodic_caching = null; + } catch ( err ) { + log.write( + cc.error( "Failed to stop in-thread periodic SNB refresh, error is: " ) + + cc.warning( owaspUtils.extract_error_message( err ) ) + + cc.error( ", stack is: " ) + "\n" + cc.stack( err.stack ) + + "\n" ); + g_interval_periodic_caching = null; // clear it anyway } - }; - g_client.send( jo ); + } + g_bHaveParallelResult = false; } function pick_random_schain_node_index( jo_schain ) { From e40aac0fa9ad380f07db0d45792d4dbb6e81cc80 Mon Sep 17 00:00:00 2001 From: Sergiy Lavrynenko Date: Thu, 9 Mar 2023 11:50:46 +0000 Subject: [PATCH 44/62] ticket-1413 - SNB stability workaround --- npms/skale-observer/observer.js | 6 +++++- npms/skale-observer/observer_worker.js | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/npms/skale-observer/observer.js b/npms/skale-observer/observer.js index 53da0c431..fb0ea3975 100644 --- a/npms/skale-observer/observer.js +++ b/npms/skale-observer/observer.js @@ -490,8 +490,9 @@ async function ensure_have_worker( opts ) { } ); g_client = new network_layer.OutOfWorkerSocketClientPipe( url, g_worker ); g_client.on( "message", function( eventData ) { + // console.log( cc.attention( ">>>> TRACE - SNB HOST OBSERVER EVENT DATA >>>>" ), cc.j( eventData ) ); const joMessage = eventData.message; - // console.log( "CLIENT <<<", JSON.stringify( joMessage ) ); + // console.log( cc.attention( ">>>> TRACE - SNB HOST OBSERVER MESSAGE >>>>" ), cc.j( joMessage ) ); switch ( joMessage.method ) { case "periodic_caching_do_now": g_arr_schains_cached = joMessage.message; @@ -568,6 +569,7 @@ async function ensure_have_worker( opts ) { } } }; + // console.log( cc.attention( "<<<< TRACE - SNB HOST OBSERVER MESSAGE <<<<" ), cc.j( jo ) ); g_client.send( jo ); } @@ -615,6 +617,7 @@ async function parallel_periodic_caching_start( strChainNameConnectedTo, w3_main addressFrom: addressFrom } }; + // console.log( cc.attention( "<<<< TRACE - SNB HOST OBSERVER MESSAGE <<<<" ), cc.j( jo ) ); g_client.send( jo ); return true; } catch ( err ) { @@ -644,6 +647,7 @@ async function periodic_caching_stop() { method: "periodic_caching_stop", message: { } }; + // console.log( cc.attention( "<<<< TRACE - SNB HOST OBSERVER MESSAGE <<<<" ), cc.j( jo ) ); g_client.send( jo ); } if( g_interval_periodic_caching ) { diff --git a/npms/skale-observer/observer_worker.js b/npms/skale-observer/observer_worker.js index a03c135d1..2943292cf 100644 --- a/npms/skale-observer/observer_worker.js +++ b/npms/skale-observer/observer_worker.js @@ -38,6 +38,7 @@ const skale_observer = require( "./observer.js" ); const g_url = "skale_observer_worker_server"; parentPort.on( "message", jo => { + // console.log( cc.attention( ">>>> TRACE - SNB WORKER MESSAGE >>>>" ), cc.j( jo ) ); if( network_layer.in_worker_apis.on_message( jo ) ) return; } ); @@ -45,7 +46,9 @@ parentPort.on( "message", jo => { const sleep = ( milliseconds ) => { return new Promise( resolve => setTimeout( resolve, milliseconds ) ); }; function doSendMessage( type, endpoint, worker_uuid, data ) { + // console.log( cc.attention( "<<<< TRACE - SNB WORKER OUTGOING DATA <<<<" ), cc.j( arguments ) ); const jo = network_layer.socket_received_data_reverse_marshall( data ); + // console.log( cc.attention( "<<<< TRACE - SNB WORKER MESSAGE <<<<" ), cc.j( jo ) ); const joSend = { worker_message_type: ( type && typeof type == "string" && type.length > 0 ) ? type : "in_worker_message", worker_endpoint: endpoint, From 67bc50e4d1f35b83cf227fc65ea452699bc72638 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 8 Jun 2023 23:24:22 +0300 Subject: [PATCH 45/62] Update ima-interfaces --- proxy/package.json | 2 +- proxy/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/proxy/package.json b/proxy/package.json index 19a2ea24d..3fa33b5be 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "^1.1.0-develop.0", + "@skalenetwork/ima-interfaces": "^2.0.0-beta.0", "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1", "@skalenetwork/upgrade-tools": "2.0.0-refactor.15", "axios": "^0.21.4", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index a7c087d95..5d37506cc 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -762,10 +762,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@^1.1.0-develop.0": - version "1.1.0-develop.0" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.1.0-develop.0.tgz#a91a794affee2138e03c779f9f32cd34652a47b7" - integrity sha512-wy1DYbsgccYETqgayxyHh9Dh8+q13F0JrDCpHn7nodwnjxp95cAtjyD9KTN4Y4/Ix/pr5rFqQjBXtXQas36uBg== +"@skalenetwork/ima-interfaces@^2.0.0-beta.0": + version "2.0.0-develop.0" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-2.0.0-develop.0.tgz#2db130e63278f7a00bd848a4f2e10dda61e353fb" + integrity sha512-vSDY3vcuuUUBDMM3fifU++HPl2W9c2VSjkFK68r5Hc1Sc0VMYWcdfpx9yRwvp5NKY/B78+k80661GJHn+vuCCQ== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From 80ce4b81c0fbdde8af35d13fc600df5e1b364f6b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 13:08:47 +0300 Subject: [PATCH 46/62] Update upgrade scripts --- proxy/migrations/upgradeMainnet.ts | 2 +- proxy/migrations/upgradeSchain.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts index b453d7482..4340aa03c 100644 --- a/proxy/migrations/upgradeMainnet.ts +++ b/proxy/migrations/upgradeMainnet.ts @@ -52,7 +52,7 @@ async function main() { await manifestSetup(pathToManifest); const upgrader = new ImaMainnetUpgrader( "proxyMainnet", - "1.3.4", + "1.4.0", await getImaMainnetAbiAndAddress(), contracts ); diff --git a/proxy/migrations/upgradeSchain.ts b/proxy/migrations/upgradeSchain.ts index a7419340a..7c850bfef 100644 --- a/proxy/migrations/upgradeSchain.ts +++ b/proxy/migrations/upgradeSchain.ts @@ -72,7 +72,7 @@ async function main() { await manifestSetup(pathToManifest); const upgrader = new ImaSchainUpgrader( "proxySchain", - "1.3.4", + "1.4.0", await getImaSchainAbiAndAddress(), contracts ); From 73c894107f0cdeac255440857f1f04b8271d1f43 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 13:22:36 +0300 Subject: [PATCH 47/62] Remove duplicate of abi module --- proxy/migrations/deployMainnet.ts | 21 ++++++++++++------- proxy/migrations/deploySchain.ts | 20 +++++++++++++----- .../deploySkaleManagerComponents.ts | 2 +- proxy/migrations/tools/abi.ts | 19 ----------------- 4 files changed, 30 insertions(+), 32 deletions(-) delete mode 100644 proxy/migrations/tools/abi.ts diff --git a/proxy/migrations/deployMainnet.ts b/proxy/migrations/deployMainnet.ts index 46238ae28..3049e8ade 100644 --- a/proxy/migrations/deployMainnet.ts +++ b/proxy/migrations/deployMainnet.ts @@ -27,8 +27,8 @@ import { Interface } from "ethers/lib/utils"; import { ethers, upgrades, artifacts, web3 } from "hardhat"; import { MessageProxyForMainnet, Linker } from "../typechain"; import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from './tools/abi'; -import { verify, verifyProxy } from './tools/verification'; +import { getAbi } from '@skalenetwork/upgrade-tools'; +import { verifyProxy } from './tools/verification'; import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; import { getVersion } from './tools/version'; @@ -223,12 +223,19 @@ async function main() { const outputObject: {[k: string]: any} = {}; for (const contract of contracts) { const contractKey = getContractKeyInAbiFile(contract); - outputObject[contractKey + "_address"] = deployed.get(contract)?.address; - outputObject[contractKey + "_abi"] = getAbi(deployed.get(contract)?.interface); + const deployedContract = deployed.get(contract); + if (deployedContract === undefined) { + throw Error(`Contract ${contract} was not found`); + } + outputObject[contractKey + "_address"] = deployedContract.address; + outputObject[contractKey + "_abi"] = getAbi(deployedContract.interface); } - - outputObject[getContractKeyInAbiFile("DepositBoxERC721WithMetadata") + "_address"] = deployed.get("DepositBoxERC721WithMetadata")?.address; - outputObject[getContractKeyInAbiFile("DepositBoxERC721WithMetadata") + "_abi"] = getAbi(deployed.get("DepositBoxERC721WithMetadata")?.interface); + const deployedDepositBoxERC721WithMetadata = deployed.get("DepositBoxERC721WithMetadata"); + if (deployedDepositBoxERC721WithMetadata === undefined) { + throw new Error("DepositBoxERC721WithMetadata was not found"); + } + outputObject[getContractKeyInAbiFile("DepositBoxERC721WithMetadata") + "_address"] = deployedDepositBoxERC721WithMetadata.address; + outputObject[getContractKeyInAbiFile("DepositBoxERC721WithMetadata") + "_abi"] = getAbi(deployedDepositBoxERC721WithMetadata.interface); await fs.writeFile("data/proxyMainnet.json", JSON.stringify(outputObject, null, 4)); diff --git a/proxy/migrations/deploySchain.ts b/proxy/migrations/deploySchain.ts index 014d89236..a24259f90 100644 --- a/proxy/migrations/deploySchain.ts +++ b/proxy/migrations/deploySchain.ts @@ -27,7 +27,7 @@ import { Interface } from "ethers/lib/utils"; import { ethers, artifacts, upgrades } from "hardhat"; import hre from "hardhat"; import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from './tools/abi'; +import { getAbi } from '@skalenetwork/upgrade-tools'; import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin"; import { Contract } from '@ethersproject/contracts'; @@ -309,11 +309,21 @@ async function main() { for( const contractName of contracts ) { const propertyName = getContractKeyInAbiFile(contractName); - jsonObjectABI[propertyName + "_address"] = deployed.get( contractName )?.address; - jsonObjectABI[propertyName + "_abi"] = getAbi(deployed.get( contractName )?.interface); + const deployedContract = deployed.get(contractName); + if (deployedContract === undefined) { + throw Error(`Contract ${contractName} was not found`); + } else { + jsonObjectABI[propertyName + "_address"] = deployedContract.address; + jsonObjectABI[propertyName + "_abi"] = getAbi(deployedContract.interface); + } + } + const deployedTokenManagerERC721WithMetadata = deployed.get( "TokenManagerERC721WithMetadata" ); + if (deployedTokenManagerERC721WithMetadata === undefined) { + throw new Error("TokenManagerERC721WithMetadata was not found"); + } else { + jsonObjectABI[getContractKeyInAbiFile("TokenManagerERC721WithMetadata") + "_address"] = deployedTokenManagerERC721WithMetadata.address; + jsonObjectABI[getContractKeyInAbiFile("TokenManagerERC721WithMetadata") + "_abi"] = getAbi(deployedTokenManagerERC721WithMetadata.interface); } - jsonObjectABI[getContractKeyInAbiFile("TokenManagerERC721WithMetadata") + "_address"] = deployed.get( "TokenManagerERC721WithMetadata" )?.address; - jsonObjectABI[getContractKeyInAbiFile("TokenManagerERC721WithMetadata") + "_abi"] = getAbi(deployed.get( "TokenManagerERC721WithMetadata" )?.interface); const erc20OnChainFactory = await ethers.getContractFactory("ERC20OnChain"); jsonObjectABI.ERC20OnChain_abi = getAbi(erc20OnChainFactory.interface); const erc721OnChainFactory = await ethers.getContractFactory("ERC721OnChain"); diff --git a/proxy/migrations/deploySkaleManagerComponents.ts b/proxy/migrations/deploySkaleManagerComponents.ts index 0c35041e1..668c6dc3f 100644 --- a/proxy/migrations/deploySkaleManagerComponents.ts +++ b/proxy/migrations/deploySkaleManagerComponents.ts @@ -25,7 +25,7 @@ import { promises as fs } from 'fs'; import { ethers, artifacts, web3 } from "hardhat"; import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from './tools/abi'; +import { getAbi } from '@skalenetwork/upgrade-tools'; import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; import { KeyStorageMock } from '../typechain/KeyStorageMock'; import { Wallet } from 'ethers'; diff --git a/proxy/migrations/tools/abi.ts b/proxy/migrations/tools/abi.ts deleted file mode 100644 index 041ffb47a..000000000 --- a/proxy/migrations/tools/abi.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Interface } from "ethers/lib/utils"; - -export function getAbi(contractInterface: Interface | undefined) { - if (!contractInterface) { - return undefined; - } - const abi = JSON.parse(contractInterface.format("json") as string); - - abi.forEach((obj: {type: string}) => { - if (obj.type === "function") { - const func = obj as {name: string, type: string, inputs: object[], outputs: object[]}; - func.inputs.concat(func.outputs).forEach((output: object) => { - Object.assign(output, Object.assign({name: ""}, output)); - }) - } - }); - - return abi; -} From b86546c2c16fb457dd5d0786823c9097a8b132d0 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:01:29 +0300 Subject: [PATCH 48/62] Remove duplicate of the factory module --- proxy/migrations/deployMainnet.ts | 36 ++------------ proxy/migrations/deploySchain.ts | 31 +----------- .../deploySkaleManagerComponents.ts | 33 +------------ proxy/migrations/tools/factory.ts | 49 ------------------- proxy/migrations/transferOwnership.ts | 1 - 5 files changed, 6 insertions(+), 144 deletions(-) delete mode 100644 proxy/migrations/tools/factory.ts diff --git a/proxy/migrations/deployMainnet.ts b/proxy/migrations/deployMainnet.ts index 3049e8ade..9cbb3fffd 100644 --- a/proxy/migrations/deployMainnet.ts +++ b/proxy/migrations/deployMainnet.ts @@ -24,12 +24,11 @@ */ import { promises as fs } from 'fs'; import { Interface } from "ethers/lib/utils"; -import { ethers, upgrades, artifacts, web3 } from "hardhat"; +import { ethers, upgrades, web3 } from "hardhat"; import { MessageProxyForMainnet, Linker } from "../typechain"; -import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from '@skalenetwork/upgrade-tools'; +import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; import { verifyProxy } from './tools/verification'; -import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; +import { Manifest } from "@openzeppelin/upgrades-core"; import { getVersion } from './tools/version'; export function getContractKeyInAbiFile(contract: string) { @@ -43,35 +42,6 @@ export async function getManifestFile(): Promise { return (await Manifest.forNetwork(ethers.provider)).file;; } -export async function getContractFactory(contract: string) { - const { linkReferences } = await artifacts.readArtifact(contract); - if (!Object.keys(linkReferences).length) - return await ethers.getContractFactory(contract); - - const libraryNames = []; - for (const key of Object.keys(linkReferences)) { - const libraryName = Object.keys(linkReferences[key])[0]; - libraryNames.push(libraryName); - } - - const libraries = await deployLibraries(libraryNames); - const libraryArtifacts: {[key: string]: any} = {}; - for (const libraryName of Object.keys(libraries)) { - const { bytecode } = await artifacts.readArtifact(libraryName); - libraryArtifacts[libraryName] = {"address": libraries[libraryName], "bytecodeHash": hashBytecode(bytecode)}; - } - let manifest: any; - try { - manifest = JSON.parse(await fs.readFile(await getManifestFile(), "utf-8")); - Object.assign(libraryArtifacts, manifest.libraries); - } finally { - Object.assign(manifest, {libraries: libraryArtifacts}); - await fs.writeFile(await getManifestFile(), JSON.stringify(manifest, null, 4)); - } - return await getLinkedContractFactory(contract, libraries); -} - - export function getContractManager() { const defaultFilePath = "../data/skaleManagerComponents.json"; const jsonData = require(defaultFilePath); diff --git a/proxy/migrations/deploySchain.ts b/proxy/migrations/deploySchain.ts index a24259f90..9661ee4dd 100644 --- a/proxy/migrations/deploySchain.ts +++ b/proxy/migrations/deploySchain.ts @@ -26,8 +26,7 @@ import { promises as fs } from 'fs'; import { Interface } from "ethers/lib/utils"; import { ethers, artifacts, upgrades } from "hardhat"; import hre from "hardhat"; -import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from '@skalenetwork/upgrade-tools'; +import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin"; import { Contract } from '@ethersproject/contracts'; @@ -57,34 +56,6 @@ export async function getManifestFile(): Promise { return (await Manifest.forNetwork(ethers.provider)).file;; } -export async function getContractFactory(contract: string) { - const { linkReferences } = await artifacts.readArtifact(contract); - if (!Object.keys(linkReferences).length) - return await ethers.getContractFactory(contract); - - const libraryNames = []; - for (const key of Object.keys(linkReferences)) { - const libraryName = Object.keys(linkReferences[key])[0]; - libraryNames.push(libraryName); - } - - const libraries = await deployLibraries(libraryNames); - const libraryArtifacts: {[key: string]: any} = {}; - for (const libraryName of Object.keys(libraries)) { - const { bytecode } = await artifacts.readArtifact(libraryName); - libraryArtifacts[libraryName] = {"address": libraries[libraryName], "bytecodeHash": hashBytecode(bytecode)}; - } - let manifest: any; - try { - manifest = JSON.parse(await fs.readFile(await getManifestFile(), "utf-8")); - Object.assign(libraryArtifacts, manifest.libraries); - } finally { - Object.assign(manifest, {libraries: libraryArtifacts}); - await fs.writeFile(await getManifestFile(), JSON.stringify(manifest, null, 4)); - } - return await getLinkedContractFactory(contract, libraries); -} - export function getProxyMainnet(contractName: string) { const defaultFilePath = "../data/proxyMainnet.json"; const jsonData = require(defaultFilePath); diff --git a/proxy/migrations/deploySkaleManagerComponents.ts b/proxy/migrations/deploySkaleManagerComponents.ts index 668c6dc3f..a1c77533d 100644 --- a/proxy/migrations/deploySkaleManagerComponents.ts +++ b/proxy/migrations/deploySkaleManagerComponents.ts @@ -24,8 +24,7 @@ */ import { promises as fs } from 'fs'; import { ethers, artifacts, web3 } from "hardhat"; -import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; -import { getAbi } from '@skalenetwork/upgrade-tools'; +import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; import { KeyStorageMock } from '../typechain/KeyStorageMock'; import { Wallet } from 'ethers'; @@ -39,34 +38,6 @@ export async function getManifestFile(): Promise { return (await Manifest.forNetwork(ethers.provider)).file;; } -export async function getContractFactory(contract: string) { - const { linkReferences } = await artifacts.readArtifact(contract); - if (!Object.keys(linkReferences).length) - return await ethers.getContractFactory(contract); - - const libraryNames = []; - for (const key of Object.keys(linkReferences)) { - const libraryName = Object.keys(linkReferences[key])[0]; - libraryNames.push(libraryName); - } - - const libraries = await deployLibraries(libraryNames); - const libraryArtifacts: {[key: string]: any} = {}; - for (const libraryName of Object.keys(libraries)) { - const { bytecode } = await artifacts.readArtifact(libraryName); - libraryArtifacts[libraryName] = {"address": libraries[libraryName], "bytecodeHash": hashBytecode(bytecode)}; - } - let manifest: any; - try { - manifest = JSON.parse(await fs.readFile(await getManifestFile(), "utf-8")); - Object.assign(libraryArtifacts, manifest.libraries); - } finally { - Object.assign(manifest, {libraries: libraryArtifacts}); - await fs.writeFile(await getManifestFile(), JSON.stringify(manifest, null, 4)); - } - return await getLinkedContractFactory(contract, libraries); -} - async function main() { const [ owner,] = await ethers.getSigners(); @@ -210,4 +181,4 @@ if (require.main === module) { console.error(error); process.exit(1); }); -} \ No newline at end of file +} diff --git a/proxy/migrations/tools/factory.ts b/proxy/migrations/tools/factory.ts deleted file mode 100644 index 7708a269a..000000000 --- a/proxy/migrations/tools/factory.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ethers, upgrades } from "hardhat"; -import hre from "hardhat"; -import { Artifact } from "hardhat/types"; - -async function getLinkedContractFactory(contractName: string, libraries: any) { - const cArtifact = await hre.artifacts.readArtifact(contractName); - const linkedBytecode = _linkBytecode(cArtifact, libraries); - const ContractFactory = await ethers.getContractFactory(cArtifact.abi, linkedBytecode); - return ContractFactory; -} - -async function deployLibraries(libraryNames: string[]) { - const libraries: any = {}; - for (const libraryName of libraryNames) { - libraries[libraryName] = await _deployLibrary(libraryName); - } - return libraries; -} - -async function _deployLibrary(libraryName: string) { - const Library = await ethers.getContractFactory(libraryName); - const library = await Library.deploy(); - await library.deployed(); - return library.address; -} - -function _linkBytecode(artifact: Artifact, libraries: { [x: string]: any }) { - let bytecode = artifact.bytecode; - for (const [, fileReferences] of Object.entries(artifact.linkReferences)) { - for (const [libName, fixups] of Object.entries(fileReferences)) { - const addr = libraries[libName]; - if (addr === undefined) { - continue; - } - for (const fixup of fixups) { - bytecode = - bytecode.substr(0, 2 + fixup.start * 2) + - addr.substr(2) + - bytecode.substr(2 + (fixup.start + fixup.length) * 2); - } - } - } - return bytecode; -} - -export { - deployLibraries, - getLinkedContractFactory -}; diff --git a/proxy/migrations/transferOwnership.ts b/proxy/migrations/transferOwnership.ts index 5cb8ad2c8..5285cd72a 100644 --- a/proxy/migrations/transferOwnership.ts +++ b/proxy/migrations/transferOwnership.ts @@ -2,7 +2,6 @@ import { contracts, getContractKeyInAbiFile, getManifestFile } from "./deployMai import { ethers, network, upgrades, artifacts } from "hardhat"; import hre from "hardhat"; import { promises as fs } from "fs"; -import { deployLibraries, getLinkedContractFactory } from "./tools/factory"; import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin"; import chalk from "chalk"; import { SafeMock } from "../typechain"; From a925ae27d326cb258c86b7df27c042ce4a3e0a20 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:06:08 +0300 Subject: [PATCH 49/62] Remove duplicate of the gnosis-safe module --- proxy/migrations/submitTransactions.ts | 11 +- proxy/migrations/tools/gnosis-safe.ts | 196 ------------------------- 2 files changed, 3 insertions(+), 204 deletions(-) delete mode 100644 proxy/migrations/tools/gnosis-safe.ts diff --git a/proxy/migrations/submitTransactions.ts b/proxy/migrations/submitTransactions.ts index caeb3096a..eeb77f086 100644 --- a/proxy/migrations/submitTransactions.ts +++ b/proxy/migrations/submitTransactions.ts @@ -1,4 +1,4 @@ -import { createMultiSendTransaction, sendSafeTransaction } from "./tools/gnosis-safe"; +import { createMultiSendTransaction, sendSafeTransaction } from "@skalenetwork/upgrade-tools"; import { ethers } from "hardhat"; import { promises as fs } from "fs"; @@ -15,11 +15,6 @@ async function main() { process.exit(1); } - let isSafeMock: boolean = false; - if (process.env.SAFE_MOCK) { - isSafeMock = true; - } - const safe = process.env.SAFE; let privateKey = process.env.PRIVATE_KEY; if (!privateKey.startsWith("0x")) { @@ -27,7 +22,7 @@ async function main() { } const safeTransactions: string[] = JSON.parse(await fs.readFile(process.env.TRANSACTIONS, "utf-8")); - const safeTx = await createMultiSendTransaction(ethers, safe, privateKey, safeTransactions, isSafeMock); + const safeTx = await createMultiSendTransaction(ethers, safe, privateKey, safeTransactions, ethers.provider.network.chainId); const chainId = (await ethers.provider.getNetwork()).chainId; await sendSafeTransaction(safe, chainId, safeTx); console.log("Done"); @@ -40,4 +35,4 @@ if (require.main === module) { console.error(error); process.exit(1); }); -} \ No newline at end of file +} diff --git a/proxy/migrations/tools/gnosis-safe.ts b/proxy/migrations/tools/gnosis-safe.ts deleted file mode 100644 index 1e5013f79..000000000 --- a/proxy/migrations/tools/gnosis-safe.ts +++ /dev/null @@ -1,196 +0,0 @@ -import axios from "axios"; -import { ethers } from "ethers"; -import * as ethUtil from 'ethereumjs-util'; -import chalk from "chalk"; -import { HardhatEthersHelpers } from "@nomiclabs/hardhat-ethers/types"; - -type Ethers = typeof ethers & HardhatEthersHelpers; - -enum Network { - MAINNET = 1, - RINKEBY = 4, - GOERLI = 5, - GANACHE = 1337, - HARDHAT = 31337, -} - -const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; - -const ADDRESSES = { - multiSend: { - [Network.MAINNET]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", - [Network.RINKEBY]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", - [Network.GOERLI]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", - }, -} - -const URLS = { - safe_transaction: { - [Network.MAINNET]: "https://safe-transaction.mainnet.gnosis.io", - [Network.RINKEBY]: "https://safe-transaction.rinkeby.gnosis.io", - [Network.GOERLI]: "https://safe-transaction.goerli.gnosis.io", - }, - safe_relay: { - [Network.MAINNET]: "https://safe-relay.mainnet.gnosis.io", - [Network.RINKEBY]: "https://safe-relay.rinkeby.gnosis.io", - [Network.GOERLI]: "https://safe-relay.goerli.gnosis.io", - } -} - -function getMultiSendAddress(chainId: number, isSafeMock: boolean = false) { - if (isSafeMock) { - return ethers.constants.AddressZero; - } else if (chainId === Network.MAINNET) { - return ADDRESSES.multiSend[chainId]; - } else if (chainId === Network.RINKEBY) { - return ADDRESSES.multiSend[chainId]; - } else if (chainId === Network.GOERLI) { - return ADDRESSES.multiSend[chainId]; - } else if ([Network.GANACHE, Network.HARDHAT].includes(chainId)) { - return ethers.constants.AddressZero; - } else { - throw Error("Can't get multiSend contract at network with chainId = " + chainId); - } -} - -export function getSafeTransactionUrl(chainId: number) { - if (chainId === Network.MAINNET) { - return URLS.safe_transaction[chainId]; - } else if (chainId === Network.RINKEBY) { - return URLS.safe_transaction[chainId]; - } else if (chainId === Network.GOERLI) { - return URLS.safe_transaction[chainId]; - } else { - throw Error("Can't get safe-transaction url at network with chainId = " + chainId); - } -} - -export function getSafeRelayUrl(chainId: number) { - if (Object.keys(URLS.safe_relay).includes(chainId.toString())) { - return URLS.safe_relay[chainId as keyof typeof URLS.safe_relay]; - } else { - throw Error("Can't get safe-relay url at network with chainId = " + chainId); - } -} - -function concatTransactions(transactions: string[]) { - return "0x" + transactions.map( (transaction) => { - if (transaction.startsWith("0x")) { - return transaction.slice(2); - } else { - return transaction; - } - }).join(""); -} - -export async function createMultiSendTransaction(ethersProvider: Ethers, safeAddress: string, privateKey: string, transactions: string[], isSafeMock: boolean = false) { - const chainId: number = (await ethersProvider.provider.getNetwork()).chainId; - const multiSendAddress = getMultiSendAddress(chainId, isSafeMock); - const multiSendAbi = [{"constant":false,"inputs":[{"internalType":"bytes","name":"transactions","type":"bytes"}],"name":"multiSend","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]; - const multiSend = new ethers.Contract(multiSendAddress, new ethers.utils.Interface(multiSendAbi), ethersProvider.provider); - const safeAbi = [{"constant":true,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum Enum.Operation","name":"operation","type":"uint8"},{"internalType":"uint256","name":"safeTxGas","type":"uint256"},{"internalType":"uint256","name":"baseGas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"address","name":"gasToken","type":"address"},{"internalType":"address","name":"refundReceiver","type":"address"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getTransactionHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"}]; - interface Safe extends ethers.Contract { - getTransactionHash: ( - to: string, - value: number, - data: string, - operation: number, - safeTxGas: number, - baseGas: number, - gasPrice: number, - gasToken: string, - refundReceiver: string, - nonce: number - ) => Promise - } - const safe = new ethers.Contract(safeAddress, new ethers.utils.Interface(safeAbi), ethersProvider.provider) as Safe; - - let nonce = 0; - if (!isSafeMock) { - try { - const nonceResponse = await axios.get(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safeAddress}/`); - nonce = nonceResponse.data.nonce; - } catch (e: any) { - if (!e.toString().startsWith("Error: Can't get safe-transaction url")) { - throw e; - } - } - } - - const tx = { - "to": multiSend.address, - "value": 0, // Value in wei - "data": multiSend.interface.encodeFunctionData("multiSend", [ concatTransactions(transactions) ]), - "operation": 1, // 0 CALL, 1 DELEGATE_CALL - "gasToken": ethers.constants.AddressZero, // Token address (hold by the Safe) to be used as a refund to the sender, if `null` is Ether - "safeTxGas": 0, // Max gas to use in the transaction - "baseGas": 0, // Gas costs not related to the transaction execution (signature check, refund payment...) - "gasPrice": 0, // Gas price used for the refund calculation - "refundReceiver": ethers.constants.AddressZero, // Address of receiver of gas payment (or `null` if tx.origin) - "nonce": nonce, // Nonce of the Safe, transaction cannot be executed until Safe's nonce is not equal to this nonce - } - - const digestHex = await safe.getTransactionHash( - tx.to, - tx.value, - tx.data, - tx.operation, - tx.safeTxGas, - tx.baseGas, - tx.gasPrice, - tx.gasToken, - tx.refundReceiver, - tx.nonce - ); - - const privateKeyBuffer = ethUtil.toBuffer(privateKey); - const { r, s, v } = ethUtil.ecsign(ethUtil.toBuffer(digestHex), privateKeyBuffer); - const signature = ethUtil.toRpcSig(v, r, s).toString(); - - const txToSend = { - ...tx, - "contractTransactionHash": digestHex, // Contract transaction hash calculated from all the field - // Owner of the Safe proposing the transaction. Must match one of the signatures - "sender": ethers.utils.getAddress(ethUtil.bufferToHex(ethUtil.privateToAddress(privateKeyBuffer))), - "signature": signature, // One or more ethereum ECDSA signatures of the `contractTransactionHash` as an hex string - "origin": "Upgrade IMA" // Give more information about the transaction, e.g. "My Custom Safe app" - } - - return txToSend; -} - -export async function sendSafeTransaction(safe: string, chainId: number, safeTx: any) { - try { - console.log("Estimate gas"); - const estimateRequest = (({ - to, - value, - data, - operation, - gasToken - }) => ({ to, value, data, operation, gasToken }))(safeTx); - - try { - const estimateResponse = await axios.post( - `${getSafeRelayUrl(chainId)}/api/v2/safes/${safe}/transactions/estimate/`, - estimateRequest - ); - console.log(chalk.cyan(`Recommend to set gas limit to ${ - parseInt(estimateResponse.data.safeTxGas, 10) + parseInt(estimateResponse.data.baseGas, 10)}`)); - } catch (e: any) { - console.log(chalk.red("Failed to estimate gas")); - console.log(e.toString()); - } - - console.log(chalk.green("Send transaction to gnosis safe")); - await axios.post(`${getSafeTransactionUrl(chainId)}/api/v1/safes/${safe}/transactions/`, safeTx) - } catch (e: any) { - if (e.response) { - console.log(JSON.stringify(e.response.data, null, 4)) - console.log(chalk.red(`Request failed with ${e.response.status} code`)); - } else { - console.log(chalk.red("Request failed with unknown reason")); - } - throw e; - } -} \ No newline at end of file From ee58921c5bb55c1b334372a125b17ce65569bd86 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:06:58 +0300 Subject: [PATCH 50/62] Remove duplicate of the mulstiSend module --- proxy/migrations/tools/multiSend.ts | 48 ----------------------------- 1 file changed, 48 deletions(-) delete mode 100644 proxy/migrations/tools/multiSend.ts diff --git a/proxy/migrations/tools/multiSend.ts b/proxy/migrations/tools/multiSend.ts deleted file mode 100644 index 1d5e2d16a..000000000 --- a/proxy/migrations/tools/multiSend.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { BigNumber } from "ethers"; - -function padWithZeros(value: string, targetLength: number) { - return ("0".repeat(targetLength) + value).slice(-targetLength); -} - -export function encodeTransaction(operation: 0 | 1, to: string, value: BigNumber | number, data: string) { - /// operation as a uint8 with 0 for a call or 1 for a delegatecall (=> 1 byte), - /// to as a address (=> 20 bytes), - /// value as a uint256 (=> 32 bytes), - /// data length as a uint256 (=> 32 bytes), - /// data as bytes. - - let _operation; - if (operation === 0) { - _operation = "00"; - } else if (operation === 1) { - _operation = "01"; - } else { - throw Error(`Operation ${operation} is not a correct value`); - } - - let _to = to; - if (to.startsWith("0x")) { - _to = _to.slice(2); - } - _to = padWithZeros(_to, 20 * 2); - - const _value = padWithZeros(BigNumber.from(value).toHexString().slice(2), 32 * 2); - - let _data = data; - if (data.startsWith("0x")) { - _data = _data.slice(2); - } - if (_data.length % 2 !== 0) { - _data = "0" + _data; - } - - const _dataLength = padWithZeros((_data.length / 2).toString(16), 32 * 2); - - return "0x" + [ - _operation, - _to, - _value, - _dataLength, - _data, - ].join(""); -} \ No newline at end of file From 4343048e166631bd252ad7b95f6b840eeaad3346 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:08:06 +0300 Subject: [PATCH 51/62] Remove duplicate of the verification module --- proxy/migrations/deployMainnet.ts | 3 +-- proxy/migrations/tools/verification.ts | 28 -------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 proxy/migrations/tools/verification.ts diff --git a/proxy/migrations/deployMainnet.ts b/proxy/migrations/deployMainnet.ts index 9cbb3fffd..4c598df2c 100644 --- a/proxy/migrations/deployMainnet.ts +++ b/proxy/migrations/deployMainnet.ts @@ -26,8 +26,7 @@ import { promises as fs } from 'fs'; import { Interface } from "ethers/lib/utils"; import { ethers, upgrades, web3 } from "hardhat"; import { MessageProxyForMainnet, Linker } from "../typechain"; -import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; -import { verifyProxy } from './tools/verification'; +import { getAbi, getContractFactory, verifyProxy } from '@skalenetwork/upgrade-tools'; import { Manifest } from "@openzeppelin/upgrades-core"; import { getVersion } from './tools/version'; diff --git a/proxy/migrations/tools/verification.ts b/proxy/migrations/tools/verification.ts deleted file mode 100644 index 6373c6741..000000000 --- a/proxy/migrations/tools/verification.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ethers, run, network } from "hardhat"; -import chalk from "chalk"; -import { getImplementationAddress } from "@openzeppelin/upgrades-core"; - -export async function verify(contractName: string, contractAddress: string, constructorArguments: object) { - if (![1337, 31337].includes((await ethers.provider.getNetwork()).chainId)) { - for (let retry = 0; retry <= 5; ++retry) { - try { - await run("verify:verify", { - address: contractAddress, - constructorArguments - }); - break; - } catch (e: any) { - if (e.toString().includes("Contract source code already verified")) { - console.log(chalk.grey(`${contractName} is already verified`)); - return; - } - console.log(chalk.red(`Contract ${contractName} was not verified on etherscan`)); - console.log(e.toString()); - } - } - } -} - -export async function verifyProxy(contractName: string, proxyAddress: string, constructorArguments: object) { - await verify(contractName, await getImplementationAddress(network.provider, proxyAddress), constructorArguments); -} \ No newline at end of file From 253d312b159419209b8271668d06be376ecd3f10 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:10:12 +0300 Subject: [PATCH 52/62] Remove duplicate of the version module --- proxy/migrations/deployMainnet.ts | 3 +-- proxy/migrations/deploySchain.ts | 7 +++---- proxy/migrations/generateManifest.ts | 3 +-- proxy/migrations/tools/version.ts | 16 ---------------- 4 files changed, 5 insertions(+), 24 deletions(-) delete mode 100644 proxy/migrations/tools/version.ts diff --git a/proxy/migrations/deployMainnet.ts b/proxy/migrations/deployMainnet.ts index 4c598df2c..7bd13f733 100644 --- a/proxy/migrations/deployMainnet.ts +++ b/proxy/migrations/deployMainnet.ts @@ -26,9 +26,8 @@ import { promises as fs } from 'fs'; import { Interface } from "ethers/lib/utils"; import { ethers, upgrades, web3 } from "hardhat"; import { MessageProxyForMainnet, Linker } from "../typechain"; -import { getAbi, getContractFactory, verifyProxy } from '@skalenetwork/upgrade-tools'; +import { getAbi, getContractFactory, verifyProxy, getVersion } from '@skalenetwork/upgrade-tools'; import { Manifest } from "@openzeppelin/upgrades-core"; -import { getVersion } from './tools/version'; export function getContractKeyInAbiFile(contract: string) { if (contract === "MessageProxyForMainnet") { diff --git a/proxy/migrations/deploySchain.ts b/proxy/migrations/deploySchain.ts index 9661ee4dd..0bdfb8abf 100644 --- a/proxy/migrations/deploySchain.ts +++ b/proxy/migrations/deploySchain.ts @@ -24,10 +24,10 @@ */ import { promises as fs } from 'fs'; import { Interface } from "ethers/lib/utils"; -import { ethers, artifacts, upgrades } from "hardhat"; +import { ethers, upgrades } from "hardhat"; import hre from "hardhat"; -import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; -import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; +import { getAbi, getVersion } from '@skalenetwork/upgrade-tools'; +import { Manifest } from "@openzeppelin/upgrades-core"; import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin"; import { Contract } from '@ethersproject/contracts'; import { @@ -43,7 +43,6 @@ import { MessageProxyForSchainWithoutSignature } from '../typechain'; import { TokenManagerERC1155 } from '../typechain/TokenManagerERC1155'; -import { getVersion } from './tools/version'; export function getContractKeyInAbiFile(contract: string): string { if (contract === "MessageProxyForSchain") { diff --git a/proxy/migrations/generateManifest.ts b/proxy/migrations/generateManifest.ts index 6b1cc1602..54f28946d 100644 --- a/proxy/migrations/generateManifest.ts +++ b/proxy/migrations/generateManifest.ts @@ -1,7 +1,6 @@ import { ethers } from "hardhat"; import { contracts, getContractKeyInAbiFile } from "./deploySchain"; import { promises as fs } from "fs"; -import { constants } from 'fs'; import { getVersion, getStorageLayout, @@ -12,7 +11,7 @@ import { StorageLayout, isCurrentValidationData } from "@openzeppelin/upgrades-core"; -import { getVersion as version } from "./tools/version"; +import { getVersion as version } from "@skalenetwork/upgrade-tools"; import { ValidationsCacheNotFound, ValidationsCacheOutdated } from "@openzeppelin/hardhat-upgrades/dist/utils"; type Addresses = { diff --git a/proxy/migrations/tools/version.ts b/proxy/migrations/tools/version.ts deleted file mode 100644 index 642345c7d..000000000 --- a/proxy/migrations/tools/version.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { promises as fs } from 'fs'; -import { exec as asyncExec } from "child_process"; -import util from 'util'; -const exec = util.promisify(asyncExec); - -export async function getVersion() { - if (process.env.VERSION) { - return process.env.VERSION; - } - try { - const tag = (await exec("git describe --tags")).stdout.trim(); - return tag; - } catch { - return (await fs.readFile("../VERSION", "utf-8")).trim(); - } -} From 2ca6c510ea102ddd00e8f9d3cbcbe812bd9e6855 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:11:00 +0300 Subject: [PATCH 53/62] Remove unused imports --- proxy/migrations/deploySkaleManagerComponents.ts | 4 ++-- proxy/migrations/transferOwnership.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/proxy/migrations/deploySkaleManagerComponents.ts b/proxy/migrations/deploySkaleManagerComponents.ts index a1c77533d..5d070552b 100644 --- a/proxy/migrations/deploySkaleManagerComponents.ts +++ b/proxy/migrations/deploySkaleManagerComponents.ts @@ -23,9 +23,9 @@ * @copyright SKALE Labs 2021-Present */ import { promises as fs } from 'fs'; -import { ethers, artifacts, web3 } from "hardhat"; +import { ethers, web3 } from "hardhat"; import { getAbi, getContractFactory } from '@skalenetwork/upgrade-tools'; -import { Manifest, hashBytecode } from "@openzeppelin/upgrades-core"; +import { Manifest } from "@openzeppelin/upgrades-core"; import { KeyStorageMock } from '../typechain/KeyStorageMock'; import { Wallet } from 'ethers'; import { getPublicKey } from '../test/utils/helper'; diff --git a/proxy/migrations/transferOwnership.ts b/proxy/migrations/transferOwnership.ts index 5285cd72a..c7010cb2d 100644 --- a/proxy/migrations/transferOwnership.ts +++ b/proxy/migrations/transferOwnership.ts @@ -1,5 +1,5 @@ -import { contracts, getContractKeyInAbiFile, getManifestFile } from "./deployMainnet"; -import { ethers, network, upgrades, artifacts } from "hardhat"; +import { contracts, getContractKeyInAbiFile } from "./deployMainnet"; +import { ethers } from "hardhat"; import hre from "hardhat"; import { promises as fs } from "fs"; import { getManifestAdmin } from "@openzeppelin/hardhat-upgrades/dist/admin"; From 52d1d54344807736b4e4f5cd16c0bc7b70583e8b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 14:13:02 +0300 Subject: [PATCH 54/62] Bump major version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index dc1e644a1..227cea215 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.0 +2.0.0 From 309b3e2aaabf354d56fef289d841e90400c871db Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 15:37:37 +0300 Subject: [PATCH 55/62] Remove coping of the versions module --- proxy/scripts/test_upgrade.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/scripts/test_upgrade.sh b/proxy/scripts/test_upgrade.sh index b6cbbd30b..71c183143 100755 --- a/proxy/scripts/test_upgrade.sh +++ b/proxy/scripts/test_upgrade.sh @@ -34,7 +34,6 @@ VERSION="$DEPLOYED_VERSION" npx hardhat run migrations/deployMainnet.ts --networ CHAIN_NAME_SCHAIN="Test" VERSION="$DEPLOYED_VERSION" npx hardhat run migrations/deploySchain.ts --network localhost cp "$GITHUB_WORKSPACE/proxy/migrations/generateManifest.ts" ./migrations/generateManifest.ts cp "$GITHUB_WORKSPACE/proxy/migrations/changeManifest.ts" ./migrations/changeManifest.ts -cp "$GITHUB_WORKSPACE/proxy/migrations/tools/version.ts" ./migrations/tools/version.ts ABI_FILENAME_SCHAIN="proxySchain_Test.json" ABI="data/$ABI_FILENAME_SCHAIN" \ From d5e6efba3ce4106c32beb9876531fb831125ff67 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 16:00:23 +0300 Subject: [PATCH 56/62] Remove unnecessary scripts --- proxy/scripts/test_upgrade.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/proxy/scripts/test_upgrade.sh b/proxy/scripts/test_upgrade.sh index 71c183143..3711481ce 100755 --- a/proxy/scripts/test_upgrade.sh +++ b/proxy/scripts/test_upgrade.sh @@ -32,8 +32,6 @@ PRIVATE_KEY_FOR_SCHAIN=$(cat "$ACCOUNTS_FILENAME" | jq -r '.private_keys | to_en CHAIN_NAME_SCHAIN="Test" VERSION="$DEPLOYED_VERSION" PRIVATE_KEY_FOR_ETHEREUM="$PRIVATE_KEY_FOR_ETHEREUM" PRIVATE_KEY_FOR_SCHAIN="$PRIVATE_KEY_FOR_SCHAIN" npx hardhat run migrations/deploySkaleManagerComponents.ts --network localhost VERSION="$DEPLOYED_VERSION" npx hardhat run migrations/deployMainnet.ts --network localhost CHAIN_NAME_SCHAIN="Test" VERSION="$DEPLOYED_VERSION" npx hardhat run migrations/deploySchain.ts --network localhost -cp "$GITHUB_WORKSPACE/proxy/migrations/generateManifest.ts" ./migrations/generateManifest.ts -cp "$GITHUB_WORKSPACE/proxy/migrations/changeManifest.ts" ./migrations/changeManifest.ts ABI_FILENAME_SCHAIN="proxySchain_Test.json" ABI="data/$ABI_FILENAME_SCHAIN" \ From 91cda2716f3f6a9cbe28b38988e84700265f7c0b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 16:34:24 +0300 Subject: [PATCH 57/62] Read a version from VERSION file --- proxy/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/package.json b/proxy/package.json index 3fa33b5be..2c3cb5ac5 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -7,8 +7,8 @@ "compile": "npx hardhat compile", "cleanCompile": "npx hardhat clean && yarn compile", "deploy-to-both-chains": "yarn deploy-to-mainnet && yarn deploy-to-schain", - "deploy-to-mainnet": "npx hardhat run migrations/deployMainnet.ts --network mainnet", - "deploy-to-schain": "npx hardhat run migrations/deploySchain.ts --network schain", + "deploy-to-mainnet": "VERSION=$(cat ../VERSION) npx hardhat run migrations/deployMainnet.ts --network mainnet", + "deploy-to-schain": "VERSION=$(cat ../VERSION) npx hardhat run migrations/deploySchain.ts --network schain", "deploy-skale-manager-components": "npx hardhat run migrations/deploySkaleManagerComponents.ts --network mainnet", "lint": "npx solhint \"contracts/**/*.sol\"", "prepare": "yarn cleanCompile", From efdf8d016e7b0e3634a4abee2f4ce13d0d862fbb Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 17:03:54 +0300 Subject: [PATCH 58/62] Add double quote --- proxy/scripts/magic_upgrade.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/proxy/scripts/magic_upgrade.sh b/proxy/scripts/magic_upgrade.sh index d5348cc2d..c56fa379c 100755 --- a/proxy/scripts/magic_upgrade.sh +++ b/proxy/scripts/magic_upgrade.sh @@ -25,22 +25,22 @@ fi IMA_RELEASES_URL="https://github.com/skalenetwork/IMA/releases/download/" cd data/ -rm -f ima-$DEPLOYED_VERSION-predeployed-abi.json -wget $IMA_RELEASES_URL/$DEPLOYED_VERSION/ima-$DEPLOYED_VERSION-predeployed-abi.json +rm -f "ima-$DEPLOYED_VERSION-predeployed-abi.json" +wget "$IMA_RELEASES_URL/$DEPLOYED_VERSION/ima-$DEPLOYED_VERSION-predeployed-abi.json" cd ../scripts/ -wget $IMA_RELEASES_URL/$DEPLOYED_VERSION/ima-schain-$DEPLOYED_VERSION-manifest.json -python3 updateManifest.py ima-schain-$DEPLOYED_VERSION-manifest.json -mv ima-schain-$DEPLOYED_VERSION-manifest.json ../.openzeppelin/unknown-$SCHAIN_ID.json +wget "$IMA_RELEASES_URL/$DEPLOYED_VERSION/ima-schain-$DEPLOYED_VERSION-manifest.json" +python3 updateManifest.py "ima-schain-$DEPLOYED_VERSION-manifest.json" +mv "ima-schain-$DEPLOYED_VERSION-manifest.json" "../.openzeppelin/unknown-$SCHAIN_ID.json" cd .. git clone https://github.com/skalenetwork/skale-network.git MAINNET_STABLE_IMA_VERSION=$(ls skale-network/releases/mainnet/IMA/ | sort -r | head -n 1) -cp skale-network/releases/mainnet/IMA/$MAINNET_STABLE_IMA_VERSION/mainnet/abi.json data/ima-$MAINNET_STABLE_IMA_VERSION-mainnet-abi.json +cp "skale-network/releases/mainnet/IMA/$MAINNET_STABLE_IMA_VERSION/mainnet/abi.json" "data/ima-$MAINNET_STABLE_IMA_VERSION-mainnet-abi.json" rm -r --interactive=never skale-network/ if [[ $MAINNET_CHAIN_ID != "1" ]]; then if [[ $MESSAGE_PROXY_MAINNET_ADDRESS ]]; then - sed -i '2s/.*/ "message_proxy_mainnet_address": "'"$MESSAGE_PROXY_MAINNET_ADDRESS"'",/' data/ima-$MAINNET_STABLE_IMA_VERSION-mainnet-abi.json + sed -i '2s/.*/ "message_proxy_mainnet_address": "'"$MESSAGE_PROXY_MAINNET_ADDRESS"'",/' "data/ima-$MAINNET_STABLE_IMA_VERSION-mainnet-abi.json" else echo "Set MESSAGE_PROXY_MAINNET_ADDRESS" exit 1 From 0f21f9e7d8e59ca80936aac4fa0952cf5f6e7ee2 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 17:43:01 +0300 Subject: [PATCH 59/62] Rename the file --- npms/skale-observer/observer.mjs | 1 - npms/skale-owasp/owaspUtils.mjs | 1 - proxy/scripts/{upgrade_instruction.md => upgrade-instruction.md} | 0 3 files changed, 2 deletions(-) rename proxy/scripts/{upgrade_instruction.md => upgrade-instruction.md} (100%) diff --git a/npms/skale-observer/observer.mjs b/npms/skale-observer/observer.mjs index a914f82ab..243024da0 100644 --- a/npms/skale-observer/observer.mjs +++ b/npms/skale-observer/observer.mjs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: AGPL-3.0-only /** diff --git a/npms/skale-owasp/owaspUtils.mjs b/npms/skale-owasp/owaspUtils.mjs index 8ceb80536..7531f04ca 100644 --- a/npms/skale-owasp/owaspUtils.mjs +++ b/npms/skale-owasp/owaspUtils.mjs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: AGPL-3.0-only /** diff --git a/proxy/scripts/upgrade_instruction.md b/proxy/scripts/upgrade-instruction.md similarity index 100% rename from proxy/scripts/upgrade_instruction.md rename to proxy/scripts/upgrade-instruction.md From 9420cf33baf3a4b068ea144e1089f6d778603c21 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 17:43:50 +0300 Subject: [PATCH 60/62] Fix markdown --- proxy/scripts/upgrade-instruction.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/proxy/scripts/upgrade-instruction.md b/proxy/scripts/upgrade-instruction.md index 42269c3fe..9ae80e2ee 100644 --- a/proxy/scripts/upgrade-instruction.md +++ b/proxy/scripts/upgrade-instruction.md @@ -1,36 +1,51 @@ # Step-by-step guide for upgrading IMA contracts on Schain side ## Install project + Git clone and run yarn install in the root of the project. + ```bash git clone https://github.com/skalenetwork/IMA.git && cd IMA/ && yarn install ``` + ## Prepare environment + Create `.env` file by path `IMA/proxy/`. Now you need to create new account. You can generate it in Metamask. Next export private key and put it in `.env` as `PRIVATE_KEY` without 0x. Also put endpoint of your chain as `ENDPOINT` to the `.env`. Also you need to add this account to your Gnosis Wallet as one of the Safe owners. Open Gnosis app, go to "Settings", click "Add new owner" and then sign transaction. Example of `.env` file: + ```bash ENDPOINT="http://127.0.0.1:8545" PRIVATE_KEY="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ``` + ## Grant role + Next you need to grant `DEPLOYER_ROLE` for account that we have created in previous step for being able to deploy new contracts on chain. One of the easiest ways to do this would be to use the Blockscout interface. First you need to find the `ConfigController` contract, its address is `0xD200200000000000000000000000000000000d2`, click `Write Proxy` connect the wallet on which there is sFUEL, find the `addToWhitelist` function and enter the address of the new account that you generated in the metamask, then click Write and confirm the transaction in the metamask. + ## Get sFUEL + Now you need to get some sFUEL on your new account. To do this, you need to use a contract that distributes sFUEL - `Etherbase`. Also you can get sFUEL from faucet available on your chain - look on [sFUEL Station](https://sfuel.skale.network). As in the previous step, you can use Blockscout or transfer a sufficient amount of sFUEL to the wallet you created earlier. In order to do this in Blockscout, you need to go to `0xd2bA3e0000000000000000000000000000000000` and find the `partiallyRetrieve` function, there will be two fields. In the "receiver" field, you need to enter the sFUEL recipient, that is, the wallet address that you generated earlier. In the "amount" field, enter the amount of sFUEL in Wei. It is important to note that only the owner of the chain can perform this transaction. + ## Switch to desired version + Before running the upgrade script, you need to switch to the desired version. The example below allows you to switch to the latest stable version. + ```bash git checkout stable && yarn install ``` + ## Run upgrade script + * `DEPLOYED_VERSION` - current version of your IMA contracts. Example: `DEPLOYED_VERSION="1.1.3-beta.0"` * `SCHAIN_ID` - chainId of SKALE chain. * `SCHAIN_NAME` - name of SKALE chain. * `SAFE_ADDRESS` - address of gnosis safe wallet on mainnet. * `MAINNET_CHAIN_ID` - chainId, use 1 for Ethereum mainnet or 5 for Goerli. -* `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. -* `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. +* `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. +* `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. * `VERSION` - version to upgrade to. Optional parametr. Leave this parameter empty if you are not sure which version you are updating to, the script will automatically take the correct version. Run the upgrade script in `IMA/proxy/` with the above parameters. + ```bash ./scripts/magic_upgrade.sh ``` From c1e0d9816484f6a3cda9650744c0d7e932f7f2d4 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 18:23:00 +0300 Subject: [PATCH 61/62] Fix indent --- npms/skale-observer/observerWorker.mjs | 1 - proxy/scripts/upgrade-instruction.md | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/npms/skale-observer/observerWorker.mjs b/npms/skale-observer/observerWorker.mjs index 520814c4d..8e13d6235 100644 --- a/npms/skale-observer/observerWorker.mjs +++ b/npms/skale-observer/observerWorker.mjs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: AGPL-3.0-only /** diff --git a/proxy/scripts/upgrade-instruction.md b/proxy/scripts/upgrade-instruction.md index 9ae80e2ee..7c5c80e43 100644 --- a/proxy/scripts/upgrade-instruction.md +++ b/proxy/scripts/upgrade-instruction.md @@ -35,14 +35,14 @@ git checkout stable && yarn install ## Run upgrade script -* `DEPLOYED_VERSION` - current version of your IMA contracts. Example: `DEPLOYED_VERSION="1.1.3-beta.0"` -* `SCHAIN_ID` - chainId of SKALE chain. -* `SCHAIN_NAME` - name of SKALE chain. -* `SAFE_ADDRESS` - address of gnosis safe wallet on mainnet. -* `MAINNET_CHAIN_ID` - chainId, use 1 for Ethereum mainnet or 5 for Goerli. -* `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. -* `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. -* `VERSION` - version to upgrade to. Optional parametr. Leave this parameter empty if you are not sure which version you are updating to, the script will automatically take the correct version. + * `DEPLOYED_VERSION` - current version of your IMA contracts. Example: `DEPLOYED_VERSION="1.1.3-beta.0"` + * `SCHAIN_ID` - chainId of SKALE chain. + * `SCHAIN_NAME` - name of SKALE chain. + * `SAFE_ADDRESS` - address of gnosis safe wallet on mainnet. + * `MAINNET_CHAIN_ID` - chainId, use 1 for Ethereum mainnet or 5 for Goerli. + * `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. + * `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. + * `VERSION` - version to upgrade to. Optional parametr. Leave this parameter empty if you are not sure which version you are updating to, the script will automatically take the correct version. Run the upgrade script in `IMA/proxy/` with the above parameters. From fc8a0a2b496f3c34c589979831e591dca649ef45 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 9 Jun 2023 19:05:19 +0300 Subject: [PATCH 62/62] Add a space before an item --- proxy/scripts/upgrade-instruction.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/proxy/scripts/upgrade-instruction.md b/proxy/scripts/upgrade-instruction.md index 7c5c80e43..4c9bf8929 100644 --- a/proxy/scripts/upgrade-instruction.md +++ b/proxy/scripts/upgrade-instruction.md @@ -35,14 +35,14 @@ git checkout stable && yarn install ## Run upgrade script - * `DEPLOYED_VERSION` - current version of your IMA contracts. Example: `DEPLOYED_VERSION="1.1.3-beta.0"` - * `SCHAIN_ID` - chainId of SKALE chain. - * `SCHAIN_NAME` - name of SKALE chain. - * `SAFE_ADDRESS` - address of gnosis safe wallet on mainnet. - * `MAINNET_CHAIN_ID` - chainId, use 1 for Ethereum mainnet or 5 for Goerli. - * `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. - * `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. - * `VERSION` - version to upgrade to. Optional parametr. Leave this parameter empty if you are not sure which version you are updating to, the script will automatically take the correct version. +* `DEPLOYED_VERSION` - current version of your IMA contracts. Example: `DEPLOYED_VERSION="1.1.3-beta.0"` +* `SCHAIN_ID` - chainId of SKALE chain. +* `SCHAIN_NAME` - name of SKALE chain. +* `SAFE_ADDRESS` - address of gnosis safe wallet on mainnet. +* `MAINNET_CHAIN_ID` - chainId, use 1 for Ethereum mainnet or 5 for Goerli. +* `MESSAGE_PROXY_MAINNET_ADDRESS` - address of MessageProxyForMainnet contract. Optional parameter. Required only if you have deployed IMA on Goerli Testnet. +* `ALLOW_NOT_ATOMIC_UPGRADE` - means that the transaction on the chain will not be executed atomically. That is, for example, if you send two transactions, there is a non-zero probability that they will be written to different blocks. Enter "OK" if you agree. +* `VERSION` - version to upgrade to. Optional parametr. Leave this parameter empty if you are not sure which version you are updating to, the script will automatically take the correct version. Run the upgrade script in `IMA/proxy/` with the above parameters.