019d5666-7210-72a7-9067-e58ac94c06d2
Open this run to answer one question: is this real attacker-relevant behavior with real impact, or just normal contract plumbing?
| ID | Type | Status | Attempts | Heartbeat |
|---|---|---|---|---|
| 42855 | artifact.fetch | complete | 1 / 3 | 1 week ago |
| 42856 | proxy.resolve | complete | 1 / 3 | 1 week ago |
| 42857 | tool.cast_disasm | complete | 1 / 3 | 1 week ago |
| 42858 | analysis.bundle | complete | 1 / 3 | 1 week ago |
| 42859 | capability.graph | complete | 1 / 3 | 1 week ago |
| 42860 | detector.run | complete | 1 / 3 | 1 week ago |
| 42861 | validation.fork | complete | 1 / 3 | 1 week ago |
| 42967 | report.consolidate | complete | 1 / 6 | 1 week ago |
| 42968 | tool.slither | failed | 2 / 2 | 1 week ago |
{
"method": "etherscan+onchain",
"status": "confirmed",
"etherscan_hint": {
"source": "etherscan",
"etherscan": {
"proxy_flag": true,
"implementation": "0x29353f77c6b0d3772d73e708cc8e1fca08c80c11"
}
},
"implementation": "0x29353f77c6b0d3772d73e708cc8e1fca08c80c11",
"onchain_method": "eip1967"
}
Traceback (most recent call last):
File "/var/www/tripwire/worker/worker.py", line 198, in main
payload = dispatch_job(job_type, job_id, job_meta, run_data, config, laravel_client)
File "/var/www/tripwire/worker/worker.py", line 114, in dispatch_job
return slither_run.run(job_id, job_meta, run_data, config, log, laravel_client)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/tripwire/worker/jobs/slither_run.py", line 1084, in run
stdout_text, stderr_text, result_json = _run_slither(
~~~~~~~~~~~~^
workspace,
^^^^^^^^^^
...<4 lines>...
target_path=target_path,
^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/var/www/tripwire/worker/jobs/slither_run.py", line 958, in _run_slither
raise RuntimeError(f"slither failed (exit {result.returncode}): {stderr_text or stdout_text}")
RuntimeError: slither failed (exit 1): 'forge clean' running (wd: /tmp/slither-1ab33d37)
'forge config --json' running
'forge build --build-info --skip ./test/** ./script/** --force' running (wd: /tmp/slither-1ab33d37)
'forge' returned non-zero exit code 1
Error: Encountered invalid solc version in lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol: No solc version exists that matches the version requirement: ^0.8.22
stderr: Encountered invalid solc version in lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol: No solc version exists that matches the version requirement: ^0.8.22
Traceback (most recent call last):
File "/var/www/tripwire/.venv/bin/slither", line 10, in <module>
sys.exit(main())
~~~~^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 776, in main
main_impl(all_detector_classes=detectors, all_printer_classes=printers)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 882, in main_impl
) = process_all(filename, args, detector_classes, printer_classes)
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/slither/__main__.py", line 96, in process_all
compilations = compile_all(target, **vars(args))
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 722, in compile_all
compilations.append(CryticCompile(target, **kwargs))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 211, in __init__
self._compile(**kwargs)
~~~~~~~~~~~~~^^^^^^^^^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/crytic_compile.py", line 633, in _compile
self._platform.compile(self, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/foundry.py", line 102, in compile
hardhat_like_parsing(
~~~~~~~~~~~~~~~~~~~~^
crytic_compile, str(self._target), build_directory, str(self._project_root)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/var/www/tripwire/.venv/lib/python3.13/site-packages/crytic_compile/platform/hardhat.py", line 52, in hardhat_like_parsing
raise InvalidCompilation(txt)
crytic_compile.platform.exceptions.InvalidCompilation: Compilation failed. Can you run build command?
/tmp/slither-1ab33d37/out/build-info is not a directory.
{"no_findings":false,"summary":"Fee-on-transfer ERC20s are accounted at the requested amount instead of the amount actually received, which can overmint wrapped balances and drain bridge collateral.","findings":[{"severity":"high","category":"other","title":"Fee-on-transfer ERC20s can overmint bridge balances and drain pooled collateral","exploit_scenario":"An attacker bridges a deflationary ERC20 that burns or taxes 10% on transfer. `DepositBoxERC20.depositERC20Direct` records and forwards `amount=100` to the destination chain, then calls `safeTransferFrom` once without checking how many tokens actually arrived. Only 90 tokens reach the box, but 100 wrapped tokens are minted on the schain. The attacker can later exit the full 100 back to mainnet (or another schain), extracting the 10-token shortfall from liquidity supplied by honest users. The same invariant break exists in schain-to-schain transfers of main-chain ERC20s, where `TokenManagerERC20` escrows `amount` before verifying the real balance delta.","recommendation":"Measure balance deltas before and after each ERC20 transfer and use the actual received amount for `transferredAmount` accounting and for the bridged message payload. Reject tokens whose received amount is smaller than the requested amount if exact-amount semantics are required.","evidence":"`DepositBoxERC20.depositERC20Direct` builds the outgoing message and increments `transferredAmount` using the caller-supplied `amount`, then performs a single `safeTransferFrom` without comparing pre/post balances. `TokenManagerERC20._exit` mirrors this pattern for schain-to-schain escrow of main-chain tokens by saving `amount` before `transferFrom` and never validating the received balance.","locations":["contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:691","contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:704","contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:705","contracts/schain/TokenManagers/TokenManagerERC20.sol:340","contracts/schain/TokenManagers/TokenManagerERC20.sol:348","contracts/schain/TokenManagers/TokenManagerERC20.sol:350"]}]}
unction mint(address account, uint256 value) external;
}
================================================================================
FILE: @skalenetwork/ima-interfaces/schain/tokens/IERC721OnChain.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* IERC721OnChain - 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.8.19 <0.9.0;
interface IERC721OnChain {
function setTokenURI(uint256 tokenId, string calldata tokenUri) external returns (bool);
function mint(address account, uint256 tokenId) external;
}
================================================================================
FILE: @skalenetwork/ima-interfaces/schain/tokens/IEthErc20.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* IEthErc20 - 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.8.19 <0.9.0;
interface IEthErc20 {
function mint(address account, uint256 amount) external;
function forceBurn(address account, uint256 amount) external;
function initialize(address tokenManagerEthAddress) external;
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/IContractManager.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
IContractManager.sol - SKALE Manager Interfaces
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaeiv
SKALE Manager Interfaces 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 Manager Interfaces 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 Manager Interfaces. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
interface IContractManager {
/**
* @dev Emitted when contract is upgraded.
*/
event ContractUpgraded(string contractsName, address contractsAddress);
function initialize() external;
function setContractsAddress(string calldata contractsName, address newContractsAddress) external;
function contracts(bytes32 nameHash) external view returns (address);
function getDelegationPeriodManager() external view returns (address);
function getBounty() external view returns (address);
function getValidatorService() external view returns (address);
function getTimeHelpers() external view returns (address);
function getConstantsHolder() external view returns (address);
function getSkaleToken() external view returns (address);
function getTokenState() external view returns (address);
function getPunisher() external view returns (address);
function getContract(string calldata name) external view returns (address);
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/INodes.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
INodes.sol - SKALE Manager
Copyright (C) 2018-Present SKALE Labs
@author Artem Payvin
SKALE Manager 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 Manager 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 Manager. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
import "./utils/IRandom.sol";
interface INodes {
// All Nodes states
enum NodeStatus {Active, Leaving, Left, In_Maintenance}
struct Node {
string name;
bytes4 ip;
bytes4 publicIP;
uint16 port;
bytes32[2] publicKey;
uint startBlock;
uint lastRewardDate;
uint finishTime;
NodeStatus status;
uint validatorId;
}
// struct to note which Nodes and which number of Nodes owned by user
struct CreatedNodes {
mapping (uint => bool) isNodeExist;
uint numberOfNodes;
}
struct SpaceManaging {
uint8 freeSpace;
uint indexInSpaceMap;
}
struct NodeCreationParams {
string name;
bytes4 ip;
bytes4 publicIp;
uint16 port;
bytes32[2] publicKey;
uint16 nonce;
string domainName;
}
/**
* @dev Emitted when a node is created.
*/
event NodeCreated(
uint nodeIndex,
address owner,
string name,
bytes4 ip,
bytes4 publicIP,
uint16 port,
uint16 nonce,
string domainName
);
/**
* @dev Emitted when a node completes a network exit.
*/
event ExitCompleted(
uint nodeIndex
);
/**
* @dev Emitted when a node begins to exit from the network.
*/
event ExitInitialized(
uint nodeIndex,
uint startLeavingPeriod
);
/**
* @dev Emitted when a node set to in compliant or compliant.
*/
event IncompliantNode(
uint indexed nodeIndex,
bool status
);
/**
* @dev Emitted when a node set to in maintenance or from in maintenance.
*/
event MaintenanceNode(
uint indexed nodeIndex,
bool status
);
/**
* @dev Emitted when a node status changed.
*/
event IPChanged(
uint indexed nodeIndex,
bytes4 previousIP,
bytes4 newIP
);
function removeSpaceFromNode(uint nodeIndex, uint8 space) external returns (bool);
function addSpaceToNode(uint nodeIndex, uint8 space) external;
function changeNodeLastRewardDate(uint nodeIndex) external;
function changeNodeFinishTime(uint nodeIndex, uint time) external;
function createNode(address from, NodeCreationParams calldata params) external;
function initExit(uint nodeIndex) external;
function completeExit(uint nodeIndex) external returns (bool);
function deleteNodeForValidator(uint validatorId, uint nodeIndex) external;
function checkPossibilityCreatingNode(address nodeAddress) external;
function checkPossibilityToMaintainNode(uint validatorId, uint nodeIndex) external returns (bool);
function setNodeInMaintenance(uint nodeIndex) external;
function removeNodeFromInMaintenance(uint nodeIndex) external;
function setNodeIncompliant(uint nodeIndex) external;
function setNodeCompliant(uint nodeIndex) external;
function setDomainName(uint nodeIndex, string memory domainName) external;
function makeNodeVisible(uint nodeIndex) external;
function makeNodeInvisible(uint nodeIndex) external;
function changeIP(uint nodeIndex, bytes4 newIP, bytes4 newPublicIP) external;
function numberOfActiveNodes() external view returns (uint);
function incompliant(uint nodeIndex) external view returns (bool);
function getRandomNodeWithFreeSpace(
uint8 freeSpace,
IRandom.RandomGenerator memory randomGenerator
)
external
view
returns (uint);
function isTimeForReward(uint nodeIndex) external view returns (bool);
function getNodeIP(uint nodeIndex) external view returns (bytes4);
function getNodeDomainName(uint nodeIndex) external view returns (string memory);
function getNodePort(uint nodeIndex) external view returns (uint16);
function getNodePublicKey(uint nodeIndex) external view returns (bytes32[2] memory);
function getNodeAddress(uint nodeIndex) external view returns (address);
function getNodeFinishTime(uint nodeIndex) external view returns (uint);
function isNodeLeft(uint nodeIndex) external view returns (bool);
function isNodeInMaintenance(uint nodeIndex) external view returns (bool);
function getNodeLastRewardDate(uint nodeIndex) external view returns (uint);
function getNodeNextRewardDate(uint nodeIndex) external view returns (uint);
function getNumberOfNodes() external view returns (uint);
function getNumberOnlineNodes() external view returns (uint);
function getActiveNodeIds() external view returns (uint[] memory activeNodeIds);
function getNodeStatus(uint nodeIndex) external view returns (NodeStatus);
function getValidatorNodeIndexes(uint validatorId) external view returns (uint[] memory);
function countNodesWithFreeSpace(uint8 freeSpace) external view returns (uint count);
function getValidatorId(uint nodeIndex) external view returns (uint);
function isNodeExist(address from, uint nodeIndex) external view returns (bool);
function isNodeActive(uint nodeIndex) external view returns (bool);
function isNodeLeaving(uint nodeIndex) external view returns (bool);
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/ISchains.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
ISchains.sol - SKALE Manager Interfaces
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaeiv
SKALE Manager Interfaces 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 Manager Interfaces 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 Manager Interfaces. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
interface ISchains {
struct SchainOption {
string name;
bytes value;
}
/**
* @dev Emitted when an schain is created.
*/
event SchainCreated(
string name,
address owner,
uint partOfNode,
uint lifetime,
uint numberOfNodes,
uint deposit,
uint16 nonce,
bytes32 schainHash
);
/**
* @dev Emitted when an schain is deleted.
*/
event SchainDeleted(
address owner,
string name,
bytes32 indexed schainHash
);
/**
* @dev Emitted when a node in an schain is rotated.
*/
event NodeRotated(
bytes32 schainHash,
uint oldNode,
uint newNode
);
/**
* @dev Emitted when a node is added to an schain.
*/
event NodeAdded(
bytes32 schainHash,
uint newNode
);
/**
* @dev Emitted when a group of nodes is created for an schain.
*/
event SchainNodes(
string name,
bytes32 schainHash,
uint[] nodesInGroup
);
function addSchain(address from, uint deposit, bytes calldata data) external;
function addSchainByFoundation(
uint lifetime,
uint8 typeOfSchain,
uint16 nonce,
string calldata name,
address schainOwner,
address schainOriginator,
SchainOption[] calldata options
)
external
payable;
function deleteSchain(address from, string calldata name) external;
function deleteSchainByRoot(string calldata name) external;
function restartSchainCreation(string calldata name) external;
function verifySchainSignature(
uint256 signA,
uint256 signB,
bytes32 hash,
uint256 counter,
uint256 hashA,
uint256 hashB,
string calldata schainName
)
external
view
returns (bool);
function getSchainPrice(uint typeOfSchain, uint lifetime) external view returns (uint);
function getOption(bytes32 schainHash, string calldata optionName) external view returns (bytes memory);
function getOptions(bytes32 schainHash) external view returns (SchainOption[] memory);
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/ISchainsInternal.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
ISchainsInternal - SKALE Manager Interfaces
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaeiv
SKALE Manager Interfaces 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 Manager Interfaces 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 Manager Interfaces. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
import "./INodes.sol";
interface ISchainsInternal {
struct Schain {
string name;
address owner;
uint indexInOwnerList;
uint8 partOfNode;
uint lifetime;
uint startDate;
uint startBlock;
uint deposit;
uint64 index;
uint generation;
address originator;
}
struct SchainType {
uint8 partOfNode;
uint numberOfNodes;
}
/**
* @dev Emitted when schain type added.
*/
event SchainTypeAdded(uint indexed schainType, uint partOfNode, uint numberOfNodes);
/**
* @dev Emitted when schain type removed.
*/
event SchainTypeRemoved(uint indexed schainType);
function initializeSchain(
string calldata name,
address from,
address originator,
uint lifetime,
uint deposit) external;
function createGroupForSchain(
bytes32 schainHash,
uint numberOfNodes,
uint8 partOfNode
)
external
returns (uint[] memory);
function changeLifetime(bytes32 schainHash, uint lifetime, uint deposit) external;
function removeSchain(bytes32 schainHash, address from) external;
function removeNodeFromSchain(uint nodeIndex, bytes32 schainHash) external;
function deleteGroup(bytes32 schainHash) external;
function setException(bytes32 schainHash, uint nodeIndex) external;
function setNodeInGroup(bytes32 schainHash, uint nodeIndex) external;
function removeHolesForSchain(bytes32 schainHash) external;
function addSchainType(uint8 partOfNode, uint numberOfNodes) external;
function removeSchainType(uint typeOfSchain) external;
function setNumberOfSchainTypes(uint newNumberOfSchainTypes) external;
function removeNodeFromAllExceptionSchains(uint nodeIndex) external;
function removeAllNodesFromSchainExceptions(bytes32 schainHash) external;
function makeSchainNodesInvisible(bytes32 schainHash) external;
function makeSchainNodesVisible(bytes32 schainHash) external;
function newGeneration() external;
function addSchainForNode(INodes nodes,uint nodeIndex, bytes32 schainHash) external;
function removeSchainForNode(uint nodeIndex, uint schainIndex) external;
function removeNodeFromExceptions(bytes32 schainHash, uint nodeIndex) external;
function isSchainActive(bytes32 schainHash) external view returns (bool);
function schainsAtSystem(uint index) external view returns (bytes32);
function numberOfSchains() external view returns (uint64);
function getSchains() external view returns (bytes32[] memory);
function getSchainsPartOfNode(bytes32 schainHash) external view returns (uint8);
function getSchainListSize(address from) external view returns (uint);
function getSchainHashesByAddress(address from) external view returns (bytes32[] memory);
function getSchainHashesForNode(uint nodeIndex) external view returns (bytes32[] memory);
function getSchainOwner(bytes32 schainHash) external view returns (address);
function getSchainOriginator(bytes32 schainHash) external view returns (address);
function isSchainNameAvailable(string calldata name) external view returns (bool);
function isTimeExpired(bytes32 schainHash) external view returns (bool);
function isOwnerAddress(address from, bytes32 schainHash) external view returns (bool);
function getSchainName(bytes32 schainHash) external view returns (string memory);
function getActiveSchain(uint nodeIndex) external view returns (bytes32);
function getActiveSchains(uint nodeIndex) external view returns (bytes32[] memory activeSchains);
function getNumberOfNodesInGroup(bytes32 schainHash) external view returns (uint);
function getNodesInGroup(bytes32 schainHash) external view returns (uint[] memory);
function isNodeAddressesInGroup(bytes32 schainHash, address sender) external view returns (bool);
function getNodeIndexInGroup(bytes32 schainHash, uint nodeHash) external view returns (uint);
function isAnyFreeNode(bytes32 schainHash) external view returns (bool);
function checkException(bytes32 schainHash, uint nodeIndex) external view returns (bool);
function checkHoleForSchain(bytes32 schainHash, uint indexOfNode) external view returns (bool);
function checkSchainOnNode(uint nodeIndex, bytes32 schainHash) external view returns (bool);
function getSchainType(uint typeOfSchain) external view returns(uint8, uint);
function getGeneration(bytes32 schainHash) external view returns (uint);
function isSchainExist(bytes32 schainHash) external view returns (bool);
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/IWallets.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
IWallets - SKALE Manager Interfaces
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaeiv
SKALE Manager Interfaces 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 Manager Interfaces 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 Manager Interfaces. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
interface IWallets {
receive() external payable;
function refundGasByValidator(uint validatorId, address payable spender, uint gasLimit) external;
function refundGasByValidatorToSchain(uint validatorId, bytes32 schainHash) external;
function refundGasBySchain(bytes32 schainId, address payable spender, uint spentGas, bool isDebt) external;
function withdrawFundsFromSchainWallet(address payable schainOwner, bytes32 schainHash) external;
function withdrawFundsFromValidatorWallet(uint amount) external;
function rechargeValidatorWallet(uint validatorId) external payable;
function rechargeSchainWallet(bytes32 schainId) external payable;
function getSchainBalance(bytes32 schainHash) external view returns (uint);
function getValidatorBalance(uint validatorId) external view returns (uint);
}
================================================================================
FILE: @skalenetwork/skale-manager-interfaces/utils/IRandom.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
IRandom.sol - SKALE Manager Interfaces
Copyright (C) 2022-Present SKALE Labs
@author Dmytro Stebaiev
SKALE Manager Interfaces 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 Manager Interfaces 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 Manager Interfaces. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity >=0.6.10 <0.9.0;
interface IRandom {
struct RandomGenerator {
uint seed;
}
}
================================================================================
exec
/bin/bash -lc "sed -n '3335,3623p' AUDIT_BUNDLE.txt" in /tmp/codex-wul8xs7h
succeeded in 0ms:
FILE: contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC721ReferenceMintAndMetadataMainnet.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/extensions/IERC721ReferenceMintAndMetadataMainnet.sol";
import "../schain/tokens/ERC721OnChain.sol";
import "./interfaces/MessageReceiver.sol";
// This contract runs on the main net and accepts deposits
contract ERC721ReferenceMintAndMetadataMainnet is MessageReceiver, IERC721ReferenceMintAndMetadataMainnet {
address public immutable erc721ContractOnMainnet;
address public senderContractOnSchain;
string public schainName;
address public immutable owner;
modifier onlyOwner() {
require(msg.sender == owner, "Sender is not an owner");
_;
}
constructor(
address newMessageProxyAddress,
address newErc721Contract,
string memory newSchainName
)
MessageProxyClient(newMessageProxyAddress)
{
require(newErc721Contract != address(0), "ERC721 contract has to be set");
erc721ContractOnMainnet = newErc721Contract;
schainName = newSchainName;
owner = msg.sender;
}
function setSenderContractOnSchain(address newSenderContractOnSchain) external override onlyOwner {
require(newSenderContractOnSchain != address(0), "Sender contract has to be set");
senderContractOnSchain = newSenderContractOnSchain;
}
function postMessage(
SchainHash schainHash,
address sender,
bytes calldata data
)
external
override
onlyMessageProxy
{
require(schainHash == SchainHash.wrap(keccak256(abi.encodePacked(schainName))), "Incorrect name of schain");
require(sender == senderContractOnSchain, "Incorrect sender contract");
address to;
uint256 tokenId;
string memory tokenURI;
(to, tokenId, tokenURI) = abi.decode(data, (address, uint256, string));
ERC721OnChain(erc721ContractOnMainnet).mint(address(this), tokenId);
require(
ERC721OnChain(erc721ContractOnMainnet).setTokenURI(tokenId, tokenURI),
"Token URI was not set"
);
ERC721OnChain(erc721ContractOnMainnet).transferFrom(address(this), to, tokenId);
}
}
================================================================================
FILE: contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC721ReferenceMintAndMetadataSchain.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/extensions/IERC721ReferenceMintAndMetadataSchain.sol";
import "../schain/tokens/ERC721OnChain.sol";
import "./interfaces/MessageSender.sol";
/**
* @title Token Manager
* @dev Runs on SKALE Chains, accepts messages from mainnet, and instructs
* TokenFactory to create clones.
When a user exits a SKALE chain, TokenFactory
* burns tokens.
*/
contract ERC721ReferenceMintAndMetadataSchain is MessageSender, IERC721ReferenceMintAndMetadataSchain {
address public immutable erc721ContractOnSchain;
address public immutable receiverContractOnMainnet;
constructor(
address newMessageProxyAddress,
address newErc721ContractOnSchain,
address newReceiverContractOnMainnet
)
MessageProxyClient(newMessageProxyAddress)
{
require(newErc721ContractOnSchain != address(0), "ERC721 contract has to be set");
require(newReceiverContractOnMainnet != address(0), "Receiver contract has to be set");
erc721ContractOnSchain = newErc721ContractOnSchain;
receiverContractOnMainnet = newReceiverContractOnMainnet;
}
function sendTokenToMainnet(address receiver, uint256 tokenId) external override {
require(
ERC721OnChain(erc721ContractOnSchain).getApproved(tokenId) == address(this),
"Not allowed ERC721 Token"
);
ERC721OnChain(erc721ContractOnSchain).transferFrom(msg.sender, address(this), tokenId);
string memory tokenURI = ERC721OnChain(erc721ContractOnSchain).tokenURI(tokenId);
ERC721OnChain(erc721ContractOnSchain).burn(tokenId);
bytes memory data = encodeParams(receiver, tokenId, tokenURI);
_sendMessage("Mainnet", receiverContractOnMainnet, data);
}
function encodeParams(
address receiver,
uint256 tokenId,
string memory tokenURI
)
public
pure
override
returns (bytes memory data)
{
data = abi.encode(receiver, tokenId, tokenURI);
}
}
================================================================================
FILE: contracts/extensions/interfaces/MessageProxyClient.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyClient.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../../MessageProxy.sol";
abstract contract MessageProxyClient {
MessageProxy public immutable messageProxy;
modifier onlyMessageProxy() {
require(msg.sender == address(messageProxy), "Sender is not a message proxy");
_;
}
constructor(address newMessageProxyAddress) {
messageProxy = MessageProxy(newMessageProxyAddress);
}
}
================================================================================
FILE: contracts/extensions/interfaces/MessageReceiver.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageReceiver.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
import "./MessageProxyClient.sol";
// solhint-disable-next-line no-empty-blocks
abstract contract MessageReceiver is MessageProxyClient, IMessageReceiver {}
================================================================================
FILE: contracts/extensions/interfaces/MessageSender.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageSender.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./MessageProxyClient.sol";
abstract contract MessageSender is MessageProxyClient {
function _sendMessage(
string memory targetChainName,
address targetContract,
bytes memory data
) internal {
messageProxy.postOutgoingMessage(
SchainHash.wrap(keccak256(abi.encodePacked(targetChainName))),
targetContract,
data
);
}
}
================================================================================
exec
/bin/bash -lc "sed -n '10645,14132p' AUDIT_BUNDLE.txt" in /tmp/codex-wul8xs7h
succeeded in 0ms:
FILE: contracts/schain/bls/FieldOperations.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
FieldOperations.sol - SKALE Manager
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaiev
SKALE Manager 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 Manager 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 Manager. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/schain/bls/IFieldOperations.sol";
import "./Precompiled.sol";
/**
* @title Fp2Operations
* @dev This library contains operations of field that is an extension by imaginary unit of
* a field of division remainders of a prime number
*
* Element of field is Fp2Point
*
* Prime divisor is P
*
* Defined operations:
*
* - addition
* - subtraction
* - scalar multiplication
* - multiplication
* - squaring
* - comparison for equality
*/
library Fp2Operations {
/**
* @dev Prime devisor
*/
uint constant public P = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
/**
* @dev Add {value1} to {value2}
*/
function addFp2(
IFieldOperations.Fp2Point memory value1,
IFieldOperations.Fp2Point memory value2
)
internal
pure
returns (IFieldOperations.Fp2Point memory)
{
return IFieldOperations.Fp2Point({ a: addmod(value1.a, value2.a, P), b: addmod(value1.b, value2.b, P) });
}
/**
* @dev Perform scalar multiplication of {value} by {scalar}
*/
function scalarMulFp2(
IFieldOperations.Fp2Point memory value,
uint scalar
)
internal
pure
returns (IFieldOperations.Fp2Point memory)
{
return IFieldOperations.Fp2Point({ a: mulmod(scalar, value.a, P), b: mulmod(scalar, value.b, P) });
}
/**
* @dev Subtract {subtracted} from {diminished}
*/
function minusFp2(
IFieldOperations.Fp2Point memory diminished,
IFieldOperations.Fp2Point memory subtracted
)
internal
pure
returns (IFieldOperations.Fp2Point memory difference)
{
uint p = P;
if (diminished.a >= subtracted.a) {
difference.a = addmod(diminished.a, p - subtracted.a, p);
} else {
difference.a = (p - addmod(subtracted.a, p - diminished.a, p)) % p;
}
if (diminished.b >= subtracted.b) {
difference.b = addmod(diminished.b, p - subtracted.b, p);
} else {
difference.b = (p - addmod(subtracted.b, p - diminished.b, p)) % p;
}
}
/**
* @dev Multiply {value1} by {value2}
*/
function mulFp2(
IFieldOperations.Fp2Point memory value1,
IFieldOperations.Fp2Point memory value2
)
internal
pure
returns (IFieldOperations.Fp2Point memory result)
{
uint p = P;
IFieldOperations.Fp2Point memory point = IFieldOperations.Fp2Point({
a: mulmod(value1.a, value2.a, p),
b: mulmod(value1.b, value2.b, p)});
result.a = addmod(
point.a,
mulmod(p - 1, point.b, p),
p);
result.b = addmod(
mulmod(
addmod(value1.a, value1.b, p),
addmod(value2.a, value2.b, p),
p),
p - addmod(point.a, point.b, p),
p);
}
/**
* @dev Square {value}
*/
function squaredFp2(
IFieldOperations.Fp2Point memory value
)
internal
pure
returns (IFieldOperations.Fp2Point memory)
{
uint p = P;
uint ab = mulmod(value.a, value.b, p);
uint multiplication = mulmod(addmod(value.a, value.b, p), addmod(value.a, mulmod(p - 1, value.b, p), p), p);
return IFieldOperations.Fp2Point({ a: multiplication, b: addmod(ab, ab, p) });
}
/**
* @dev Check if {value1} is equal to {value2}
*/
function isEqual(
IFieldOperations.Fp2Point memory value1,
IFieldOperations.Fp2Point memory value2
)
internal
pure
returns (bool)
{
return value1.a == value2.a && value1.b == value2.b;
}
}
/**
* @title G1Operations
* @dev This library contains operations of a group of elements {x, y}
* where y^2 = x^3 + 3 mod P and (x + iy) is an element of Fp2
*
* Element of the group is Fp2Point
*
* Prime divisor is Fp2Operations.P
*
* A group generator is {1, 2}
*
* Defined operations:
*
* - check if a point is in the group G1
* - check if a point is in the field Fp2
* - for x of Fp calculate -x
*/
library G1Operations {
using Fp2Operations for IFieldOperations.Fp2Point;
/**
* @dev Get G1 group generator
*/
function getG1Generator() internal pure returns (IFieldOperations.Fp2Point memory) {
// Current solidity version does not support Constants of non-value type
// so we implemented this function
return IFieldOperations.Fp2Point({
a: 1,
b: 2
});
}
/**
* @dev Check if ({x], {y}) is a G1 element
*/
function isG1Point(uint x, uint y) internal pure returns (bool) {
uint p = Fp2Operations.P;
return mulmod(y, y, p) ==
addmod(mulmod(mulmod(x, x, p), x, p), 3, p);
}
/**
* @dev Check if {point} is a G1 element
*/
function isG1(IFieldOperations.Fp2Point memory point) internal pure returns (bool) {
return isG1Point(point.a, point.b);
}
/**
* @dev Check if {point} is a Fp2 element
*/
function checkRange(IFieldOperations.Fp2Point memory point) internal pure returns (bool) {
return point.a < Fp2Operations.P && point.b < Fp2Operations.P;
}
/**
* @dev For {y} of Fp calculate -y
*/
function negate(uint y) internal pure returns (uint) {
return (Fp2Operations.P - y) % Fp2Operations.P;
}
}
/**
* @title G2Operations
* @dev This library contains operations of a group of elements {x, y}
* where y^2 = x^3 + TWISTB and x and y are elements of Fp2
*
* Element of the group is G2Point
*
* Prime divisor is Fp2Operations.P
* TWISTB is
* {
* 19485874751759354771024239261021720505790618469301721065564631296452457478373,
* 266929791119991161246907387137283842545076965332900288569378510910307636690
* }
* A group generator is
* {
* {
* 10857046999023057135944570762232829481370756359578518086990519993285655852781,
* 11559732032986387107991004021392285783925812861821192530917403151452391805634
* },
* {
* 8495653923123431417604973247489272438418190587263600148770280649306958101930,
* 4082367875863433681332203403145435568316851327593401208105741076214120093531
* }
* }
*
* Defined operations:
*
* - check if a point is in the group G2
* - check if a point is zero element of group G2
* - comparison for equality
*/
library G2Operations {
using Fp2Operations for IFieldOperations.Fp2Point;
/**
* @dev Get value of TWISTB
*/
function getTWISTB() internal pure returns (IFieldOperations.Fp2Point memory) {
// Current solidity version does not support Constants of non-value type
// so we implemented this function
return IFieldOperations.Fp2Point({
a: 19485874751759354771024239261021720505790618469301721065564631296452457478373,
b: 266929791119991161246907387137283842545076965332900288569378510910307636690
});
}
/**
* @dev Get G2 group generator
*/
function getG2Generator() internal pure returns (IFieldOperations.G2Point memory) {
// Current solidity version does not support Constants of non-value type
// so we implemented this function
return IFieldOperations.G2Point({
x: IFieldOperations.Fp2Point({
a: 10857046999023057135944570762232829481370756359578518086990519993285655852781,
b: 11559732032986387107991004021392285783925812861821192530917403151452391805634
}),
y: IFieldOperations.Fp2Point({
a: 8495653923123431417604973247489272438418190587263600148770280649306958101930,
b: 4082367875863433681332203403145435568316851327593401208105741076214120093531
})
});
}
/**
* @dev Get G2 zero element
*/
function getG2Zero() internal pure returns (IFieldOperations.G2Point memory) {
// Current solidity version does not support Constants of non-value type
// so we implemented this function
return IFieldOperations.G2Point({
x: IFieldOperations.Fp2Point({
a: 0,
b: 0
}),
y: IFieldOperations.Fp2Point({
a: 1,
b: 0
})
});
}
/**
* @dev Check if ({x}, {y}) is an element of G2
*/
function isG2Point(
IFieldOperations.Fp2Point memory x,
IFieldOperations.Fp2Point memory y
)
internal
pure
returns (bool)
{
if (isG2ZeroPoint(x, y)) {
return true;
}
IFieldOperations.Fp2Point memory squaredY = y.squaredFp2();
IFieldOperations.Fp2Point memory res = squaredY.minusFp2(
x.squaredFp2().mulFp2(x)
).minusFp2(getTWISTB());
return res.a == 0 && res.b == 0;
}
/**
* @dev Check if {value} is an element of G2
*/
function isG2(IFieldOperations.G2Point memory value) internal pure returns (bool) {
return isG2Point(value.x, value.y);
}
/**
* @dev Check if ({x}, {y}) is a zero element of G2
*/
function isG2ZeroPoint(
IFieldOperations.Fp2Point memory x,
IFieldOperations.Fp2Point memory y
)
internal
pure
returns (bool)
{
return x.a == 0 && x.b == 0 && y.a == 1 && y.b == 0;
}
/**
* @dev Check if {value} is a zero element of G2
*/
function isG2Zero(IFieldOperations.G2Point memory value) internal pure returns (bool) {
return value.x.a == 0 && value.x.b == 0 && value.y.a == 1 && value.y.b == 0;
}
/**
* @dev Check if {value1} is equal to {value2}
*/
function isEqual(
IFieldOperations.G2Point memory value1,
IFieldOperations.G2Point memory value2
)
internal
pure
returns (bool)
{
return value1.x.isEqual(value2.x) && value1.y.isEqual(value2.y);
}
}
================================================================================
FILE: contracts/schain/bls/Precompiled.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
Precompiled.sol - SKALE Manager
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaiev
SKALE Manager 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 Manager 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 Manager. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
/**
* @title Precompiled
* @dev This library is a wrapper to call precompiled contracts
*
* Defined calls:
*
* - bn256Pairing
*/
library Precompiled {
/**
* @dev Calls precompiled contract with address 0x8
* for elliptic curve pairing operations are required in order to perform zkSNARK verification
* within the block gas limit.
* see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md for more details
*/
function bn256Pairing(
uint x1,
uint y1,
uint a1,
uint b1,
uint c1,
uint d1,
uint x2,
uint y2,
uint a2,
uint b2,
uint c2,
uint d2)
internal view returns (bool)
{
bool success;
uint[12] memory inputToPairing;
inputToPairing[0] = x1;
inputToPairing[1] = y1;
inputToPairing[2] = a1;
inputToPairing[3] = b1;
inputToPairing[4] = c1;
inputToPairing[5] = d1;
inputToPairing[6] = x2;
inputToPairing[7] = y2;
inputToPairing[8] = a2;
inputToPairing[9] = b2;
inputToPairing[10] = c2;
inputToPairing[11] = d2;
uint[1] memory out;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(not(0), 8, inputToPairing, mul(12, 0x20), out, 0x20)
}
require(success, "Pairing check failed");
return out[0] != 0;
}
}
================================================================================
FILE: contracts/schain/bls/SkaleVerifier.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
SkaleVerifier.sol - SKALE Manager
Copyright (C) 2021-Present SKALE Labs
@author Dmytro Stebaiev
SKALE Manager 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 Manager 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 Manager. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./Precompiled.sol";
import "./FieldOperations.sol";
/**
* @title SkaleVerifier
* @dev Contains verify function to perform BLS signature verification.
*/
library SkaleVerifier {
using Fp2Operations for IFieldOperations.Fp2Point;
/**
* @dev Verifies a BLS signature.
*
* Requirements:
*
* - Signature is in G1.
* - Hash is in G1.
* - G2.one in G2.
* - Public Key in G2.
*/
function verify(
IFieldOperations.Fp2Point memory signature,
bytes32 hash,
uint counter,
uint hashA,
uint hashB,
IFieldOperations.G2Point memory publicKey
)
internal
view
returns (bool)
{
require(G1Operations.checkRange(signature), "Signature is not valid");
if (!_checkHashToGroupWithHelper(
hash,
counter,
hashA,
hashB
)
)
{
return false;
}
uint newSignB = G1Operations.negate(signature.b);
require(G1Operations.isG1Point(signature.a, newSignB), "Sign not in G1");
require(G1Operations.isG1Point(hashA, hashB), "Hash not in G1");
IFieldOperations.G2Point memory g2 = G2Operations.getG2Generator();
require(
G2Operations.isG2(publicKey),
"Public Key not in G2"
);
return Precompiled.bn256Pairing(
signature.a, newSignB,
g2.x.b, g2.x.a, g2.y.b, g2.y.a,
hashA, hashB,
publicKey.x.b, publicKey.x.a, publicKey.y.b, publicKey.y.a
);
}
function _checkHashToGroupWithHelper(
bytes32 hash,
uint counter,
uint hashA,
uint hashB
)
private
pure
returns (bool)
{
if (counter > 100) {
return false;
}
uint xCoordinate = uint(hash) % Fp2Operations.P;
xCoordinate = (xCoordinate + counter) % Fp2Operations.P;
uint ySquared = addmod(
mulmod(mulmod(xCoordinate, xCoordinate, Fp2Operations.P), xCoordinate, Fp2Operations.P),
3,
Fp2Operations.P
);
if (hashB < Fp2Operations.P / 2 || mulmod(hashB, hashB, Fp2Operations.P) != ySquared || xCoordinate != hashA) {
return false;
}
return true;
}
}
================================================================================
FILE: contracts/schain/tokens/ERC1155OnChain.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC1155OnChain.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
* @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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IERC1155OnChain.sol";
/**
* @title ERC1155OnChain
* @dev ERC1155 token that is used as an automatically deployed clone of ERC1155 on mainnet.
*/
contract ERC1155OnChain is AccessControlEnumerableUpgradeable, ERC1155BurnableUpgradeable, IERC1155OnChain {
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(
string memory uri
) initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC1155Upgradeable.__ERC1155_init(uri);
ERC1155BurnableUpgradeable.__ERC1155Burnable_init();
_setRoleAdmin(MINTER_ROLE, MINTER_ROLE);
_setupRole(MINTER_ROLE, _msgSender());
}
/**
* @dev Mint tokens.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(
address account,
uint256 id,
uint256 amount,
bytes memory data
)
external
override
{
require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
_mint(account, id, amount, data);
}
/**
* @dev Mint batch of tokens.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mintBatch(
address account,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
)
external
override
{
require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
_mintBatch(account, ids, amounts, data);
}
/**
* @dev Check if contract support {interfaceId} interface.
*
* See https://eips.ethereum.org/EIPS/eip-165 for more details.
*/
function supportsInterface(
bytes4 interfaceId
)
public
view
override(AccessControlEnumerableUpgradeable, ERC1155Upgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
================================================================================
FILE: contracts/schain/tokens/ERC20OnChain.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC20OnChain.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
* @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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IERC20OnChain.sol";
/**
* @title ERC20OnChain
* @dev ERC20 token that is used as an automatically deployed clone of ERC20 on mainnet.
*/
contract ERC20OnChain is AccessControlEnumerableUpgradeable, ERC20BurnableUpgradeable, IERC20OnChain {
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(
string memory contractName,
string memory contractSymbol
) initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC20Upgradeable.__ERC20_init(contractName, contractSymbol);
ERC20BurnableUpgradeable.__ERC20Burnable_init();
_setRoleAdmin(MINTER_ROLE, MINTER_ROLE);
_setupRole(MINTER_ROLE, _msgSender());
}
/**
* @dev Mint tokens.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(address account, uint256 value) external override {
require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
_mint(account, value);
}
}
================================================================================
FILE: contracts/schain/tokens/ERC721OnChain.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC721OnChain.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
* @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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IERC721OnChain.sol";
/**
* @title ERC721OnChain
* @dev ERC721 token that is used as an automatically deployed clone of ERC721 on mainnet.
*/
contract ERC721OnChain is
AccessControlEnumerableUpgradeable,
ERC721BurnableUpgradeable,
ERC721URIStorageUpgradeable,
IERC721OnChain
{
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(
string memory contractName,
string memory contractSymbol
) initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC721Upgradeable.__ERC721_init(contractName, contractSymbol);
ERC721BurnableUpgradeable.__ERC721Burnable_init();
_setRoleAdmin(MINTER_ROLE, MINTER_ROLE);
_setupRole(MINTER_ROLE, _msgSender());
}
/**
* @dev Set URI of ERC721 token.
*
* Requirements:
*
* - token with {tokenId} must exist.
* - sender must be the token owner or approved for the token.
*/
function setTokenURI(uint256 tokenId, string calldata tokenUri)
external
override
returns (bool)
{
require(_exists(tokenId), "Token does not exists");
require(
_isApprovedOrOwner(msg.sender, tokenId) ||
hasRole(MINTER_ROLE, _msgSender()),
"Sender can not set token URI"
);
_setTokenURI(tokenId, tokenUri);
return true;
}
/**
* @dev Mint token.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(address account, uint256 tokenId)
external
override
{
require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
_mint(account, tokenId);
}
/**
* @dev Check if contract support {interfaceId} interface.
*
* See https://eips.ethereum.org/EIPS/eip-165 for more details.
*/
function supportsInterface(
bytes4 interfaceId
)
public
view
override(AccessControlEnumerableUpgradeable, ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
/**
* @dev Get token URI.
*/
function tokenURI(
uint256 tokenId
)
public
view
override (ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return ERC721URIStorageUpgradeable.tokenURI(tokenId);
}
// private
/**
* @dev Burn {tokenId}.
*/
function _burn(uint256 tokenId) internal override (ERC721Upgradeable, ERC721URIStorageUpgradeable) {
ERC721URIStorageUpgradeable._burn(tokenId);
}
}
================================================================================
FILE: contracts/schain/tokens/EthErc20.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* EthErc20.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IEthErc20.sol";
/**
* @title EthErc20
* @dev ERC20 token that represents ETH on mainnet.
*/
contract EthErc20 is AccessControlEnumerableUpgradeable, ERC20BurnableUpgradeable, IEthErc20 {
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
/**
* @dev id of a role that allows token burning.
*/
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
/**
* @dev Mint tokens.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(address account, uint256 amount) external override {
require(hasRole(MINTER_ROLE, _msgSender()), "MINTER role is required");
_mint(account, amount);
}
/**
* @dev Burn tokens for any account.
*
* Requirements:
*
* - sender must be granted with {BURNER_ROLE}.
*/
function forceBurn(address account, uint256 amount) external override {
require(hasRole(BURNER_ROLE, _msgSender()), "BURNER role is required");
_burn(account, amount);
}
/**
* @dev Is called once during contract deployment.
*/
function initialize(address tokenManagerEthAddress)
external
override
initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC20Upgradeable.__ERC20_init("ERC20 Ether Clone", "ETHC");
ERC20BurnableUpgradeable.__ERC20Burnable_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(MINTER_ROLE, tokenManagerEthAddress);
_setupRole(BURNER_ROLE, tokenManagerEthAddress);
}
}
================================================================================
FILE: contracts/test/ConfigReader.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ConfigReader.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
library ConfigReader {
uint256 public constant FREE_MEM_PTR = 0x40;
uint256 public constant FN_NUM_LOG_TEXT_MESSAGE = 0x12;
uint256 public constant FN_NUM_GET_CONFIG_VARIABLE_UINT256 = 0x13;
uint256 public constant FN_NUM_GET_CONFIG_VARIABLE_ADDRESS = 0x14;
uint256 public constant FN_NUM_GET_CONFIG_VARIABLE_STRING = 0x15;
uint256 public constant FN_NUM_RESERVED = 0x16;
uint256 public constant FN_NUM_GET_CONFIG_PERMISSION_FLAG = 0x17;
function getConfigVariableUint256(
string memory strConfigVariableName
)
external
view
returns ( uint256 rv )
{
uint256 fmp = FREE_MEM_PTR;
uint256 blocks = (bytes(strConfigVariableName).length + 31) / 32 + 1;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(fmp)
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add(strConfigVariableName, mul(32, i)))
mstore(where, what)
}
success := staticcall(not(0), FN_NUM_GET_CONFIG_VARIABLE_UINT256, ptr, mul( blocks, 32 ), ptr, 32)
rv := mload(ptr)
}
require(success, "Get config uint256 failed");
}
function getConfigVariableAddress(
string memory strConfigVariableName
)
external
view
returns ( address rv )
{
uint256 fmp = FREE_MEM_PTR;
uint256 blocks = (bytes(strConfigVariableName).length + 31) / 32 + 1;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(fmp)
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add(strConfigVariableName, mul(32, i)))
mstore(where, what)
}
success := staticcall(not(0), FN_NUM_GET_CONFIG_VARIABLE_ADDRESS, ptr, mul( blocks, 32 ), ptr, 32)
rv := mload(ptr)
}
require(success, "Get config address failed");
}
function getConfigVariableString( string memory strConfigVariableName ) public view returns ( string memory rv ) {
uint256 fmp = FREE_MEM_PTR;
uint256 blocks = (bytes(strConfigVariableName).length + 31) / 32 + 1;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(fmp)
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add(strConfigVariableName, mul(32, i)))
mstore(where, what)
}
success := staticcall(
not(0),
FN_NUM_GET_CONFIG_VARIABLE_STRING,
ptr,
mul( blocks, 32 ),
rv,
mul( 1024, 1024 )
)
}
require(success, "Get config string failed");
}
function getConfigPermissionFlag(
address a,
string memory strConfigVariableName
)
public
view
returns (uint256 rv)
{
uint256 fmp = FREE_MEM_PTR;
uint256 fnc = FN_NUM_GET_CONFIG_PERMISSION_FLAG;
uint256 blocks = (bytes(strConfigVariableName).length + 31) / 32 + 1;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
let p := mload(fmp)
mstore(p, a)
let ptr := add(p, 32)
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add(strConfigVariableName, mul(32, i)))
mstore(where, what)
}
success := staticcall(not(0), fnc, p, add(64, mul(blocks, 32) ), p, 32)
rv := mload(ptr)
}
require(success, "Get config permission failed");
}
}
================================================================================
FILE: contracts/test/EtherbaseMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* EtherbaseMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/etherbase-interfaces/IEtherbaseUpgradeable.sol";
contract EtherbaseMock is IEtherbaseUpgradeable, AccessControlEnumerableUpgradeable {
bytes32 public constant override ETHER_MANAGER_ROLE = keccak256("ETHER_MANAGER_ROLE");
event EtherReceived(
address sender,
uint amount
);
event EtherSent(
address receiver,
uint amount
);
modifier onlyEtherManager() {
require(hasRole(ETHER_MANAGER_ROLE, msg.sender), "ETHER_MANAGER_ROLE is required");
_;
}
receive() external payable override {
emit EtherReceived(msg.sender, msg.value);
}
function retrieve(address payable receiver) external override onlyEtherManager {
partiallyRetrieve(receiver, address(this).balance);
}
function initialize(address schainOwner) external initializer override
{
AccessControlUpgradeable.__AccessControl_init();
_setupRole(DEFAULT_ADMIN_ROLE, schainOwner);
_setupRole(ETHER_MANAGER_ROLE, schainOwner);
}
function partiallyRetrieve(address payable receiver, uint amount) public override onlyEtherManager {
require(receiver != address(0), "Receiver address is not set");
require(amount <= address(this).balance, "Insufficient funds");
emit EtherSent(receiver, amount);
receiver.transfer(amount);
}
}
================================================================================
FILE: contracts/test/FallbackEthTester.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* FallbackEthTester.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2022-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/mainnet/DepositBoxes/IDepositBoxEth.sol";
import "@skalenetwork/ima-interfaces/mainnet/ICommunityPool.sol";
interface IFallbackEthTester {
receive() external payable;
function deposit() external payable;
function rechargeUserWallet() external payable;
function getMyEth() external;
}
contract FallbackEthTester is IFallbackEthTester {
IDepositBoxEth public depositBoxEth;
ICommunityPool public communityPool;
string public schainName;
bool private _receiveInProgress;
bool private _getMyEthInProgress;
constructor(
IDepositBoxEth newDepositBoxEth,
ICommunityPool newCommunityPool,
string memory newSchainName
) {
depositBoxEth = newDepositBoxEth;
communityPool = newCommunityPool;
schainName = newSchainName;
}
receive() external payable override {
if (!_receiveInProgress && !_getMyEthInProgress) {
_receiveInProgress = true;
uint256 balance = communityPool.getBalance(address(this), schainName);
communityPool.withdrawFunds(schainName, balance);
_receiveInProgress = false;
}
}
function deposit() external payable override {
depositBoxEth.deposit{value: msg.value}(schainName);
}
function rechargeUserWallet() external payable override {
communityPool.rechargeUserWallet{value: msg.value}(schainName, address(this));
}
function getMyEth() external override {
_getMyEthInProgress = true;
depositBoxEth.getMyEth();
_getMyEthInProgress = false;
}
}
================================================================================
FILE: contracts/test/KeyStorageMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* KeyStorageMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../schain/KeyStorage.sol";
interface IKeyStorageMock is IKeyStorage {
function setBlsCommonPublicKey(IFieldOperations.G2Point calldata key) external;
function setBlsCommonPublicKeyForSchain(bytes32 schainHash, IFieldOperations.G2Point calldata key) external;
function getBlsCommonPublicKeyForSchain(bytes32 schainHash) external view returns (IFieldOperations.G2Point memory);
}
contract KeyStorageMock is KeyStorage, IKeyStorageMock {
IFieldOperations.G2Point public blsCommonPublicKey;
mapping (bytes32 => IFieldOperations.G2Point) public blsCommonPublicKeys;
string public hello = "Hello";
function setBlsCommonPublicKey(IFieldOperations.G2Point calldata key) external override {
// TODO: remove when update compiler will be updated
IFieldOperations.G2Point memory _key = key;
blsCommonPublicKey = _key;
}
function setBlsCommonPublicKeyForSchain(
bytes32 schainHash,
IFieldOperations.G2Point calldata key
)
external
override
{
// TODO: remove when update compiler will be updated
IFieldOperations.G2Point memory _key = key;
blsCommonPublicKeys[schainHash] = _key;
}
function getBlsCommonPublicKey()
external
view
override(IKeyStorage, KeyStorage)
returns (IFieldOperations.G2Point memory)
{
require(
!(blsCommonPublicKey.x.a == 0 &&
blsCommonPublicKey.x.b == 0 &&
blsCommonPublicKey.y.a == 0 &&
blsCommonPublicKey.y.b == 0),
"BLS common public key is not set in the mock"
);
return blsCommonPublicKey;
}
function getBlsCommonPublicKeyForSchain(
bytes32 schainHash
)
external
view
override
returns (IFieldOperations.G2Point memory)
{
IFieldOperations.G2Point memory key = blsCommonPublicKeys[schainHash];
require(
!(key.x.a == 0 &&
key.x.b == 0 &&
key.y.a == 0 &&
key.y.b == 0),
"BLS common public key is not set in the mock"
);
return key;
}
}
================================================================================
FILE: contracts/test/Logger.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* Logger.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
library Logger {
uint256 public constant FREE_MEM_PTR = 0x40;
uint256 public constant FN_NUM_LOG_TEXT_MESSAGE = 0x12;
function logTextMessage( uint256 messageType, string memory strTextMessage ) public view returns ( uint256 rv ) {
uint256 fmp = FREE_MEM_PTR;
uint256 fnc = FN_NUM_LOG_TEXT_MESSAGE;
address who = msg.sender;
uint256 blocks = (bytes(strTextMessage).length + 31) / 32 + 1;
// solhint-disable-next-line no-inline-assembly
assembly {
let p := mload(fmp)
let ptr := p
// who
mstore(ptr, who)
ptr := add(ptr, 32)
// type
mstore(ptr, messageType )
ptr := add(ptr, 32)
// message
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add( strTextMessage, mul(32, i)))
mstore(where, what)
}
rv := staticcall(not(0), fnc, p, add( 64, mul(blocks, 32) ), p, 32)
}
}
function logMessage( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(0, strMessage);
}
function logDebug ( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(1, strMessage);
}
function logTrace ( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(2, strMessage);
}
function logWarning( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(3, strMessage);
}
function logError ( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(4, strMessage);
}
function logFatal ( string memory strMessage ) public view returns (uint256 rv) {
rv = logTextMessage(5, strMessage);
}
}
================================================================================
FILE: contracts/test/MessageProxyCaller.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyCaller.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../mainnet/MessageProxyForMainnet.sol";
import "../schain/MessageProxyForSchain.sol";
interface IMessageProxyCaller {
function postOutgoingMessageTester(
MessageProxyForMainnet messageProxyForMainnet,
SchainHash targetChainHash,
address targetContract,
bytes calldata data
) external;
function postOutgoingMessageTesterOnSchain(
MessageProxyForSchain messageProxyForSchain,
SchainHash targetChainHash,
address targetContract,
bytes calldata data
) external;
}
contract MessageProxyCaller is IMessageProxyCaller {
function postOutgoingMessageTester(
MessageProxyForMainnet messageProxyForMainnet,
SchainHash targetChainHash,
address targetContract,
bytes calldata data
)
external
override
{
messageProxyForMainnet.postOutgoingMessage(targetChainHash, targetContract, data);
}
function postOutgoingMessageTesterOnSchain(
MessageProxyForSchain messageProxyForSchain,
SchainHash targetChainHash,
address targetContract,
bytes calldata data
)
external
override
{
messageProxyForSchain.postOutgoingMessage(targetChainHash, targetContract, data);
}
}
================================================================================
FILE: contracts/test/MessageProxyForMainnetTester.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyForSchainTester.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../mainnet/MessageProxyForMainnet.sol";
interface IMessageProxyForMainnetTester {
function refundGasByUser(
SchainHash fromSchainHash,
address payable node,
address user,
uint256 gas
) external;
}
contract MessageProxyForMainnetTester is MessageProxyForMainnet, IMessageProxyForMainnetTester {
function refundGasByUser(
SchainHash fromSchainHash,
address payable node,
address user,
uint256 gas
)
external
override
{
communityPool.refundGasByUser(fromSchainHash, node, user, gas);
}
}
================================================================================
FILE: contracts/test/MessageProxyForSchainTester.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyForSchainTester.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../schain/MessageProxyForSchain.sol";
interface IMessageProxyForSchainTester {
function postMessage(
IMessageReceiver targetContract,
SchainHash fromSchainHash,
address sender,
bytes calldata data
)
external;
function postOutgoingMessageTester(
MessageProxyForSchain targetContract,
SchainHash targetChainHash,
address dstContract,
bytes calldata data
)
external;
function setEtherbase(IEtherbaseUpgradeable etherbaseAddress) external;
}
contract MessageProxyForSchainTester is MessageProxyForSchain, IMessageProxyForSchainTester {
IEtherbaseUpgradeable public etherbase = ETHERBASE;
constructor(IKeyStorage _keyStorage, string memory schainName) {
MessageProxyForSchain.initialize(_keyStorage, schainName);
}
function postMessage(
IMessageReceiver targetContract,
SchainHash fromSchainHash,
address sender,
bytes calldata data
)
external
override
{
targetContract.postMessage(fromSchainHash, sender, data);
}
function postOutgoingMessageTester(
MessageProxyForSchain targetContract,
SchainHash targetChainHash,
address dstContract,
bytes calldata data
)
external
override
{
targetContract.postOutgoingMessage(targetChainHash, dstContract, data);
}
function setEtherbase(IEtherbaseUpgradeable etherbaseAddress) external override {
etherbase = etherbaseAddress;
}
function _getEtherbase() internal view override returns (IEtherbaseUpgradeable) {
return etherbase;
}
}
================================================================================
FILE: contracts/test/MessageProxyForSchainWithoutSignature.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyForSchainWithoutSignature.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./MessageProxyForSchainTester.sol";
contract MessageProxyForSchainWithoutSignature is MessageProxyForSchainTester {
constructor(string memory schainName)
MessageProxyForSchainTester(IKeyStorage(address(0)), schainName)
// solhint-disable-next-line no-empty-blocks
{}
function _verifyMessages(
bytes32,
Signature calldata
)
internal
pure
override
returns (bool)
{
return true;
}
}
================================================================================
FILE: contracts/test/MessagesTester.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessagesTester.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../Messages.sol";
interface IMessagesTester {
function encodeTransferEthMessage(address receiver, uint256 amount) external pure returns (bytes memory);
function encodeTransferErc20Message(
address token,
address receiver,
uint256 amount
) external pure returns (bytes memory);
function encodeTransferErc20AndTotalSupplyMessage(
address token,
address receiver,
uint256 amount,
uint256 totalSupply
) external pure returns (bytes memory);
function encodeTransferErc20AndTokenInfoMessage(
address token,
address receiver,
uint256 amount,
uint256 totalSupply,
Messages.Erc20TokenInfo memory tokenInfo
) external pure returns (bytes memory);
function encodeTransferErc721Message(
address token,
address receiver,
uint256 tokenId
) external pure returns (bytes memory);
function encodeTransferErc721AndTokenInfoMessage(
address token,
address receiver,
uint256 tokenId,
Messages.Erc721TokenInfo memory tokenInfo
) external pure returns (bytes memory);
function encodeTransferErc721MessageWithMetadata(
address token,
address receiver,
uint256 tokenId,
string memory tokenURI
) external pure returns (bytes memory);
function encodeTransferErc721WithMetadataAndTokenInfoMessage(
address token,
address receiver,
uint256 tokenId,
string memory tokenURI,
Messages.Erc721TokenInfo memory tokenInfo
) external pure returns (bytes memory);
function encodeActivateUserMessage(address receiver) external pure returns (bytes memory);
function encodeLockUserMessage(address receiver) external pure returns (bytes memory);
function encodeInterchainConnectionMessage(bool isAllowed) external pure returns (bytes memory);
function encodeTransferErc1155Message(
address token,
address receiver,
uint256 id,
uint256 amount
) external pure returns (bytes memory);
function encodeTransferErc1155AndTokenInfoMessage(
address token,
address receiver,
uint256 id,
uint256 amount,
Messages.Erc1155TokenInfo memory tokenInfo
) external pure returns (bytes memory);
function encodeTransferErc1155BatchMessage(
address token,
address receiver,
uint256[] memory ids,
uint256[] memory amounts
) external pure returns (bytes memory);
function encodeTransferErc1155BatchAndTokenInfoMessage(
address token,
address receiver,
uint256[] memory ids,
uint256[] memory amounts,
Messages.Erc1155TokenInfo memory tokenInfo
) external pure returns (bytes memory);
}
contract MessagesTester is IMessagesTester {
function encodeTransferEthMessage(address receiver, uint256 amount) external pure override returns (bytes memory) {
return Messages.encodeTransferEthMessage(receiver, amount);
}
function encodeTransferErc20Message(
address token,
address receiver,
uint256 amount
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc20Message(token, receiver, amount);
}
function encodeTransferErc20AndTotalSupplyMessage(
address token,
address receiver,
uint256 amount,
uint256 totalSupply
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc20AndTotalSupplyMessage(token, receiver, amount, totalSupply);
}
function encodeTransferErc20AndTokenInfoMessage(
address token,
address receiver,
uint256 amount,
uint256 totalSupply,
Messages.Erc20TokenInfo memory tokenInfo
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc20AndTokenInfoMessage(token, receiver, amount, totalSupply, tokenInfo);
}
function encodeTransferErc721Message(
address token,
address receiver,
uint256 tokenId
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc721Message(token, receiver, tokenId);
}
function encodeTransferErc721AndTokenInfoMessage(
address token,
address receiver,
uint256 tokenId,
Messages.Erc721TokenInfo memory tokenInfo
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc721AndTokenInfoMessage(token, receiver, tokenId, tokenInfo);
}
function encodeTransferErc721MessageWithMetadata(
address token,
address receiver,
uint256 tokenId,
string memory tokenURI
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc721MessageWithMetadata(token, receiver, tokenId, tokenURI);
}
function encodeTransferErc721WithMetadataAndTokenInfoMessage(
address token,
address receiver,
uint256 tokenId,
string memory tokenURI,
Messages.Erc721TokenInfo memory tokenInfo
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc721WithMetadataAndTokenInfoMessage(
token,
receiver,
tokenId,
tokenURI,
tokenInfo
);
}
function encodeActivateUserMessage(address receiver) external pure override returns (bytes memory) {
return Messages.encodeActivateUserMessage(receiver);
}
function encodeLockUserMessage(address receiver) external pure override returns (bytes memory) {
return Messages.encodeLockUserMessage(receiver);
}
function encodeInterchainConnectionMessage(bool isAllowed) external pure override returns (bytes memory) {
return Messages.encodeInterchainConnectionMessage(isAllowed);
}
function encodeTransferErc1155Message(
address token,
address receiver,
uint256 id,
uint256 amount
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc1155Message(token, receiver, id, amount);
}
function encodeTransferErc1155AndTokenInfoMessage(
address token,
address receiver,
uint256 id,
uint256 amount,
Messages.Erc1155TokenInfo memory tokenInfo
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc1155AndTokenInfoMessage(token, receiver, id, amount, tokenInfo);
}
function encodeTransferErc1155BatchMessage(
address token,
address receiver,
uint256[] memory ids,
uint256[] memory amounts
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc1155BatchMessage(token, receiver, ids, amounts);
}
function encodeTransferErc1155BatchAndTokenInfoMessage(
address token,
address receiver,
uint256[] memory ids,
uint256[] memory amounts,
Messages.Erc1155TokenInfo memory tokenInfo
) external pure override returns (bytes memory) {
return Messages.encodeTransferErc1155BatchAndTokenInfoMessage(token, receiver, ids, amounts, tokenInfo);
}
}
================================================================================
FILE: contracts/test/PrecompiledMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestPrecompiled.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
library PrecompiledMock {
function bigModExp(uint base, uint power, uint modulus) internal view returns (uint) {
uint[6] memory inputToBigModExp;
inputToBigModExp[0] = 32;
inputToBigModExp[1] = 32;
inputToBigModExp[2] = 32;
inputToBigModExp[3] = base;
inputToBigModExp[4] = power;
inputToBigModExp[5] = modulus;
uint[1] memory out;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(not(0), 5, inputToBigModExp, mul(6, 0x20), out, 0x20)
}
require(success, "BigModExp failed");
return out[0];
}
function bn256ScalarMul(uint x, uint y, uint k) internal view returns (uint , uint ) {
uint[3] memory inputToMul;
uint[2] memory output;
inputToMul[0] = x;
inputToMul[1] = y;
inputToMul[2] = k;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(not(0), 7, inputToMul, 0x60, output, 0x40)
}
require(success, "Multiplication failed");
return (output[0], output[1]);
}
function bn256Pairing(
uint x1,
uint y1,
uint a1,
uint b1,
uint c1,
uint d1,
uint x2,
uint y2,
uint a2,
uint b2,
uint c2,
uint d2)
internal view returns (bool)
{
bool success;
uint[12] memory inputToPairing;
inputToPairing[0] = x1;
inputToPairing[1] = y1;
inputToPairing[2] = a1;
inputToPairing[3] = b1;
inputToPairing[4] = c1;
inputToPairing[5] = d1;
inputToPairing[6] = x2;
inputToPairing[7] = y2;
inputToPairing[8] = a2;
inputToPairing[9] = b2;
inputToPairing[10] = c2;
inputToPairing[11] = d2;
uint[1] memory out;
// solhint-disable-next-line no-inline-assembly
assembly {
success := staticcall(not(0), 8, inputToPairing, mul(12, 0x20), out, 0x20)
}
// require(success, "Pairing check failed");
return true;
}
}
================================================================================
FILE: contracts/test/ReceiverGasLimitMainnetMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ReceiverMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
contract ReceiverGasLimitMainnetMock is IMessageReceiver {
uint public a = 0;
function postMessage(
SchainHash,
address,
bytes calldata
)
external
override
{
while(true) {
a++;
}
}
}
================================================================================
FILE: contracts/test/ReceiverGasLimitSchainMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ReceiverMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
contract ReceiverGasLimitSchainMock is IMessageReceiver {
uint public a = 0;
function postMessage(
SchainHash,
address,
bytes calldata
)
external
override
{
while(true) {
a++;
}
}
}
================================================================================
FILE: contracts/test/ReceiverMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ReceiverMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
contract ReceiverMock is IMessageReceiver {
function postMessage(
SchainHash,
address,
bytes calldata
)
external
pure
override
{
return;
}
}
================================================================================
FILE: contracts/test/SafeMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/*
SafeMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
interface ISafeMock {
enum Operation {Call, DelegateCall}
function transferProxyAdminOwnership(OwnableUpgradeable proxyAdmin, address newOwner) external;
function destroy() external;
function multiSend(bytes memory transactions) external;
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes32);
}
contract SafeMock is OwnableUpgradeable, ISafeMock {
bool public constant IS_SAFE_MOCK = true;
bytes32 public constant SAFE_TX_TYPE_HASH = keccak256(
"SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,"
"address gasToken,address refundReceiver,uint256 nonce)"
);
bytes32 public constant DOMAIN_SEPARATOR_TYPE_HASH = keccak256(
"EIP712Domain(uint256 chainId,address verifyingContract)"
);
constructor() initializer {
OwnableUpgradeable.__Ownable_init();
multiSend(""); // this is needed to remove slither warning
}
function transferProxyAdminOwnership(OwnableUpgradeable proxyAdmin, address newOwner) external override onlyOwner {
proxyAdmin.transferOwnership(newOwner);
}
function destroy() external override onlyOwner {
selfdestruct(payable(msg.sender));
}
/// @dev Sends multiple transactions and reverts all if one fails.
/// @param transactions Encoded transactions. Each transaction is encoded as a packed bytes of
/// 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.
/// see abi.encodePacked for more information on packed encoding
function multiSend(bytes memory transactions) public override
{
// solhint-disable-next-line no-inline-assembly
assembly {
let length := mload(transactions)
let i := 0x20
// solhint-disable-next-line no-empty-blocks
for { } lt(i, length) { } {
// First byte of the data is the operation.
// We shift by 248 bits (256 - 8 [operation byte]) it right
// since mload will always load 32 bytes (a word).
// This will also zero out unused data.
let operation := shr(0xf8, mload(add(transactions, i)))
// We offset the load address by 1 byte (operation byte)
// We shift it right by 96 bits (256 - 160 [20 address bytes])
// to right-align the data and zero out unused data.
let to := shr(0x60, mload(add(transactions, add(i, 0x01))))
// We offset the load address by 21 byte (operation byte + 20 address bytes)
let value := mload(add(transactions, add(i, 0x15)))
// We offset the load address by 53 byte (operation byte + 20 address bytes + 32 value bytes)
let dataLength := mload(add(transactions, add(i, 0x35)))
// We offset the load address by 85 byte
// (operation byte + 20 address bytes + 32 value bytes + 32 data length bytes)
let data := add(transactions, add(i, 0x55))
let success := 0
switch operation
case 0 { success := call(gas(), to, value, data, dataLength, 0, 0) }
case 1 { success := delegatecall(gas(), to, data, dataLength, 0, 0) }
if eq(success, 0) { revert(0, 0) }
// Next entry starts at 85 byte + data length
i := add(i, add(0x55, dataLength))
}
}
}
/// @dev Returns hash to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Fas that should be used for the safe transaction.
/// @param baseGas Gas costs for data used to trigger the safe transaction.
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash.
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) public view override returns (bytes32) {
return keccak256(
_encodeTransactionData(
to,
value,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
_nonce
)
);
}
/// @dev Returns the bytes that are hashed to be signed by owners.
/// @param to Destination address.
/// @param value Ether value.
/// @param data Data payload.
/// @param operation Operation type.
/// @param safeTxGas Gas that should be used for the safe transaction.
/// @param baseGas Gas costs for that are independent of the transaction execution
/// (e.g. base transaction fee, signature check, payment of the refund)
/// @param gasPrice Maximum gas price that should be used for this transaction.
/// @param gasToken Token address (or 0 if ETH) that is used for the payment.
/// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
/// @param _nonce Transaction nonce.
/// @return Transaction hash bytes.
function _encodeTransactionData(
address to,
uint256 value,
bytes calldata data,
Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) private view returns (bytes memory) {
bytes32 safeTxHash =
keccak256(
abi.encode(
SAFE_TX_TYPE_HASH,
to,
value,
keccak256(data),
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
_nonce
)
);
return abi.encodePacked(bytes1(0x19), bytes1(0x01), _domainSeparator(), safeTxHash);
}
function _domainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPE_HASH, block.chainid, this));
}
}
================================================================================
FILE: contracts/test/SkaleManagerMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* SkaleManagerMock.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2024-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./TestContractManager.sol";
interface ISkaleManagerMock {
function setVersion(string calldata newVersion) external;
}
contract SkaleManagerMock is ISkaleManagerMock, ContractManager {
ContractManager public contractManager;
string public version;
constructor(address newContractManager) {
contractManager = ContractManager(newContractManager);
}
function setVersion(string calldata newVersion) external override {
version = newVersion;
}
}
================================================================================
FILE: contracts/test/SkaleVerifierMock.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestSkaleVerifier.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "../schain/bls/FieldOperations.sol";
import "./PrecompiledMock.sol";
interface ISkaleVerifierMock {
function verify(
IFieldOperations.Fp2Point calldata signature,
bytes32 hash,
uint counter,
uint hashA,
uint hashB,
IFieldOperations.G2Point calldata publicKey
)
external
view
returns (bool);
}
contract SkaleVerifierMock is ISkaleVerifierMock {
/**
* @dev Verifies a BLS signature.
*
* Requirements:
*
* - Signature is in G1.
* - Hash is in G1.
* - G2.one in G2.
* - Public Key in G2.
*/
function verify(
IFieldOperations.Fp2Point calldata signature,
bytes32 hash,
uint counter,
uint hashA,
uint hashB,
IFieldOperations.G2Point calldata publicKey
)
external
view
override
returns (bool)
{
require(G1Operations.checkRange(signature), "Signature is not valid");
if (!_checkHashToGroupWithHelper(
hash,
counter,
hashA,
hashB
)
)
{
return false;
}
uint newSignB = G1Operations.negate(signature.b);
require(G1Operations.isG1Point(signature.a, newSignB) || true, "Sign not in G1");
require(G1Operations.isG1Point(hashA, hashB) || true, "Hash not in G1");
IFieldOperations.G2Point memory g2 = G2Operations.getG2Generator();
require(
G2Operations.isG2(publicKey),
"Public Key not in G2"
);
return PrecompiledMock.bn256Pairing(
signature.a, newSignB,
g2.x.b, g2.x.a, g2.y.b, g2.y.a,
hashA, hashB,
publicKey.x.b, publicKey.x.a, publicKey.y.b, publicKey.y.a
);
// return true;
}
function _checkHashToGroupWithHelper(
bytes32 hash,
uint counter,
uint hashA,
uint hashB
)
private
pure
returns (bool)
{
if (counter > 100) {
return false;
}
uint xCoordinate = uint(hash) % Fp2Operations.P;
xCoordinate = (xCoordinate + counter) % Fp2Operations.P;
uint ySquared = addmod(
mulmod(mulmod(xCoordinate, xCoordinate, Fp2Operations.P), xCoordinate, Fp2Operations.P),
3,
Fp2Operations.P
);
if (hashB < Fp2Operations.P / 2 || mulmod(hashB, hashB, Fp2Operations.P) != ySquared || xCoordinate != hashA) {
return true;
}
return true;
}
}
================================================================================
FILE: contracts/test/TestCallReceiverContract.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ReceiverMock.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@skalenetwork/ima-interfaces/IMessageReceiver.sol";
contract TestCallReceiverContract is IMessageReceiver {
event Error(uint error);
function postMessage(
SchainHash,
address,
bytes calldata data
)
external
override
{
uint revertCode = abi.decode(data, (uint));
uint one = 1;
uint zero = 0;
if (revertCode == 1) {
revert("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
} else if (revertCode == 2) {
emit Error(one / zero);
}
}
}
================================================================================
FILE: contracts/test/TestContractManager.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestContractManager.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
interface IContractManagerTester {
function setContractsAddress(string calldata contractsName, address newContractsAddress) external;
function getContract(string memory contractName) external view returns (address);
}
contract ContractManager is IContractManagerTester {
using AddressUpgradeable for address;
// mapping of actual smart contracts addresses
mapping (bytes32 => address) public contracts;
address public owner;
event ContractUpgraded(string contractsName, address contractsAddress);
error ContractNotFound(
string contractName
);
constructor() {
owner = msg.sender;
}
/**
* Adds actual contract to mapping of actual contract addresses
* @param contractsName - contracts name in skale manager system
* @param newContractsAddress - contracts address in skale manager system
*/
function setContractsAddress(string calldata contractsName, address newContractsAddress) external override {
// check newContractsAddress is not equal zero
require(newContractsAddress != address(0), "New address is equal zero");
// create hash of contractsName
bytes32 contractId = keccak256(abi.encodePacked(contractsName));
// check newContractsAddress is not equal the previous contract's address
require(contracts[contractId] != newContractsAddress, "Contract is already added");
// check newContractsAddress contains code
require(newContractsAddress.isContract(), "Given contracts address is not contain code");
// add newContractsAddress to mapping of actual contract addresses
contracts[contractId] = newContractsAddress;
emit ContractUpgraded(contractsName, newContractsAddress);
}
/**
* @dev Returns the contract address for a given contractName.
*/
function getContract(
string memory name
)
public
view
override
returns (address contractAddress)
{
contractAddress = contracts[keccak256(abi.encodePacked(name))];
if (contractAddress == address(0)) {
revert ContractNotFound(name);
}
}
}
================================================================================
FILE: contracts/test/TestNodes.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestNodes.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
interface INodesTester {
function createNode(address, Nodes.NodeCreationParams calldata params) external;
function getNodeAddress(uint nodeIndex) external view returns (address);
function isNodeExist(address from, uint nodeIndex) external view returns (bool);
}
contract Nodes is INodesTester {
enum NodeStatus {Active, Leaving, Left, In_Maintenance}
struct Node {
string name;
bytes4 ip;
bytes4 publicIP;
uint16 port;
bytes32[2] publicKey;
uint startBlock;
uint lastRewardDate;
uint finishTime;
NodeStatus status;
uint validatorId;
}
struct NodeCreationParams {
string name;
bytes4 ip;
bytes4 publicIp;
uint16 port;
bytes32[2] publicKey;
uint16 nonce;
string domainName;
}
struct CreatedNodes {
mapping (uint => bool) isNodeExist;
uint numberOfNodes;
}
Node[] public nodes;
mapping (address => CreatedNodes) public nodeIndexes;
modifier checkNodeExists(uint nodeIndex) {
_checkNodeIndex(nodeIndex);
_;
}
function createNode(address from, NodeCreationParams calldata params)
external override
{
nodes.push(Node({
name: params.name,
ip: params.ip,
publicIP: params.publicIp,
port: params.port,
publicKey: params.publicKey,
startBlock: block.number,
lastRewardDate: block.timestamp,
finishTime: 0,
status: NodeStatus.Active,
validatorId: 1337
}));
nodeIndexes[from].isNodeExist[nodes.length - 1] = true;
nodeIndexes[from].numberOfNodes++;
}
function getNodeAddress(uint nodeIndex)
external
view
override
checkNodeExists(nodeIndex)
returns (address)
{
return _publicKeyToAddress(nodes[nodeIndex].publicKey);
}
function isNodeExist(address from, uint nodeIndex)
public
view
override
checkNodeExists(nodeIndex)
returns (bool)
{
return nodeIndexes[from].isNodeExist[nodeIndex];
}
function _checkNodeIndex(uint nodeIndex) private view {
require(nodeIndex < nodes.length, "Node with such index does not exist");
}
function _publicKeyToAddress(bytes32[2] memory pubKey) private pure returns (address) {
bytes32 hash = keccak256(abi.encodePacked(pubKey[0], pubKey[1]));
bytes20 addr;
for (uint8 i = 12; i < 32; i++) {
addr |= bytes20(hash[i] & 0xFF) >> ((i - 12) * 8);
}
return address(addr);
}
}
================================================================================
FILE: contracts/test/TestSchains.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestSchains.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./TestContractManager.sol";
import "./KeyStorageMock.sol";
import "./SkaleVerifierMock.sol";
interface ISchainsTester {
function addContractManager(address newContractManager) external;
function verifySchainSignature(
uint signatureA,
uint signatureB,
bytes32 hash,
uint counter,
uint hashA,
uint hashB,
string calldata schainName
)
external
view
returns (bool);
}
contract Schains is ISchainsTester {
ContractManager public contractManager;
function addContractManager(address newContractManager) external override {
contractManager = ContractManager(newContractManager);
}
function verifySchainSignature(
uint signatureA,
uint signatureB,
bytes32 hash,
uint counter,
uint hashA,
uint hashB,
string calldata schainName
)
external
view
override
returns (bool)
{
SkaleVerifierMock skaleVerifier = SkaleVerifierMock(contractManager.getContract("SkaleVerifier"));
IFieldOperations.G2Point memory publicKey = KeyStorageMock(
contractManager.getContract("KeyStorage")
).getBlsCommonPublicKeyForSchain(
keccak256(abi.encodePacked(schainName))
);
return skaleVerifier.verify(
IFieldOperations.Fp2Point({
a: signatureA,
b: signatureB
}),
hash, counter,
hashA, hashB,
publicKey
);
}
}
================================================================================
FILE: contracts/test/TestSchainsInternal.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestSchainsInternal.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./TestContractManager.sol";
import "./TestNodes.sol";
interface ISchainsInternalTester {
function addContractManager(address newContractManager) external;
function initializeSchain(
string calldata name,
address from,
uint lifetime,
uint deposit) external;
function addNodesToSchainsGroups(bytes32 schainHash, uint[] memory nodes) external;
function isNodeAddressesInGroup(bytes32 schainHash, address sender) external view returns (bool);
function isOwnerAddress(address from, bytes32 schainHash) external view returns (bool);
function isSchainExist(bytes32 schainHash) external view returns (bool);
function getSchains() external view returns (bytes32[] memory);
function getSchainName(bytes32 schainHash) external view returns (string memory);
function getNodesInGroup(bytes32 schainHash) external view returns (uint[] memory);
}
contract SchainsInternal is ISchainsInternalTester {
struct Schain {
string name;
address owner;
uint indexInOwnerList;
uint8 partOfNode;
uint lifetime;
uint startDate;
uint startBlock;
uint deposit;
uint64 index;
}
ContractManager public contractManager;
mapping (bytes32 => Schain) public schains;
mapping (bytes32 => bool) public isSchainActive;
mapping (bytes32 => uint[]) public schainsGroups;
bytes32[] public schainsAtSystem;
mapping (bytes32 => mapping (address => bool)) private _nodeAddressInSchain;
function addContractManager(address newContractManager) external override {
contractManager = ContractManager(newContractManager);
}
function initializeSchain(
string calldata name,
address from,
uint lifetime,
uint deposit) external override
{
bytes32 schainHash = keccak256(abi.encodePacked(name));
schains[schainHash].name = name;
schains[schainHash].owner = from;
schains[schainHash].startDate = block.timestamp;
schains[schainHash].startBlock = block.number;
schains[schainHash].lifetime = lifetime;
schains[schainHash].deposit = deposit;
schains[schainHash].index = 1337;
isSchainActive[schainHash] = true;
schainsAtSystem.push(schainHash);
}
function addNodesToSchainsGroups(bytes32 schainHash, uint[] memory nodes) external override {
Nodes nodesContract = Nodes(contractManager.getContract("Nodes"));
schainsGroups[schainHash] = nodes;
for (uint i = 0; i < nodes.length; i++) {
address nodeAddress = nodesContract.getNodeAddress(nodes[i]);
_nodeAddressInSchain[schainHash][nodeAddress] = true;
}
}
function isNodeAddressesInGroup(bytes32 schainHash, address sender) external view override returns (bool) {
return _nodeAddressInSchain[schainHash][sender];
}
function isOwnerAddress(address from, bytes32 schainHash) external view override returns (bool) {
return schains[schainHash].owner == from;
}
function getSchains() external view override returns (bytes32[] memory) {
return schainsAtSystem;
}
function getSchainName(bytes32 schainHash)
external
view
override
returns (string memory)
{
return schains[schainHash].name;
}
function getNodesInGroup(bytes32 schainHash)
external
view
override
returns (uint[] memory)
{
return schainsGroups[schainHash];
}
function isSchainExist(bytes32) external pure override returns (bool) {
return true;
}
}
================================================================================
FILE: contracts/test/TestWallets.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* TestWallets.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "./TestSchainsInternal.sol";
interface IWalletsTester {
function addContractManager(address newContractManager) external;
function refundGasBySchain(
bytes32 schainHash,
address payable spender,
uint spentGas,
bool
) external;
function rechargeSchainWallet(bytes32 schainHash) external payable;
function getSchainBalance(bytes32 schainHash) external view returns (uint);
}
contract Wallets is IWalletsTester {
ContractManager public contractManager;
mapping (bytes32 => uint) private _schainWallets;
event SchainWalletRecharged(address sponsor, uint amount, bytes32 schainHash);
event NodeRefundedBySchain(address node, bytes32 schainHash, uint amount);
function addContractManager(address newContractManager) external override {
contractManager = ContractManager(newContractManager);
}
function refundGasBySchain(
bytes32 schainHash,
address payable spender,
uint spentGas,
bool
)
external
override
{
uint amount = tx.gasprice * spentGas;
require(schainHash != bytes32(0), "SchainHash cannot be null");
require(amount <= _schainWallets[schainHash], "Schain wallet has not enough funds");
_schainWallets[schainHash] -= amount;
emit NodeRefundedBySchain(spender, schainHash, amount);
spender.transfer(amount);
}
function rechargeSchainWallet(bytes32 schainHash) external payable override {
SchainsInternal schainsInternal = SchainsInternal(contractManager.getContract("SchainsInternal"));
require(schainsInternal.isSchainActive(schainHash), "Schain should be active for recharging");
_schainWallets[schainHash] += msg.value;
emit SchainWalletRecharged(msg.sender, msg.value, schainHash);
}
function getSchainBalance(bytes32 schainHash) external view override returns (uint) {
return _schainWallets[schainHash];
}
}
================================================================================
FILE: contracts/test/erc20/ERC20IncorrectTransfer.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.27;
import "./ERC20WithoutTransfer.sol";
interface IERC20IncorrectTransfer is IERC20WithoutTransfer {
function transferFrom(address sender, address recipient, uint256 amount, bytes memory) external;
}
contract ERC20IncorrectTransfer is IERC20IncorrectTransfer, ERC20WithoutTransfer {
// solhint-disable-next-line no-empty-blocks
constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {}
function transferFrom(address sender, address recipient, uint256 amount, bytes memory) public override {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
allowance(sender, msg.sender) - amount
);
}
}
================================================================================
FILE: contracts/test/erc20/ERC20TransferWithFalseReturn.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.27;
import "./ERC20WithoutTransfer.sol";
interface IERC20TransferWithFalseReturn is IERC20WithoutTransfer {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
contract ERC20TransferWithFalseReturn is IERC20TransferWithFalseReturn, ERC20WithoutTransfer {
// solhint-disable-next-line no-empty-blocks
constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {}
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
allowance(sender, msg.sender) - amount
);
return false;
}
}
================================================================================
FILE: contracts/test/erc20/ERC20TransferWithoutReturn.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.27;
import "./ERC20WithoutTransfer.sol";
interface IERC20TransferWithoutReturn is IERC20WithoutTransfer {
function transferFrom(address sender, address recipient, uint256 amount) external;
}
contract ERC20TransferWithoutReturn is IERC20TransferWithoutReturn, ERC20WithoutTransfer {
// solhint-disable-next-line no-empty-blocks
constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {}
function transferFrom(address sender, address recipient, uint256 amount) public override {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
allowance(sender, msg.sender) - amount
);
}
}
================================================================================
FILE: contracts/test/erc20/ERC20WithoutTransfer.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.27;
interface IERC20WithoutTransfer {
function mint(address account, uint256 amount) external returns (bool);
function burn(uint256 amount) external;
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
}
abstract contract ERC20WithoutTransfer is IERC20WithoutTransfer {
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
event Approval(address owner, address spender, uint256 amount);
event Transfer(address from, address to, uint256 amount);
constructor(string memory tokenName, string memory tokenSymbol) {
_name = tokenName;
_symbol = tokenSymbol;
_decimals = 18;
}
function mint(address account, uint256 amount) external override returns (bool) {
_mint(account, amount);
return true;
}
/**
* @dev burn - destroys token on msg sender
*
* NEED TO HAVE THIS FUNCTION ON SKALE-CHAIN
*
* @param amount - amount of tokens
*/
function burn(uint256 amount) external override {
_burn(msg.sender, amount);
}
function transfer(address recipient, uint256 amount) public override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
function approve(address spender, uint256 amount) public override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public override returns (bool) {
_approve(
msg.sender,
spender,
_allowances[msg.sender][spender] - subtractedValue
);
return true;
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function decimals() public view override returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_balances[sender] = _balances[sender] - amount;
_balances[recipient] = _balances[recipient] + amount;
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply = _totalSupply + amount;
_balances[account] = _balances[account] + amount;
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_balances[account] = _balances[account] - amount;
_totalSupply = _totalSupply - amount;
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}
================================================================================
FILE: contracts/test/erc20/RevertableERC20.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
/**
* RevertableERC20.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2022-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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
interface IRevertableERC20 {
function enable() external;
function disable() external;
function mint(address account, uint amount) external;
}
contract RevertableERC20 is IRevertableERC20, ERC20Upgradeable {
bool public enabled = true;
constructor(string memory name, string memory symbol) initializer {
super.__ERC20_init(name, symbol);
}
function enable() external override {
enabled = true;
}
function disable() external override {
enabled = false;
}
function mint(address account, uint amount) external override {
_mint(account, amount);
}
function _transfer(
address from,
address to,
uint256 amount
)
internal
override
{
require(enabled, "Transfers are disabled");
super._transfer(from, to, amount);
}
}
================================================================================
FILE: contracts/thirdparty/ERC1155ReceiverUpgradeableWithoutGap.sol
================================================================================
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgradeable.sol";
abstract contract ERC1155ReceiverUpgradeableWithoutGap is
Initializable,
ERC165Upgradeable,
IERC1155ReceiverUpgradeable
{
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC165Upgradeable, IERC165Upgradeable)
returns (bool)
{
return interfaceId == type(IERC1155ReceiverUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
// solhint-disable-next-line func-name-mixedcase
function __ERC1155Receiver_init() internal initializer {
__ERC165_init_unchained();
__ERC1155Receiver_init_unchained();
}
// solhint-disable-next-line func-name-mixedcase, no-empty-blocks
function __ERC1155Receiver_init_unchained() internal initializer {
}
}
exec
/bin/bash -lc "sed -n '1,220p' contracts/schain/tokens/ERC721OnChain.sol" in /tmp/codex-wul8xs7h
succeeded in 0ms:
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ERC721OnChain.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2021-Present SKALE Labs
* @author Artem Payvin
* @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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IERC721OnChain.sol";
/**
* @title ERC721OnChain
* @dev ERC721 token that is used as an automatically deployed clone of ERC721 on mainnet.
*/
contract ERC721OnChain is
AccessControlEnumerableUpgradeable,
ERC721BurnableUpgradeable,
ERC721URIStorageUpgradeable,
IERC721OnChain
{
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(
string memory contractName,
string memory contractSymbol
) initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC721Upgradeable.__ERC721_init(contractName, contractSymbol);
ERC721BurnableUpgradeable.__ERC721Burnable_init();
_setRoleAdmin(MINTER_ROLE, MINTER_ROLE);
_setupRole(MINTER_ROLE, _msgSender());
}
/**
* @dev Set URI of ERC721 token.
*
* Requirements:
*
* - token with {tokenId} must exist.
* - sender must be the token owner or approved for the token.
*/
function setTokenURI(uint256 tokenId, string calldata tokenUri)
external
override
returns (bool)
{
require(_exists(tokenId), "Token does not exists");
require(
_isApprovedOrOwner(msg.sender, tokenId) ||
hasRole(MINTER_ROLE, _msgSender()),
"Sender can not set token URI"
);
_setTokenURI(tokenId, tokenUri);
return true;
}
/**
* @dev Mint token.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(address account, uint256 tokenId)
external
override
{
require(hasRole(MINTER_ROLE, _msgSender()), "Sender is not a Minter");
_mint(account, tokenId);
}
/**
* @dev Check if contract support {interfaceId} interface.
*
* See https://eips.ethereum.org/EIPS/eip-165 for more details.
*/
function supportsInterface(
bytes4 interfaceId
)
public
view
override(AccessControlEnumerableUpgradeable, ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
/**
* @dev Get token URI.
*/
function tokenURI(
uint256 tokenId
)
public
view
override (ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return ERC721URIStorageUpgradeable.tokenURI(tokenId);
}
// private
/**
* @dev Burn {tokenId}.
*/
function _burn(uint256 tokenId) internal override (ERC721Upgradeable, ERC721URIStorageUpgradeable) {
ERC721URIStorageUpgradeable._burn(tokenId);
}
}
exec
/bin/bash -lc "sed -n '1,220p' contracts/schain/tokens/EthErc20.sol" in /tmp/codex-wul8xs7h
succeeded in 0ms:
// SPDX-License-Identifier: AGPL-3.0-only
/**
* EthErc20.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2019-Present SKALE Labs
* @author Artem Payvin
*
* 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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/tokens/IEthErc20.sol";
/**
* @title EthErc20
* @dev ERC20 token that represents ETH on mainnet.
*/
contract EthErc20 is AccessControlEnumerableUpgradeable, ERC20BurnableUpgradeable, IEthErc20 {
/**
* @dev id of a role that allows token minting.
*/
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
/**
* @dev id of a role that allows token burning.
*/
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
/**
* @dev Mint tokens.
*
* Requirements:
*
* - sender must be granted with {MINTER_ROLE}.
*/
function mint(address account, uint256 amount) external override {
require(hasRole(MINTER_ROLE, _msgSender()), "MINTER role is required");
_mint(account, amount);
}
/**
* @dev Burn tokens for any account.
*
* Requirements:
*
* - sender must be granted with {BURNER_ROLE}.
*/
function forceBurn(address account, uint256 amount) external override {
require(hasRole(BURNER_ROLE, _msgSender()), "BURNER role is required");
_burn(account, amount);
}
/**
* @dev Is called once during contract deployment.
*/
function initialize(address tokenManagerEthAddress)
external
override
initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
ERC20Upgradeable.__ERC20_init("ERC20 Ether Clone", "ETHC");
ERC20BurnableUpgradeable.__ERC20Burnable_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(MINTER_ROLE, tokenManagerEthAddress);
_setupRole(BURNER_ROLE, tokenManagerEthAddress);
}
}
exec
/bin/bash -lc "sed -n '1,220p' contracts/schain/DefaultAddresses.sol" in /tmp/codex-wul8xs7h
succeeded in 0ms:
// SPDX-License-Identifier: AGPL-3.0-only
/**
* DefaultAddresses.sol - SKALE Interchain Messaging Agent
* Copyright (C) 2022-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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
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));
}
exec
/bin/bash -lc "sed -n '1,220p' contracts/schain/KeyStorage.sol" in /tmp/codex-wul8xs7h
succeeded in 0ms:
// SPDX-License-Identifier: AGPL-3.0-only
/**
* MessageProxyForSchain.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 <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.27;
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import "@skalenetwork/ima-interfaces/schain/IKeyStorage.sol";
import "./bls/FieldOperations.sol";
/**
* @title KeyStorage
* @dev Holds common BLS public key.
*/
contract KeyStorage is IKeyStorage, AccessControlEnumerableUpgradeable {
uint256 public constant FREE_MEM_PTR = 0x40;
/**
* @dev Address of custom precompiled contract on SKALE chain
* to get uin256 value from the config.
*/
uint256 public constant FN_NUM_GET_CONFIG_VARIABLE_UINT256 = 0x13;
/**
* @dev Address of custom precompiled contract on SKALE chain
* to get current BLS public key.
*/
uint256 public constant FN_NUM_GET_CURRENT_BLS_PUBLIC_KEY = 0x19;
/**
* @dev Is called once during contract deployment.
*/
function initialize()
external
override
initializer
{
AccessControlEnumerableUpgradeable.__AccessControlEnumerable_init();
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
* @dev Get BLS common public key.
*/
function getBlsCommonPublicKey() external view override virtual returns (IFieldOperations.G2Point memory) {
return _getCurrentBLSPublicKey();
}
// private
/**
* @dev Get uint256 value from the skaled config.
*/
function _getConfigVariableUint256(
string memory strConfigVariableName
)
private
view
returns ( uint256 rv )
{
uint256 fmp = FREE_MEM_PTR;
uint256 blocks = (bytes(strConfigVariableName).length + 31) / 32 + 1;
bool success;
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(fmp)
for { let i := 0 } lt( i, blocks ) { i := add(1, i) } {
let where := add(ptr, mul(32, i))
let what := mload(add(strConfigVariableName, mul(32, i)))
mstore(where, what)
}
success := staticcall(not(0), FN_NUM_GET_CONFIG_VARIABLE_UINT256, ptr, mul( blocks, 32 ), ptr, 32)
rv := mload(ptr)
}
require(success, "Get config uint256 failed");
}
/**
* @dev Get current BLS public key the skaled.
*/
function _getCurrentBLSPublicKey()
private
view
returns ( IFieldOperations.G2Point memory pk )
{
uint256 fmp = FREE_MEM_PTR;
bool success;
uint xa;
uint xb;
uint ya;
uint yb;
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(fmp)
success := staticcall(not(0), FN_NUM_GET_CURRENT_BLS_PUBLIC_KEY, ptr, 0, ptr, 128)
xa := mload(ptr)
xb := mload(add(ptr, 32))
ya := mload(add(ptr, 64))
yb := mload(add(ptr, 96))
}
pk.x.a = xa;
pk.x.b = xb;
pk.y.a = ya;
pk.y.b = yb;
require(success, "Get current BLS public key failed");
}
}
exec
/bin/bash -lc "rg -n \"TODO|signature is not verified|verifySignature|setGasPrice|TODO: uncomment|tx.gasprice|getApproved\\(|isApprovedForAll\\(|allowance\\(|transferFrom\\(|sendValue\\(|delegatecall|call\\{|try this\\.doTransfer|messageInProgress\" contracts -g '"'!contracts/test/**'"'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
contracts/mainnet/CommunityPool.sol:114: uint amount = tx.gasprice * gas;
contracts/mainnet/CommunityPool.sol:127: node.sendValue(amount);
contracts/mainnet/CommunityPool.sol:128: return (tx.gasprice * gas - amount) / tx.gasprice;
contracts/mainnet/CommunityPool.sol:190: require(!messageProxy.messageInProgress(), "Message is in progress");
contracts/mainnet/CommunityPool.sol:203: payable(msg.sender).sendValue(amount);
contracts/mainnet/CommunityPool.sol:267: require(tx.gasprice != 0, "Gas price is not set");
contracts/mainnet/CommunityPool.sol:279: return delta + _userWallets[receiver][schainHash] >= minTransactionGas * tx.gasprice;
contracts/mainnet/CommunityPool.sol:283: return minTransactionGas * tx.gasprice * multiplierNumerator / multiplierDivider;
contracts/mainnet/MessageProxyForMainnet.sol:82: bool public override messageInProgress;
contracts/mainnet/MessageProxyForMainnet.sol:141: modifier messageInProgressLocker() {
contracts/mainnet/MessageProxyForMainnet.sol:142: require(!messageInProgress, "Message is in progress");
contracts/mainnet/MessageProxyForMainnet.sol:143: messageInProgress = true;
contracts/mainnet/MessageProxyForMainnet.sol:145: messageInProgress = false;
contracts/mainnet/MessageProxyForMainnet.sol:291: messageInProgressLocker
contracts/mainnet/MessageProxyForMainnet.sol:539: ).getSchainBalance(SchainHash.unwrap(schainHash)) >= (MESSAGES_LENGTH + 1) * gasLimit * tx.gasprice;
contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:375: IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)),
contracts/mainnet/DepositBoxes/DepositBoxERC1155.sol:418: IERC1155Upgradeable(erc1155OnMainnet).isApprovedForAll(msg.sender, address(this)),
contracts/schain/MessageProxyForSchain.sol:107: bool public override messageInProgress;
contracts/schain/MessageProxyForSchain.sol:126: modifier messageInProgressLocker() {
contracts/schain/MessageProxyForSchain.sol:127: require(!messageInProgress, "Message is in progress");
contracts/schain/MessageProxyForSchain.sol:128: messageInProgress = true;
contracts/schain/MessageProxyForSchain.sol:130: messageInProgress = false;
contracts/schain/MessageProxyForSchain.sol:212: messageInProgressLocker
contracts/schain/MessageProxyForSchain.sol:282: function verifySignature(bytes32 hashedMessage, MessageProxyForSchain.Signature calldata signature)
contracts/schain/MessageProxyForSchain.sol:420: uint balance = msg.sender.balance + gasleft() * tx.gasprice;
contracts/mainnet/DepositBoxes/DepositBoxERC721WithMetadata.sol:67: IERC721Upgradeable(message.erc721message.token).transferFrom(
contracts/extensions/ERC721ReferenceMintAndMetadataMainnet.sol:82: ERC721OnChain(erc721ContractOnMainnet).transferFrom(address(this), to, tokenId);
contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:36: function transferFrom(address _from, address _to, uint256 _amount) external;
contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:695: IERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount,
contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:734: try this.doTransfer(transfer.token, transfer.receiver, transfer.amount) {
contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol:57: ERC721OnChain(erc721ContractOnSchain).getApproved(tokenId) == address(this),
contracts/extensions/ERC721ReferenceMintAndMetadataSchain.sol:60: ERC721OnChain(erc721ContractOnSchain).transferFrom(msg.sender, address(this), tokenId);
contracts/schain/CommunityLocker.sol:252: function setGasPrice(
contracts/schain/CommunityLocker.sol:262: // TODO: uncomment when oracle finished
contracts/schain/CommunityLocker.sol:264: // messageProxy.verifySignature(keccak256(abi.encodePacked(gasPrice, timestamp)), signature),
contracts/mainnet/DepositBoxes/DepositBoxEth.sol:100: payable(message.receiver).sendValue(message.amount);
contracts/mainnet/DepositBoxes/DepositBoxEth.sol:116: payable(msg.sender).sendValue(amount);
contracts/mainnet/DepositBoxes/DepositBoxEth.sol:139: receiver.sendValue(amount);
contracts/schain/TokenManagerLinker.sol:176: // TODO: optimize algorithm to save gas
contracts/schain/TokenManagers/TokenManagerERC20.sol:333: contractOnSchain.allowance(
contracts/schain/TokenManagers/TokenManagerERC20.sol:350: contractOnSchain.transferFrom(msg.sender, address(this), amount),
contracts/schain/TokenManagers/TokenManagerERC20.sol:355: contractOnSchain.transferFrom(msg.sender, address(this), amount),
contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:108: IERC721Upgradeable(message.token).transferFrom(address(this), message.receiver, message.tokenId);
contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:150: IERC721Upgradeable(erc721OnMainnet).transferFrom(address(this), receiver, tokenId);
contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:246: IERC721Upgradeable(erc721OnMainnet).getApproved(tokenId) == address(this),
contracts/mainnet/DepositBoxes/DepositBoxERC721.sol:256: IERC721Upgradeable(erc721OnMainnet).transferFrom(msg.sender, address(this), tokenId);
contracts/schain/TokenManagers/TokenManagerERC721.sol:247: IERC721Upgradeable(token).transferFrom(address(this), receiver, tokenId);
contracts/schain/TokenManagers/TokenManagerERC721.sol:335: require(contractOnSchain.getApproved(tokenId) == address(this), "Not allowed ERC721 Token");
contracts/schain/TokenManagers/TokenManagerERC721.sol:346: contractOnSchain.transferFrom(msg.sender, address(this), tokenId);
contracts/schain/TokenManagers/TokenManagerERC721.sol:348: contractOnSchain.transferFrom(msg.sender, address(this), tokenId);
contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol:117: IERC721Upgradeable(token).transferFrom(address(this), receiver, tokenId);
contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol:148: require(contractOnSchain.getApproved(tokenId) == address(this), "Not allowed ERC721 Token");
contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol:164: contractOnSchain.transferFrom(msg.sender, address(this), tokenId);
contracts/schain/TokenManagers/TokenManagerERC721WithMetadata.sol:166: contractOnSchain.transferFrom(msg.sender, address(this), tokenId);
contracts/schain/TokenManagers/TokenManagerERC1155.sol:439: require(contractOnSchain.isApprovedForAll(msg.sender, address(this)), "Not allowed ERC1155 Token");
contracts/schain/TokenManagers/TokenManagerERC1155.sol:484: require(contractOnSchain.isApprovedForAll(msg.sender, address(this)), "Not allowed ERC1155 Token");
exec
/bin/bash -lc "rg -n \"reentr|overflow|underflow|unchecked|TODO|HACK|XXX|FIXME|slither-disable-next-line reentrancy\" contracts -g '"'!contracts/test/**'"'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:308: // need to restrict big delays to avoid overflow
contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:331: // need to restrict big delays to avoid overflow
contracts/schain/CommunityLocker.sol:262: // TODO: uncomment when oracle finished
contracts/schain/TokenManagerLinker.sol:176: // TODO: optimize algorithm to save gas
web search:
web search: site:etherscan.io/address "0x588801ca36558310d91234afc2511502282b1621"
exec
/bin/bash -lc "rg -n \"mainnetGasPrice|gasPriceTimestamp|setGasPrice\\(\" contracts -g '"'!contracts/test/**'"'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
contracts/schain/CommunityLocker.sol:100: uint256 public mainnetGasPrice;
contracts/schain/CommunityLocker.sol:105: uint256 public gasPriceTimestamp;
contracts/schain/CommunityLocker.sol:244: * @dev Set value of {mainnetGasPrice}.
contracts/schain/CommunityLocker.sol:252: function setGasPrice(
contracts/schain/CommunityLocker.sol:260: require(timestamp > gasPriceTimestamp, "Gas price timestamp already updated");
contracts/schain/CommunityLocker.sol:269: mainnetGasPrice,
contracts/schain/CommunityLocker.sol:272: mainnetGasPrice = gasPrice;
contracts/schain/CommunityLocker.sol:273: gasPriceTimestamp = timestamp;
exec
/bin/bash -lc 'rg -n "DelayedTransfer|TransferDelayed|retrieveFor|escalate|validateTransfer|rejectTransfer|setGasPrice|approveTransfers|activeEthTransfers" contracts/test AUDIT_BUNDLE.txt' in /tmp/codex-wul8xs7h
succeeded in 0ms:
AUDIT_BUNDLE.txt:493: function escalate(uint256 transferId) external;
AUDIT_BUNDLE.txt:501: function rejectTransfer(uint transferId) external;
AUDIT_BUNDLE.txt:503: function retrieveFor(address receiver) external;
AUDIT_BUNDLE.txt:509: function validateTransfer(uint transferId) external;
AUDIT_BUNDLE.txt:931: function setGasPrice(
AUDIT_BUNDLE.txt:4691: enum DelayedTransferStatus {
AUDIT_BUNDLE.txt:4697: struct DelayedTransfer {
AUDIT_BUNDLE.txt:4703: DelayedTransferStatus status;
AUDIT_BUNDLE.txt:4735: /// @custom:oz-retyped-from mapping(uint256 => struct DepositBoxERC20.DelayedTransfer)
AUDIT_BUNDLE.txt:4736: mapping(uint256 => DelayedTransfer) public delayedTransfers;
AUDIT_BUNDLE.txt:4751: event TransferDelayed(uint256 id, address receiver, address token, uint256 amount);
AUDIT_BUNDLE.txt:4849: _createDelayedTransfer(schainHash, message, delay);
AUDIT_BUNDLE.txt:5018: retrieveFor(msg.sender);
AUDIT_BUNDLE.txt:5029: function escalate(uint256 transferId) external override {
AUDIT_BUNDLE.txt:5035: require(delayedTransfers[transferId].status == DelayedTransferStatus.DELAYED, "The transfer has to be delayed");
AUDIT_BUNDLE.txt:5036: delayedTransfers[transferId].status = DelayedTransferStatus.ARBITRAGE;
AUDIT_BUNDLE.txt:5052: function validateTransfer(
AUDIT_BUNDLE.txt:5059: DelayedTransfer storage transfer = delayedTransfers[transferId];
AUDIT_BUNDLE.txt:5060: require(transfer.status == DelayedTransferStatus.ARBITRAGE, "Arbitrage has to be active");
AUDIT_BUNDLE.txt:5061: transfer.status = DelayedTransferStatus.COMPLETED;
AUDIT_BUNDLE.txt:5074: function rejectTransfer(
AUDIT_BUNDLE.txt:5081: DelayedTransfer storage transfer = delayedTransfers[transferId];
AUDIT_BUNDLE.txt:5082: require(transfer.status == DelayedTransferStatus.ARBITRAGE, "Arbitrage has to be active");
AUDIT_BUNDLE.txt:5083: transfer.status = DelayedTransferStatus.COMPLETED;
AUDIT_BUNDLE.txt:5170: DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
AUDIT_BUNDLE.txt:5171: DelayedTransferStatus status = transfer.status;
AUDIT_BUNDLE.txt:5173: if (status == DelayedTransferStatus.DELAYED || status == DelayedTransferStatus.ARBITRAGE) {
AUDIT_BUNDLE.txt:5195: DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
AUDIT_BUNDLE.txt:5196: DelayedTransferStatus status = transfer.status;
AUDIT_BUNDLE.txt:5198: if (status != DelayedTransferStatus.COMPLETED) {
AUDIT_BUNDLE.txt:5201: if (status == DelayedTransferStatus.DELAYED) {
AUDIT_BUNDLE.txt:5246: function retrieveFor(address receiver) public override {
AUDIT_BUNDLE.txt:5254: DelayedTransfer[] memory transfers = new DelayedTransfer[](transfersAmount);
AUDIT_BUNDLE.txt:5258: DelayedTransfer memory transfer = delayedTransfers[transferId];
AUDIT_BUNDLE.txt:5259: if (transfer.status != DelayedTransferStatus.COMPLETED) {
AUDIT_BUNDLE.txt:5264: if (transfer.status == DelayedTransferStatus.DELAYED) {
AUDIT_BUNDLE.txt:5270: _removeOldestDelayedTransfer(receiver);
AUDIT_BUNDLE.txt:5272: delayedTransfers[transferId].status = DelayedTransferStatus.COMPLETED;
AUDIT_BUNDLE.txt:5283: _removeOldestDelayedTransfer(receiver);
AUDIT_BUNDLE.txt:5363: DelayedTransfer[] memory transfers,
AUDIT_BUNDLE.txt:5370: DelayedTransfer memory transfer = transfers[i];
AUDIT_BUNDLE.txt:5496: * Create instance of DelayedTransfer and initialize all auxiliary fields.
AUDIT_BUNDLE.txt:5498: function _createDelayedTransfer(
AUDIT_BUNDLE.txt:5506: delayedTransfers[delayId] = DelayedTransfer({
AUDIT_BUNDLE.txt:5512: status: DelayedTransferStatus.DELAYED
AUDIT_BUNDLE.txt:5515: emit TransferDelayed(delayId, message.receiver, message.token, message.amount);
AUDIT_BUNDLE.txt:5519: * Remove instance of DelayedTransfer and clean auxiliary fields.
AUDIT_BUNDLE.txt:5521: function _removeOldestDelayedTransfer(address receiver) private {
AUDIT_BUNDLE.txt:6103: mapping(address => uint256) public approveTransfers;
AUDIT_BUNDLE.txt:6109: mapping(SchainHash => bool) public activeEthTransfers;
AUDIT_BUNDLE.txt:6160: if (!activeEthTransfers[schainHash]) {
AUDIT_BUNDLE.txt:6161: approveTransfers[message.receiver] += message.amount;
AUDIT_BUNDLE.txt:6176: require(approveTransfers[msg.sender] > 0, "User has insufficient ETH");
AUDIT_BUNDLE.txt:6177: uint256 amount = approveTransfers[msg.sender];
AUDIT_BUNDLE.txt:6178: approveTransfers[msg.sender] = 0;
AUDIT_BUNDLE.txt:6220: require(!activeEthTransfers[schainHash], "Active eth transfers enabled");
AUDIT_BUNDLE.txt:6222: activeEthTransfers[schainHash] = true;
AUDIT_BUNDLE.txt:6240: require(activeEthTransfers[schainHash], "Active eth transfers disabled");
AUDIT_BUNDLE.txt:6242: activeEthTransfers[schainHash] = false;
AUDIT_BUNDLE.txt:7572: function setGasPrice(
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '684,712p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
684 address receiver
685 )
686 public
687 override
688 rightTransaction(schainName, receiver)
689 whenNotKilled(_schainHash(schainName))
690 {
691 SchainHash schainHash = _schainHash(schainName);
692 address contractReceiver = schainLinks[schainHash];
693 require(contractReceiver != address(0), "Unconnected chain");
694 require(
695 IERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount,
696 "DepositBox was not approved for ERC20 token"
697 );
698 bytes memory data = _receiveERC20(
699 schainName,
700 erc20OnMainnet,
701 receiver,
702 amount
703 );
704 _saveTransferredAmount(schainHash, erc20OnMainnet, amount);
705 IERC20MetadataUpgradeable(erc20OnMainnet).safeTransferFrom(msg.sender, address(this), amount);
706 messageProxy.postOutgoingMessage(
707 schainHash,
708 contractReceiver,
709 data
710 );
711 }
712
exec
/bin/bash -lc "nl -ba contracts/schain/TokenManagers/TokenManagerERC20.sol | sed -n '338,356p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
338 );
339 bytes memory data = Messages.encodeTransferErc20Message(address(contractOnMainChain), to, amount);
340 if (isMainChainToken) {
341 require(chainHash != MAINNET_HASH, "Main chain token could not be transferred to Mainnet");
342 data = _receiveERC20(
343 chainHash,
344 address(contractOnSchain),
345 to,
346 amount
347 );
348 _saveTransferredAmount(chainHash, address(contractOnSchain), amount);
349 require(
350 contractOnSchain.transferFrom(msg.sender, address(this), amount),
351 "Transfer was failed"
352 );
353 } else {
354 require(
355 contractOnSchain.transferFrom(msg.sender, address(this), amount),
356 "Transfer was failed"
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '525,592p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
525 }
526
527 /**
528 * @dev Get amount of tokens that are delayed for specified receiver
529 */
530 function getDelayedAmount(address receiver, address token) external view override returns (uint256 value) {
531 uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
532 for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
533 DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
534 DelayedTransferStatus status = transfer.status;
535 if (transfer.token == token) {
536 if (status == DelayedTransferStatus.DELAYED || status == DelayedTransferStatus.ARBITRAGE) {
537 value += transfer.amount;
538 }
539 }
540 }
541 }
542
543 /**
544 * @dev Get timestamp of next unlock of tokens that are delayed for specified receiver
545 */
546 function getNextUnlockTimestamp(
547 address receiver,
548 address token
549 )
550 external
551 view
552 override
553 returns (uint256 unlockTimestamp)
554 {
555 uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
556 unlockTimestamp = type(uint256).max;
557 for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
558 DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
559 DelayedTransferStatus status = transfer.status;
560 if (transfer.token == token) {
561 if (status != DelayedTransferStatus.COMPLETED) {
562 unlockTimestamp = MathUpgradeable.min(unlockTimestamp, transfer.untilTimestamp);
563 }
564 if (status == DelayedTransferStatus.DELAYED) {
565 break;
566 }
567 }
568 }
569 }
570
571 /**
572 * @dev Get amount of addresses that are added to the whitelist
573 */
574 function getTrustedReceiversAmount(SchainHash schainHash) external view override returns (uint256) {
575 return _delayConfig[schainHash].trustedReceivers.length();
576 }
577
578 /**
579 * @dev Get i-th address of the whitelist
580 */
581 function getTrustedReceiver(string calldata schainName, uint256 index) external view override returns (address) {
582 return _delayConfig[_schainHash(schainName)].trustedReceivers.at(index);
583 }
584
585 /**
586 * @dev Get amount of tokens that are considered as a big transfer
587 */
588 function getBigTransferThreshold(SchainHash schainHash, address token) external view override returns (uint256) {
589 return _delayConfig[schainHash].bigTransferThreshold[token];
590 }
591
592 /**
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '742,786p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
742 /**
743 * @dev Saves amount of tokens that was transferred to schain.
744 */
745 function _saveTransferredAmount(SchainHash schainHash, address erc20Token, uint256 amount) private {
746 transferredAmount[schainHash][erc20Token] += amount;
747 }
748
749 /**
750 * @dev Removes amount of tokens that was transferred from schain.
751 */
752 function _removeTransferredAmount(SchainHash schainHash, address erc20Token, uint256 amount) private {
753 transferredAmount[schainHash][erc20Token] -= amount;
754 }
755
756 /**
757 * @dev Allows DepositBoxERC20 to receive ERC20 tokens.
758 *
759 * Emits an {ERC20TokenReady} event.
760 *
761 * Requirements:
762 *
763 * - Amount must be less than or equal to the total supply of the ERC20 contract.
764 * - Whitelist should be turned off for auto adding tokens to DepositBoxERC20.
765 */
766 function _receiveERC20(
767 string calldata schainName,
768 address erc20OnMainnet,
769 address to,
770 uint256 amount
771 )
772 private
773 returns (bytes memory data)
774 {
775 SchainHash schainHash = _schainHash(schainName);
776 IERC20MetadataUpgradeable erc20 = IERC20MetadataUpgradeable(erc20OnMainnet);
777 uint256 totalSupply = erc20.totalSupply();
778 require(amount <= totalSupply, "Amount is incorrect");
779 bool isERC20AddedToSchain = _schainToERC20[schainHash].contains(erc20OnMainnet);
780 if (!isERC20AddedToSchain) {
781 require(!isWhitelisted(schainName), "Whitelist is enabled");
782 _addERC20ForSchain(schainName, erc20OnMainnet);
783 data = Messages.encodeTransferErc20AndTokenInfoMessage(
784 erc20OnMainnet,
785 to,
786 amount,
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '544,568p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
544 * @dev Get timestamp of next unlock of tokens that are delayed for specified receiver
545 */
546 function getNextUnlockTimestamp(
547 address receiver,
548 address token
549 )
550 external
551 view
552 override
553 returns (uint256 unlockTimestamp)
554 {
555 uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
556 unlockTimestamp = type(uint256).max;
557 for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
558 DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
559 DelayedTransferStatus status = transfer.status;
560 if (transfer.token == token) {
561 if (status != DelayedTransferStatus.COMPLETED) {
562 unlockTimestamp = MathUpgradeable.min(unlockTimestamp, transfer.untilTimestamp);
563 }
564 if (status == DelayedTransferStatus.DELAYED) {
565 break;
566 }
567 }
568 }
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '524,542p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
524 }
525 }
526
527 /**
528 * @dev Get amount of tokens that are delayed for specified receiver
529 */
530 function getDelayedAmount(address receiver, address token) external view override returns (uint256 value) {
531 uint256 delayedTransfersAmount = delayedTransfersByReceiver[receiver].length();
532 for (uint256 i = 0; i < delayedTransfersAmount; ++i) {
533 DelayedTransfer storage transfer = delayedTransfers[uint256(delayedTransfersByReceiver[receiver].at(i))];
534 DelayedTransferStatus status = transfer.status;
535 if (transfer.token == token) {
536 if (status == DelayedTransferStatus.DELAYED || status == DelayedTransferStatus.ARBITRAGE) {
537 value += transfer.amount;
538 }
539 }
540 }
541 }
542
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '612,666p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
612 _QUEUE_PROCESSING_LIMIT
613 );
614 uint256 currentIndex = 0;
615 bool retrieved = false;
616 uint256 countToTransfer = 0;
617 DelayedTransfer[] memory transfers = new DelayedTransfer[](transfersAmount);
618 uint256[] memory transfersIds = new uint256[](transfersAmount);
619 for (uint256 i = 0; i < transfersAmount; ++i) {
620 uint256 transferId = uint256(delayedTransfersByReceiver[receiver].at(currentIndex++));
621 DelayedTransfer memory transfer = delayedTransfers[transferId];
622 if (transfer.status != DelayedTransferStatus.COMPLETED) {
623 if (block.timestamp < transfer.untilTimestamp) {
624 // disable detector until slither fixes false positive
625 // https://github.com/crytic/slither/issues/778
626 // slither-disable-next-line incorrect-equality
627 if (transfer.status == DelayedTransferStatus.DELAYED) {
628 break;
629 } // else status is ARBITRAGE -> continue
630 } else { // it's time to unlock
631 if (currentIndex == 1) {
632 --currentIndex;
633 _removeOldestDelayedTransfer(receiver);
634 } else {
635 delayedTransfers[transferId].status = DelayedTransferStatus.COMPLETED;
636 }
637 retrieved = true;
638 transfers[countToTransfer] = transfer;
639 transfersIds[countToTransfer] = transferId;
640 ++countToTransfer;
641 }
642 } else { // status is COMPLETED
643 if (currentIndex == 1) {
644 --currentIndex;
645 retrieved = true;
646 _removeOldestDelayedTransfer(receiver);
647 }
648 }
649 }
650 require(retrieved, "There are no transfers available for retrieving");
651 _doNTransfers(transfers, transfersIds, countToTransfer);
652 }
653
654 /**
655 * @dev Creates a new DepositBoxERC20 contract.
656 */
657 function initialize(
658 IContractManager contractManagerOfSkaleManagerValue,
659 ILinker linkerValue,
660 IMessageProxyForMainnet messageProxyValue
661 )
662 public
663 override(DepositBox, IDepositBox)
664 initializer
665 {
666 DepositBox.initialize(contractManagerOfSkaleManagerValue, linkerValue, messageProxyValue);
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '835,879p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
835 * the element is added at back - depthLimit index
836 */
837 function _addToDelayedQueueWithPriority(
838 DoubleEndedQueueUpgradeable.Bytes32Deque storage queue,
839 uint256 id,
840 uint256 until,
841 uint256 depthLimit
842 )
843 private
844 {
845 if (depthLimit == 0 || queue.empty()) {
846 queue.pushBack(bytes32(id));
847 } else {
848 if (delayedTransfers[uint256(queue.back())].untilTimestamp <= until) {
849 queue.pushBack(bytes32(id));
850 } else {
851 bytes32 lowPriorityValue = queue.popBack();
852 _addToDelayedQueueWithPriority(queue, id, until, depthLimit - 1);
853 queue.pushBack(lowPriorityValue);
854 }
855 }
856 }
857
858 /**
859 * Create instance of DelayedTransfer and initialize all auxiliary fields.
860 */
861 function _createDelayedTransfer(
862 SchainHash schainHash,
863 Messages.TransferErc20Message memory message,
864 uint256 delay
865 )
866 private
867 {
868 uint256 delayId = delayedTransfersSize++;
869 delayedTransfers[delayId] = DelayedTransfer({
870 receiver: message.receiver,
871 schainHash: schainHash,
872 token: message.token,
873 amount: message.amount,
874 untilTimestamp: block.timestamp + delay,
875 status: DelayedTransferStatus.DELAYED
876 });
877 _addToDelayedQueue(message.receiver, delayId, block.timestamp + delay);
878 emit TransferDelayed(delayId, message.receiver, message.token, message.amount);
879 }
exec
/bin/bash -lc "nl -ba contracts/mainnet/Linker.sol | sed -n '88,136p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
88 *
89 * - Numbers of mainnet contracts and schain contracts must be equal.
90 * - Mainnet contract must implement method `addSchainContract`.
91 */
92 function connectSchain(
93 string calldata schainName,
94 address[] calldata schainContracts
95 )
96 external
97 override
98 onlyLinker
99 {
100 require(schainContracts.length == _mainnetContracts.length(), "Incorrect number of addresses");
101 for (uint i = 0; i < schainContracts.length; i++) {
102 Twin(_mainnetContracts.at(i)).addSchainContract(schainName, schainContracts[i]);
103 }
104 messageProxy.addConnectedChain(schainName);
105 }
106
107 /**
108 * @dev Allows Schain owner and contract deployer to kill schain.
109 * To kill the schain, both entities must call this function, and the order is not important.
110 *
111 * Requirements:
112 *
113 * - Interchain connection should be turned off.
114 */
115 function kill(string calldata schainName) override external {
116 SchainHash schainHash = _schainHash(schainName);
117 if (statuses[schainHash] == KillProcess.NotKilled) {
118 if (hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {
119 statuses[schainHash] = KillProcess.PartiallyKilledByContractOwner;
120 } else if (isSchainOwner(msg.sender, schainHash)) {
121 statuses[schainHash] = KillProcess.PartiallyKilledBySchainOwner;
122 } else {
123 revert("Not allowed");
124 }
125 } else if (
126 (
127 statuses[schainHash] == KillProcess.PartiallyKilledBySchainOwner &&
128 hasRole(DEFAULT_ADMIN_ROLE, msg.sender)
129 ) || (
130 statuses[schainHash] == KillProcess.PartiallyKilledByContractOwner &&
131 isSchainOwner(msg.sender, schainHash)
132 )
133 ) {
134 statuses[schainHash] = KillProcess.Killed;
135 } else {
136 revert("Already killed or incorrect sender");
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '274,295p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
274 )
275 external
276 override
277 onlySchainOwner(schainName)
278 {
279 SchainHash schainHash = _schainHash(schainName);
280 emit BigTransferThresholdIsChanged(
281 schainHash,
282 token,
283 _delayConfig[schainHash].bigTransferThreshold[token],
284 value
285 );
286 _delayConfig[schainHash].bigTransferThreshold[token] = value;
287 }
288
289 /**
290 * @dev Set a time delay.
291 * If amount of tokens that exits IMA is bigger than a threshold
292 * the transfer is delayed for set amount of time
293 * and can be canceled by a voting
294 *
295 * Requirements:
exec
/bin/bash -lc "nl -ba contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | sed -n '228,270p'" in /tmp/codex-wul8xs7h
succeeded in 0ms:
228 function addERC20TokenByOwner(string calldata schainName, address erc20OnMainnet)
229 external
230 override
231 onlySchainOwner(schainName)
232 whenNotKilled(_schainHash(schainName))
233 {
234 _addERC20ForSchain(schainName, erc20OnMainnet);
235 }
236
237 /**
238 * @dev Allows Schain owner to return each user their tokens.
239 * The Schain owner decides which tokens to send to which address,
240 * since the contract on mainnet does not store information about which tokens belong to whom.
241 *
242 * Requirements:
243 *
244 * - Amount of tokens on schain should be equal or more than transferred amount.
245 * - msg.sender should be an owner of schain
246 * - IMA transfers Mainnet <-> schain should be killed
247 */
248 function getFunds(string calldata schainName, address erc20OnMainnet, address receiver, uint amount)
249 external
250 override
251 onlySchainOwner(schainName)
252 whenKilled(_schainHash(schainName))
253 {
254 SchainHash schainHash = _schainHash(schainName);
255 require(transferredAmount[schainHash][erc20OnMainnet] >= amount, "Incorrect amount");
256 _removeTransferredAmount(schainHash, erc20OnMainnet, amount);
257 IERC20MetadataUpgradeable(erc20OnMainnet).safeTransfer(receiver, amount);
258 }
259
260 /**
261 * @dev Set a threshold amount of tokens.
262 * If amount of tokens that exits IMA is bigger than the threshold
263 * the transfer is delayed for configurable amount of time
264 * and can be canceled by a voting
265 *
266 * Requirements:
267 *
268 * - msg.sender should be an owner of schain
269 */
270 function setBigTransferValue(
codex
{"no_findings":false,"summary":"Fee-on-transfer ERC20s are accounted at the requested amount instead of the amount actually received, which can overmint wrapped balances and drain bridge collateral.","findings":[{"severity":"high","category":"other","title":"Fee-on-transfer ERC20s can overmint bridge balances and drain pooled collateral","exploit_scenario":"An attacker bridges a deflationary ERC20 that burns or taxes 10% on transfer. `DepositBoxERC20.depositERC20Direct` records and forwards `amount=100` to the destination chain, then calls `safeTransferFrom` once without checking how many tokens actually arrived. Only 90 tokens reach the box, but 100 wrapped tokens are minted on the schain. The attacker can later exit the full 100 back to mainnet (or another schain), extracting the 10-token shortfall from liquidity supplied by honest users. The same invariant break exists in schain-to-schain transfers of main-chain ERC20s, where `TokenManagerERC20` escrows `amount` before verifying the real balance delta.","recommendation":"Measure balance deltas before and after each ERC20 transfer and use the actual received amount for `transferredAmount` accounting and for the bridged message payload. Reject tokens whose received amount is smaller than the requested amount if exact-amount semantics are required.","evidence":"`DepositBoxERC20.depositERC20Direct` builds the outgoing message and increments `transferredAmount` using the caller-supplied `amount`, then performs a single `safeTransferFrom` without comparing pre/post balances. `TokenManagerERC20._exit` mirrors this pattern for schain-to-schain escrow of main-chain tokens by saving `amount` before `transferFrom` and never validating the received balance.","locations":["contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:691","contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:704","contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:705","contracts/schain/TokenManagers/TokenManagerERC20.sol:340","contracts/schain/TokenManagers/TokenManagerERC20.sol:348","contracts/schain/TokenManagers/TokenManagerERC20.sol:350"]}]}
tokens used
168,153
{
"codex": {
"ran_at": "2026-04-04T03:44:21.688682+00:00",
"returncode": 0
},
"project": {
"mode": "source",
"file_count": 143,
"import_count": 168,
"first_party_contracts_count": 105
},
"summary": "Fee-on-transfer ERC20s are accounted at the requested amount instead of the amount actually received, which can overmint wrapped balances and drain bridge collateral.",
"raw_final": {
"summary": "Fee-on-transfer ERC20s are accounted at the requested amount instead of the amount actually received, which can overmint wrapped balances and drain bridge collateral.",
"findings": [
{
"title": "Fee-on-transfer ERC20s can overmint bridge balances and drain pooled collateral",
"category": "other",
"evidence": "`DepositBoxERC20.depositERC20Direct` builds the outgoing message and increments `transferredAmount` using the caller-supplied `amount`, then performs a single `safeTransferFrom` without comparing pre/post balances. `TokenManagerERC20._exit` mirrors this pattern for schain-to-schain escrow of main-chain tokens by saving `amount` before `transferFrom` and never validating the received balance.",
"severity": "high",
"locations": [
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:691",
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:704",
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:705",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:340",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:348",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:350"
],
"recommendation": "Measure balance deltas before and after each ERC20 transfer and use the actual received amount for `transferredAmount` accounting and for the bridged message payload. Reject tokens whose received amount is smaller than the requested amount if exact-amount semantics are required.",
"exploit_scenario": "An attacker bridges a deflationary ERC20 that burns or taxes 10% on transfer. `DepositBoxERC20.depositERC20Direct` records and forwards `amount=100` to the destination chain, then calls `safeTransferFrom` once without checking how many tokens actually arrived. Only 90 tokens reach the box, but 100 wrapped tokens are minted on the schain. The attacker can later exit the full 100 back to mainnet (or another schain), extracting the 10-token shortfall from liquidity supplied by honest users. The same invariant break exists in schain-to-schain transfers of main-chain ERC20s, where `TokenManagerERC20` escrows `amount` before verifying the real balance delta."
}
],
"no_findings": false
},
"no_findings": false,
"proxy_context": {
"proxy_run_id": "019d5666-7210-72a7-9067-e58ac94c06d2",
"proxy_address": "0x588801ca36558310d91234afc2511502282b1621",
"implementation_run_id": "019d5666-e916-7246-acfd-c2f7d6ef4d74",
"implementation_address": "0x29353f77c6b0d3772d73e708cc8e1fca08c80c11"
},
"schema_version": 1
}
00000000: PUSH1 0x80 00000002: PUSH1 0x40 00000004: MSTORE 00000005: PUSH1 0x04 00000007: CALLDATASIZE 00000008: LT 00000009: PUSH2 0x004e 0000000c: JUMPI 0000000d: PUSH1 0x00 0000000f: CALLDATALOAD 00000010: PUSH1 0xe0 00000012: SHR 00000013: DUP1 00000014: PUSH4 0x3659cfe6 00000019: EQ 0000001a: PUSH2 0x0065 0000001d: JUMPI 0000001e: DUP1 0000001f: PUSH4 0x4f1ef286 00000024: EQ 00000025: PUSH2 0x0085 00000028: JUMPI 00000029: DUP1 0000002a: PUSH4 0x5c60da1b 0000002f: EQ 00000030: PUSH2 0x0098 00000033: JUMPI 00000034: DUP1 00000035: PUSH4 0x8f283970 0000003a: EQ 0000003b: PUSH2 0x00c9 0000003e: JUMPI 0000003f: DUP1 00000040: PUSH4 0xf851a440 00000045: EQ 00000046: PUSH2 0x00e9 00000049: JUMPI 0000004a: PUSH2 0x005d 0000004d: JUMP 0000004e: JUMPDEST 0000004f: CALLDATASIZE 00000050: PUSH2 0x005d 00000053: JUMPI 00000054: PUSH2 0x005b 00000057: PUSH2 0x00fe 0000005a: JUMP 0000005b: JUMPDEST 0000005c: STOP 0000005d: JUMPDEST 0000005e: PUSH2 0x005b 00000061: PUSH2 0x00fe 00000064: JUMP 00000065: JUMPDEST 00000066: CALLVALUE 00000067: DUP1 00000068: ISZERO 00000069: PUSH2 0x0071 0000006c: JUMPI 0000006d: PUSH1 0x00 0000006f: DUP1 00000070: REVERT 00000071: JUMPDEST 00000072: POP 00000073: PUSH2 0x005b 00000076: PUSH2 0x0080 00000079: CALLDATASIZE 0000007a: PUSH1 0x04 0000007c: PUSH2 0x06ed 0000007f: JUMP 00000080: JUMPDEST 00000081: PUSH2 0x0118 00000084: JUMP 00000085: JUMPDEST 00000086: PUSH2 0x005b 00000089: PUSH2 0x0093 0000008c: CALLDATASIZE 0000008d: PUSH1 0x04 0000008f: PUSH2 0x0707 00000092: JUMP 00000093: JUMPDEST 00000094: PUSH2 0x0164 00000097: JUMP 00000098: JUMPDEST 00000099: CALLVALUE 0000009a: DUP1 0000009b: ISZERO 0000009c: PUSH2 0x00a4 0000009f: JUMPI 000000a0: PUSH1 0x00 000000a2: DUP1 000000a3: REVERT 000000a4: JUMPDEST 000000a5: POP 000000a6: PUSH2 0x00ad 000000a9: PUSH2 0x01da 000000ac: JUMP 000000ad: JUMPDEST 000000ae: PUSH1 0x40 000000b0: MLOAD 000000b1: PUSH1 0x01 000000b3: PUSH1 0x01 000000b5: PUSH1 0xa0 000000b7: SHL 000000b8: SUB 000000b9: SWAP1 000000ba: SWAP2 000000bb: AND 000000bc: DUP2 000000bd: MSTORE 000000be: PUSH1 0x20 000000c0: ADD 000000c1: PUSH1 0x40 000000c3: MLOAD 000000c4: DUP1 000000c5: SWAP2 000000c6: SUB 000000c7: SWAP1 000000c8: RETURN 000000c9: JUMPDEST 000000ca: CALLVALUE 000000cb: DUP1 000000cc: ISZERO 000000cd: PUSH2 0x00d5 000000d0: JUMPI 000000d1: PUSH1 0x00 000000d3: DUP1 000000d4: REVERT 000000d5: JUMPDEST 000000d6: POP 000000d7: PUSH2 0x005b 000000da: PUSH2 0x00e4 000000dd: CALLDATASIZE 000000de: PUSH1 0x04 000000e0: PUSH2 0x06ed 000000e3: JUMP 000000e4: JUMPDEST 000000e5: PUSH2 0x0217 000000e8: JUMP 000000e9: JUMPDEST 000000ea: CALLVALUE 000000eb: DUP1 000000ec: ISZERO 000000ed: PUSH2 0x00f5 000000f0: JUMPI 000000f1: PUSH1 0x00 000000f3: DUP1 000000f4: REVERT 000000f5: JUMPDEST 000000f6: POP 000000f7: PUSH2 0x00ad 000000fa: PUSH2 0x0241 000000fd: JUMP 000000fe: JUMPDEST 000000ff: PUSH2 0x0106 00000102: PUSH2 0x02a2 00000105: JUMP 00000106: JUMPDEST 00000107: PUSH2 0x0116 0000010a: PUSH2 0x0111 0000010d: PUSH2 0x0346 00000110: JUMP 00000111: JUMPDEST 00000112: PUSH2 0x0355 00000115: JUMP 00000116: JUMPDEST 00000117: JUMP 00000118: JUMPDEST 00000119: PUSH2 0x0120 0000011c: PUSH2 0x0379 0000011f: JUMP 00000120: JUMPDEST 00000121: PUSH1 0x01 00000123: PUSH1 0x01 00000125: PUSH1 0xa0 00000127: SHL 00000128: SUB 00000129: AND 0000012a: CALLER 0000012b: PUSH1 0x01 0000012d: PUSH1 0x01 0000012f: PUSH1 0xa0 00000131: SHL 00000132: SUB 00000133: AND 00000134: EQ 00000135: ISZERO 00000136: PUSH2 0x0159 00000139: JUMPI 0000013a: PUSH2 0x0154 0000013d: DUP2 0000013e: PUSH1 0x40 00000140: MLOAD 00000141: DUP1 00000142: PUSH1 0x20 00000144: ADD 00000145: PUSH1 0x40 00000147: MSTORE 00000148: DUP1 00000149: PUSH1 0x00 0000014b: DUP2 0000014c: MSTORE 0000014d: POP 0000014e: PUSH1 0x00 00000150: PUSH2 0x03ac 00000153: JUMP 00000154: JUMPDEST 00000155: PUSH2 0x0161 00000158: JUMP 00000159: JUMPDEST 0000015a: PUSH2 0x0161 0000015d: PUSH2 0x00fe 00000160: JUMP 00000161: JUMPDEST 00000162: POP 00000163: JUMP 00000164: JUMPDEST 00000165: PUSH2 0x016c 00000168: PUSH2 0x0379 0000016b: JUMP 0000016c: JUMPDEST 0000016d: PUSH1 0x01 0000016f: PUSH1 0x01 00000171: PUSH1 0xa0 00000173: SHL 00000174: SUB 00000175: AND 00000176: CALLER 00000177: PUSH1 0x01 00000179: PUSH1 0x01 0000017b: PUSH1 0xa0 0000017d: SHL 0000017e: SUB 0000017f: AND 00000180: EQ 00000181: ISZERO 00000182: PUSH2 0x01cd 00000185: JUMPI 00000186: PUSH2 0x01c8 00000189: DUP4 0000018a: DUP4 0000018b: DUP4 0000018c: DUP1 0000018d: DUP1 0000018e: PUSH1 0x1f 00000190: ADD 00000191: PUSH1 0x20 00000193: DUP1 00000194: SWAP2 00000195: DIV 00000196: MUL 00000197: PUSH1 0x20 00000199: ADD 0000019a: PUSH1 0x40 0000019c: MLOAD 0000019d: SWAP1 0000019e: DUP2 0000019f: ADD 000001a0: PUSH1 0x40 000001a2: MSTORE 000001a3: DUP1 000001a4: SWAP4 000001a5: SWAP3 000001a6: SWAP2 000001a7: SWAP1 000001a8: DUP2 000001a9: DUP2 000001aa: MSTORE 000001ab: PUSH1 0x20 000001ad: ADD 000001ae: DUP4 000001af: DUP4 000001b0: DUP1 000001b1: DUP3 000001b2: DUP5 000001b3: CALLDATACOPY 000001b4: PUSH1 0x00 000001b6: SWAP3 000001b7: ADD 000001b8: SWAP2 000001b9: SWAP1 000001ba: SWAP2 000001bb: MSTORE 000001bc: POP 000001bd: PUSH1 0x01 000001bf: SWAP3 000001c0: POP 000001c1: PUSH2 0x03ac 000001c4: SWAP2 000001c5: POP 000001c6: POP 000001c7: JUMP 000001c8: JUMPDEST 000001c9: PUSH2 0x01d5 000001cc: JUMP 000001cd: JUMPDEST 000001ce: PUSH2 0x01d5 000001d1: PUSH2 0x00fe 000001d4: JUMP 000001d5: JUMPDEST 000001d6: POP 000001d7: POP 000001d8: POP 000001d9: JUMP 000001da: JUMPDEST 000001db: PUSH1 0x00 000001dd: PUSH2 0x01e4 000001e0: PUSH2 0x0379 000001e3: JUMP 000001e4: JUMPDEST 000001e5: PUSH1 0x01 000001e7: PUSH1 0x01 000001e9: PUSH1 0xa0 000001eb: SHL 000001ec: SUB 000001ed: AND 000001ee: CALLER 000001ef: PUSH1 0x01 000001f1: PUSH1 0x01 000001f3: PUSH1 0xa0 000001f5: SHL 000001f6: SUB 000001f7: AND 000001f8: EQ 000001f9: ISZERO 000001fa: PUSH2 0x020c 000001fd: JUMPI 000001fe: PUSH2 0x0205 00000201: PUSH2 0x0346 00000204: JUMP 00000205: JUMPDEST 00000206: SWAP1 00000207: POP 00000208: PUSH2 0x0214 0000020b: JUMP 0000020c: JUMPDEST 0000020d: PUSH2 0x0214 00000210: PUSH2 0x00fe 00000213: JUMP 00000214: JUMPDEST 00000215: SWAP1 00000216: JUMP 00000217: JUMPDEST 00000218: PUSH2 0x021f 0000021b: PUSH2 0x0379 0000021e: JUMP 0000021f: JUMPDEST 00000220: PUSH1 0x01 00000222: PUSH1 0x01 00000224: PUSH1 0xa0 00000226: SHL 00000227: SUB 00000228: AND 00000229: CALLER 0000022a: PUSH1 0x01 0000022c: PUSH1 0x01 0000022e: PUSH1 0xa0 00000230: SHL 00000231: SUB 00000232: AND 00000233: EQ 00000234: ISZERO 00000235: PUSH2 0x0159 00000238: JUMPI 00000239: PUSH2 0x0154 0000023c: DUP2 0000023d: PUSH2 0x040b 00000240: JUMP 00000241: JUMPDEST 00000242: PUSH1 0x00 00000244: PUSH2 0x024b 00000247: PUSH2 0x0379 0000024a: JUMP 0000024b: JUMPDEST 0000024c: PUSH1 0x01 0000024e: PUSH1 0x01 00000250: PUSH1 0xa0 00000252: SHL 00000253: SUB 00000254: AND 00000255: CALLER 00000256: PUSH1 0x01 00000258: PUSH1 0x01 0000025a: PUSH1 0xa0 0000025c: SHL 0000025d: SUB 0000025e: AND 0000025f: EQ 00000260: ISZERO 00000261: PUSH2 0x020c 00000264: JUMPI 00000265: PUSH2 0x0205 00000268: PUSH2 0x0379 0000026b: JUMP 0000026c: JUMPDEST 0000026d: PUSH1 0x60 0000026f: PUSH2 0x0291 00000272: DUP4 00000273: DUP4 00000274: PUSH1 0x40 00000276: MLOAD 00000277: DUP1 00000278: PUSH1 0x60 0000027a: ADD 0000027b: PUSH1 0x40 0000027d: MSTORE 0000027e: DUP1 0000027f: PUSH1 0x27 00000281: DUP2 00000282: MSTORE 00000283: PUSH1 0x20 00000285: ADD 00000286: PUSH2 0x0801 00000289: PUSH1 0x27 0000028b: SWAP2 0000028c: CODECOPY 0000028d: PUSH2 0x045f 00000290: JUMP 00000291: JUMPDEST 00000292: SWAP4 00000293: SWAP3 00000294: POP 00000295: POP 00000296: POP 00000297: JUMP 00000298: JUMPDEST 00000299: DUP1 0000029a: EXTCODESIZE 0000029b: ISZERO 0000029c: ISZERO 0000029d: JUMPDEST 0000029e: SWAP2 0000029f: SWAP1 000002a0: POP 000002a1: JUMP 000002a2: JUMPDEST 000002a3: PUSH2 0x02aa 000002a6: PUSH2 0x0379 000002a9: JUMP 000002aa: JUMPDEST 000002ab: PUSH1 0x01 000002ad: PUSH1 0x01 000002af: PUSH1 0xa0 000002b1: SHL 000002b2: SUB 000002b3: AND 000002b4: CALLER 000002b5: PUSH1 0x01 000002b7: PUSH1 0x01 000002b9: PUSH1 0xa0 000002bb: SHL 000002bc: SUB 000002bd: AND 000002be: EQ 000002bf: ISZERO 000002c0: PUSH2 0x0341 000002c3: JUMPI 000002c4: PUSH1 0x40 000002c6: MLOAD 000002c7: PUSH3 0x461bcd 000002cb: PUSH1 0xe5 000002cd: SHL 000002ce: DUP2 000002cf: MSTORE 000002d0: PUSH1 0x20 000002d2: PUSH1 0x04 000002d4: DUP3 000002d5: ADD 000002d6: MSTORE 000002d7: PUSH1 0x42 000002d9: PUSH1 0x24 000002db: DUP3 000002dc: ADD 000002dd: MSTORE 000002de: PUSH32 0x5472616e73706172656e745570677261646561626c6550726f78793a2061646d 000002ff: PUSH1 0x44 00000301: DUP3 00000302: ADD 00000303: MSTORE 00000304: PUSH32 0x696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267 00000325: PUSH1 0x64 00000327: DUP3 00000328: ADD 00000329: MSTORE 0000032a: PUSH2 0x195d 0000032d: PUSH1 0xf2 0000032f: SHL 00000330: PUSH1 0x84 00000332: DUP3 00000333: ADD 00000334: MSTORE 00000335: PUSH1 0xa4 00000337: ADD 00000338: JUMPDEST 00000339: PUSH1 0x40 0000033b: MLOAD 0000033c: DUP1 0000033d: SWAP2 0000033e: SUB 0000033f: SWAP1 00000340: REVERT 00000341: JUMPDEST 00000342: PUSH2 0x0116 00000345: JUMP 00000346: JUMPDEST 00000347: PUSH1 0x00 00000349: PUSH2 0x0350 0000034c: PUSH2 0x053a 0000034f: JUMP 00000350: JUMPDEST 00000351: SWAP1 00000352: POP 00000353: SWAP1 00000354: JUMP 00000355: JUMPDEST 00000356: CALLDATASIZE 00000357: PUSH1 0x00 00000359: DUP1 0000035a: CALLDATACOPY 0000035b: PUSH1 0x00 0000035d: DUP1 0000035e: CALLDATASIZE 0000035f: PUSH1 0x00 00000361: DUP5 00000362: GAS 00000363: DELEGATECALL 00000364: RETURNDATASIZE 00000365: PUSH1 0x00 00000367: DUP1 00000368: RETURNDATACOPY 00000369: DUP1 0000036a: DUP1 0000036b: ISZERO 0000036c: PUSH2 0x0374 0000036f: JUMPI 00000370: RETURNDATASIZE 00000371: PUSH1 0x00 00000373: RETURN 00000374: JUMPDEST 00000375: RETURNDATASIZE 00000376: PUSH1 0x00 00000378: REVERT 00000379: JUMPDEST 0000037a: PUSH1 0x00 0000037c: PUSH32 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 0000039d: JUMPDEST 0000039e: SLOAD 0000039f: PUSH1 0x01 000003a1: PUSH1 0x01 000003a3: PUSH1 0xa0 000003a5: SHL 000003a6: SUB 000003a7: AND 000003a8: SWAP1 000003a9: POP 000003aa: SWAP1 000003ab: JUMP 000003ac: JUMPDEST 000003ad: PUSH2 0x03b5 000003b0: DUP4 000003b1: PUSH2 0x0562 000003b4: JUMP 000003b5: JUMPDEST 000003b6: PUSH1 0x40 000003b8: MLOAD 000003b9: PUSH1 0x01 000003bb: PUSH1 0x01 000003bd: PUSH1 0xa0 000003bf: SHL 000003c0: SUB 000003c1: DUP5 000003c2: AND 000003c3: SWAP1 000003c4: PUSH32 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b 000003e5: SWAP1 000003e6: PUSH1 0x00 000003e8: SWAP1 000003e9: LOG2 000003ea: PUSH1 0x00 000003ec: DUP3 000003ed: MLOAD 000003ee: GT 000003ef: DUP1 000003f0: PUSH2 0x03f6 000003f3: JUMPI 000003f4: POP 000003f5: DUP1 000003f6: JUMPDEST 000003f7: ISZERO 000003f8: PUSH2 0x01d5 000003fb: JUMPI 000003fc: PUSH2 0x0405 000003ff: DUP4 00000400: DUP4 00000401: PUSH2 0x026c 00000404: JUMP 00000405: JUMPDEST 00000406: POP 00000407: POP 00000408: POP 00000409: POP 0000040a: JUMP 0000040b: JUMPDEST 0000040c: PUSH32 0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f 0000042d: PUSH2 0x0434 00000430: PUSH2 0x0379 00000433: JUMP 00000434: JUMPDEST 00000435: PUSH1 0x40 00000437: DUP1 00000438: MLOAD 00000439: PUSH1 0x01 0000043b: PUSH1 0x01 0000043d: PUSH1 0xa0 0000043f: SHL 00000440: SUB 00000441: SWAP3 00000442: DUP4 00000443: AND 00000444: DUP2 00000445: MSTORE 00000446: SWAP2 00000447: DUP5 00000448: AND 00000449: PUSH1 0x20 0000044b: DUP4 0000044c: ADD 0000044d: MSTORE 0000044e: ADD 0000044f: PUSH1 0x40 00000451: MLOAD 00000452: DUP1 00000453: SWAP2 00000454: SUB 00000455: SWAP1 00000456: LOG1 00000457: PUSH2 0x0161 0000045a: DUP2 0000045b: PUSH2 0x0611 0000045e: JUMP 0000045f: JUMPDEST 00000460: PUSH1 0x60 00000462: PUSH2 0x046a 00000465: DUP5 00000466: PUSH2 0x0298 00000469: JUMP 0000046a: JUMPDEST 0000046b: PUSH2 0x04c5 0000046e: JUMPI 0000046f: PUSH1 0x40 00000471: MLOAD 00000472: PUSH3 0x461bcd 00000476: PUSH1 0xe5 00000478: SHL 00000479: DUP2 0000047a: MSTORE 0000047b: PUSH1 0x20 0000047d: PUSH1 0x04 0000047f: DUP3 00000480: ADD 00000481: MSTORE 00000482: PUSH1 0x26 00000484: PUSH1 0x24 00000486: DUP3 00000487: ADD 00000488: MSTORE 00000489: PUSH32 0x416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f 000004aa: PUSH1 0x44 000004ac: DUP3 000004ad: ADD 000004ae: MSTORE 000004af: PUSH6 0x1b9d1c9858dd 000004b6: PUSH1 0xd2 000004b8: SHL 000004b9: PUSH1 0x64 000004bb: DUP3 000004bc: ADD 000004bd: MSTORE 000004be: PUSH1 0x84 000004c0: ADD 000004c1: PUSH2 0x0338 000004c4: JUMP 000004c5: JUMPDEST 000004c6: PUSH1 0x00 000004c8: DUP1 000004c9: DUP6 000004ca: PUSH1 0x01 000004cc: PUSH1 0x01 000004ce: PUSH1 0xa0 000004d0: SHL 000004d1: SUB 000004d2: AND 000004d3: DUP6 000004d4: PUSH1 0x40 000004d6: MLOAD 000004d7: PUSH2 0x04e0 000004da: SWAP2 000004db: SWAP1 000004dc: PUSH2 0x0785 000004df: JUMP 000004e0: JUMPDEST 000004e1: PUSH1 0x00 000004e3: PUSH1 0x40 000004e5: MLOAD 000004e6: DUP1 000004e7: DUP4 000004e8: SUB 000004e9: DUP2 000004ea: DUP6 000004eb: GAS 000004ec: DELEGATECALL 000004ed: SWAP2 000004ee: POP 000004ef: POP 000004f0: RETURNDATASIZE 000004f1: DUP1 000004f2: PUSH1 0x00 000004f4: DUP2 000004f5: EQ 000004f6: PUSH2 0x051b 000004f9: JUMPI 000004fa: PUSH1 0x40 000004fc: MLOAD 000004fd: SWAP2 000004fe: POP 000004ff: PUSH1 0x1f 00000501: NOT 00000502: PUSH1 0x3f 00000504: RETURNDATASIZE 00000505: ADD 00000506: AND 00000507: DUP3 00000508: ADD 00000509: PUSH1 0x40 0000050b: MSTORE 0000050c: RETURNDATASIZE 0000050d: DUP3 0000050e: MSTORE 0000050f: RETURNDATASIZE 00000510: PUSH1 0x00 00000512: PUSH1 0x20 00000514: DUP5 00000515: ADD 00000516: RETURNDATACOPY 00000517: PUSH2 0x0520 0000051a: JUMP 0000051b: JUMPDEST 0000051c: PUSH1 0x60 0000051e: SWAP2 0000051f: POP 00000520: JUMPDEST 00000521: POP 00000522: SWAP2 00000523: POP 00000524: SWAP2 00000525: POP 00000526: PUSH2 0x0530 00000529: DUP3 0000052a: DUP3 0000052b: DUP7 0000052c: PUSH2 0x069d 0000052f: JUMP 00000530: JUMPDEST 00000531: SWAP7 00000532: SWAP6 00000533: POP 00000534: POP 00000535: POP 00000536: POP 00000537: POP 00000538: POP 00000539: JUMP 0000053a: JUMPDEST 0000053b: PUSH1 0x00 0000053d: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 0000055e: PUSH2 0x039d 00000561: JUMP 00000562: JUMPDEST 00000563: PUSH2 0x056b 00000566: DUP2 00000567: PUSH2 0x0298 0000056a: JUMP 0000056b: JUMPDEST 0000056c: PUSH2 0x05cd 0000056f: JUMPI 00000570: PUSH1 0x40 00000572: MLOAD 00000573: PUSH3 0x461bcd 00000577: PUSH1 0xe5 00000579: SHL 0000057a: DUP2 0000057b: MSTORE 0000057c: PUSH1 0x20 0000057e: PUSH1 0x04 00000580: DUP3 00000581: ADD 00000582: MSTORE 00000583: PUSH1 0x2d 00000585: PUSH1 0x24 00000587: DUP3 00000588: ADD 00000589: MSTORE 0000058a: PUSH32 0x455243313936373a206e657720696d706c656d656e746174696f6e206973206e 000005ab: PUSH1 0x44 000005ad: DUP3 000005ae: ADD 000005af: MSTORE 000005b0: PUSH13 0x1bdd08184818dbdb9d1c9858dd 000005be: PUSH1 0x9a 000005c0: SHL 000005c1: PUSH1 0x64 000005c3: DUP3 000005c4: ADD 000005c5: MSTORE 000005c6: PUSH1 0x84 000005c8: ADD 000005c9: PUSH2 0x0338 000005cc: JUMP 000005cd: JUMPDEST 000005ce: DUP1 000005cf: PUSH32 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc 000005f0: JUMPDEST 000005f1: DUP1 000005f2: SLOAD 000005f3: PUSH1 0x01 000005f5: PUSH1 0x01 000005f7: PUSH1 0xa0 000005f9: SHL 000005fa: SUB 000005fb: NOT 000005fc: AND 000005fd: PUSH1 0x01 000005ff: PUSH1 0x01 00000601: PUSH1 0xa0 00000603: SHL 00000604: SUB 00000605: SWAP3 00000606: SWAP1 00000607: SWAP3 00000608: AND 00000609: SWAP2 0000060a: SWAP1 0000060b: SWAP2 0000060c: OR 0000060d: SWAP1 0000060e: SSTORE 0000060f: POP 00000610: JUMP 00000611: JUMPDEST 00000612: PUSH1 0x01 00000614: PUSH1 0x01 00000616: PUSH1 0xa0 00000618: SHL 00000619: SUB 0000061a: DUP2 0000061b: AND 0000061c: PUSH2 0x0676 0000061f: JUMPI 00000620: PUSH1 0x40 00000622: MLOAD 00000623: PUSH3 0x461bcd 00000627: PUSH1 0xe5 00000629: SHL 0000062a: DUP2 0000062b: MSTORE 0000062c: PUSH1 0x20 0000062e: PUSH1 0x04 00000630: DUP3 00000631: ADD 00000632: MSTORE 00000633: PUSH1 0x26 00000635: PUSH1 0x24 00000637: DUP3 00000638: ADD 00000639: MSTORE 0000063a: PUSH32 0x455243313936373a206e65772061646d696e20697320746865207a65726f2061 0000065b: PUSH1 0x44 0000065d: DUP3 0000065e: ADD 0000065f: MSTORE 00000660: PUSH6 0x646472657373 00000667: PUSH1 0xd0 00000669: SHL 0000066a: PUSH1 0x64 0000066c: DUP3 0000066d: ADD 0000066e: MSTORE 0000066f: PUSH1 0x84 00000671: ADD 00000672: PUSH2 0x0338 00000675: JUMP 00000676: JUMPDEST 00000677: DUP1 00000678: PUSH32 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 00000699: PUSH2 0x05f0 0000069c: JUMP 0000069d: JUMPDEST 0000069e: PUSH1 0x60 000006a0: DUP4 000006a1: ISZERO 000006a2: PUSH2 0x06ac 000006a5: JUMPI 000006a6: POP 000006a7: DUP2 000006a8: PUSH2 0x0291 000006ab: JUMP 000006ac: JUMPDEST 000006ad: DUP3 000006ae: MLOAD 000006af: ISZERO 000006b0: PUSH2 0x06bc 000006b3: JUMPI 000006b4: DUP3 000006b5: MLOAD 000006b6: DUP1 000006b7: DUP5 000006b8: PUSH1 0x20 000006ba: ADD 000006bb: REVERT 000006bc: JUMPDEST 000006bd: DUP2 000006be: PUSH1 0x40 000006c0: MLOAD 000006c1: PUSH3 0x461bcd 000006c5: PUSH1 0xe5 000006c7: SHL 000006c8: DUP2 000006c9: MSTORE 000006ca: PUSH1 0x04 000006cc: ADD 000006cd: PUSH2 0x0338 000006d0: SWAP2 000006d1: SWAP1 000006d2: PUSH2 0x07a1 000006d5: JUMP 000006d6: JUMPDEST 000006d7: DUP1 000006d8: CALLDATALOAD 000006d9: PUSH1 0x01 000006db: PUSH1 0x01 000006dd: PUSH1 0xa0 000006df: SHL 000006e0: SUB 000006e1: DUP2 000006e2: AND 000006e3: DUP2 000006e4: EQ 000006e5: PUSH2 0x029d 000006e8: JUMPI 000006e9: PUSH1 0x00 000006eb: DUP1 000006ec: REVERT 000006ed: JUMPDEST 000006ee: PUSH1 0x00 000006f0: PUSH1 0x20 000006f2: DUP3 000006f3: DUP5 000006f4: SUB 000006f5: SLT 000006f6: ISZERO 000006f7: PUSH2 0x06fe 000006fa: JUMPI 000006fb: DUP1 000006fc: DUP2 000006fd: REVERT 000006fe: JUMPDEST 000006ff: PUSH2 0x0291 00000702: DUP3 00000703: PUSH2 0x06d6 00000706: JUMP 00000707: JUMPDEST 00000708: PUSH1 0x00 0000070a: DUP1 0000070b: PUSH1 0x00 0000070d: PUSH1 0x40 0000070f: DUP5 00000710: DUP7 00000711: SUB 00000712: SLT 00000713: ISZERO 00000714: PUSH2 0x071b 00000717: JUMPI 00000718: DUP2 00000719: DUP3 0000071a: REVERT 0000071b: JUMPDEST 0000071c: PUSH2 0x0724 0000071f: DUP5 00000720: PUSH2 0x06d6 00000723: JUMP 00000724: JUMPDEST 00000725: SWAP3 00000726: POP 00000727: PUSH1 0x20 00000729: DUP5 0000072a: ADD 0000072b: CALLDATALOAD 0000072c: PUSH8 0xffffffffffffffff 00000735: DUP1 00000736: DUP3 00000737: GT 00000738: ISZERO 00000739: PUSH2 0x0740 0000073c: JUMPI 0000073d: DUP4 0000073e: DUP5 0000073f: REVERT 00000740: JUMPDEST 00000741: DUP2 00000742: DUP7 00000743: ADD 00000744: SWAP2 00000745: POP 00000746: DUP7 00000747: PUSH1 0x1f 00000749: DUP4 0000074a: ADD 0000074b: SLT 0000074c: PUSH2 0x0753 0000074f: JUMPI 00000750: DUP4 00000751: DUP5 00000752: REVERT 00000753: JUMPDEST 00000754: DUP2 00000755: CALLDATALOAD 00000756: DUP2 00000757: DUP2 00000758: GT 00000759: ISZERO 0000075a: PUSH2 0x0761 0000075d: JUMPI 0000075e: DUP5 0000075f: DUP6 00000760: REVERT 00000761: JUMPDEST 00000762: DUP8 00000763: PUSH1 0x20 00000765: DUP3 00000766: DUP6 00000767: ADD 00000768: ADD 00000769: GT 0000076a: ISZERO 0000076b: PUSH2 0x0772 0000076e: JUMPI 0000076f: DUP5 00000770: DUP6 00000771: REVERT 00000772: JUMPDEST 00000773: PUSH1 0x20 00000775: DUP4 00000776: ADD 00000777: SWAP5 00000778: POP 00000779: DUP1 0000077a: SWAP4 0000077b: POP 0000077c: POP 0000077d: POP 0000077e: POP 0000077f: SWAP3 00000780: POP 00000781: SWAP3 00000782: POP 00000783: SWAP3 00000784: JUMP 00000785: JUMPDEST 00000786: PUSH1 0x00 00000788: DUP3 00000789: MLOAD 0000078a: PUSH2 0x0797 0000078d: DUP2 0000078e: DUP5 0000078f: PUSH1 0x20 00000791: DUP8 00000792: ADD 00000793: PUSH2 0x07d4 00000796: JUMP 00000797: JUMPDEST 00000798: SWAP2 00000799: SWAP1 0000079a: SWAP2 0000079b: ADD 0000079c: SWAP3 0000079d: SWAP2 0000079e: POP 0000079f: POP 000007a0: JUMP 000007a1: JUMPDEST 000007a2: PUSH1 0x00 000007a4: PUSH1 0x20 000007a6: DUP3 000007a7: MSTORE 000007a8: DUP3 000007a9: MLOAD 000007aa: DUP1 000007ab: PUSH1 0x20 000007ad: DUP5 000007ae: ADD 000007af: MSTORE 000007b0: PUSH2 0x07c0 000007b3: DUP2 000007b4: PUSH1 0x40 000007b6: DUP6 000007b7: ADD 000007b8: PUSH1 0x20 000007ba: DUP8 000007bb: ADD 000007bc: PUSH2 0x07d4 000007bf: JUMP 000007c0: JUMPDEST 000007c1: PUSH1 0x1f 000007c3: ADD 000007c4: PUSH1 0x1f 000007c6: NOT 000007c7: AND 000007c8: SWAP2 000007c9: SWAP1 000007ca: SWAP2 000007cb: ADD 000007cc: PUSH1 0x40 000007ce: ADD 000007cf: SWAP3 000007d0: SWAP2 000007d1: POP 000007d2: POP 000007d3: JUMP 000007d4: JUMPDEST 000007d5: PUSH1 0x00 000007d7: JUMPDEST 000007d8: DUP4 000007d9: DUP2 000007da: LT 000007db: ISZERO 000007dc: PUSH2 0x07ef 000007df: JUMPI 000007e0: DUP2 000007e1: DUP2 000007e2: ADD 000007e3: MLOAD 000007e4: DUP4 000007e5: DUP3 000007e6: ADD 000007e7: MSTORE 000007e8: PUSH1 0x20 000007ea: ADD 000007eb: PUSH2 0x07d7 000007ee: JUMP 000007ef: JUMPDEST 000007f0: DUP4 000007f1: DUP2 000007f2: GT 000007f3: ISZERO 000007f4: PUSH2 0x0405 000007f7: JUMPI 000007f8: POP 000007f9: POP 000007fa: PUSH1 0x00 000007fc: SWAP2 000007fd: ADD 000007fe: MSTORE 000007ff: JUMP 00000800: INVALID 00000801: COINBASE 00000802: PUSH5 0x6472657373 00000808: GASPRICE 00000809: KECCAK256 0000080a: PUSH13 0x6f772d6c6576656c2064656c65 00000818: PUSH8 0x6174652063616c6c 00000821: KECCAK256 00000822: PUSH7 0x61696c6564a264 0000082a: PUSH10 0x7066735822122093f028 00000835: UNKNOWN(0x25) 00000836: POP 00000837: CALLDATALOAD 00000838: UNKNOWN(0xB6) 00000839: SAR 0000083a: DELEGATECALL 0000083b: PUSH23 0xb13b9dba3c4f06f60e51b9b4caee31680b389aef327f64 00000853: PUSH20
| Severity | Category | Tool | Title | Confidence | Validated | Confirmed | Details |
|---|---|---|---|---|---|---|---|
| critical | upgradeability | detector | Untrusted DELEGATECALL target reachable | 70 | no | no |
viewtrace_id: 0x5ce6e86648576fc0957b372932ca920d9d5d984b87536f8bab2901ba21b51bdd
call_targets:
0x29353f77c6b0d3772d73e708cc8e1fca08c80c11
target_varies:
no
classification:
constant_target
validation_json{
"sink": "DELEGATECALL",
"errors": 0,
"status": "sink_reached",
"attempts": 2,
"trace_id": "0x5ce6e86648576fc0957b372932ca920d9d5d984b87536f8bab2901ba21b51bdd",
"confirmed": false,
"trace_mode": "callTracer",
"call_targets": [
"0x29353f77c6b0d3772d73e708cc8e1fca08c80c11"
],
"matched_probe": null,
"target_varies": false,
"classification": "constant_target"
}
witness_json{
"notes": "heuristic witness; entrypoints are best-effort selectors with zeroed calldata",
"constraints": [],
"entrypoints": [
{
"calldata": "0x3659cfe6",
"selector": "0x3659cfe6",
"calldata_variants": [
"0x3659cfe6",
"0x3659cfe60000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x4f1ef286",
"selector": "0x4f1ef286",
"calldata_variants": [
"0x4f1ef286",
"0x4f1ef2860000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x5c60da1b",
"selector": "0x5c60da1b",
"calldata_variants": [
"0x5c60da1b",
"0x5c60da1b0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0x8f283970",
"selector": "0x8f283970",
"calldata_variants": [
"0x8f283970",
"0x8f2839700000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"calldata": "0xf851a440",
"selector": "0xf851a440",
"calldata_variants": [
"0xf851a440",
"0xf851a4400000000000000000000000000000000000000000000000000000000000000000"
]
}
]
}
evidence_json{
"examples": [
{
"pc": 867,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
},
{
"pc": 1260,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
},
{
"pc": 2106,
"opcode": "DELEGATECALL",
"returndata_checked": null,
"value_expression_category": "n/a",
"target_expression_category": "computed"
}
],
"guards_detected": [],
"delegatecall_count": 3,
"untrusted_delegatecall_count": 3
}
|
| high | other | codex | Fee-on-transfer ERC20s can overmint bridge balances and drain pooled collateral | 85 | no | — |
viewevidence_json{
"evidence": "`DepositBoxERC20.depositERC20Direct` builds the outgoing message and increments `transferredAmount` using the caller-supplied `amount`, then performs a single `safeTransferFrom` without comparing pre/post balances. `TokenManagerERC20._exit` mirrors this pattern for schain-to-schain escrow of main-chain tokens by saving `amount` before `transferFrom` and never validating the received balance.",
"locations": [
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:691",
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:704",
"contracts/mainnet/DepositBoxes/DepositBoxERC20.sol:705",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:340",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:348",
"contracts/schain/TokenManagers/TokenManagerERC20.sol:350"
],
"recommendation": "Measure balance deltas before and after each ERC20 transfer and use the actual received amount for `transferredAmount` accounting and for the bridged message payload. Reject tokens whose received amount is smaller than the requested amount if exact-amount semantics are required.",
"exploit_scenario": "An attacker bridges a deflationary ERC20 that burns or taxes 10% on transfer. `DepositBoxERC20.depositERC20Direct` records and forwards `amount=100` to the destination chain, then calls `safeTransferFrom` once without checking how many tokens actually arrived. Only 90 tokens reach the box, but 100 wrapped tokens are minted on the schain. The attacker can later exit the full 100 back to mainnet (or another schain), extracting the 10-token shortfall from liquidity supplied by honest users. The same invariant break exists in schain-to-schain transfers of main-chain ERC20s, where `TokenManagerERC20` escrows `amount` before verifying the real balance delta."
}
|
| medium | upgradeability | cast | DELEGATECALL present | 80 | no | — |
viewevidence_json{
"notes": "delegatecall enables execution in caller context; common in proxies/upgradeable patterns",
"delegatecall_count": 3
}
|