Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SecuritizeBridge
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/**
* Copyright 2024 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.20;
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {IDSToken} from "@securitize/digital_securities/contracts/token/IDSToken.sol";
import {IDSServiceConsumer} from "@securitize/digital_securities/contracts/service/IDSServiceConsumer.sol";
import {IDSRegistryService} from "@securitize/digital_securities/contracts/registry/IDSRegistryService.sol";
import {IDSComplianceService} from "@securitize/digital_securities/contracts/compliance/IDSComplianceService.sol";
import {IDSComplianceConfigurationService} from "@securitize/digital_securities/contracts/compliance/IDSComplianceConfigurationService.sol";
import {TokenIssuer} from "@securitize/digital_securities/contracts/issuance/TokenIssuer.sol";
import {BaseDSContract} from "@securitize/digital_securities/contracts/utils/BaseDSContract.sol";
import {IWormholeReceiver} from "../wormhole/interfaces/IWormholeReceiver.sol";
import {IWormholeRelayer} from "../wormhole/interfaces/IWormholeRelayer.sol";
import {BaseContract} from "../utils/BaseContract.sol";
import {ISecuritizeBridge} from "./ISecuritizeBridge.sol";
contract SecuritizeBridge is IWormholeReceiver, ISecuritizeBridge, BaseContract, ReentrancyGuardUpgradeable {
string private constant BRIDGE_REASON = 'bridge';
uint256 internal constant US = 1;
IWormholeRelayer public wormholeRelayer;
IDSToken public dsToken;
IDSServiceConsumer public dsServiceConsumer;
uint256 public gasLimit;
uint16 public whChainId;
mapping(uint16 wmChainId => address bridge) public bridgeAddresses;
modifier addressNotZero(address _address) {
if (_address == address(0)) {
revert NonZeroAddress();
}
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(uint16 _whChainId, address _wormholeRelayer, address _dsToken, address _owner) public override onlyProxy initializer {
__BaseDSContract_init(_owner);
whChainId = _whChainId;
wormholeRelayer = IWormholeRelayer(_wormholeRelayer);
dsToken = IDSToken(_dsToken);
dsServiceConsumer = IDSServiceConsumer(_dsToken);
gasLimit = 2_500_000;
}
function setBridgeAddress(uint16 chainId, address bridgeAddress) external override onlyOwner {
bridgeAddresses[chainId] = bridgeAddress;
emit BridgeAddressAdded(chainId, bridgeAddress);
}
function removeBridgeAddress(uint16 chainId) external override onlyOwner {
delete bridgeAddresses[chainId];
emit BridgeAddressRemoved(chainId);
}
function updateGasLimit(uint256 _gasLimit) external override onlyOwner {
emit GasLimitUpdate(gasLimit, _gasLimit);
gasLimit = _gasLimit;
}
function quoteBridge(uint16 targetChain) public override view returns (uint256 cost) {
cost = _quoteBridge(wormholeRelayer, gasLimit, targetChain);
}
function bridgeDSTokens(uint16 targetChain, uint256 value) external override payable whenNotPaused {
require(value > 0, "DSToken value must be greater than 0");
IWormholeRelayer _wormholeRelayer = wormholeRelayer;
uint256 _gasLimit = gasLimit;
uint256 cost = _quoteBridge(_wormholeRelayer, _gasLimit, targetChain);
require(msg.value >= cost, "Transaction value should be equal or greater than quoteBridge response");
require(dsToken.balanceOf(_msgSender()) >= value, "Not enough balance in source chain to bridge");
address targetAddress = bridgeAddresses[targetChain];
require(targetAddress != address(0), "No bridge address available");
IDSServiceConsumer _dsServiceConsumer = dsServiceConsumer;
IDSRegistryService registryService = IDSRegistryService(_dsServiceConsumer.getDSService(_dsServiceConsumer.REGISTRY_SERVICE()));
require(registryService.isWallet(_msgSender()), "Investor not registered");
string memory investorId = registryService.getInvestor(_msgSender());
validateLockedTokens(investorId, value, registryService, _dsServiceConsumer);
InvestorDetail memory investorDetail = getInvestorData(investorId, registryService);
// Perform DSToken burn on source chain
dsToken.burn(_msgSender(), value, BRIDGE_REASON);
// Send Relayer message
_wormholeRelayer.sendPayloadToEvm{value: msg.value} (
targetChain,
targetAddress,
abi.encode(
investorDetail.investorId,
value,
_msgSender(),
investorDetail.country,
investorDetail.attributeValues,
investorDetail.attributeExpirations
), // payload
0, // no receiver value needed since we"re just passing a message
_gasLimit,
whChainId,
_msgSender()
);
emit DSTokenBridgeSend(targetChain, address(dsToken), _msgSender(), value);
}
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory, // additionalVaas
bytes32 sourceBridge, // address that called "sendPayloadToEvm" (DSTokenBridge contract)
uint16 sourceChain,
bytes32 // unique identifier of delivery
) public override payable whenNotPaused {
require(_msgSender() == address(wormholeRelayer), "Only an authorized relayer can call this method");
require(address(uint160(uint256(sourceBridge))) == bridgeAddresses[sourceChain], "Wrong bridge initiator");
// Parse the payload and do the corresponding actions
(
string memory investorId,
uint256 value,
address investorWallet,
string memory country,
uint256[] memory attributeValues,
uint256[] memory attributeExpirations
) = abi.decode(payload, (string, uint256, address, string, uint256[], uint256[]));
// Perform DSToken operation
IDSRegistryService registryService = IDSRegistryService(dsServiceConsumer.getDSService(dsServiceConsumer.REGISTRY_SERVICE()));
uint8[] memory attributeIds = new uint8[](4);
attributeIds[0] = 1; // KYC
attributeIds[1] = 2; // Accredited
attributeIds[2] = 4; // Qualified
attributeIds[3] = 8; // Professional
address[] memory investorWallets = new address[](1);
investorWallets[0] = investorWallet;
registryService.updateInvestor(investorId, investorId, country, investorWallets, attributeIds, attributeValues, attributeExpirations);
dsToken.issueTokens(investorWallet, value);
emit DSTokenBridgeReceive(sourceChain, address(dsToken), investorWallet, value);
}
function withdrawETH(address payable _to) external nonReentrant addressNotZero(_to) onlyOwner {
uint256 amount = address(this).balance;
(bool sent, ) = _to.call{value: amount}("");
if (!sent) revert ETHTransferError();
emit ETHWithdrawn(_to, amount);
}
/////// private/internal methods ////////
function _quoteBridge(IWormholeRelayer relayer, uint256 _gasLimit, uint16 targetChain) internal view returns (uint256 cost) {
(cost, ) = relayer.quoteEVMDeliveryPrice(targetChain, 0, _gasLimit);
}
function getInvestorData(string memory investorId, IDSRegistryService registryService) private view returns (InvestorDetail memory) {
(string memory country, uint256[] memory attributeValues, uint256[] memory attributeExpirations, , , , ) = registryService.getInvestorDetailsFull(investorId);
InvestorDetail memory detail = InvestorDetail({
investorId: investorId,
country: country,
attributeValues: attributeValues,
attributeExpirations: attributeExpirations
});
return detail;
}
function validateLockedTokens(string memory investorId, uint256 _value, IDSRegistryService _registryService, IDSServiceConsumer _dsServiceConsumer) private view {
IDSComplianceService complianceService = IDSComplianceService(_dsServiceConsumer.getDSService(_dsServiceConsumer.COMPLIANCE_SERVICE()));
IDSComplianceConfigurationService complianceConfigurationService = IDSComplianceConfigurationService(_dsServiceConsumer.getDSService(_dsServiceConsumer.COMPLIANCE_CONFIGURATION_SERVICE()));
string memory country = _registryService.getCountry(investorId);
uint256 region = complianceConfigurationService.getCountryCompliance(country);
// lock/hold up validation
uint256 lockPeriod = (region == US) ? complianceConfigurationService.getUSLockPeriod() : complianceConfigurationService.getNonUSLockPeriod();
uint256 availableBalanceForTransfer = complianceService.getComplianceTransferableTokens(_msgSender(), block.timestamp, uint64(lockPeriod));
require(availableBalanceForTransfer >= _value, "Not enough unlocked balance in source chain to bridge");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSComplianceConfigurationService {
function initialize() public virtual;
event DSComplianceUIntRuleSet(string ruleName, uint256 prevValue, uint256 newValue);
event DSComplianceBoolRuleSet(string ruleName, bool prevValue, bool newValue);
event DSComplianceStringToUIntMapRuleSet(string ruleName, string keyValue, uint256 prevValue, uint256 newValue);
function getCountryCompliance(string memory _country) public view virtual returns (uint256);
function setCountriesCompliance(string[] calldata _countries, uint256[] calldata _values) public virtual;
function setCountryCompliance(
string calldata _country,
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getTotalInvestorsLimit() public view virtual returns (uint256);
function setTotalInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMinUSTokens() public view virtual returns (uint256);
function setMinUSTokens(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMinEUTokens() public view virtual returns (uint256);
function setMinEUTokens(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getUSInvestorsLimit() public view virtual returns (uint256);
function setUSInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getJPInvestorsLimit() public view virtual returns (uint256);
function setJPInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getUSAccreditedInvestorsLimit() public view virtual returns (uint256);
function setUSAccreditedInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getNonAccreditedInvestorsLimit() public view virtual returns (uint256);
function setNonAccreditedInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMaxUSInvestorsPercentage() public view virtual returns (uint256);
function setMaxUSInvestorsPercentage(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getBlockFlowbackEndTime() public view virtual returns (uint256);
function setBlockFlowbackEndTime(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getNonUSLockPeriod() public view virtual returns (uint256);
function setNonUSLockPeriod(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMinimumTotalInvestors() public view virtual returns (uint256);
function setMinimumTotalInvestors(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMinimumHoldingsPerInvestor() public view virtual returns (uint256);
function setMinimumHoldingsPerInvestor(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getMaximumHoldingsPerInvestor() public view virtual returns (uint256);
function setMaximumHoldingsPerInvestor(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getEURetailInvestorsLimit() public view virtual returns (uint256);
function setEURetailInvestorsLimit(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getUSLockPeriod() public view virtual returns (uint256);
function setUSLockPeriod(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getForceFullTransfer() public view virtual returns (bool);
function setForceFullTransfer(
bool _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getForceAccredited() public view virtual returns (bool);
function setForceAccredited(
bool _value /*onlyTransferAgentOrAbove*/
) public virtual;
function setForceAccreditedUS(
bool _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getForceAccreditedUS() public view virtual returns (bool);
function setWorldWideForceFullTransfer(
bool _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getWorldWideForceFullTransfer() public view virtual returns (bool);
function getAuthorizedSecurities() public view virtual returns (uint256);
function setAuthorizedSecurities(
uint256 _value /*onlyTransferAgentOrAbove*/
) public virtual;
function getDisallowBackDating() public view virtual returns (bool);
function setDisallowBackDating(
bool _value /*onlyTransferAgentOrAbove*/
) public virtual;
function setAll(
uint256[] calldata _uint_values,
bool[] calldata _bool_values /*onlyTransferAgentOrAbove*/
) public virtual;
function getAll() public view virtual returns (uint256[] memory, bool[] memory);
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSComplianceService {
uint256 internal constant NONE = 0;
uint256 internal constant US = 1;
uint256 internal constant EU = 2;
uint256 internal constant FORBIDDEN = 4;
uint256 internal constant JP = 8;
string internal constant TOKEN_PAUSED = "Token Paused";
string internal constant NOT_ENOUGH_TOKENS = "Not Enough Tokens";
string internal constant TOKENS_LOCKED = "Tokens Locked";
string internal constant WALLET_NOT_IN_REGISTRY_SERVICE = "Wallet not in registry Service";
string internal constant DESTINATION_RESTRICTED = "Destination restricted";
string internal constant VALID = "Valid";
string internal constant HOLD_UP = "Under lock-up";
string internal constant ONLY_FULL_TRANSFER = "Only Full Transfer";
string internal constant FLOWBACK = "Flowback";
string internal constant MAX_INVESTORS_IN_CATEGORY = "Max Investors in category";
string internal constant AMOUNT_OF_TOKENS_UNDER_MIN = "Amount of tokens under min";
string internal constant AMOUNT_OF_TOKENS_ABOVE_MAX = "Amount of tokens above max";
string internal constant ONLY_ACCREDITED = "Only accredited";
string internal constant ONLY_US_ACCREDITED = "Only us accredited";
string internal constant NOT_ENOUGH_INVESTORS = "Not enough investors";
string internal constant MAX_AUTHORIZED_SECURITIES_EXCEEDED = "Max authorized securities exceeded";
function initialize() public virtual;
function adjustInvestorCountsAfterCountryChange(
string memory _id,
string memory _country,
string memory _prevCountry
) public virtual returns (bool);
//*****************************************
// TOKEN ACTION VALIDATIONS
//*****************************************
function validateTransfer(
address _from,
address _to,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function validateTransfer(
address _from,
address _to,
uint256 _value, /*onlyToken*/
bool _pausedToken,
uint256 _balanceFrom
) public virtual returns (bool);
function validateIssuance(
address _to,
uint256 _value,
uint256 _issuanceTime /*onlyToken*/
) public virtual returns (bool);
function validateIssuanceWithNoCompliance(
address _to,
uint256 _value,
uint256 _issuanceTime /*onlyToken*/
) public virtual returns (bool);
function validateBurn(
address _who,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function validateSeize(
address _from,
address _to,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function preIssuanceCheck(address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);
function preTransferCheck(
address _from,
address _to,
uint256 _value
) public view virtual returns (uint256 code, string memory reason);
function newPreTransferCheck(
address _from,
address _to,
uint256 _value,
uint256 _balanceFrom,
bool _pausedToken
) public view virtual returns (uint256 code, string memory reason);
function preInternalTransferCheck(
address _from,
address _to,
uint256 _value
) public view virtual returns (uint256 code, string memory reason);
function validateIssuanceTime(uint256 _issuanceTime) public view virtual returns (uint256 issuanceTime);
function getComplianceTransferableTokens(
address _who,
uint256 _time,
uint64 _lockTime
) public view virtual returns (uint256);
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSLockManager {
function initialize() public virtual;
modifier validLock(uint256 _valueLocked, uint256 _releaseTime) {
require(_valueLocked > 0, "Value is zero");
require(_releaseTime == 0 || _releaseTime > uint256(block.timestamp), "Release time is in the past");
_;
}
event Locked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event Unlocked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event HolderLocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event HolderUnlocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
/**
* @dev creates a lock record for wallet address
* @param _to address to lock the tokens at
* @param _valueLocked value of tokens to lock
* @param _reason reason for lock
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* Note: The user MAY have at a certain time more locked tokens than actual tokens
*/
function addManualLockRecord(
address _to,
uint256 _valueLocked,
string calldata _reason,
uint256 _releaseTime /*issuerOrAboveOrToken*/
) public virtual;
/**
* @dev creates a lock record for investor Id
* @param _investor investor id to lock the tokens at
* @param _valueLocked value of tokens to lock
* @param _reasonCode reason code for lock
* @param _reasonString reason for lock
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* Note: The user MAY have at a certain time more locked tokens than actual tokens
*/
function createLockForInvestor(
string memory _investor,
uint256 _valueLocked,
uint256 _reasonCode,
string calldata _reasonString,
uint256 _releaseTime /*onlyIssuerOrAboveOrToken*/
) public virtual;
/**
* @dev Releases a specific lock record for a wallet
* @param _to address to release the tokens for
* @param _lockIndex the index of the lock to remove
*
* note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.
* @return true on success
*/
function removeLockRecord(
address _to,
uint256 _lockIndex /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Releases a specific lock record for a investor
* @param _investorId investor id to release the tokens for
* @param _lockIndex the index of the lock to remove
*
* note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.
* @return true on success
*/
function removeLockRecordForInvestor(
string memory _investorId,
uint256 _lockIndex /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Get number of locks currently associated with an address
* @param _who address to get count for
*
* @return number of locks
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockCount(address _who) public view virtual returns (uint256);
/**
* @dev Get number of locks currently associated with a investor
* @param _investorId investor id to get count for
*
* @return number of locks
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockCountForInvestor(string memory _investorId) public view virtual returns (uint256);
/**
* @dev Get details of a specific lock associated with an address
* can be used to iterate through the locks of a user
* @param _who address to get token lock for
* @param _lockIndex the 0 based index of the lock.
* @return reasonCode the reason code
* @return reasonString the reason for the lock
* @return value the value of tokens locked
* @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockInfo(address _who, uint256 _lockIndex) public view virtual returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);
/**
* @dev Get details of a specific lock associated with a investor
* can be used to iterate through the locks of a user
* @param _investorId investorId to get token lock for
* @param _lockIndex the 0 based index of the lock.
* @return reasonCode the reason code
* @return reasonString the reason for the lock
* @return value the value of tokens locked
* @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockInfoForInvestor(
string memory _investorId,
uint256 _lockIndex
) public view virtual returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);
/**
* @dev get total number of transferable tokens for a wallet, at a certain time
* @param _who address to get number of transferable tokens for
* @param _time time to calculate for
*/
function getTransferableTokens(address _who, uint256 _time) public view virtual returns (uint256);
/**
* @dev get total number of transferable tokens for a investor, at a certain time
* @param _investorId investor id
* @param _time time to calculate for
*/
function getTransferableTokensForInvestor(string memory _investorId, uint256 _time) public view virtual returns (uint256);
/**
* @dev pause investor
* @param _investorId investor id
*/
function lockInvestor(
string memory _investorId /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev unpauses investor
* @param _investorId investor id
*/
function unlockInvestor(
string memory _investorId /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Returns true if paused, otherwise false
* @param _investorId investor id
*/
function isInvestorLocked(string memory _investorId) public view virtual returns (bool);
}pragma solidity ^0.8.20;
import "./IDSLockManager.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSLockManagerPartitioned {
event LockedPartition(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);
event UnlockedPartition(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);
event HolderLockedPartition(string investorId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);
event HolderUnlockedPartition(string investorId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime, bytes32 indexed partition);
function createLockForInvestor(
string memory _investorId,
uint256 _valueLocked,
uint256 _reasonCode,
string memory _reasonString,
uint256 _releaseTime,
bytes32 _partition
) public virtual;
function addManualLockRecord(
address _to,
uint256 _valueLocked,
string memory _reason,
uint256 _releaseTime,
bytes32 _partition /*issuerOrAboveOrToken*/
) public virtual;
function removeLockRecord(
address _to,
uint256 _lockIndex,
bytes32 _partition /*issuerOrAbove*/
) public virtual returns (bool);
function removeLockRecordForInvestor(
string memory _investorId,
uint256 _lockIndex,
bytes32 _partition /*issuerOrAbove*/
) public virtual returns (bool);
function lockCount(address _who, bytes32 _partition) public view virtual returns (uint256);
function lockInfo(
address _who,
uint256 _lockIndex,
bytes32 _partition
)
public
view
virtual
returns (
uint256 reasonCode,
string memory reasonString,
uint256 value,
uint256 autoReleaseTime
);
function lockCountForInvestor(string memory _investorId, bytes32 _partition) public view virtual returns (uint256);
function lockInfoForInvestor(
string memory _investorId,
uint256 _lockIndex,
bytes32 _partition
)
public
view
virtual
returns (
uint256 reasonCode,
string memory reasonString,
uint256 value,
uint256 autoReleaseTime
);
function getTransferableTokens(
address _who,
uint256 _time,
bytes32 _partition
) public view virtual returns (uint256);
function getTransferableTokensForInvestor(
string memory _investorId,
uint256 _time,
bytes32 _partition
) public view virtual returns (uint256);
/*************** Legacy functions ***************/
function createLockForHolder(
string memory _investorId,
uint256 _valueLocked,
uint256 _reasonCode,
string memory _reasonString,
uint256 _releaseTime,
bytes32 _partition
) public virtual;
function removeLockRecordForHolder(
string memory _investorId,
uint256 _lockIndex,
bytes32 _partition
) public virtual returns (bool);
function lockCountForHolder(string memory _holderId, bytes32 _partition) public view virtual returns (uint256);
function lockInfoForHolder(
string memory _holderId,
uint256 _lockIndex,
bytes32 _partition
)
public
view
virtual
returns (
uint256 reasonCode,
string memory reasonString,
uint256 value,
uint256 autoReleaseTime
);
function getTransferableTokensForHolder(
string memory _holderId,
uint256 _time,
bytes32 _partition
) public view virtual returns (uint256);
/******************************/
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSPartitionsManager {
event PartitionCreated(uint256 _date, uint256 _region, bytes32 _partition);
function initialize() public virtual;
function ensurePartition(
uint256 _issuanceDate,
uint256 _region /*onlyIssuerOrAboveOrToken*/
) public virtual returns (bytes32 partition);
function getPartition(bytes32 _partition) public view virtual returns (uint256 date, uint256 region);
function getPartitionIssuanceDate(bytes32 _partition) public view virtual returns (uint256);
function getPartitionRegion(bytes32 _partition) public view virtual returns (uint256);
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSWalletManager {
function initialize() public virtual;
// Special wallets constants
uint8 public constant NONE = 0;
uint8 public constant ISSUER = 1;
uint8 public constant PLATFORM = 2;
uint8 public constant EXCHANGE = 4;
/**
* @dev should be emitted when a special wallet is added.
*/
event DSWalletManagerSpecialWalletAdded(address wallet, uint8 walletType, address sender);
/**
* @dev should be emitted when a special wallet is removed.
*/
event DSWalletManagerSpecialWalletRemoved(address wallet, uint8 walletType, address sender);
/**
* @dev should be emitted when the number of reserved slots is set for a wallet.
*/
event DSWalletManagerReservedSlotsSet(address wallet, string country, uint8 accreditationStatus, uint256 slots, address sender);
/**
* @dev Sets a wallet to be an special wallet. (internal)
* @param _wallet The address of the wallet.
* @param _type The type of the wallet.
* @return A boolean that indicates if the operation was successful.
*/
function setSpecialWallet(address _wallet, uint8 _type) internal virtual returns (bool);
/**
* @dev gets a wallet type
* @param _wallet the address of the wallet to check.
*/
function getWalletType(address _wallet) public view virtual returns (uint8);
/**
* @dev Returns true if it is platform wallet
* @param _wallet the address of the wallet to check.
*/
function isPlatformWallet(address _wallet) external view virtual returns (bool);
/**
* @dev Returns true if it is special wallet
* @param _wallet the address of the wallet to check.
*/
function isSpecialWallet(address _wallet) external view virtual returns (bool);
/**
* @dev Returns true if it is issuer special wallet
* @param _wallet the address of the wallet to check.
*/
function isIssuerSpecialWallet(address _wallet) external view virtual returns (bool);
/**
* @dev Sets a wallet to be an issuer wallet.
* @param _wallet The address of the wallet.
* @return A boolean that indicates if the operation was successful.
*/
function addIssuerWallet(
address _wallet /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Sets an array of wallets to be issuer wallets.
* @param _wallets The address of the wallets.
* @return A boolean that indicates if the operation was successful.
*/
function addIssuerWallets(address[] memory _wallets) public virtual returns (bool);
/**
* @dev Sets a wallet to be a platform wallet.
* @param _wallet The address of the wallet.
* @return A boolean that indicates if the operation was successful.
*/
function addPlatformWallet(
address _wallet /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Sets an array of wallets to be platforms wallet.
* @param _wallets The address of the wallets.
* @return A boolean that indicates if the operation was successful.
*/
function addPlatformWallets(address[] memory _wallets) public virtual returns (bool);
/**
* @dev Sets a wallet to be an exchange wallet.
* @param _wallet The address of the wallet.
* @param _owner The address of the owner.
* @return A boolean that indicates if the operation was successful.
*/
function addExchangeWallet(address _wallet, address _owner) public virtual returns (bool);
/**
* @dev Removes a special wallet.
* @param _wallet The address of the wallet.
* @return A boolean that indicates if the operation was successful.
*/
function removeSpecialWallet(
address _wallet /*onlyIssuerOrAbove*/
) public virtual returns (bool);
}pragma solidity ^0.8.20;
import "./ServiceConsumerDataStore.sol";
//SPDX-License-Identifier: GPL-3.0
contract OmnibusTBEControllerDataStore is ServiceConsumerDataStore {
address internal omnibusWallet;
bool internal isPartitionedToken;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
contract ServiceConsumerDataStore {
mapping(uint256 => address) internal services;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSTokenIssuer {
function initialize() public virtual;
//Same values as IDSRegistryService
uint8 public constant KYC_APPROVED = 1;
uint8 public constant ACCREDITED = 2;
uint8 public constant QUALIFIED = 4;
function issueTokens(
string memory _id,
address _to,
uint256[] memory _issuanceValues,
string calldata _reason,
uint256[] memory _locksValues,
uint64[] memory _lockReleaseTimes,
string memory _collisionHash,
string memory _country,
uint256[] memory attributeValues,
uint256[] memory attributeExpirations /*onlyIssuerOrAbove*/
) public virtual returns (bool);
}pragma solidity ^0.8.20;
import "./IDSTokenIssuer.sol";
import "../utils/BaseDSContract.sol";
//SPDX-License-Identifier: GPL-3.0
contract TokenIssuer is IDSTokenIssuer, BaseDSContract {
function initialize() public override onlyProxy initializer {
__BaseDSContract_init();
}
function issueTokens(
string memory _id,
address _to,
uint256[] memory _issuanceValues,
string calldata _reason,
uint256[] memory _locksValues,
uint64[] memory _lockReleaseTimes,
string memory _collisionHash,
string memory _country,
uint256[] memory _attributeValues,
uint256[] memory _attributeExpirations
) public override onlyIssuerOrAbove returns (bool) {
require(_issuanceValues.length == 2, "Wrong length of parameters");
require(_attributeValues.length == _attributeExpirations.length, "Wrong length of parameters");
require(_locksValues.length == _lockReleaseTimes.length, "Wrong length of parameters");
if (getRegistryService().isWallet(_to)) {
require(CommonUtils.isEqualString(getRegistryService().getInvestor(_to), _id), "Wallet does not belong to investor");
} else {
registerInvestor(_id, _to, _collisionHash, _country, _attributeValues, _attributeExpirations);
}
getToken().issueTokensWithMultipleLocks(_to, _issuanceValues[0], _issuanceValues[1], _locksValues, _reason, _lockReleaseTimes);
return true;
}
function registerInvestor(
string memory _id,
address _wallet,
string memory _collisionHash,
string memory _country,
uint256[] memory _attributeValues,
uint256[] memory _attributeExpirations
) private {
if (!getRegistryService().isInvestor(_id)) {
getRegistryService().registerInvestor(_id, _collisionHash);
getRegistryService().setCountry(_id, _country);
if (_attributeValues.length > 0) {
require(_attributeValues.length == 3, "Wrong length of parameters");
getRegistryService().setAttribute(_id, KYC_APPROVED, _attributeValues[0], _attributeExpirations[0], "");
getRegistryService().setAttribute(_id, ACCREDITED, _attributeValues[1], _attributeExpirations[1], "");
getRegistryService().setAttribute(_id, QUALIFIED, _attributeValues[2], _attributeExpirations[2], "");
}
}
getRegistryService().addWallet(_wallet, _id);
}
}pragma solidity ^0.8.20;
import "../service/ServiceConsumer.sol";
import "../data-stores/OmnibusTBEControllerDataStore.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSOmnibusTBEController {
function initialize(address _omnibusWallet, bool _isPartitionedToken) public virtual;
function bulkIssuance(
uint256 value,
uint256 issuanceTime,
uint256 totalInvestors,
uint256 accreditedInvestors,
uint256 usAccreditedInvestors,
uint256 usTotalInvestors,
uint256 jpTotalInvestors,
bytes32[] calldata euRetailCountries,
uint256[] calldata euRetailCountryCounts
) public virtual;
function bulkBurn(
uint256 value,
uint256 totalInvestors,
uint256 accreditedInvestors,
uint256 usAccreditedInvestors,
uint256 usTotalInvestors,
uint256 jpTotalInvestors,
bytes32[] calldata euRetailCountries,
uint256[] calldata euRetailCountryCounts
) public virtual;
function bulkTransfer(address[] calldata wallets, uint256[] calldata values) public virtual;
function adjustCounters(
int256 totalDelta,
int256 accreditedDelta,
int256 usAccreditedDelta,
int256 usTotalDelta,
int256 jpTotalDelta,
bytes32[] calldata euRetailCountries,
int256[] calldata euRetailCountryDeltas
) public virtual;
function getOmnibusWallet() public view virtual returns (address);
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSOmnibusWalletController {
uint8 public constant BENEFICIARY = 0;
uint8 public constant HOLDER_OF_RECORD = 1;
function initialize(address _omnibusWallet) public virtual;
function setAssetTrackingMode(uint8 _assetTrackingMode) public virtual;
function getAssetTrackingMode() public view virtual returns (uint8);
function isHolderOfRecord() public view virtual returns (bool);
function balanceOf(address _who) public view virtual returns (uint256);
function transfer(
address _from,
address _to,
uint256 _value /*onlyOperator*/
) public virtual;
function deposit(
address _to,
uint256 _value /*onlyToken*/
) public virtual;
function withdraw(
address _from,
uint256 _value /*onlyToken*/
) public virtual;
function seize(
address _from,
uint256 _value /*onlyToken*/
) public virtual;
function burn(
address _from,
uint256 _value /*onlyToken*/
) public virtual;
}pragma solidity ^0.8.20;
import "../utils/CommonUtils.sol";
import "../omnibus/IDSOmnibusWalletController.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSRegistryService {
function initialize() public virtual;
event DSRegistryServiceInvestorAdded(string investorId, address sender);
event DSRegistryServiceInvestorRemoved(string investorId, address sender);
event DSRegistryServiceInvestorCountryChanged(string investorId, string country, address sender);
event DSRegistryServiceInvestorAttributeChanged(string investorId, uint256 attributeId, uint256 value, uint256 expiry, string proofHash, address sender);
event DSRegistryServiceWalletAdded(address wallet, string investorId, address sender);
event DSRegistryServiceWalletRemoved(address wallet, string investorId, address sender);
event DSRegistryServiceOmnibusWalletAdded(address omnibusWallet, string investorId, IDSOmnibusWalletController omnibusWalletController);
event DSRegistryServiceOmnibusWalletRemoved(address omnibusWallet, string investorId);
uint8 public constant NONE = 0;
uint8 public constant KYC_APPROVED = 1;
uint8 public constant ACCREDITED = 2;
uint8 public constant QUALIFIED = 4;
uint8 public constant PROFESSIONAL = 8;
uint8 public constant PENDING = 0;
uint8 public constant APPROVED = 1;
uint8 public constant REJECTED = 2;
uint8 public constant EXCHANGE = 4;
modifier investorExists(string memory _id) {
require(isInvestor(_id), "Unknown investor");
_;
}
modifier newInvestor(string memory _id) {
require(!CommonUtils.isEmptyString(_id), "Investor id must not be empty");
require(!isInvestor(_id), "Investor already exists");
_;
}
modifier walletExists(address _address) {
require(isWallet(_address), "Unknown wallet");
_;
}
modifier newWallet(address _address) {
require(!isWallet(_address), "Wallet already exists");
_;
}
modifier newOmnibusWallet(address _omnibusWallet) {
require(!isOmnibusWallet(_omnibusWallet), "Omnibus wallet already exists");
_;
}
modifier omnibusWalletExists(address _omnibusWallet) {
require(isOmnibusWallet(_omnibusWallet), "Unknown omnibus wallet");
_;
}
modifier walletBelongsToInvestor(address _address, string memory _id) {
require(CommonUtils.isEqualString(getInvestor(_address), _id), "Wallet does not belong to investor");
_;
}
function registerInvestor(
string calldata _id,
string calldata _collision_hash /*onlyExchangeOrAbove newInvestor(_id)*/
) public virtual returns (bool);
function updateInvestor(
string calldata _id,
string calldata _collisionHash,
string memory _country,
address[] memory _wallets,
uint8[] memory _attributeIds,
uint256[] memory _attributeValues,
uint256[] memory _attributeExpirations /*onlyIssuerOrAbove*/
) public virtual returns (bool);
function removeInvestor(
string calldata _id /*onlyExchangeOrAbove investorExists(_id)*/
) public virtual returns (bool);
function setCountry(
string calldata _id,
string memory _country /*onlyExchangeOrAbove investorExists(_id)*/
) public virtual returns (bool);
function getCountry(string memory _id) public view virtual returns (string memory);
function getCollisionHash(string calldata _id) public view virtual returns (string memory);
function setAttribute(
string calldata _id,
uint8 _attributeId,
uint256 _value,
uint256 _expiry,
string memory _proofHash /*onlyExchangeOrAbove investorExists(_id)*/
) public virtual returns (bool);
function getAttributeValue(string memory _id, uint8 _attributeId) public view virtual returns (uint256);
function getAttributeExpiry(string memory _id, uint8 _attributeId) public view virtual returns (uint256);
function getAttributeProofHash(string memory _id, uint8 _attributeId) public view virtual returns (string memory);
function addWallet(
address _address,
string memory _id /*onlyExchangeOrAbove newWallet(_address)*/
) public virtual returns (bool);
function addWalletByInvestor(address _address) public virtual returns (bool);
function removeWallet(
address _address,
string memory _id /*onlyExchangeOrAbove walletExists walletBelongsToInvestor(_address, _id)*/
) public virtual returns (bool);
function addOmnibusWallet(
string memory _id,
address _omnibusWallet,
IDSOmnibusWalletController _omnibusWalletController /*onlyIssuerOrAbove newOmnibusWallet*/
) public virtual;
function removeOmnibusWallet(
string memory _id,
address _omnibusWallet /*onlyIssuerOrAbove omnibusWalletControllerExists*/
) public virtual;
function getOmnibusWalletController(address _omnibusWallet) public view virtual returns (IDSOmnibusWalletController);
function isOmnibusWallet(address _omnibusWallet) public view virtual returns (bool);
function getInvestor(address _address) public view virtual returns (string memory);
function getInvestorDetails(address _address) public view virtual returns (string memory, string memory);
function getInvestorDetailsFull(string memory _id)
public
view
virtual
returns (string memory, uint256[] memory, uint256[] memory, string memory, string memory, string memory, string memory);
function isInvestor(string memory _id) public view virtual returns (bool);
function isWallet(address _address) public view virtual returns (bool);
function isAccreditedInvestor(string calldata _id) external view virtual returns (bool);
function isQualifiedInvestor(string calldata _id) external view virtual returns (bool);
function isAccreditedInvestor(address _wallet) external view virtual returns (bool);
function isQualifiedInvestor(address _wallet) external view virtual returns (bool);
function getInvestors(address _from, address _to) external view virtual returns (string memory, string memory);
}pragma solidity ^0.8.20;
import "../omnibus/IDSOmnibusWalletController.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSServiceConsumer {
uint256 public constant TRUST_SERVICE = 1;
uint256 public constant DS_TOKEN = 2;
uint256 public constant REGISTRY_SERVICE = 4;
uint256 public constant COMPLIANCE_SERVICE = 8;
uint256 public constant UNUSED_1 = 16;
uint256 public constant WALLET_MANAGER = 32;
uint256 public constant LOCK_MANAGER = 64;
uint256 public constant PARTITIONS_MANAGER = 128;
uint256 public constant COMPLIANCE_CONFIGURATION_SERVICE = 256;
uint256 public constant TOKEN_ISSUER = 512;
uint256 public constant WALLET_REGISTRAR = 1024;
uint256 public constant OMNIBUS_TBE_CONTROLLER = 2048;
uint256 public constant TRANSACTION_RELAYER = 4096;
uint256 public constant TOKEN_REALLOCATOR = 8192;
uint256 public constant ISSUER_MULTICALL = 8194;
uint256 public constant TA_MULTICALL = 8195;
uint256 public constant SECURITIZE_SWAP = 16384;
function getDSService(uint256 _serviceId) public view virtual returns (address);
function setDSService(
uint256 _serviceId,
address _address /*onlyMaster*/
) public virtual returns (bool);
event DSServiceSet(uint256 serviceId, address serviceAddress);
}pragma solidity ^0.8.20;
import "./IDSServiceConsumer.sol";
import "../data-stores/ServiceConsumerDataStore.sol";
import "../token/IDSToken.sol";
import "../compliance/IDSWalletManager.sol";
import "../compliance/IDSLockManager.sol";
import "../compliance/IDSLockManagerPartitioned.sol";
import "../compliance/IDSComplianceService.sol";
import "../compliance/IDSPartitionsManager.sol";
import "../compliance/IDSComplianceConfigurationService.sol";
import "../registry/IDSRegistryService.sol";
import "../omnibus/IDSOmnibusTBEController.sol";
import "../trust/IDSTrustService.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract ServiceConsumer is IDSServiceConsumer, ServiceConsumerDataStore, OwnableUpgradeable {
// Bring role constants to save gas both in deployment (less bytecode) and usage
uint8 public constant ROLE_NONE = 0;
uint8 public constant ROLE_MASTER = 1;
uint8 public constant ROLE_ISSUER = 2;
uint8 public constant ROLE_EXCHANGE = 4;
uint8 public constant ROLE_TRANSFER_AGENT = 8;
function __ServiceConsumer_init() public virtual onlyInitializing {
__Ownable_init(msg.sender);
}
modifier onlyMaster {
IDSTrustService trustManager = getTrustService();
require(owner() == msg.sender || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
_;
}
/**
* @dev Allow invoking functions only by the users who have the MASTER role or the ISSUER role or the TRANSFER AGENT role.
*/
modifier onlyIssuerOrTransferAgentOrAbove() {
IDSTrustService trustManager = getTrustService();
require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
_;
}
modifier onlyIssuerOrAbove {
IDSTrustService trustManager = getTrustService();
require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
_;
}
modifier onlyTransferAgentOrAbove {
IDSTrustService trustManager = getTrustService();
require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
_;
}
modifier onlyExchangeOrAbove {
IDSTrustService trustManager = getTrustService();
require(
trustManager.getRole(msg.sender) == ROLE_EXCHANGE
|| trustManager.getRole(msg.sender) == ROLE_ISSUER
|| trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT
|| trustManager.getRole(msg.sender) == ROLE_MASTER,
"Insufficient trust level"
);
_;
}
modifier onlyToken {
require(msg.sender == getDSService(DS_TOKEN), "This function can only called by the associated token");
_;
}
modifier onlyRegistry {
require(msg.sender == getDSService(REGISTRY_SERVICE), "This function can only called by the registry service");
_;
}
modifier onlyIssuerOrAboveOrToken {
if (msg.sender != getDSService(DS_TOKEN)) {
IDSTrustService trustManager = IDSTrustService(getDSService(TRUST_SERVICE));
require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
}
_;
}
modifier onlyTransferAgentOrAboveOrToken {
if (msg.sender != getDSService(DS_TOKEN)) {
IDSTrustService trustManager = IDSTrustService(getDSService(TRUST_SERVICE));
require(trustManager.getRole(msg.sender) == ROLE_TRANSFER_AGENT || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
}
_;
}
modifier onlyOmnibusWalletController(address omnibusWallet, IDSOmnibusWalletController omnibusWalletController) {
require(getRegistryService().getOmnibusWalletController(omnibusWallet) == omnibusWalletController, "Wrong controller address");
_;
}
modifier onlyTBEOmnibus {
require(msg.sender == address(getOmnibusTBEController()), "Not authorized");
_;
}
modifier onlyMasterOrTBEOmnibus {
IDSTrustService trustManager = getTrustService();
require(msg.sender == address(getOmnibusTBEController()) ||
owner() == msg.sender || trustManager.getRole(msg.sender) == ROLE_MASTER, "Not authorized");
_;
}
modifier onlyOwnerOrIssuerOrAbove {
if(owner() != msg.sender) {
IDSTrustService trustManager = getTrustService();
require(trustManager.getRole(msg.sender) == ROLE_ISSUER || trustManager.getRole(msg.sender) == ROLE_MASTER, "Insufficient trust level");
}
_;
}
function getDSService(uint256 _serviceId) public view override returns (address) {
return services[_serviceId];
}
function setDSService(uint256 _serviceId, address _address) public override onlyMaster returns (bool) {
services[_serviceId] = _address;
emit DSServiceSet(_serviceId, _address);
return true;
}
function getToken() internal view returns (IDSToken) {
return IDSToken(getDSService(DS_TOKEN));
}
function getTrustService() internal view returns (IDSTrustService) {
return IDSTrustService(getDSService(TRUST_SERVICE));
}
function getWalletManager() internal view returns (IDSWalletManager) {
return IDSWalletManager(getDSService(WALLET_MANAGER));
}
function getLockManager() internal view returns (IDSLockManager) {
return IDSLockManager(getDSService(LOCK_MANAGER));
}
function getLockManagerPartitioned() internal view returns (IDSLockManagerPartitioned) {
return IDSLockManagerPartitioned(getDSService(LOCK_MANAGER));
}
function getComplianceService() internal view returns (IDSComplianceService) {
return IDSComplianceService(getDSService(COMPLIANCE_SERVICE));
}
function getRegistryService() internal view returns (IDSRegistryService) {
return IDSRegistryService(getDSService(REGISTRY_SERVICE));
}
function getPartitionsManager() internal view returns (IDSPartitionsManager) {
return IDSPartitionsManager(getDSService(PARTITIONS_MANAGER));
}
function getComplianceConfigurationService() internal view returns (IDSComplianceConfigurationService) {
return IDSComplianceConfigurationService(getDSService(COMPLIANCE_CONFIGURATION_SERVICE));
}
function getOmnibusTBEController() internal view returns (IDSOmnibusTBEController) {
return IDSOmnibusTBEController(getDSService(OMNIBUS_TBE_CONTROLLER));
}
}pragma solidity ^0.8.20;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../utils/CommonUtils.sol";
import "../omnibus/IDSOmnibusWalletController.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSToken is IERC20, Initializable {
event Issue(address indexed to, uint256 value, uint256 valueLocked);
event Burn(address indexed burner, uint256 value, string reason);
event Seize(address indexed from, address indexed to, uint256 value, string reason);
event OmnibusDeposit(address indexed omnibusWallet, address to, uint256 value, uint8 assetTrackingMode);
event OmnibusWithdraw(address indexed omnibusWallet, address from, uint256 value, uint8 assetTrackingMode);
event OmnibusSeize(address indexed omnibusWallet, address from, uint256 value, string reason, uint8 assetTrackingMode);
event OmnibusBurn(address indexed omnibusWallet, address who, uint256 value, string reason, uint8 assetTrackingMode);
event OmnibusTransfer(address indexed omnibusWallet, address from, address to, uint256 value, uint8 assetTrackingMode);
event OmnibusTBEOperation(address indexed omnibusWallet, int256 totalDelta, int256 accreditedDelta,
int256 usAccreditedDelta, int256 usTotalDelta, int256 jpTotalDelta);
event OmnibusTBETransfer(address omnibusWallet, string externalId);
event WalletAdded(address wallet);
event WalletRemoved(address wallet);
function initialize(string calldata _name, string calldata _symbol, uint8 _decimals) public virtual;
/******************************
CONFIGURATION
*******************************/
/**
* @dev Sets the total issuance cap
* Note: The cap is compared to the total number of issued token, not the total number of tokens available,
* So if a token is burned, it is not removed from the "total number of issued".
* This call cannot be called again after it was called once.
* @param _cap address The address which is going to receive the newly issued tokens
*/
function setCap(
uint256 _cap /*onlyMaster*/
) public virtual;
/******************************
TOKEN ISSUANCE (MINTING)
*******************************/
/**
* @dev Issues unlocked tokens
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @return true if successful
*/
function issueTokens(
address _to,
uint256 _value /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Issuing tokens from the fund
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @param _valueLocked uint256 value of tokens, from those issued, to lock immediately.
* @param _reason reason for token locking
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* @return true if successful
*/
function issueTokensCustom(
address _to,
uint256 _value,
uint256 _issuanceTime,
uint256 _valueLocked,
string memory _reason,
uint64 _releaseTime /*onlyIssuerOrAbove*/
) public virtual returns (bool);
function issueTokensWithMultipleLocks(
address _to,
uint256 _value,
uint256 _issuanceTime,
uint256[] memory _valuesLocked,
string memory _reason,
uint64[] memory _releaseTimes /*onlyIssuerOrAbove*/
) public virtual returns (bool);
function issueTokensWithNoCompliance(address _to, uint256 _value) public virtual /*onlyIssuerOrAbove*/;
//*********************
// TOKEN BURNING
//*********************
function burn(
address _who,
uint256 _value,
string calldata _reason /*onlyIssuerOrAbove*/
) public virtual;
function omnibusBurn(
address _omnibusWallet,
address _who,
uint256 _value,
string calldata _reason /*onlyIssuerOrAbove*/
) public virtual;
//*********************
// TOKEN SIEZING
//*********************
function seize(
address _from,
address _to,
uint256 _value,
string calldata _reason /*onlyIssuerOrAbove*/
) public virtual;
function omnibusSeize(
address _omnibusWallet,
address _from,
address _to,
uint256 _value,
string calldata
/*onlyIssuerOrAbove*/
) public virtual;
//*********************
// WALLET ENUMERATION
//*********************
function getWalletAt(uint256 _index) public view virtual returns (address);
function walletCount() public view virtual returns (uint256);
//**************************************
// MISCELLANEOUS FUNCTIONS
//**************************************
function isPaused() public view virtual returns (bool);
function balanceOfInvestor(string memory _id) public view virtual returns (uint256);
function updateOmnibusInvestorBalance(
address _omnibusWallet,
address _wallet,
uint256 _value,
CommonUtils.IncDec _increase /*onlyOmnibusWalletController*/
) public virtual returns (bool);
function emitOmnibusTransferEvent(
address _omnibusWallet,
address _from,
address _to,
uint256 _value /*onlyOmnibusWalletController*/
) public virtual;
function emitOmnibusTBEEvent(address omnibusWallet, int256 totalDelta, int256 accreditedDelta,
int256 usAccreditedDelta, int256 usTotalDelta, int256 jpTotalDelta /*onlyTBEOmnibus*/
) public virtual;
function emitOmnibusTBETransferEvent(address omnibusWallet, string memory externalId) public virtual;
function updateInvestorBalance(address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal virtual returns (bool);
function preTransferCheck(address _from, address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);
}pragma solidity ^0.8.20;
/**
* @title IDSTrustService
* @dev An interface for a trust service which allows role-based access control for other contracts.
*/
//SPDX-License-Identifier: GPL-3.0
abstract contract IDSTrustService {
function initialize() public virtual;
/**
* @dev Should be emitted when a role is set for a user.
*/
event DSTrustServiceRoleAdded(address targetAddress, uint8 role, address sender);
/**
* @dev Should be emitted when a role is removed for a user.
*/
event DSTrustServiceRoleRemoved(address targetAddress, uint8 role, address sender);
// Role constants
uint8 public constant NONE = 0;
uint8 public constant MASTER = 1;
uint8 public constant ISSUER = 2;
uint8 public constant EXCHANGE = 4;
uint8 public constant TRANSFER_AGENT = 8;
/**
* @dev Transfers the ownership (MASTER role) of the contract.
* @param _address The address which the ownership needs to be transferred to.
* @return A boolean that indicates if the operation was successful.
*/
function setServiceOwner(
address _address /*onlyMaster*/
) public virtual returns (bool);
/**
* @dev Sets a role for an array of wallets.
* @dev Should not be used for setting MASTER (use setServiceOwner) or role removal (use removeRole).
* @param _addresses The array of wallet whose role needs to be set.
* @param _roles The array of role to be set. The length and order must match with _addresses
* @return A boolean that indicates if the operation was successful.
*/
function setRoles(address[] calldata _addresses, uint8[] calldata _roles) public virtual returns (bool);
/**
* @dev Sets a role for a wallet.
* @dev Should not be used for setting MASTER (use setServiceOwner) or role removal (use removeRole).
* @param _address The wallet whose role needs to be set.
* @param _role The role to be set.
* @return A boolean that indicates if the operation was successful.
*/
function setRole(
address _address,
uint8 _role /*onlyMasterOrIssuer*/
) public virtual returns (bool);
/**
* @dev Removes the role for a wallet.
* @dev Should not be used to remove MASTER (use setServiceOwner).
* @param _address The wallet whose role needs to be removed.
* @return A boolean that indicates if the operation was successful.
*/
function removeRole(
address _address /*onlyMasterOrIssuer*/
) public virtual returns (bool);
/**
* @dev Gets the role for a wallet.
* @param _address The wallet whose role needs to be fetched.
* @return A boolean that indicates if the operation was successful.
*/
function getRole(address _address) public view virtual returns (uint8);
function addEntity(
string calldata _name,
address _owner /*onlyMasterOrIssuer onlyNewEntity onlyNewEntityOwner*/
) public virtual;
function changeEntityOwner(
string calldata _name,
address _oldOwner,
address _newOwner /*onlyMasterOrIssuer onlyExistingEntityOwner*/
) public virtual;
function addOperator(
string calldata _name,
address _operator /*onlyEntityOwnerOrAbove onlyNewOperator*/
) public virtual;
function removeOperator(
string calldata _name,
address _operator /*onlyEntityOwnerOrAbove onlyExistingOperator*/
) public virtual;
function addResource(
string calldata _name,
address _resource /*onlyMasterOrIssuer onlyExistingEntity onlyNewResource*/
) public virtual;
function removeResource(
string calldata _name,
address _resource /*onlyMasterOrIssuer onlyExistingResource*/
) public virtual;
function getEntityByOwner(address _owner) public view virtual returns (string memory);
function getEntityByOperator(address _operator) public view virtual returns (string memory);
function getEntityByResource(address _resource) public view virtual returns (string memory);
function isResourceOwner(address _resource, address _owner) public view virtual returns (bool);
function isResourceOperator(address _resource, address _operator) public view virtual returns (bool);
}pragma solidity ^0.8.20;
import "../service/ServiceConsumer.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
//SPDX-License-Identifier: GPL-3.0
abstract contract BaseDSContract is UUPSUpgradeable, ServiceConsumer {
function __BaseDSContract_init() public onlyProxy onlyInitializing {
__UUPSUpgradeable_init();
__ServiceConsumer_init();
}
/**
* @dev required by the OZ UUPS module
*/
function _authorizeUpgrade(address) internal override onlyMaster {}
/**
* @dev returns proxy ERC1967 implementation address
*/
function getImplementationAddress() external view returns (address) {
return ERC1967Utils.getImplementation();
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function getInitializedVersion() external view returns (uint64) {
return _getInitializedVersion();
}
}pragma solidity ^0.8.20;
//SPDX-License-Identifier: GPL-3.0
library CommonUtils {
enum IncDec { Increase, Decrease }
function encodeString(string memory _str) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_str));
}
function isEqualString(string memory _str1, string memory _str2) internal pure returns (bool) {
return encodeString(_str1) == encodeString(_str2);
}
function isEmptyString(string memory _str) internal pure returns (bool) {
return isEqualString(_str, "");
}
}/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.20;
interface IBridge {
/// @notice Thrown when a zero address is provided where a non-zero address is required
/// @custom:selector 0xbf8d7175
error NonZeroAddress();
/// @notice Thrown when eth transfer fails
/// @custom:selector 0x7ea369e9
error ETHTransferError();
/**
* @notice Emitted when a new bridge address is set
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param chainId Bridge chain id
* @param bridgeAddress bridge address
*/
event BridgeAddressAdded(uint16 chainId, address bridgeAddress);
/**
* @notice Emitted when a new bridge address is removed
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param chainId Bridge chain id
*/
event BridgeAddressRemoved(uint16 chainId);
/**
* @notice Emitted when a gas limit value is updated
* @param oldGasLimit old gas limit value
* @param newGasLimit new gas limit value
*/
event GasLimitUpdate(uint256 oldGasLimit, uint256 newGasLimit);
/**
* @notice Emitted when and admin withdraw contract funds
* @param recipient Recipient address.
* @param amount Balance value.
*/
event ETHWithdrawn(address payable recipient, uint256 amount);
/**
* @notice Remove a chain bridge address
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param chainId Bridge chain id
*/
function removeBridgeAddress(uint16 chainId) external;
/**
* @notice Update gas limit value
* @param _gasLimit new gas limit value
*/
function updateGasLimit(uint256 _gasLimit) external;
/**
* @notice Get total cost of bridge operation
* @dev targetChainId is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param targetChainId chain id
*/
function quoteBridge(uint16 targetChainId) external view returns (uint256);
/**
* @notice Withdraws the full ETH balance of the contract to a specified address.
* @dev Only callable by an address with the admin role.
* @param _to The address that will receive the ETH.
*/
function withdrawETH(address payable _to) external;
}/**
* Copyright 2024 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.20;
import {IBridge} from "./IBridge.sol";
interface ISecuritizeBridge is IBridge {
struct InvestorDetail {
string investorId;
string country;
uint256[] attributeValues;
uint256[] attributeExpirations;
}
/**
* @notice UUPSUpgradeable initiator method
* @param _whChainId wormhole chain id
* @param _wormholeRelayer bridge relayer address
* @param _dsToken ds token address
* @param _owner contract owner
*/
function initialize(uint16 _whChainId, address _wormholeRelayer, address _dsToken, address _owner) external;
/**
* @notice Emitted when tokens are burnt and sent from source blockchain
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param targetChainId chain id
* @param dsToken token address
* @param investorWallet holder wallet
* @param value amount bridged
*/
event DSTokenBridgeSend(uint16 targetChainId, address dsToken, address investorWallet, uint256 value);
/**
* @notice Emitted when tokens are received and issued in target blockchain
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param sourceChainId chain id
* @param dsToken token address
* @param investorWallet holder wallet
* @param value amount bridged
*/
event DSTokenBridgeReceive(uint16 sourceChainId, address dsToken, address investorWallet, uint256 value);
/**
* @notice Set a mapping with available bridges per chain
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param chainId Bridge chain id
* @param bridgeAddress bridge address
*/
function setBridgeAddress(uint16 chainId, address bridgeAddress) external;
/**
* @notice Bridge dsTokens between blockchain
* @dev chain Id is not EVM chain id, please refer to https://wormhole.com/docs/build/reference/chain-ids/
* @param targetChainId chain id
* @param value - Amount to be bridged
*/
function bridgeDSTokens(uint16 targetChainId, uint256 value) external payable;
}/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.20;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
abstract contract BaseContract is UUPSUpgradeable, PausableUpgradeable, OwnableUpgradeable {
uint256[50] private __gap;
function __BaseDSContract_init(address owner) internal onlyInitializing {
__UUPSUpgradeable_init();
__Pausable_init();
__Ownable_init(owner);
}
/**
* @dev required by the OZ UUPS module
*/
function _authorizeUpgrade(address) internal override onlyOwner {}
/**
* @dev returns proxy ERC1967 implementation address
*/
function getImplementationAddress() external view returns (address) {
return ERC1967Utils.getImplementation();
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function getInitializedVersion() external view returns (uint64) {
return _getInitializedVersion();
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
/**
* @notice Interface for a contract which can receive Wormhole messages.
*/
interface IWormholeReceiver {
/**
* @notice When a `send` is performed with this contract as the target, this function will be
* invoked by the WormholeRelayer contract
*
* NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.
*
* We also recommend that this function checks that `sourceChain` and `sourceAddress` are indeed who
* you expect to have requested the calling of `send` on the source chain
*
* The invocation of this function corresponding to the `send` request will have msg.value equal
* to the receiverValue specified in the send request.
*
* If the invocation of this function reverts or exceeds the gas limit
* specified by the send requester, this delivery will result in a `ReceiverFailure`.
*
* @param payload - an arbitrary message which was included in the delivery by the
* requester. This message's signature will already have been verified (as long as msg.sender is the Wormhole Relayer contract)
* @param additionalMessages - Additional messages which were requested to be included in this delivery.
* Note: There are no contract-level guarantees that the messages in this array are what was requested
* so **you should verify any sensitive information given here!**
*
* For example, if a 'VaaKey' was specified on the source chain, then MAKE SURE the corresponding message here
* has valid signatures (by calling `parseAndVerifyVM(message)` on the Wormhole core contract)
*
* This field can be used to perform and relay TokenBridge or CCTP transfers, and there are example
* usages of this at
* https://github.com/wormhole-foundation/hello-token
* https://github.com/wormhole-foundation/hello-cctp
*
* @param sourceAddress - the (wormhole format) address on the sending chain which requested
* this delivery.
* @param sourceChain - the wormhole chain ID where this delivery was requested.
* @param deliveryHash - the VAA hash of the deliveryVAA.
*
*/
function receiveWormholeMessages(
bytes memory payload,
bytes[] memory additionalMessages,
bytes32 sourceAddress,
uint16 sourceChain,
bytes32 deliveryHash
) external payable;
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
/**
* @title WormholeRelayer
* @author
* @notice This project allows developers to build cross-chain applications powered by Wormhole without needing to
* write and run their own relaying infrastructure
*
* We implement the IWormholeRelayer interface that allows users to request a delivery provider to relay a payload (and/or additional messages)
* to a chain and address of their choice.
*/
/**
* @notice VaaKey identifies a wormhole message
*
* @custom:member chainId Wormhole chain ID of the chain where this VAA was emitted from
* @custom:member emitterAddress Address of the emitter of the VAA, in Wormhole bytes32 format
* @custom:member sequence Sequence number of the VAA
*/
struct VaaKey {
uint16 chainId;
bytes32 emitterAddress;
uint64 sequence;
}
// 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
uint8 constant VAA_KEY_TYPE = 1;
struct MessageKey {
uint8 keyType; // 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
bytes encodedKey;
}
interface IWormholeRelayerBase {
event SendEvent(
uint64 indexed sequence,
uint256 deliveryQuote,
uint256 paymentForExtraReceiverValue
);
function getRegisteredWormholeRelayerContract(
uint16 chainId
) external view returns (bytes32);
/**
* @notice Returns true if a delivery has been attempted for the given deliveryHash
* Note: invalid deliveries where the tx reverts are not considered attempted
*/
function deliveryAttempted(
bytes32 deliveryHash
) external view returns (bool attempted);
/**
* @notice block number at which a delivery was successfully executed
*/
function deliverySuccessBlock(
bytes32 deliveryHash
) external view returns (uint256 blockNumber);
/**
* @notice block number of the latest attempt to execute a delivery that failed
*/
function deliveryFailureBlock(
bytes32 deliveryHash
) external view returns (uint256 blockNumber);
}
/**
* @title IWormholeRelayerSend
* @notice The interface to request deliveries
*/
interface IWormholeRelayerSend is IWormholeRelayerBase {
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendPayloadToEvm` function
* with `refundChain` and `refundAddress` as parameters
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendVaasToEvm` function
* with `refundChain` and `refundAddress` as parameters
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
VaaKey[] memory vaaKeys
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
VaaKey[] memory vaaKeys,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and external messages specified by `messageKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected
* DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
MessageKey[] memory messageKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function send(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected
* DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function send(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
MessageKey[] memory messageKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Requests a previously published delivery instruction to be redelivered
* (e.g. with a different delivery provider)
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, newReceiverValue, newGasLimit, newDeliveryProviderAddress)
*
* @notice *** This will only be able to succeed if the following is true **
* - newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
* - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
*
* @param deliveryVaaKey VaaKey identifying the wormhole message containing the
* previously published delivery instructions
* @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
* @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param newGasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider, to the refund chain and address specified in the original request
* @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return sequence sequence number of published VAA containing redelivery instructions
*
* @notice *** This will only be able to succeed if the following is true **
* - newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
*/
function resendToEvm(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
uint256 newReceiverValue,
uint256 newGasLimit,
address newDeliveryProviderAddress
) external payable returns (uint64 sequence);
/**
* @notice Requests a previously published delivery instruction to be redelivered
*
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, newReceiverValue, newEncodedExecutionParameters, newDeliveryProviderAddress)
*
* @param deliveryVaaKey VaaKey identifying the wormhole message containing the
* previously published delivery instructions
* @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
* @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param newEncodedExecutionParameters new encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return sequence sequence number of published VAA containing redelivery instructions
*
* @notice *** This will only be able to succeed if the following is true **
* - (For EVM_V1) newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
* - (For EVM_V1) newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
*/
function resend(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
uint256 newReceiverValue,
bytes memory newEncodedExecutionParameters,
address newDeliveryProviderAddress
) external payable returns (uint64 sequence);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified.
* Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a
* promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain.
* If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain.
*/
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit
)
external
view
returns (
uint256 nativePriceQuote,
uint256 targetChainRefundPerGasUnused
);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified
* Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a
* promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain.
* If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain.
*/
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit,
address deliveryProviderAddress
)
external
view
returns (
uint256 nativePriceQuote,
uint256 targetChainRefundPerGasUnused
);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return encodedExecutionInfo encoded information on how the delivery will be executed
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` and `targetChainRefundPerGasUnused`
* (which is the amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified)
*/
function quoteDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
bytes memory encodedExecutionParameters,
address deliveryProviderAddress
)
external
view
returns (uint256 nativePriceQuote, bytes memory encodedExecutionInfo);
/**
* @notice Returns the (extra) amount of target chain currency that `targetAddress`
* will be called with, if the `paymentForExtraReceiverValue` field is set to `currentChainAmount`
*
* @param targetChain in Wormhole Chain ID format
* @param currentChainAmount The value that `paymentForExtraReceiverValue` will be set to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return targetChainAmount The amount such that if `targetAddress` will be called with `msg.value` equal to
* receiverValue + targetChainAmount
*/
function quoteNativeForChain(
uint16 targetChain,
uint256 currentChainAmount,
address deliveryProviderAddress
) external view returns (uint256 targetChainAmount);
/**
* @notice Returns the address of the current default delivery provider
* @return deliveryProvider The address of (the default delivery provider)'s contract on this source
* chain. This must be a contract that implements IDeliveryProvider.
*/
function getDefaultDeliveryProvider()
external
view
returns (address deliveryProvider);
}
/**
* @title IWormholeRelayerDelivery
* @notice The interface to execute deliveries. Only relevant for Delivery Providers
*/
interface IWormholeRelayerDelivery is IWormholeRelayerBase {
enum DeliveryStatus {
SUCCESS,
RECEIVER_FAILURE
}
enum RefundStatus {
REFUND_SENT,
REFUND_FAIL,
CROSS_CHAIN_REFUND_SENT,
CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED,
CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH,
NO_REFUND_REQUESTED
}
/**
* @custom:member recipientContract - The target contract address
* @custom:member sourceChain - The chain which this delivery was requested from (in wormhole
* ChainID format)
* @custom:member sequence - The wormhole sequence number of the delivery VAA on the source chain
* corresponding to this delivery request
* @custom:member deliveryVaaHash - The hash of the delivery VAA corresponding to this delivery
* request
* @custom:member gasUsed - The amount of gas that was used to call your target contract
* @custom:member status:
* - RECEIVER_FAILURE, if the target contract reverts
* - SUCCESS, if the target contract doesn't revert
* @custom:member additionalStatusInfo:
* - If status is SUCCESS, then this is empty.
* - If status is RECEIVER_FAILURE, this is `RETURNDATA_TRUNCATION_THRESHOLD` bytes of the
* return data (i.e. potentially truncated revert reason information).
* @custom:member refundStatus - Result of the refund. REFUND_SUCCESS or REFUND_FAIL are for
* refunds where targetChain=refundChain; the others are for targetChain!=refundChain,
* where a cross chain refund is necessary, or if the default code path is used where no refund is requested (NO_REFUND_REQUESTED)
* @custom:member overridesInfo:
* - If not an override: empty bytes array
* - Otherwise: An encoded `DeliveryOverride`
*/
event Delivery(
address indexed recipientContract,
uint16 indexed sourceChain,
uint64 indexed sequence,
bytes32 deliveryVaaHash,
DeliveryStatus status,
uint256 gasUsed,
RefundStatus refundStatus,
bytes additionalStatusInfo,
bytes overridesInfo
);
/**
* @notice The delivery provider calls `deliver` to relay messages as described by one delivery instruction
*
* The delivery provider must pass in the specified (by VaaKeys[]) signed wormhole messages (VAAs) from the source chain
* as well as the signed wormhole message with the delivery instructions (the delivery VAA)
*
* The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met:
* - the delivery VAA has a valid signature
* - the delivery VAA's emitter is one of these WormholeRelayer contracts
* - the delivery provider passed in at least enough of this chain's currency as msg.value (enough meaning the maximum possible refund)
* - the instruction's target chain is this chain
* - the relayed signed VAAs match the descriptions in container.messages (the VAA hashes match, or the emitter address, sequence number pair matches, depending on the description given)
*
* @param encodedVMs - An array of signed wormhole messages (all from the same source chain
* transaction)
* @param encodedDeliveryVAA - Signed wormhole message from the source chain's WormholeRelayer
* contract with payload being the encoded delivery instruction container
* @param relayerRefundAddress - The address to which any refunds to the delivery provider
* should be sent
* @param deliveryOverrides - Optional overrides field which must be either an empty bytes array or
* an encoded DeliveryOverride struct
*/
function deliver(
bytes[] memory encodedVMs,
bytes memory encodedDeliveryVAA,
address payable relayerRefundAddress,
bytes memory deliveryOverrides
) external payable;
}
interface IWormholeRelayer is IWormholeRelayerDelivery, IWormholeRelayerSend {}
/*
* Errors thrown by IWormholeRelayer contract
*/
// Bound chosen by the following formula: `memoryWord * 4 + selectorSize`.
// This means that an error identifier plus four fixed size arguments should be available to developers.
// In the case of a `require` revert with error message, this should provide 2 memory word's worth of data.
uint256 constant RETURNDATA_TRUNCATION_THRESHOLD = 132;
//When msg.value was not equal to `delivery provider's quoted delivery price` + `paymentForExtraReceiverValue`
error InvalidMsgValue(uint256 msgValue, uint256 totalFee);
error RequestedGasLimitTooLow();
error DeliveryProviderDoesNotSupportTargetChain(
address relayer,
uint16 chainId
);
error DeliveryProviderCannotReceivePayment();
error DeliveryProviderDoesNotSupportMessageKeyType(uint8 keyType);
//When calling `delivery()` a second time even though a delivery is already in progress
error ReentrantDelivery(address msgSender, address lockedBy);
error InvalidPayloadId(uint8 parsed, uint8 expected);
error InvalidPayloadLength(uint256 received, uint256 expected);
error InvalidVaaKeyType(uint8 parsed);
error TooManyMessageKeys(uint256 numMessageKeys);
error InvalidDeliveryVaa(string reason);
//When the delivery VAA (signed wormhole message with delivery instructions) was not emitted by the
// registered WormholeRelayer contract
error InvalidEmitter(bytes32 emitter, bytes32 registered, uint16 chainId);
error MessageKeysLengthDoesNotMatchMessagesLength(uint256 keys, uint256 vaas);
error VaaKeysDoNotMatchVaas(uint8 index);
//When someone tries to call an external function of the WormholeRelayer that is only intended to be
// called by the WormholeRelayer itself (to allow retroactive reverts for atomicity)
error RequesterNotWormholeRelayer();
//When trying to relay a `DeliveryInstruction` to any other chain but the one it was specified for
error TargetChainIsNotThisChain(uint16 targetChain);
//When a `DeliveryOverride` contains a gas limit that's less than the original
error InvalidOverrideGasLimit();
//When a `DeliveryOverride` contains a receiver value that's less than the original
error InvalidOverrideReceiverValue();
//When a `DeliveryOverride` contains a 'refund per unit of gas unused' that's less than the original
error InvalidOverrideRefundPerGasUnused();
//When the delivery provider doesn't pass in sufficient funds (i.e. msg.value does not cover the
// maximum possible refund to the user)
error InsufficientRelayerFunds(uint256 msgValue, uint256 minimum);
//When a bytes32 field can't be converted into a 20 byte EVM address, because the 12 padding bytes
// are non-zero (duplicated from Utils.sol)
error NotAnEvmAddress(bytes32);{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"ETHTransferError","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NonZeroAddress","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"bridgeAddress","type":"address"}],"name":"BridgeAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"BridgeAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"sourceChainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"dsToken","type":"address"},{"indexed":false,"internalType":"address","name":"investorWallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DSTokenBridgeReceive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"targetChainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"dsToken","type":"address"},{"indexed":false,"internalType":"address","name":"investorWallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DSTokenBridgeSend","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address payable","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasLimit","type":"uint256"}],"name":"GasLimitUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"wmChainId","type":"uint16"}],"name":"bridgeAddresses","outputs":[{"internalType":"address","name":"bridge","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"bridgeDSTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"dsServiceConsumer","outputs":[{"internalType":"contract IDSServiceConsumer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dsToken","outputs":[{"internalType":"contract IDSToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getImplementationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitializedVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_whChainId","type":"uint16"},{"internalType":"address","name":"_wormholeRelayer","type":"address"},{"internalType":"address","name":"_dsToken","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"}],"name":"quoteBridge","outputs":[{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes[]","name":"","type":"bytes[]"},{"internalType":"bytes32","name":"sourceBridge","type":"bytes32"},{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"receiveWormholeMessages","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"removeBridgeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"bridgeAddress","type":"address"}],"name":"setBridgeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"updateGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"whChainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wormholeRelayer","outputs":[{"internalType":"contract IWormholeRelayer","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051612a586200010460003960008181611438015281816114610152611c6e0152612a586000f3fe6080604052600436106101655760003560e01c8063715018a6116100d1578063ad3cb1cc1161008a578063e93b582f11610064578063e93b582f1461043f578063f2fde38b14610475578063f68016b714610495578063f687d12a146104ab57600080fd5b8063ad3cb1cc146103b4578063b3c65015146103f2578063da25b7251461041f57600080fd5b8063715018a6146102df5780637d97bf40146102f45780638456cb59146103145780638a60c3e5146103295780638da5cb5b14610357578063aaea53631461039457600080fd5b8063529dca3211610123578063529dca321461021957806352d1902d1461022c5780635c975abb1461024f57806364a8c00b1461027f578063690d83201461029f57806369eb0b1b146102bf57600080fd5b80622d2fda1461016a57806306fc66871461018c5780630cbcae701461019f5780633f4ba83a146101d15780634f1ef286146101e6578063504ce999146101f9575b600080fd5b34801561017657600080fd5b5061018a61018536600461207f565b6104cb565b005b61018a61019a3660046120d9565b610637565b3480156101ab57600080fd5b506101b4610c70565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101dd57600080fd5b5061018a610c96565b61018a6101f43660046121c6565b610ca8565b34801561020557600080fd5b5061018a610214366004612215565b610cc7565b61018a61022736600461226f565b610d3a565b34801561023857600080fd5b50610241611194565b6040519081526020016101c8565b34801561025b57600080fd5b50600080516020612a038339815191525460ff1660405190151581526020016101c8565b34801561028b57600080fd5b506034546101b4906001600160a01b031681565b3480156102ab57600080fd5b5061018a6102ba366004612364565b6111b1565b3480156102cb57600080fd5b506033546101b4906001600160a01b031681565b3480156102eb57600080fd5b5061018a6112ce565b34801561030057600080fd5b5061018a61030f366004612381565b6112e0565b34801561032057600080fd5b5061018a611341565b34801561033557600080fd5b506036546103449061ffff1681565b60405161ffff90911681526020016101c8565b34801561036357600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166101b4565b3480156103a057600080fd5b506102416103af366004612381565b611351565b3480156103c057600080fd5b506103e5604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101c891906123ec565b3480156103fe57600080fd5b50610407611376565b6040516001600160401b0390911681526020016101c8565b34801561042b57600080fd5b506032546101b4906001600160a01b031681565b34801561044b57600080fd5b506101b461045a366004612381565b6037602052600090815260409020546001600160a01b031681565b34801561048157600080fd5b5061018a610490366004612364565b6113a9565b3480156104a157600080fd5b5061024160355481565b3480156104b757600080fd5b5061018a6104c63660046123ff565b6113e4565b6104d361142d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156105185750825b90506000826001600160401b031660011480156105345750303b155b905081158015610542575080155b156105605760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561058a57845460ff60401b1916600160401b1785555b610593866114d2565b6036805461ffff8b1661ffff19909116179055603280546001600160a01b03808b166001600160a01b03199283161790925560338054928a1692821683179055603480549091169091179055622625a0603555831561062c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b61063f6114f3565b600081116106a05760405162461bcd60e51b8152602060048201526024808201527f4453546f6b656e2076616c7565206d75737420626520677265617465722074686044820152630616e20360e41b60648201526084015b60405180910390fd5b6032546035546001600160a01b039091169060006106bf838387611524565b9050803410156107465760405162461bcd60e51b815260206004820152604660248201527f5472616e73616374696f6e2076616c75652073686f756c64206265206571756160448201527f6c206f722067726561746572207468616e2071756f746542726964676520726560648201526573706f6e736560d01b608482015260a401610697565b60335484906001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561079e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c29190612418565b10156108255760405162461bcd60e51b815260206004820152602c60248201527f4e6f7420656e6f7567682062616c616e636520696e20736f757263652063686160448201526b696e20746f2062726964676560a01b6064820152608401610697565b61ffff85166000908152603760205260409020546001600160a01b03168061088f5760405162461bcd60e51b815260206004820152601b60248201527f4e6f20627269646765206164647265737320617661696c61626c6500000000006044820152606401610697565b603454604080516344be001760e11b815290516001600160a01b03909216916000918391630e5324be91839163897c002e916004808201926020929091908290030181865afa1580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a9190612418565b6040518263ffffffff1660e01b815260040161092891815260200190565b602060405180830381865afa158015610945573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109699190612431565b90506001600160a01b03811663ce5570ec336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e3919061244e565b610a2f5760405162461bcd60e51b815260206004820152601760248201527f496e766573746f72206e6f7420726567697374657265640000000000000000006044820152606401610697565b60006001600160a01b038216638f35a75e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610aad91908101906124bd565b9050610abb818984866115a9565b6000610ac78284611a17565b603354604080518082018252600681526562726964676560d01b6020820152905163057d5c3760e21b81529293506001600160a01b03909116916315f570dc91610b179133918e916004016124f1565b600060405180830381600087803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b50505050876001600160a01b0316634b5ca6f4348c8885600001518e610b683390565b886020015189604001518a60600151604051602001610b8c96959493929190612553565b60408051808303601f190181529190526036546000908e9061ffff16336040518963ffffffff1660e01b8152600401610bcb97969594939291906125c3565b60206040518083038185885af1158015610be9573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610c0e919061261c565b506033546040805161ffff8d1681526001600160a01b0390921660208301523382820152606082018b9052517f4351f6706a6389b725bcb6eeeef18d35b0a46729b615d322eeadc477ddae4cdc9181900360800190a150505050505050505050565b6000610c916000805160206129e3833981519152546001600160a01b031690565b905090565b610c9e611ae4565b610ca6611b3f565b565b610cb061142d565b610cb982611b99565b610cc38282611ba1565b5050565b610ccf611ae4565b61ffff821660008181526037602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527ff6e966c088b81f796a8adddc1d4c458e3245c0da1c7a3bb9418bad2367bafb53910160405180910390a15050565b610d426114f3565b6032546001600160a01b0316336001600160a01b031614610dbd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c7920616e20617574686f72697a65642072656c617965722063616e206360448201526e185b1b081d1a1a5cc81b595d1a1bd9608a1b6064820152608401610697565b61ffff82166000908152603760205260409020546001600160a01b03848116911614610e245760405162461bcd60e51b81526020600482015260166024820152752bb937b73390313934b233b29034b734ba34b0ba37b960511b6044820152606401610697565b6000806000806000808a806020019051810190610e4191906126b6565b603454604080516344be001760e11b81529051979d50959b50939950919750955093506000926001600160a01b0390911691630e5324be91839163897c002e9160048083019260209291908290030181865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec99190612418565b6040518263ffffffff1660e01b8152600401610ee791815260200190565b602060405180830381865afa158015610f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f289190612431565b60408051600480825260a082019092529192506000919060208201608080368337019050509050600181600081518110610f6457610f6461277b565b602002602001019060ff16908160ff1681525050600281600181518110610f8d57610f8d61277b565b602002602001019060ff16908160ff1681525050600481600281518110610fb657610fb661277b565b602002602001019060ff16908160ff1681525050600881600381518110610fdf57610fdf61277b565b60ff9290921660209283029190910190910152604080516001808252818301909252600091816020016020820280368337019050509050868160008151811061102a5761102a61277b565b6001600160a01b03928316602091820292909201015260405163ba9be7ed60e01b81529084169063ba9be7ed90611071908c9081908b90879089908d908d906004016127c4565b6020604051808303816000875af1158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061244e565b5060335460405163475a9fa960e01b81526001600160a01b038981166004830152602482018b90529091169063475a9fa9906044016020604051808303816000875af1158015611108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112c919061244e565b506033546040805161ffff8e1681526001600160a01b03928316602082015291891682820152606082018a9052517f15e282eb9531b9cf86d564e700c0ad57d504676d5efda43e10a2533489ead4ed9181900360800190a15050505050505050505050505050565b600061119e611c63565b506000805160206129e383398151915290565b6111b9611cac565b806001600160a01b0381166111e15760405163bf8d717560e01b815260040160405180910390fd5b6111e9611ae4565b60405147906000906001600160a01b0385169083908381818185875af1925050503d8060008114611236576040519150601f19603f3d011682016040523d82523d6000602084013e61123b565b606091505b505090508061125d57604051637ea369e960e01b815260040160405180910390fd5b604080516001600160a01b0386168152602081018490527f94b2de810873337ed265c5f8cf98c9cffefa06b8607f9a2f1fbaebdfbcfbef1c910160405180910390a15050506112cb60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b6112d6611ae4565b610ca66000611cf6565b6112e8611ae4565b61ffff811660008181526037602090815260409182902080546001600160a01b031916905590519182527fe7dd3922e67b1405a10881a341821790b88e3fbfebfe19347db445c1bf76812291015b60405180910390a150565b611349611ae4565b610ca6611d67565b603254603554600091611370916001600160a01b039091169084611524565b92915050565b6000610c917ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00546001600160401b031690565b6113b1611ae4565b6001600160a01b0381166113db57604051631e4fbdf760e01b815260006004820152602401610697565b6112cb81611cf6565b6113ec611ae4565b60355460408051918252602082018390527fc1d450c3bb55eba5a02505c12a824cfebfb8692b2d3a5ad2b23b3c32c068d56e910160405180910390a1603555565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806114b457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166114a86000805160206129e3833981519152546001600160a01b031690565b6001600160a01b031614155b15610ca65760405163703e46dd60e11b815260040160405180910390fd5b6114da611db0565b6114e2611df9565b6114ea611e01565b6112cb81611e11565b600080516020612a038339815191525460ff1615610ca65760405163d93c066560e01b815260040160405180910390fd5b60405163c23ee3c360e01b815261ffff8216600482015260006024820181905260448201849052906001600160a01b0385169063c23ee3c3906064016040805180830381865afa15801561157c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a09190612888565b50949350505050565b6000816001600160a01b0316630e5324be836001600160a01b031663b8632a046040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190612418565b6040518263ffffffff1660e01b815260040161163a91815260200190565b602060405180830381865afa158015611657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167b9190612431565b90506000826001600160a01b0316630e5324be846001600160a01b031663c75401506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f09190612418565b6040518263ffffffff1660e01b815260040161170e91815260200190565b602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612431565b90506000846001600160a01b031663848924cb886040518263ffffffff1660e01b815260040161177f91906123ec565b600060405180830381865afa15801561179c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117c491908101906124bd565b90506000826001600160a01b0316636a528307836040518263ffffffff1660e01b81526004016117f491906123ec565b602060405180830381865afa158015611811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118359190612418565b90506000600182146118a857836001600160a01b0316639f9b9a816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a39190612418565b61190a565b836001600160a01b031663295a217d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190612418565b905060006001600160a01b03861663c67016d7336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201524260248201526001600160401b0385166044820152606401602060405180830381865afa158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190612418565b905088811015611a0b5760405162461bcd60e51b815260206004820152603560248201527f4e6f7420656e6f75676820756e6c6f636b65642062616c616e636520696e20736044820152746f7572636520636861696e20746f2062726964676560581b6064820152608401610697565b50505050505050505050565b611a426040518060800160405280606081526020016060815260200160608152602001606081525090565b6000806000846001600160a01b031663a9796bd1876040518263ffffffff1660e01b8152600401611a7391906123ec565b600060405180830381865afa158015611a90573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ab891908101906128ac565b5050604080516080810182529b8c5260208c019590955250509188015260608701525093949350505050565b33611b167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610ca65760405163118cdaa760e01b8152336004820152602401610697565b611b47611e22565b600080516020612a03833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b039091168152602001611336565b6112cb611ae4565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611bfb575060408051601f3d908101601f19168201909252611bf891810190612418565b60015b611c2357604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610697565b6000805160206129e38339815191528114611c5457604051632a87526960e21b815260048101829052602401610697565b611c5e8383611e52565b505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ca65760405163703e46dd60e11b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611cf057604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611d6f6114f3565b600080516020612a03833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611b81565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ca657604051631afcd79f60e31b815260040160405180910390fd5b610ca6611db0565b611e09611db0565b610ca6611ea8565b611e19611db0565b6112cb81611ec9565b600080516020612a038339815191525460ff16610ca657604051638dfc202b60e01b815260040160405180910390fd5b611e5b82611ed1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611ea057611c5e8282611f36565b610cc3611fac565b611eb0611db0565b600080516020612a03833981519152805460ff19169055565b6113b1611db0565b806001600160a01b03163b600003611f0757604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610697565b6000805160206129e383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611f5391906129c6565b600060405180830381855af49150503d8060008114611f8e576040519150601f19603f3d011682016040523d82523d6000602084013e611f93565b606091505b5091509150611fa3858383611fcb565b95945050505050565b3415610ca65760405163b398979f60e01b815260040160405180910390fd5b606082611fe057611fdb8261202a565b612023565b8151158015611ff757506001600160a01b0384163b155b1561202057604051639996b31560e01b81526001600160a01b0385166004820152602401610697565b50805b9392505050565b80511561203a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b803561ffff8116811461206557600080fd5b919050565b6001600160a01b03811681146112cb57600080fd5b6000806000806080858703121561209557600080fd5b61209e85612053565b935060208501356120ae8161206a565b925060408501356120be8161206a565b915060608501356120ce8161206a565b939692955090935050565b600080604083850312156120ec57600080fd5b6120f583612053565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561214157612141612103565b604052919050565b60006001600160401b0382111561216257612162612103565b50601f01601f191660200190565b600082601f83011261218157600080fd5b813561219461218f82612149565b612119565b8181528460208386010111156121a957600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156121d957600080fd5b82356121e48161206a565b915060208301356001600160401b038111156121ff57600080fd5b61220b85828601612170565b9150509250929050565b6000806040838503121561222857600080fd5b61223183612053565b915060208301356122418161206a565b809150509250929050565b60006001600160401b0382111561226557612265612103565b5060051b60200190565b600080600080600060a0868803121561228757600080fd5b85356001600160401b038082111561229e57600080fd5b6122aa89838a01612170565b96506020915081880135818111156122c157600080fd5b8801601f81018a136122d257600080fd5b80356122e061218f8261224c565b81815260059190911b8201840190848101908c8311156122ff57600080fd5b8584015b838110156123375780358681111561231b5760008081fd5b6123298f8983890101612170565b845250918601918601612303565b5098505050506040880135945061235391505060608701612053565b949793965091946080013592915050565b60006020828403121561237657600080fd5b81356120238161206a565b60006020828403121561239357600080fd5b61202382612053565b60005b838110156123b757818101518382015260200161239f565b50506000910152565b600081518084526123d881602086016020860161239c565b601f01601f19169290920160200192915050565b60208152600061202360208301846123c0565b60006020828403121561241157600080fd5b5035919050565b60006020828403121561242a57600080fd5b5051919050565b60006020828403121561244357600080fd5b81516120238161206a565b60006020828403121561246057600080fd5b8151801515811461202357600080fd5b600082601f83011261248157600080fd5b815161248f61218f82612149565b8181528460208386010111156124a457600080fd5b6124b582602083016020870161239c565b949350505050565b6000602082840312156124cf57600080fd5b81516001600160401b038111156124e557600080fd5b6124b584828501612470565b60018060a01b0384168152826020820152606060408201526000611fa360608301846123c0565b600081518084526020808501945080840160005b838110156125485781518752958201959082019060010161252c565b509495945050505050565b60c08152600061256660c08301896123c0565b602083018890526001600160a01b0387166040840152828103606084015261258e81876123c0565b905082810360808401526125a28186612518565b905082810360a08401526125b68185612518565b9998505050505050505050565b600061ffff808a16835260018060a01b03808a16602085015260e060408501526125f060e085018a6123c0565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b60006020828403121561262e57600080fd5b81516001600160401b038116811461202357600080fd5b80516120658161206a565b600082601f83011261266157600080fd5b8151602061267161218f8361224c565b82815260059290921b8401810191818101908684111561269057600080fd5b8286015b848110156126ab5780518352918301918301612694565b509695505050505050565b60008060008060008060c087890312156126cf57600080fd5b86516001600160401b03808211156126e657600080fd5b6126f28a838b01612470565b97506020890151965061270760408a01612645565b9550606089015191508082111561271d57600080fd5b6127298a838b01612470565b9450608089015191508082111561273f57600080fd5b61274b8a838b01612650565b935060a089015191508082111561276157600080fd5b5061276e89828a01612650565b9150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b8381101561254857815160ff16875295820195908201906001016127a5565b60e0815260006127d760e083018a6123c0565b6020838203818501526127ea828b6123c0565b915083820360408501526127fe828a6123c0565b84810360608601528851808252828a0193509082019060005b8181101561283c5784516001600160a01b031683529383019391830191600101612817565b505084810360808601526128508189612791565b9250505082810360a08401526128668186612518565b905082810360c084015261287a8185612518565b9a9950505050505050505050565b6000806040838503121561289b57600080fd5b505080516020909101519092909150565b600080600080600080600060e0888a0312156128c757600080fd5b87516001600160401b03808211156128de57600080fd5b6128ea8b838c01612470565b985060208a015191508082111561290057600080fd5b61290c8b838c01612650565b975060408a015191508082111561292257600080fd5b61292e8b838c01612650565b965060608a015191508082111561294457600080fd5b6129508b838c01612470565b955060808a015191508082111561296657600080fd5b6129728b838c01612470565b945060a08a015191508082111561298857600080fd5b6129948b838c01612470565b935060c08a01519150808211156129aa57600080fd5b506129b78a828b01612470565b91505092959891949750929550565b600082516129d881846020870161239c565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbccd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a26469706673582212204894ed5afc9644b11c415d4268a21cd21f8405f2fdd92df66731eb1099d737d864736f6c63430008140033
Deployed Bytecode
0x6080604052600436106101655760003560e01c8063715018a6116100d1578063ad3cb1cc1161008a578063e93b582f11610064578063e93b582f1461043f578063f2fde38b14610475578063f68016b714610495578063f687d12a146104ab57600080fd5b8063ad3cb1cc146103b4578063b3c65015146103f2578063da25b7251461041f57600080fd5b8063715018a6146102df5780637d97bf40146102f45780638456cb59146103145780638a60c3e5146103295780638da5cb5b14610357578063aaea53631461039457600080fd5b8063529dca3211610123578063529dca321461021957806352d1902d1461022c5780635c975abb1461024f57806364a8c00b1461027f578063690d83201461029f57806369eb0b1b146102bf57600080fd5b80622d2fda1461016a57806306fc66871461018c5780630cbcae701461019f5780633f4ba83a146101d15780634f1ef286146101e6578063504ce999146101f9575b600080fd5b34801561017657600080fd5b5061018a61018536600461207f565b6104cb565b005b61018a61019a3660046120d9565b610637565b3480156101ab57600080fd5b506101b4610c70565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101dd57600080fd5b5061018a610c96565b61018a6101f43660046121c6565b610ca8565b34801561020557600080fd5b5061018a610214366004612215565b610cc7565b61018a61022736600461226f565b610d3a565b34801561023857600080fd5b50610241611194565b6040519081526020016101c8565b34801561025b57600080fd5b50600080516020612a038339815191525460ff1660405190151581526020016101c8565b34801561028b57600080fd5b506034546101b4906001600160a01b031681565b3480156102ab57600080fd5b5061018a6102ba366004612364565b6111b1565b3480156102cb57600080fd5b506033546101b4906001600160a01b031681565b3480156102eb57600080fd5b5061018a6112ce565b34801561030057600080fd5b5061018a61030f366004612381565b6112e0565b34801561032057600080fd5b5061018a611341565b34801561033557600080fd5b506036546103449061ffff1681565b60405161ffff90911681526020016101c8565b34801561036357600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03166101b4565b3480156103a057600080fd5b506102416103af366004612381565b611351565b3480156103c057600080fd5b506103e5604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101c891906123ec565b3480156103fe57600080fd5b50610407611376565b6040516001600160401b0390911681526020016101c8565b34801561042b57600080fd5b506032546101b4906001600160a01b031681565b34801561044b57600080fd5b506101b461045a366004612381565b6037602052600090815260409020546001600160a01b031681565b34801561048157600080fd5b5061018a610490366004612364565b6113a9565b3480156104a157600080fd5b5061024160355481565b3480156104b757600080fd5b5061018a6104c63660046123ff565b6113e4565b6104d361142d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03166000811580156105185750825b90506000826001600160401b031660011480156105345750303b155b905081158015610542575080155b156105605760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561058a57845460ff60401b1916600160401b1785555b610593866114d2565b6036805461ffff8b1661ffff19909116179055603280546001600160a01b03808b166001600160a01b03199283161790925560338054928a1692821683179055603480549091169091179055622625a0603555831561062c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b61063f6114f3565b600081116106a05760405162461bcd60e51b8152602060048201526024808201527f4453546f6b656e2076616c7565206d75737420626520677265617465722074686044820152630616e20360e41b60648201526084015b60405180910390fd5b6032546035546001600160a01b039091169060006106bf838387611524565b9050803410156107465760405162461bcd60e51b815260206004820152604660248201527f5472616e73616374696f6e2076616c75652073686f756c64206265206571756160448201527f6c206f722067726561746572207468616e2071756f746542726964676520726560648201526573706f6e736560d01b608482015260a401610697565b60335484906001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561079e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c29190612418565b10156108255760405162461bcd60e51b815260206004820152602c60248201527f4e6f7420656e6f7567682062616c616e636520696e20736f757263652063686160448201526b696e20746f2062726964676560a01b6064820152608401610697565b61ffff85166000908152603760205260409020546001600160a01b03168061088f5760405162461bcd60e51b815260206004820152601b60248201527f4e6f20627269646765206164647265737320617661696c61626c6500000000006044820152606401610697565b603454604080516344be001760e11b815290516001600160a01b03909216916000918391630e5324be91839163897c002e916004808201926020929091908290030181865afa1580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a9190612418565b6040518263ffffffff1660e01b815260040161092891815260200190565b602060405180830381865afa158015610945573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109699190612431565b90506001600160a01b03811663ce5570ec336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e3919061244e565b610a2f5760405162461bcd60e51b815260206004820152601760248201527f496e766573746f72206e6f7420726567697374657265640000000000000000006044820152606401610697565b60006001600160a01b038216638f35a75e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401600060405180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610aad91908101906124bd565b9050610abb818984866115a9565b6000610ac78284611a17565b603354604080518082018252600681526562726964676560d01b6020820152905163057d5c3760e21b81529293506001600160a01b03909116916315f570dc91610b179133918e916004016124f1565b600060405180830381600087803b158015610b3157600080fd5b505af1158015610b45573d6000803e3d6000fd5b50505050876001600160a01b0316634b5ca6f4348c8885600001518e610b683390565b886020015189604001518a60600151604051602001610b8c96959493929190612553565b60408051808303601f190181529190526036546000908e9061ffff16336040518963ffffffff1660e01b8152600401610bcb97969594939291906125c3565b60206040518083038185885af1158015610be9573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610c0e919061261c565b506033546040805161ffff8d1681526001600160a01b0390921660208301523382820152606082018b9052517f4351f6706a6389b725bcb6eeeef18d35b0a46729b615d322eeadc477ddae4cdc9181900360800190a150505050505050505050565b6000610c916000805160206129e3833981519152546001600160a01b031690565b905090565b610c9e611ae4565b610ca6611b3f565b565b610cb061142d565b610cb982611b99565b610cc38282611ba1565b5050565b610ccf611ae4565b61ffff821660008181526037602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527ff6e966c088b81f796a8adddc1d4c458e3245c0da1c7a3bb9418bad2367bafb53910160405180910390a15050565b610d426114f3565b6032546001600160a01b0316336001600160a01b031614610dbd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c7920616e20617574686f72697a65642072656c617965722063616e206360448201526e185b1b081d1a1a5cc81b595d1a1bd9608a1b6064820152608401610697565b61ffff82166000908152603760205260409020546001600160a01b03848116911614610e245760405162461bcd60e51b81526020600482015260166024820152752bb937b73390313934b233b29034b734ba34b0ba37b960511b6044820152606401610697565b6000806000806000808a806020019051810190610e4191906126b6565b603454604080516344be001760e11b81529051979d50959b50939950919750955093506000926001600160a01b0390911691630e5324be91839163897c002e9160048083019260209291908290030181865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec99190612418565b6040518263ffffffff1660e01b8152600401610ee791815260200190565b602060405180830381865afa158015610f04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f289190612431565b60408051600480825260a082019092529192506000919060208201608080368337019050509050600181600081518110610f6457610f6461277b565b602002602001019060ff16908160ff1681525050600281600181518110610f8d57610f8d61277b565b602002602001019060ff16908160ff1681525050600481600281518110610fb657610fb661277b565b602002602001019060ff16908160ff1681525050600881600381518110610fdf57610fdf61277b565b60ff9290921660209283029190910190910152604080516001808252818301909252600091816020016020820280368337019050509050868160008151811061102a5761102a61277b565b6001600160a01b03928316602091820292909201015260405163ba9be7ed60e01b81529084169063ba9be7ed90611071908c9081908b90879089908d908d906004016127c4565b6020604051808303816000875af1158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061244e565b5060335460405163475a9fa960e01b81526001600160a01b038981166004830152602482018b90529091169063475a9fa9906044016020604051808303816000875af1158015611108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112c919061244e565b506033546040805161ffff8e1681526001600160a01b03928316602082015291891682820152606082018a9052517f15e282eb9531b9cf86d564e700c0ad57d504676d5efda43e10a2533489ead4ed9181900360800190a15050505050505050505050505050565b600061119e611c63565b506000805160206129e383398151915290565b6111b9611cac565b806001600160a01b0381166111e15760405163bf8d717560e01b815260040160405180910390fd5b6111e9611ae4565b60405147906000906001600160a01b0385169083908381818185875af1925050503d8060008114611236576040519150601f19603f3d011682016040523d82523d6000602084013e61123b565b606091505b505090508061125d57604051637ea369e960e01b815260040160405180910390fd5b604080516001600160a01b0386168152602081018490527f94b2de810873337ed265c5f8cf98c9cffefa06b8607f9a2f1fbaebdfbcfbef1c910160405180910390a15050506112cb60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b6112d6611ae4565b610ca66000611cf6565b6112e8611ae4565b61ffff811660008181526037602090815260409182902080546001600160a01b031916905590519182527fe7dd3922e67b1405a10881a341821790b88e3fbfebfe19347db445c1bf76812291015b60405180910390a150565b611349611ae4565b610ca6611d67565b603254603554600091611370916001600160a01b039091169084611524565b92915050565b6000610c917ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00546001600160401b031690565b6113b1611ae4565b6001600160a01b0381166113db57604051631e4fbdf760e01b815260006004820152602401610697565b6112cb81611cf6565b6113ec611ae4565b60355460408051918252602082018390527fc1d450c3bb55eba5a02505c12a824cfebfb8692b2d3a5ad2b23b3c32c068d56e910160405180910390a1603555565b306001600160a01b037f0000000000000000000000009753bda360cf4cf7dfe72e77bc9d2f1961f899321614806114b457507f0000000000000000000000009753bda360cf4cf7dfe72e77bc9d2f1961f899326001600160a01b03166114a86000805160206129e3833981519152546001600160a01b031690565b6001600160a01b031614155b15610ca65760405163703e46dd60e11b815260040160405180910390fd5b6114da611db0565b6114e2611df9565b6114ea611e01565b6112cb81611e11565b600080516020612a038339815191525460ff1615610ca65760405163d93c066560e01b815260040160405180910390fd5b60405163c23ee3c360e01b815261ffff8216600482015260006024820181905260448201849052906001600160a01b0385169063c23ee3c3906064016040805180830381865afa15801561157c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a09190612888565b50949350505050565b6000816001600160a01b0316630e5324be836001600160a01b031663b8632a046040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190612418565b6040518263ffffffff1660e01b815260040161163a91815260200190565b602060405180830381865afa158015611657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167b9190612431565b90506000826001600160a01b0316630e5324be846001600160a01b031663c75401506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f09190612418565b6040518263ffffffff1660e01b815260040161170e91815260200190565b602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612431565b90506000846001600160a01b031663848924cb886040518263ffffffff1660e01b815260040161177f91906123ec565b600060405180830381865afa15801561179c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117c491908101906124bd565b90506000826001600160a01b0316636a528307836040518263ffffffff1660e01b81526004016117f491906123ec565b602060405180830381865afa158015611811573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118359190612418565b90506000600182146118a857836001600160a01b0316639f9b9a816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a39190612418565b61190a565b836001600160a01b031663295a217d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190a9190612418565b905060006001600160a01b03861663c67016d7336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201524260248201526001600160401b0385166044820152606401602060405180830381865afa158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190612418565b905088811015611a0b5760405162461bcd60e51b815260206004820152603560248201527f4e6f7420656e6f75676820756e6c6f636b65642062616c616e636520696e20736044820152746f7572636520636861696e20746f2062726964676560581b6064820152608401610697565b50505050505050505050565b611a426040518060800160405280606081526020016060815260200160608152602001606081525090565b6000806000846001600160a01b031663a9796bd1876040518263ffffffff1660e01b8152600401611a7391906123ec565b600060405180830381865afa158015611a90573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ab891908101906128ac565b5050604080516080810182529b8c5260208c019590955250509188015260608701525093949350505050565b33611b167f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b031614610ca65760405163118cdaa760e01b8152336004820152602401610697565b611b47611e22565b600080516020612a03833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b039091168152602001611336565b6112cb611ae4565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611bfb575060408051601f3d908101601f19168201909252611bf891810190612418565b60015b611c2357604051634c9c8ce360e01b81526001600160a01b0383166004820152602401610697565b6000805160206129e38339815191528114611c5457604051632a87526960e21b815260048101829052602401610697565b611c5e8383611e52565b505050565b306001600160a01b037f0000000000000000000000009753bda360cf4cf7dfe72e77bc9d2f1961f899321614610ca65760405163703e46dd60e11b815260040160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901611cf057604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611d6f6114f3565b600080516020612a03833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611b81565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ca657604051631afcd79f60e31b815260040160405180910390fd5b610ca6611db0565b611e09611db0565b610ca6611ea8565b611e19611db0565b6112cb81611ec9565b600080516020612a038339815191525460ff16610ca657604051638dfc202b60e01b815260040160405180910390fd5b611e5b82611ed1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115611ea057611c5e8282611f36565b610cc3611fac565b611eb0611db0565b600080516020612a03833981519152805460ff19169055565b6113b1611db0565b806001600160a01b03163b600003611f0757604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610697565b6000805160206129e383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051611f5391906129c6565b600060405180830381855af49150503d8060008114611f8e576040519150601f19603f3d011682016040523d82523d6000602084013e611f93565b606091505b5091509150611fa3858383611fcb565b95945050505050565b3415610ca65760405163b398979f60e01b815260040160405180910390fd5b606082611fe057611fdb8261202a565b612023565b8151158015611ff757506001600160a01b0384163b155b1561202057604051639996b31560e01b81526001600160a01b0385166004820152602401610697565b50805b9392505050565b80511561203a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b803561ffff8116811461206557600080fd5b919050565b6001600160a01b03811681146112cb57600080fd5b6000806000806080858703121561209557600080fd5b61209e85612053565b935060208501356120ae8161206a565b925060408501356120be8161206a565b915060608501356120ce8161206a565b939692955090935050565b600080604083850312156120ec57600080fd5b6120f583612053565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561214157612141612103565b604052919050565b60006001600160401b0382111561216257612162612103565b50601f01601f191660200190565b600082601f83011261218157600080fd5b813561219461218f82612149565b612119565b8181528460208386010111156121a957600080fd5b816020850160208301376000918101602001919091529392505050565b600080604083850312156121d957600080fd5b82356121e48161206a565b915060208301356001600160401b038111156121ff57600080fd5b61220b85828601612170565b9150509250929050565b6000806040838503121561222857600080fd5b61223183612053565b915060208301356122418161206a565b809150509250929050565b60006001600160401b0382111561226557612265612103565b5060051b60200190565b600080600080600060a0868803121561228757600080fd5b85356001600160401b038082111561229e57600080fd5b6122aa89838a01612170565b96506020915081880135818111156122c157600080fd5b8801601f81018a136122d257600080fd5b80356122e061218f8261224c565b81815260059190911b8201840190848101908c8311156122ff57600080fd5b8584015b838110156123375780358681111561231b5760008081fd5b6123298f8983890101612170565b845250918601918601612303565b5098505050506040880135945061235391505060608701612053565b949793965091946080013592915050565b60006020828403121561237657600080fd5b81356120238161206a565b60006020828403121561239357600080fd5b61202382612053565b60005b838110156123b757818101518382015260200161239f565b50506000910152565b600081518084526123d881602086016020860161239c565b601f01601f19169290920160200192915050565b60208152600061202360208301846123c0565b60006020828403121561241157600080fd5b5035919050565b60006020828403121561242a57600080fd5b5051919050565b60006020828403121561244357600080fd5b81516120238161206a565b60006020828403121561246057600080fd5b8151801515811461202357600080fd5b600082601f83011261248157600080fd5b815161248f61218f82612149565b8181528460208386010111156124a457600080fd5b6124b582602083016020870161239c565b949350505050565b6000602082840312156124cf57600080fd5b81516001600160401b038111156124e557600080fd5b6124b584828501612470565b60018060a01b0384168152826020820152606060408201526000611fa360608301846123c0565b600081518084526020808501945080840160005b838110156125485781518752958201959082019060010161252c565b509495945050505050565b60c08152600061256660c08301896123c0565b602083018890526001600160a01b0387166040840152828103606084015261258e81876123c0565b905082810360808401526125a28186612518565b905082810360a08401526125b68185612518565b9998505050505050505050565b600061ffff808a16835260018060a01b03808a16602085015260e060408501526125f060e085018a6123c0565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b60006020828403121561262e57600080fd5b81516001600160401b038116811461202357600080fd5b80516120658161206a565b600082601f83011261266157600080fd5b8151602061267161218f8361224c565b82815260059290921b8401810191818101908684111561269057600080fd5b8286015b848110156126ab5780518352918301918301612694565b509695505050505050565b60008060008060008060c087890312156126cf57600080fd5b86516001600160401b03808211156126e657600080fd5b6126f28a838b01612470565b97506020890151965061270760408a01612645565b9550606089015191508082111561271d57600080fd5b6127298a838b01612470565b9450608089015191508082111561273f57600080fd5b61274b8a838b01612650565b935060a089015191508082111561276157600080fd5b5061276e89828a01612650565b9150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b8381101561254857815160ff16875295820195908201906001016127a5565b60e0815260006127d760e083018a6123c0565b6020838203818501526127ea828b6123c0565b915083820360408501526127fe828a6123c0565b84810360608601528851808252828a0193509082019060005b8181101561283c5784516001600160a01b031683529383019391830191600101612817565b505084810360808601526128508189612791565b9250505082810360a08401526128668186612518565b905082810360c084015261287a8185612518565b9a9950505050505050505050565b6000806040838503121561289b57600080fd5b505080516020909101519092909150565b600080600080600080600060e0888a0312156128c757600080fd5b87516001600160401b03808211156128de57600080fd5b6128ea8b838c01612470565b985060208a015191508082111561290057600080fd5b61290c8b838c01612650565b975060408a015191508082111561292257600080fd5b61292e8b838c01612650565b965060608a015191508082111561294457600080fd5b6129508b838c01612470565b955060808a015191508082111561296657600080fd5b6129728b838c01612470565b945060a08a015191508082111561298857600080fd5b6129948b838c01612470565b935060c08a01519150808211156129aa57600080fd5b506129b78a828b01612470565b91505092959891949750929550565b600082516129d881846020870161239c565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbccd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a26469706673582212204894ed5afc9644b11c415d4268a21cd21f8405f2fdd92df66731eb1099d737d864736f6c63430008140033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.