Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FrictionlessOnChainAssetToken
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
pragma solidity ^0.8.16;
import { BasicFrictionlessToken } from "@core/BasicFrictionlessToken.sol";
import { IFrictionlessOnChainAssetToken } from "@interface/IFrictionlessOnChainAssetToken.sol";
/**
* @title FrictionlessOnChainAssetToken - Implementation of the `IFrictionlessOnChainAssetToken`
* @author Frictionless Group Holdings S.à.r.l
* @notice See {IFrictionlessOnChainAssetToken} {BasicFrictionlessToken}
*/
contract FrictionlessOnChainAssetToken is IFrictionlessOnChainAssetToken, BasicFrictionlessToken {
/// @dev instance of the immutable data
FOCASpecData public specificationData;
/// @dev instance of the immutable data
FOCAIssuanceData public issuanceData;
/// @dev instance of the mutable data
FOCAUpdateData public updateData;
/// @inheritdoc IFrictionlessOnChainAssetToken
function setSpecificationData(FOCASpecData calldata specificationData_) public onlyOwner {
if (!_isEmptyString(specificationData.baseCurrency)) {
revert FrictionlessOnChainAssetTokenUnableToUpdateData();
}
specificationData = specificationData_;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function setIssuanceData(FOCAIssuanceData calldata issuanceData_) public onlyOwner {
if (!_isEmptyString(issuanceData.onChainAssetUUID)) {
revert FrictionlessOnChainAssetTokenUnableToUpdateData();
}
issuanceData = issuanceData_;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function setUpdateData(FOCAUpdateData calldata updateData_) public onlyOwner {
updateData = updateData_;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function getSpecificationData() public view returns (FOCASpecData memory) {
return specificationData;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function getIssuanceData() public view returns (FOCAIssuanceData memory) {
return issuanceData;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function getUpdateData() public view returns (FOCAUpdateData memory) {
return updateData;
}
/// @inheritdoc IFrictionlessOnChainAssetToken
function getCurrency() public view returns (string memory) {
return specificationData.baseCurrency;
}
/// @dev verifies if a string is empty
function _isEmptyString(string memory str_) internal pure returns (bool) {
return keccak256(abi.encode(str_)) == keccak256(abi.encode(""));
}
}// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
pragma solidity ^0.8.16;
import { Token } from "@ERC-3643/token/Token.sol";
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title BasicFrictionlessToken - Implementation of the `IBasicFrictionlessToken`
* @author Frictionless Group Holdings S.à.r.l
* @notice See {IBasicFrictionlessToken}
*/
contract BasicFrictionlessToken is IBasicFrictionlessToken, Token {
/// @dev the tokenType
FrictionlessTokenTypes private _frictionlessTokenType;
/// @inheritdoc IBasicFrictionlessToken
function setFrictionlessTokenType(FrictionlessTokenTypes newTokenType_) external onlyOwner {
if (_frictionlessTokenType != FrictionlessTokenTypes.NONE) {
revert BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType();
}
_frictionlessTokenType = newTokenType_;
}
/// @inheritdoc IBasicFrictionlessToken
function getFrictionlessTokenType() public view override returns (FrictionlessTokenTypes) {
return _frictionlessTokenType;
}
}// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
pragma solidity ^0.8.16;
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title FrictionlessOnChainAssetToken is the extension of the ERC-3643 Token to represent OnChain Assets
* @author Frictionless Group Holdings S.à.r.l
* @notice Implementation of the storage of the underlying OnChain Asset and it's data.
*/
interface IFrictionlessOnChainAssetToken is IBasicFrictionlessToken {
/// @dev Enum for the schedule of the payments by the Manager, either pro_rat or coupon/bullet style.
enum FrictionlessOnChainAssetSchedule {
// The Manager will make payments for the `FrictionlessOnChainAssetToken` on an coupon_only basis, with a bullet payment for the principal investment.
SCHEDULE_COUPON_ONLY,
// The Manager will make pro-rata payments for the `FrictionlessOnChainAssetToken` for both the principal investment and the coupon.
SCHEDULE_PRO_RATA
}
/// @dev Enum for the periodicity of payments by the Manager
enum FrictionlessOnChainAssetPaymentFrequency {
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made daily
PAYMENT_FREQUENCY_DAILY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made weekly
PAYMENT_FREQUENCY_WEEKLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made monthly
PAYMENT_FREQUENCY_MONTHLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made quarterly
PAYMENT_FREQUENCY_QUARTERLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made semi-annually
PAYMENT_FREQUENCY_SEMI_ANNUALLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made annually
PAYMENT_FREQUENCY_ANNUALLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made once
PAYMENT_FREQUENCY_SINGLE
}
/// @dev Enum for the yield for this `FrictionlessOnChainAssetToken` is a fixed/floating rate
enum FrictionlessOnChainAssetYieldType {
// The yield for this `FrictionlessOnChainAssetToken` is a fixed rate
YIELD_FIXED,
// The yield for this `FrictionlessOnChainAssetToken` is a floating rate
YIELD_FLOATING
}
/// @dev Enum for the price quote status obtained at auction
enum FrictionlessOnChainAssetPriceStatus {
// The `FrictionlessOnChainAssetToken` did not receive enough offers at the offer price
PRICE_QUOTE_STATUS_UNDER_SUBSCRIBED,
// The aggregate bid at auction matched the offer
PRICE_QUOTE_STATUS_PRICED_AT_PAR,
// The aggregate bid at auction is lower than the offer
PRICE_QUOTE_STATUS_PRICED_AT_DISCOUNT,
// The aggregate bid at auction is higher than the offer
PRICE_QUOTE_STATUS_PRICED_AT_PREMIUM
}
/// @dev Enum for the current status of the `FrictionlessOnChainAssetToken`. Updated over time by the Treasury
enum FrictionlessOnChainAssetStatus {
// Status reserved for `FrictionlessOnChainAssetToken` that are MINTED onChain
STATUS_MINTED,
// Status reserved for `FrictionlessOnChainAssetToken` that are fully purchased, which means they have minted the digital securities.
STATUS_PURCHASED,
// Status reserved for `FrictionlessOnChainAssetToken` that have reached their maturity event
STATUS_MATURED,
// Status reserved for `FrictionlessOnChainAssetToken` that are in an impaired state. The parValue may be affected.
STATUS_IMPAIRED,
// Status reserved for `FrictionlessOnChainAssetToken` that are fully matured and have been fully redeemed.
STATUS_REDEEMED
}
/// @dev Enum for the current S&P style riskGrade of the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Treasury/Risk Oracle.
enum FrictionlessOnChainAssetRiskGrade {
BER_AAA,
BER_AA,
BER_A,
BER_BBB,
BER_BB,
BER_B,
BER_CCC,
BER_CC,
BER_C,
BER_D,
BER_UNRATED
}
/**
* @dev The specification data for the `FrictionlessOnChainAssetToken`, this is an immutable data struct.
* @param issuedOn the date this `FrictionlessOnChainAssetToken` is issued by the legal Issuer, Frictionless Markets S.à.r.l
* @param maturityDays the number of days to maturity for this `FrictionlessOnChainAssetToken`
* @param schedule the schedule of the payments by the Manager, either pro_rat or coupon/bullet style.
* @param paymentFrequency the periodicity of payments by the Manager
* @param yieldType the yield for this `FrictionlessOnChainAssetToken` is a fixed/floating rate
* @param baseCurrency the currrency the `FrictionlessOnChainAssetToken` is issued in.
* @param stripTotal the principal amount for the `FrictionlessOnChainAssetToken`
* @param name the name for the `FrictionlessOnChainAssetToken`
* @param symbol the ticker symbol for the `FrictionlessOnChainAssetToken`
*/
struct FOCASpecData {
uint256 issuedOn;
uint256 maturityDays;
FrictionlessOnChainAssetSchedule schedule;
FrictionlessOnChainAssetPaymentFrequency paymentFrequency;
FrictionlessOnChainAssetYieldType yieldType;
string baseCurrency;
uint256 stripTotal;
string name;
string symbol;
}
/**
* @dev The issuance data for the `FrictionlessOnChainAssetToken`, this is an immutable data struct.
* @param auctionedOn the date this `FrictionlessOnChainAssetToken` is auctioned by the legal Issuer, Frictionless Markets S.à.r.l
* @param priceQuoteStatus the price quote status obtained at auction
* @param onChainAssetUUID the off-chain UUID in the graphQL for the token
* @param issuerUUID the off-chain UUID in the graphQL for the Manager issuing via the legal Issuer, Frictionless Markets S.à.r.l
* @param isin the ISIN numbre or equivalent for the `FrictionlessOnChainAssetToken`
* @param issuanceDocs the location of the issuance docs accessible via URI or the hash of the issuance docs.
* @param assetClass the Managers/Issuers definition of the underlying asset class for the `FrictionlessOnChainAssetToken`
*/
struct FOCAIssuanceData {
uint256 auctionedOn;
FrictionlessOnChainAssetPriceStatus priceQuoteStatus;
string onChainAssetUUID;
string issuerUUID;
string isin;
string issuanceDocs;
string assetClass;
}
/**
* @dev The uopdatable data for the `FrictionlessOnChainAssetToken`.
* @param maturesOn the date this `FrictionlessOnChainAssetToken` fully matures. Updatable if the underlying fund is extended.
* @param total the total value of the `FrictionlessOnChainAssetToken` (strip + yield over time). Updatable based on Manager IRRs, totalReturn, etc.
* @param status the current status of the `FrictionlessOnChainAssetToken`. Updated over time by the Treasury
* @param yield the current yield being paid on the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Calculating Agent.
* @param riskGrade the current riskGrade of the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Treasury/Risk Oracle.
* @param pullToParValue the calculation of the pullToPar value of this `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Calculating Agent
* @param custodianAddress the address of the custodian for the `FrictionlessOnChainAssetToken`
*/
struct FOCAUpdateData {
uint256 maturesOn;
uint256 total;
FrictionlessOnChainAssetStatus status;
uint256 yield;
FrictionlessOnChainAssetRiskGrade riskGrade;
uint256 pullToParValue;
address custodianAddress;
}
/// @dev error throw if there is an attempt to modify the immutable data.
error FrictionlessOnChainAssetTokenUnableToUpdateData();
/**
* @dev Sets the specData data for the `FrictionlessOnChainAssetToken`.
* throws `FrictionlessOnChainAssetTokenUnableToUpdateData` This data is immutable, an attempt to modify will generate the error `FrictionlessOnChainAssetTokenUnableToUpdateData`
* @param specData the specData data for the `FrictionlessOnChainAssetToken`
*/
function setSpecificationData(FOCASpecData calldata specData) external;
/**
* @dev Sets the issuanceData data for the `FrictionlessOnChainAssetToken`
* throws `FrictionlessOnChainAssetTokenUnableToUpdateData` This data is immutable, an attempt to modify will generate the error `FrictionlessOnChainAssetTokenUnableToUpdateData`
* @param issuanceData the updatable data for the `FrictionlessOnChainAssetToken`
*/
function setIssuanceData(FOCAIssuanceData calldata issuanceData) external;
/**
* @dev Sets the updatable data for the `FrictionlessOnChainAssetToken`
* @param updateData the updatable data for the `FrictionlessOnChainAssetToken`
*/
function setUpdateData(FOCAUpdateData calldata updateData) external;
/**
* @dev Get the specData data for the `FrictionlessOnChainAssetToken`.
* @return the specData data for the `FrictionlessOnChainAssetToken`
*/
function getSpecificationData() external view returns (FOCASpecData memory);
/**
* @dev Get the issuanceData data for the `FrictionlessOnChainAssetToken`.
* @return the issuanceData data for the `FrictionlessOnChainAssetToken`
*/
function getIssuanceData() external view returns (FOCAIssuanceData memory);
/**
* @dev Get the updateData data for the `FrictionlessOnChainAssetToken`.
* @return the updateData data for the `FrictionlessOnChainAssetToken`
*/
function getUpdateData() external view returns (FOCAUpdateData memory);
/**
* @dev Get the currency the `FrictionlessOnChainAssetToken` is issued in.
* @return the currency the `FrictionlessOnChainAssetToken` is issued in.
*/
function getCurrency() external view returns (string memory);
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "./IToken.sol";
import "@onchain-id/solidity/contracts/interface/IIdentity.sol";
import "./TokenStorage.sol";
import "../roles/AgentRoleUpgradeable.sol";
contract Token is IToken, AgentRoleUpgradeable, TokenStorage {
/// modifiers
/// @dev Modifier to make a function callable only when the contract is not paused.
modifier whenNotPaused() {
require(!_tokenPaused, "Pausable: paused");
_;
}
/// @dev Modifier to make a function callable only when the contract is paused.
modifier whenPaused() {
require(_tokenPaused, "Pausable: not paused");
_;
}
/**
* @dev the constructor initiates the token contract
* msg.sender is set automatically as the owner of the smart contract
* @param _identityRegistry the address of the Identity registry linked to the token
* @param _compliance the address of the compliance contract linked to the token
* @param _name the name of the token
* @param _symbol the symbol of the token
* @param _decimals the decimals of the token
* @param _onchainID the address of the onchainID of the token
* emits an `UpdatedTokenInformation` event
* emits an `IdentityRegistryAdded` event
* emits a `ComplianceAdded` event
*/
function init(
address _identityRegistry,
address _compliance,
string memory _name,
string memory _symbol,
uint8 _decimals,
// _onchainID can be zero address if not set, can be set later by owner
address _onchainID
) external initializer {
// that require is protecting legacy versions of TokenProxy contracts
// as there was a bug with the initializer modifier on these proxies
// that check is preventing attackers to call the init functions on those
// legacy contracts.
require(owner() == address(0), "already initialized");
require(
_identityRegistry != address(0)
&& _compliance != address(0)
, "invalid argument - zero address");
require(
keccak256(abi.encode(_name)) != keccak256(abi.encode(""))
&& keccak256(abi.encode(_symbol)) != keccak256(abi.encode(""))
, "invalid argument - empty string");
require(0 <= _decimals && _decimals <= 18, "decimals between 0 and 18");
__Ownable_init();
_tokenName = _name;
_tokenSymbol = _symbol;
_tokenDecimals = _decimals;
_tokenOnchainID = _onchainID;
_tokenPaused = true;
setIdentityRegistry(_identityRegistry);
setCompliance(_compliance);
emit UpdatedTokenInformation(_tokenName, _tokenSymbol, _tokenDecimals, _TOKEN_VERSION, _tokenOnchainID);
}
/**
* @dev See {IERC20-approve}.
*/
function approve(address _spender, uint256 _amount) external virtual override returns (bool) {
_approve(msg.sender, _spender, _amount);
return true;
}
/**
* @dev See {ERC20-increaseAllowance}.
*/
function increaseAllowance(address _spender, uint256 _addedValue) external virtual returns (bool) {
_approve(msg.sender, _spender, _allowances[msg.sender][_spender] + (_addedValue));
return true;
}
/**
* @dev See {ERC20-decreaseAllowance}.
*/
function decreaseAllowance(address _spender, uint256 _subtractedValue) external virtual returns (bool) {
_approve(msg.sender, _spender, _allowances[msg.sender][_spender] - _subtractedValue);
return true;
}
/**
* @dev See {IToken-setName}.
*/
function setName(string calldata _name) external override onlyOwner {
require(keccak256(abi.encode(_name)) != keccak256(abi.encode("")), "invalid argument - empty string");
_tokenName = _name;
emit UpdatedTokenInformation(_tokenName, _tokenSymbol, _tokenDecimals, _TOKEN_VERSION, _tokenOnchainID);
}
/**
* @dev See {IToken-setSymbol}.
*/
function setSymbol(string calldata _symbol) external override onlyOwner {
require(keccak256(abi.encode(_symbol)) != keccak256(abi.encode("")), "invalid argument - empty string");
_tokenSymbol = _symbol;
emit UpdatedTokenInformation(_tokenName, _tokenSymbol, _tokenDecimals, _TOKEN_VERSION, _tokenOnchainID);
}
/**
* @dev See {IToken-setOnchainID}.
* if _onchainID is set at zero address it means no ONCHAINID is bound to this token
*/
function setOnchainID(address _onchainID) external override onlyOwner {
_tokenOnchainID = _onchainID;
emit UpdatedTokenInformation(_tokenName, _tokenSymbol, _tokenDecimals, _TOKEN_VERSION, _tokenOnchainID);
}
/**
* @dev See {IToken-pause}.
*/
function pause() external override onlyAgent whenNotPaused {
_tokenPaused = true;
emit Paused(msg.sender);
}
/**
* @dev See {IToken-unpause}.
*/
function unpause() external override onlyAgent whenPaused {
_tokenPaused = false;
emit Unpaused(msg.sender);
}
/**
* @dev See {IToken-batchTransfer}.
*/
function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external override {
for (uint256 i = 0; i < _toList.length; i++) {
transfer(_toList[i], _amounts[i]);
}
}
/**
* @notice ERC-20 overridden function that include logic to check for trade validity.
* Require that the from and to addresses are not frozen.
* Require that the value should not exceed available balance .
* Require that the to address is a verified address
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The number of tokens to transfer
* @return `true` if successful and revert if unsuccessful
*/
function transferFrom(
address _from,
address _to,
uint256 _amount
) external override whenNotPaused returns (bool) {
require(!_frozen[_to] && !_frozen[_from], "wallet is frozen");
require(_amount <= balanceOf(_from) - (_frozenTokens[_from]), "Insufficient Balance");
if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(_from, _to, _amount)) {
_approve(_from, msg.sender, _allowances[_from][msg.sender] - (_amount));
_transfer(_from, _to, _amount);
_tokenCompliance.transferred(_from, _to, _amount);
return true;
}
revert("Transfer not possible");
}
/**
* @dev See {IToken-batchForcedTransfer}.
*/
function batchForcedTransfer(
address[] calldata _fromList,
address[] calldata _toList,
uint256[] calldata _amounts
) external override {
for (uint256 i = 0; i < _fromList.length; i++) {
forcedTransfer(_fromList[i], _toList[i], _amounts[i]);
}
}
/**
* @dev See {IToken-batchMint}.
*/
function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external override {
for (uint256 i = 0; i < _toList.length; i++) {
mint(_toList[i], _amounts[i]);
}
}
/**
* @dev See {IToken-batchBurn}.
*/
function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
for (uint256 i = 0; i < _userAddresses.length; i++) {
burn(_userAddresses[i], _amounts[i]);
}
}
/**
* @dev See {IToken-batchSetAddressFrozen}.
*/
function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external override {
for (uint256 i = 0; i < _userAddresses.length; i++) {
setAddressFrozen(_userAddresses[i], _freeze[i]);
}
}
/**
* @dev See {IToken-batchFreezePartialTokens}.
*/
function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
for (uint256 i = 0; i < _userAddresses.length; i++) {
freezePartialTokens(_userAddresses[i], _amounts[i]);
}
}
/**
* @dev See {IToken-batchUnfreezePartialTokens}.
*/
function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external override {
for (uint256 i = 0; i < _userAddresses.length; i++) {
unfreezePartialTokens(_userAddresses[i], _amounts[i]);
}
}
/**
* @dev See {IToken-recoveryAddress}.
*/
function recoveryAddress(
address _lostWallet,
address _newWallet,
address _investorOnchainID
) external override onlyAgent returns (bool) {
require(balanceOf(_lostWallet) != 0, "no tokens to recover");
IIdentity _onchainID = IIdentity(_investorOnchainID);
bytes32 _key = keccak256(abi.encode(_newWallet));
if (_onchainID.keyHasPurpose(_key, 1)) {
uint256 investorTokens = balanceOf(_lostWallet);
uint256 frozenTokens = _frozenTokens[_lostWallet];
_tokenIdentityRegistry.registerIdentity(_newWallet, _onchainID, _tokenIdentityRegistry.investorCountry
(_lostWallet));
forcedTransfer(_lostWallet, _newWallet, investorTokens);
if (frozenTokens > 0) {
freezePartialTokens(_newWallet, frozenTokens);
}
if (_frozen[_lostWallet] == true) {
setAddressFrozen(_newWallet, true);
}
_tokenIdentityRegistry.deleteIdentity(_lostWallet);
emit RecoverySuccess(_lostWallet, _newWallet, _investorOnchainID);
return true;
}
revert("Recovery not possible");
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() external view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address _owner, address _spender) external view virtual override returns (uint256) {
return _allowances[_owner][_spender];
}
/**
* @dev See {IToken-identityRegistry}.
*/
function identityRegistry() external view override returns (IIdentityRegistry) {
return _tokenIdentityRegistry;
}
/**
* @dev See {IToken-compliance}.
*/
function compliance() external view override returns (IModularCompliance) {
return _tokenCompliance;
}
/**
* @dev See {IToken-paused}.
*/
function paused() external view override returns (bool) {
return _tokenPaused;
}
/**
* @dev See {IToken-isFrozen}.
*/
function isFrozen(address _userAddress) external view override returns (bool) {
return _frozen[_userAddress];
}
/**
* @dev See {IToken-getFrozenTokens}.
*/
function getFrozenTokens(address _userAddress) external view override returns (uint256) {
return _frozenTokens[_userAddress];
}
/**
* @dev See {IToken-decimals}.
*/
function decimals() external view override returns (uint8) {
return _tokenDecimals;
}
/**
* @dev See {IToken-name}.
*/
function name() external view override returns (string memory) {
return _tokenName;
}
/**
* @dev See {IToken-onchainID}.
*/
function onchainID() external view override returns (address) {
return _tokenOnchainID;
}
/**
* @dev See {IToken-symbol}.
*/
function symbol() external view override returns (string memory) {
return _tokenSymbol;
}
/**
* @dev See {IToken-version}.
*/
function version() external pure override returns (string memory) {
return _TOKEN_VERSION;
}
/**
* @notice ERC-20 overridden function that include logic to check for trade validity.
* Require that the msg.sender and to addresses are not frozen.
* Require that the value should not exceed available balance .
* Require that the to address is a verified address
* @param _to The address of the receiver
* @param _amount The number of tokens to transfer
* @return `true` if successful and revert if unsuccessful
*/
function transfer(address _to, uint256 _amount) public override whenNotPaused returns (bool) {
require(!_frozen[_to] && !_frozen[msg.sender], "wallet is frozen");
require(_amount <= balanceOf(msg.sender) - (_frozenTokens[msg.sender]), "Insufficient Balance");
if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(msg.sender, _to, _amount)) {
_transfer(msg.sender, _to, _amount);
_tokenCompliance.transferred(msg.sender, _to, _amount);
return true;
}
revert("Transfer not possible");
}
/**
* @dev See {IToken-forcedTransfer}.
*/
function forcedTransfer(
address _from,
address _to,
uint256 _amount
) public override onlyAgent returns (bool) {
require(balanceOf(_from) >= _amount, "sender balance too low");
uint256 freeBalance = balanceOf(_from) - (_frozenTokens[_from]);
if (_amount > freeBalance) {
uint256 tokensToUnfreeze = _amount - (freeBalance);
_frozenTokens[_from] = _frozenTokens[_from] - (tokensToUnfreeze);
emit TokensUnfrozen(_from, tokensToUnfreeze);
}
if (_tokenIdentityRegistry.isVerified(_to)) {
_transfer(_from, _to, _amount);
_tokenCompliance.transferred(_from, _to, _amount);
return true;
}
revert("Transfer not possible");
}
/**
* @dev See {IToken-mint}.
*/
function mint(address _to, uint256 _amount) public override onlyAgent {
require(_tokenIdentityRegistry.isVerified(_to), "Identity is not verified.");
require(_tokenCompliance.canTransfer(address(0), _to, _amount), "Compliance not followed");
_mint(_to, _amount);
_tokenCompliance.created(_to, _amount);
}
/**
* @dev See {IToken-burn}.
*/
function burn(address _userAddress, uint256 _amount) public override onlyAgent {
require(balanceOf(_userAddress) >= _amount, "cannot burn more than balance");
uint256 freeBalance = balanceOf(_userAddress) - _frozenTokens[_userAddress];
if (_amount > freeBalance) {
uint256 tokensToUnfreeze = _amount - (freeBalance);
_frozenTokens[_userAddress] = _frozenTokens[_userAddress] - (tokensToUnfreeze);
emit TokensUnfrozen(_userAddress, tokensToUnfreeze);
}
_burn(_userAddress, _amount);
_tokenCompliance.destroyed(_userAddress, _amount);
}
/**
* @dev See {IToken-setAddressFrozen}.
*/
function setAddressFrozen(address _userAddress, bool _freeze) public override onlyAgent {
_frozen[_userAddress] = _freeze;
emit AddressFrozen(_userAddress, _freeze, msg.sender);
}
/**
* @dev See {IToken-freezePartialTokens}.
*/
function freezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent {
uint256 balance = balanceOf(_userAddress);
require(balance >= _frozenTokens[_userAddress] + _amount, "Amount exceeds available balance");
_frozenTokens[_userAddress] = _frozenTokens[_userAddress] + (_amount);
emit TokensFrozen(_userAddress, _amount);
}
/**
* @dev See {IToken-unfreezePartialTokens}.
*/
function unfreezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent {
require(_frozenTokens[_userAddress] >= _amount, "Amount should be less than or equal to frozen tokens");
_frozenTokens[_userAddress] = _frozenTokens[_userAddress] - (_amount);
emit TokensUnfrozen(_userAddress, _amount);
}
/**
* @dev See {IToken-setIdentityRegistry}.
*/
function setIdentityRegistry(address _identityRegistry) public override onlyOwner {
_tokenIdentityRegistry = IIdentityRegistry(_identityRegistry);
emit IdentityRegistryAdded(_identityRegistry);
}
/**
* @dev See {IToken-setCompliance}.
*/
function setCompliance(address _compliance) public override onlyOwner {
if (address(_tokenCompliance) != address(0)) {
_tokenCompliance.unbindToken(address(this));
}
_tokenCompliance = IModularCompliance(_compliance);
_tokenCompliance.bindToken(address(this));
emit ComplianceAdded(_compliance);
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address _userAddress) public view override returns (uint256) {
return _balances[_userAddress];
}
/**
* @dev See {ERC20-_transfer}.
*/
function _transfer(
address _from,
address _to,
uint256 _amount
) internal virtual {
require(_from != address(0), "ERC20: transfer from the zero address");
require(_to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(_from, _to, _amount);
_balances[_from] = _balances[_from] - _amount;
_balances[_to] = _balances[_to] + _amount;
emit Transfer(_from, _to, _amount);
}
/**
* @dev See {ERC20-_mint}.
*/
function _mint(address _userAddress, uint256 _amount) internal virtual {
require(_userAddress != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), _userAddress, _amount);
_totalSupply = _totalSupply + _amount;
_balances[_userAddress] = _balances[_userAddress] + _amount;
emit Transfer(address(0), _userAddress, _amount);
}
/**
* @dev See {ERC20-_burn}.
*/
function _burn(address _userAddress, uint256 _amount) internal virtual {
require(_userAddress != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(_userAddress, address(0), _amount);
_balances[_userAddress] = _balances[_userAddress] - _amount;
_totalSupply = _totalSupply - _amount;
emit Transfer(_userAddress, address(0), _amount);
}
/**
* @dev See {ERC20-_approve}.
*/
function _approve(
address _owner,
address _spender,
uint256 _amount
) internal virtual {
require(_owner != address(0), "ERC20: approve from the zero address");
require(_spender != address(0), "ERC20: approve to the zero address");
_allowances[_owner][_spender] = _amount;
emit Approval(_owner, _spender, _amount);
}
/**
* @dev See {ERC20-_beforeTokenTransfer}.
*/
// solhint-disable-next-line no-empty-blocks
function _beforeTokenTransfer(address _from, address _to, uint256 _amount) internal virtual {}
}// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
pragma solidity ^0.8.16;
import { IToken } from "@ERC-3643/token/IToken.sol";
/**
* @title IBasicFrictionlessToken - Represents the base interface for Frictionless protocol tokens.
* @author Frictionless Group Holdings S.à.r.l
* @notice The IBasicFrictionlessToken Represents the base interface for Frictionless protocol tokens, this interface is used to determine a token type.
*/
interface IBasicFrictionlessToken is IToken {
/**
* @dev Enumeration to represent each of the tokens in the Frictionless protocol.
*/
enum FrictionlessTokenTypes {
NONE,
FUND_DEPOSIT_TOKEN, // IFrictionlessFundDepositToken
DIGITAL_SECURITY_TOKEN, // IFrictionlessDigitalSecurityToken
ON_CHAIN_ASSET_TOKEN // IFrictionlessOnChainAssetToken
}
/// @dev error thrown if an attempt to set an invalid token type during function `setFrictionlessTokenType`
error BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType();
/**
* @dev Sets the token type according to the specified enumeration
* @param newTokenType_ the token type to set
*/
function setFrictionlessTokenType(FrictionlessTokenTypes newTokenType_) external;
/**
* @dev Returns the token type according to the specified enumeration
* @return FrictionlessTokenTypes the token type according to the specified enumeration
*/
function getFrictionlessTokenType() external view returns (FrictionlessTokenTypes);
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "../registry/interface/IIdentityRegistry.sol";
import "../compliance/modular/IModularCompliance.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @dev interface
interface IToken is IERC20 {
/// events
/**
* this event is emitted when the token information is updated.
* the event is emitted by the token init function and by the setTokenInformation function
* `_newName` is the name of the token
* `_newSymbol` is the symbol of the token
* `_newDecimals` is the decimals of the token
* `_newVersion` is the version of the token, current version is 3.0
* `_newOnchainID` is the address of the onchainID of the token
*/
event UpdatedTokenInformation(string indexed _newName, string indexed _newSymbol, uint8 _newDecimals, string
_newVersion, address indexed _newOnchainID);
/**
* this event is emitted when the IdentityRegistry has been set for the token
* the event is emitted by the token constructor and by the setIdentityRegistry function
* `_identityRegistry` is the address of the Identity Registry of the token
*/
event IdentityRegistryAdded(address indexed _identityRegistry);
/**
* this event is emitted when the Compliance has been set for the token
* the event is emitted by the token constructor and by the setCompliance function
* `_compliance` is the address of the Compliance contract of the token
*/
event ComplianceAdded(address indexed _compliance);
/**
* this event is emitted when an investor successfully recovers his tokens
* the event is emitted by the recoveryAddress function
* `_lostWallet` is the address of the wallet that the investor lost access to
* `_newWallet` is the address of the wallet that the investor provided for the recovery
* `_investorOnchainID` is the address of the onchainID of the investor who asked for a recovery
*/
event RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID);
/**
* this event is emitted when the wallet of an investor is frozen or unfrozen
* the event is emitted by setAddressFrozen and batchSetAddressFrozen functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_isFrozen` is the freezing status of the wallet
* if `_isFrozen` equals `true` the wallet is frozen after emission of the event
* if `_isFrozen` equals `false` the wallet is unfrozen after emission of the event
* `_owner` is the address of the agent who called the function to freeze the wallet
*/
event AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner);
/**
* this event is emitted when a certain amount of tokens is frozen on a wallet
* the event is emitted by freezePartialTokens and batchFreezePartialTokens functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_amount` is the amount of tokens that are frozen
*/
event TokensFrozen(address indexed _userAddress, uint256 _amount);
/**
* this event is emitted when a certain amount of tokens is unfrozen on a wallet
* the event is emitted by unfreezePartialTokens and batchUnfreezePartialTokens functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_amount` is the amount of tokens that are unfrozen
*/
event TokensUnfrozen(address indexed _userAddress, uint256 _amount);
/**
* this event is emitted when the token is paused
* the event is emitted by the pause function
* `_userAddress` is the address of the wallet that called the pause function
*/
event Paused(address _userAddress);
/**
* this event is emitted when the token is unpaused
* the event is emitted by the unpause function
* `_userAddress` is the address of the wallet that called the unpause function
*/
event Unpaused(address _userAddress);
/// functions
/**
* @dev sets the token name
* @param _name the name of token to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setName(string calldata _name) external;
/**
* @dev sets the token symbol
* @param _symbol the token symbol to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setSymbol(string calldata _symbol) external;
/**
* @dev sets the onchain ID of the token
* @param _onchainID the address of the onchain ID to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setOnchainID(address _onchainID) external;
/**
* @dev pauses the token contract, when contract is paused investors cannot transfer tokens anymore
* This function can only be called by a wallet set as agent of the token
* emits a `Paused` event
*/
function pause() external;
/**
* @dev unpauses the token contract, when contract is unpaused investors can transfer tokens
* if their wallet is not blocked & if the amount to transfer is <= to the amount of free tokens
* This function can only be called by a wallet set as agent of the token
* emits an `Unpaused` event
*/
function unpause() external;
/**
* @dev sets an address frozen status for this token.
* @param _userAddress The address for which to update frozen status
* @param _freeze Frozen status of the address
* This function can only be called by a wallet set as agent of the token
* emits an `AddressFrozen` event
*/
function setAddressFrozen(address _userAddress, bool _freeze) external;
/**
* @dev freezes token amount specified for given address.
* @param _userAddress The address for which to update frozen tokens
* @param _amount Amount of Tokens to be frozen
* This function can only be called by a wallet set as agent of the token
* emits a `TokensFrozen` event
*/
function freezePartialTokens(address _userAddress, uint256 _amount) external;
/**
* @dev unfreezes token amount specified for given address
* @param _userAddress The address for which to update frozen tokens
* @param _amount Amount of Tokens to be unfrozen
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event
*/
function unfreezePartialTokens(address _userAddress, uint256 _amount) external;
/**
* @dev sets the Identity Registry for the token
* @param _identityRegistry the address of the Identity Registry to set
* Only the owner of the token smart contract can call this function
* emits an `IdentityRegistryAdded` event
*/
function setIdentityRegistry(address _identityRegistry) external;
/**
* @dev sets the compliance contract of the token
* @param _compliance the address of the compliance contract to set
* Only the owner of the token smart contract can call this function
* calls bindToken on the compliance contract
* emits a `ComplianceAdded` event
*/
function setCompliance(address _compliance) external;
/**
* @dev force a transfer of tokens between 2 whitelisted wallets
* In case the `from` address has not enough free tokens (unfrozen tokens)
* but has a total balance higher or equal to the `amount`
* the amount of frozen tokens is reduced in order to have enough free tokens
* to proceed the transfer, in such a case, the remaining balance on the `from`
* account is 100% composed of frozen tokens post-transfer.
* Require that the `to` address is a verified address,
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The number of tokens to transfer
* @return `true` if successful and revert if unsuccessful
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_from`
* emits a `Transfer` event
*/
function forcedTransfer(
address _from,
address _to,
uint256 _amount
) external returns (bool);
/**
* @dev mint tokens on a wallet
* Improved version of default mint method. Tokens can be minted
* to an address if only it is a verified address as per the security token.
* @param _to Address to mint the tokens to.
* @param _amount Amount of tokens to mint.
* This function can only be called by a wallet set as agent of the token
* emits a `Transfer` event
*/
function mint(address _to, uint256 _amount) external;
/**
* @dev burn tokens on a wallet
* In case the `account` address has not enough free tokens (unfrozen tokens)
* but has a total balance higher or equal to the `value` amount
* the amount of frozen tokens is reduced in order to have enough free tokens
* to proceed the burn, in such a case, the remaining balance on the `account`
* is 100% composed of frozen tokens post-transaction.
* @param _userAddress Address to burn the tokens from.
* @param _amount Amount of tokens to burn.
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_userAddress`
* emits a `Transfer` event
*/
function burn(address _userAddress, uint256 _amount) external;
/**
* @dev recovery function used to force transfer tokens from a
* lost wallet to a new wallet for an investor.
* @param _lostWallet the wallet that the investor lost
* @param _newWallet the newly provided wallet on which tokens have to be transferred
* @param _investorOnchainID the onchainID of the investor asking for a recovery
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if there is some frozen tokens on the lost wallet if the recovery process is successful
* emits a `Transfer` event if the recovery process is successful
* emits a `RecoverySuccess` event if the recovery process is successful
* emits a `RecoveryFails` event if the recovery process fails
*/
function recoveryAddress(
address _lostWallet,
address _newWallet,
address _investorOnchainID
) external returns (bool);
/**
* @dev function allowing to issue transfers in batch
* Require that the msg.sender and `to` addresses are not frozen.
* Require that the total value should not exceed available balance.
* Require that the `to` addresses are all verified addresses,
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to transfer to the corresponding receiver
* emits _toList.length `Transfer` events
*/
function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external;
/**
* @dev function allowing to issue forced transfers in batch
* Require that `_amounts[i]` should not exceed available balance of `_fromList[i]`.
* Require that the `_toList` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_fromList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _fromList The addresses of the senders
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to transfer to the corresponding receiver
* This function can only be called by a wallet set as agent of the token
* emits `TokensUnfrozen` events if `_amounts[i]` is higher than the free balance of `_fromList[i]`
* emits _fromList.length `Transfer` events
*/
function batchForcedTransfer(
address[] calldata _fromList,
address[] calldata _toList,
uint256[] calldata _amounts
) external;
/**
* @dev function allowing to mint tokens in batch
* Require that the `_toList` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to mint to the corresponding receiver
* This function can only be called by a wallet set as agent of the token
* emits _toList.length `Transfer` events
*/
function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external;
/**
* @dev function allowing to burn tokens in batch
* Require that the `_userAddresses` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses of the wallets concerned by the burn
* @param _amounts The number of tokens to burn from the corresponding wallets
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `Transfer` events
*/
function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @dev function allowing to set frozen addresses in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses for which to update frozen status
* @param _freeze Frozen status of the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `AddressFrozen` events
*/
function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external;
/**
* @dev function allowing to freeze tokens partially in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses on which tokens need to be frozen
* @param _amounts the amount of tokens to freeze on the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `TokensFrozen` events
*/
function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @dev function allowing to unfreeze tokens partially in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses on which tokens need to be unfrozen
* @param _amounts the amount of tokens to unfreeze on the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `TokensUnfrozen` events
*/
function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 1 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* balanceOf() and transfer().
*/
function decimals() external view returns (uint8);
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the address of the onchainID of the token.
* the onchainID of the token gives all the information available
* about the token and is managed by the token issuer or his agent.
*/
function onchainID() external view returns (address);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the TREX version of the token.
* current version is 3.0.0
*/
function version() external view returns (string memory);
/**
* @dev Returns the Identity Registry linked to the token
*/
function identityRegistry() external view returns (IIdentityRegistry);
/**
* @dev Returns the Compliance contract linked to the token
*/
function compliance() external view returns (IModularCompliance);
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() external view returns (bool);
/**
* @dev Returns the freezing status of a wallet
* if isFrozen returns `true` the wallet is frozen
* if isFrozen returns `false` the wallet is not frozen
* isFrozen returning `true` doesn't mean that the balance is free, tokens could be blocked by
* a partial freeze or the whole token could be blocked by pause
* @param _userAddress the address of the wallet on which isFrozen is called
*/
function isFrozen(address _userAddress) external view returns (bool);
/**
* @dev Returns the amount of tokens that are partially frozen on a wallet
* the amount of frozen tokens is always <= to the total balance of the wallet
* @param _userAddress the address of the wallet on which getFrozenTokens is called
*/
function getFrozenTokens(address _userAddress) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import "./IERC734.sol";
import "./IERC735.sol";
// solhint-disable-next-line no-empty-blocks
interface IIdentity is IERC734, IERC735 {}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "../compliance/modular/IModularCompliance.sol";
import "../registry/interface/IIdentityRegistry.sol";
contract TokenStorage {
/// @dev ERC20 basic variables
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) internal _allowances;
uint256 internal _totalSupply;
/// @dev Token information
string internal _tokenName;
string internal _tokenSymbol;
uint8 internal _tokenDecimals;
address internal _tokenOnchainID;
string internal constant _TOKEN_VERSION = "4.0.1";
/// @dev Variables of freeze and pause functions
mapping(address => bool) internal _frozen;
mapping(address => uint256) internal _frozenTokens;
bool internal _tokenPaused = false;
/// @dev Identity Registry contract used by the onchain validator system
IIdentityRegistry internal _tokenIdentityRegistry;
/// @dev Compliance contract linked to the onchain validator system
IModularCompliance internal _tokenCompliance;
/**
* @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.
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./Roles.sol";
contract AgentRoleUpgradeable is OwnableUpgradeable {
using Roles for Roles.Role;
Roles.Role private _agents;
event AgentAdded(address indexed _agent);
event AgentRemoved(address indexed _agent);
modifier onlyAgent() {
require(isAgent(msg.sender), "AgentRole: caller does not have the Agent role");
_;
}
function addAgent(address _agent) public onlyOwner {
require(_agent != address(0), "invalid argument - zero address");
_agents.add(_agent);
emit AgentAdded(_agent);
}
function removeAgent(address _agent) public onlyOwner {
require(_agent != address(0), "invalid argument - zero address");
_agents.remove(_agent);
emit AgentRemoved(_agent);
}
function isAgent(address _agent) public view returns (bool) {
return _agents.has(_agent);
}
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "./ITrustedIssuersRegistry.sol";
import "./IClaimTopicsRegistry.sol";
import "./IIdentityRegistryStorage.sol";
import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol";
import "@onchain-id/solidity/contracts/interface/IIdentity.sol";
interface IIdentityRegistry {
/**
* this event is emitted when the ClaimTopicsRegistry has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `claimTopicsRegistry` is the address of the Claim Topics Registry contract
*/
event ClaimTopicsRegistrySet(address indexed claimTopicsRegistry);
/**
* this event is emitted when the IdentityRegistryStorage has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `identityStorage` is the address of the Identity Registry Storage contract
*/
event IdentityStorageSet(address indexed identityStorage);
/**
* this event is emitted when the TrustedIssuersRegistry has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `trustedIssuersRegistry` is the address of the Trusted Issuers Registry contract
*/
event TrustedIssuersRegistrySet(address indexed trustedIssuersRegistry);
/**
* this event is emitted when an Identity is registered into the Identity Registry.
* the event is emitted by the 'registerIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityRegistered(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity is removed from the Identity Registry.
* the event is emitted by the 'deleteIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityRemoved(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity has been updated
* the event is emitted by the 'updateIdentity' function
* `oldIdentity` is the old Identity contract's address to update
* `newIdentity` is the new Identity contract's
*/
event IdentityUpdated(IIdentity indexed oldIdentity, IIdentity indexed newIdentity);
/**
* this event is emitted when an Identity's country has been updated
* the event is emitted by the 'updateCountry' function
* `investorAddress` is the address on which the country has been updated
* `country` is the numeric code (ISO 3166-1) of the new country
*/
event CountryUpdated(address indexed investorAddress, uint16 indexed country);
/**
* @dev Register an identity contract corresponding to a user address.
* Requires that the user doesn't have an identity contract already registered.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's identity contract
* @param _country The country of the investor
* emits `IdentityRegistered` event
*/
function registerIdentity(
address _userAddress,
IIdentity _identity,
uint16 _country
) external;
/**
* @dev Removes an user from the identity registry.
* Requires that the user have an identity contract already deployed that will be deleted.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user to be removed
* emits `IdentityRemoved` event
*/
function deleteIdentity(address _userAddress) external;
/**
* @dev Replace the actual identityRegistryStorage contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _identityRegistryStorage The address of the new Identity Registry Storage
* emits `IdentityStorageSet` event
*/
function setIdentityRegistryStorage(address _identityRegistryStorage) external;
/**
* @dev Replace the actual claimTopicsRegistry contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _claimTopicsRegistry The address of the new claim Topics Registry
* emits `ClaimTopicsRegistrySet` event
*/
function setClaimTopicsRegistry(address _claimTopicsRegistry) external;
/**
* @dev Replace the actual trustedIssuersRegistry contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _trustedIssuersRegistry The address of the new Trusted Issuers Registry
* emits `TrustedIssuersRegistrySet` event
*/
function setTrustedIssuersRegistry(address _trustedIssuersRegistry) external;
/**
* @dev Updates the country corresponding to a user address.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _country The new country of the user
* emits `CountryUpdated` event
*/
function updateCountry(address _userAddress, uint16 _country) external;
/**
* @dev Updates an identity contract corresponding to a user address.
* Requires that the user address should be the owner of the identity contract.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's new identity contract
* emits `IdentityUpdated` event
*/
function updateIdentity(address _userAddress, IIdentity _identity) external;
/**
* @dev function allowing to register identities in batch
* This function can only be called by a wallet set as agent of the smart contract
* Requires that none of the users has an identity contract already registered.
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses of the users
* @param _identities The addresses of the corresponding identity contracts
* @param _countries The countries of the corresponding investors
* emits _userAddresses.length `IdentityRegistered` events
*/
function batchRegisterIdentity(
address[] calldata _userAddresses,
IIdentity[] calldata _identities,
uint16[] calldata _countries
) external;
/**
* @dev This functions checks whether a wallet has its Identity registered or not
* in the Identity Registry.
* @param _userAddress The address of the user to be checked.
* @return 'True' if the address is contained in the Identity Registry, 'false' if not.
*/
function contains(address _userAddress) external view returns (bool);
/**
* @dev This functions checks whether an identity contract
* corresponding to the provided user address has the required claims or not based
* on the data fetched from trusted issuers registry and from the claim topics registry
* @param _userAddress The address of the user to be verified.
* @return 'True' if the address is verified, 'false' if not.
*/
function isVerified(address _userAddress) external view returns (bool);
/**
* @dev Returns the onchainID of an investor.
* @param _userAddress The wallet of the investor
*/
function identity(address _userAddress) external view returns (IIdentity);
/**
* @dev Returns the country code of an investor.
* @param _userAddress The wallet of the investor
*/
function investorCountry(address _userAddress) external view returns (uint16);
/**
* @dev Returns the IdentityRegistryStorage linked to the current IdentityRegistry.
*/
function identityStorage() external view returns (IIdentityRegistryStorage);
/**
* @dev Returns the TrustedIssuersRegistry linked to the current IdentityRegistry.
*/
function issuersRegistry() external view returns (ITrustedIssuersRegistry);
/**
* @dev Returns the ClaimTopicsRegistry linked to the current IdentityRegistry.
*/
function topicsRegistry() external view returns (IClaimTopicsRegistry);
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
interface IModularCompliance {
/// events
/**
* @dev Event emitted for each executed interaction with a module contract.
* For gas efficiency, only the interaction calldata selector (first 4
* bytes) is included in the event. For interactions without calldata or
* whose calldata is shorter than 4 bytes, the selector will be `0`.
*/
event ModuleInteraction(address indexed target, bytes4 selector);
/**
* this event is emitted when a token has been bound to the compliance contract
* the event is emitted by the bindToken function
* `_token` is the address of the token to bind
*/
event TokenBound(address _token);
/**
* this event is emitted when a token has been unbound from the compliance contract
* the event is emitted by the unbindToken function
* `_token` is the address of the token to unbind
*/
event TokenUnbound(address _token);
/**
* this event is emitted when a module has been added to the list of modules bound to the compliance contract
* the event is emitted by the addModule function
* `_module` is the address of the compliance module
*/
event ModuleAdded(address indexed _module);
/**
* this event is emitted when a module has been removed from the list of modules bound to the compliance contract
* the event is emitted by the removeModule function
* `_module` is the address of the compliance module
*/
event ModuleRemoved(address indexed _module);
/// functions
/**
* @dev binds a token to the compliance contract
* @param _token address of the token to bind
* This function can be called ONLY by the owner of the compliance contract
* Emits a TokenBound event
*/
function bindToken(address _token) external;
/**
* @dev unbinds a token from the compliance contract
* @param _token address of the token to unbind
* This function can be called ONLY by the owner of the compliance contract
* Emits a TokenUnbound event
*/
function unbindToken(address _token) external;
/**
* @dev adds a module to the list of compliance modules
* @param _module address of the module to add
* there cannot be more than 25 modules bound to the modular compliance for gas cost reasons
* This function can be called ONLY by the owner of the compliance contract
* Emits a ModuleAdded event
*/
function addModule(address _module) external;
/**
* @dev removes a module from the list of compliance modules
* @param _module address of the module to remove
* This function can be called ONLY by the owner of the compliance contract
* Emits a ModuleRemoved event
*/
function removeModule(address _module) external;
/**
* @dev calls any function on bound modules
* can be called only on bound modules
* @param callData the bytecode for interaction with the module, abi encoded
* @param _module The address of the module
* This function can be called only by the modular compliance owner
* emits a `ModuleInteraction` event
*/
function callModuleFunction(bytes calldata callData, address _module) external;
/**
* @dev function called whenever tokens are transferred
* from one wallet to another
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the transfer
* This function calls moduleTransferAction() on each module bound to the compliance contract
*/
function transferred(
address _from,
address _to,
uint256 _amount
) external;
/**
* @dev function called whenever tokens are created on a wallet
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the minting
* This function calls moduleMintAction() on each module bound to the compliance contract
*/
function created(address _to, uint256 _amount) external;
/**
* @dev function called whenever tokens are destroyed from a wallet
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _from The address on which tokens are burnt
* @param _amount The amount of tokens involved in the burn
* This function calls moduleBurnAction() on each module bound to the compliance contract
*/
function destroyed(address _from, uint256 _amount) external;
/**
* @dev checks that the transfer is compliant.
* default compliance always returns true
* READ ONLY FUNCTION, this function cannot be used to increment
* counters, emit events, ...
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the transfer
* This function will call moduleCheck() on every module bound to the compliance
* If each of the module checks return TRUE, this function will return TRUE as well
* returns FALSE otherwise
*/
function canTransfer(
address _from,
address _to,
uint256 _amount
) external view returns (bool);
/**
* @dev getter for the modules bound to the compliance contract
* returns address array of module contracts bound to the compliance
*/
function getModules() external view returns (address[] memory);
/**
* @dev getter for the address of the token bound
* returns the address of the token
*/
function getTokenBound() external view returns (address);
/**
* @dev checks if a module is bound to the compliance contract
* returns true if module is bound, false otherwise
*/
function isModuleBound(address _module) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount
) external returns (bool);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
/**
* @dev interface of the ERC734 (Key Holder) standard as defined in the EIP.
*/
interface IERC734 {
/**
* @dev Emitted when an execution request was approved.
*
* Specification: MUST be triggered when approve was successfully called.
*/
event Approved(uint256 indexed executionId, bool approved);
/**
* @dev Emitted when an execute operation was approved and successfully performed.
*
* Specification: MUST be triggered when approve was called and the execution was successfully approved.
*/
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when an execution request was performed via `execute`.
*
* Specification: MUST be triggered when execute was successfully called.
*/
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when an execute operation was called and failed
*
* Specification: MUST be triggered when execute call failed
*/
event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when a key was added to the Identity.
*
* Specification: MUST be triggered when addKey was successfully called.
*/
event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
/**
* @dev Emitted when a key was removed from the Identity.
*
* Specification: MUST be triggered when removeKey was successfully called.
*/
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
/**
* @dev Adds a _key to the identity. The _purpose specifies the purpose of the key.
*
* Triggers Event: `KeyAdded`
*
* Specification: MUST only be done by keys of purpose 1, or the identity
* itself. If it's the identity itself, the approval process will determine its approval.
*/
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) external returns (bool success);
/**
* @dev Approves an execution.
*
* Triggers Event: `Approved`
* Triggers on execution successful Event: `Executed`
* Triggers on execution failure Event: `ExecutionFailed`
*/
function approve(uint256 _id, bool _approve) external returns (bool success);
/**
* @dev Removes _purpose for _key from the identity.
*
* Triggers Event: `KeyRemoved`
*
* Specification: MUST only be done by keys of purpose 1, or the identity itself.
* If it's the identity itself, the approval process will determine its approval.
*/
function removeKey(bytes32 _key, uint256 _purpose) external returns (bool success);
/**
* @dev Passes an execution instruction to an ERC734 identity.
* How the execution is handled is up to the identity implementation:
* An execution COULD be requested and require `approve` to be called with one or more keys of purpose 1 or 2 to
* approve this execution.
* Execute COULD be used as the only accessor for `addKey` and `removeKey`.
*
* Triggers Event: ExecutionRequested
* Triggers on direct execution Event: Executed
*/
function execute(address _to, uint256 _value, bytes calldata _data) external payable returns (uint256 executionId);
/**
* @dev Returns the full key data, if present in the identity.
*/
function getKey(bytes32 _key) external view returns (uint256[] memory purposes, uint256 keyType, bytes32 key);
/**
* @dev Returns the list of purposes associated with a key.
*/
function getKeyPurposes(bytes32 _key) external view returns(uint256[] memory _purposes);
/**
* @dev Returns an array of public key bytes32 held by this identity.
*/
function getKeysByPurpose(uint256 _purpose) external view returns (bytes32[] memory keys);
/**
* @dev Returns TRUE if a key is present and has the given purpose. If the key is not present it returns FALSE.
*/
function keyHasPurpose(bytes32 _key, uint256 _purpose) external view returns (bool exists);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
/**
* @dev interface of the ERC735 (Claim Holder) standard as defined in the EIP.
*/
interface IERC735 {
/**
* @dev Emitted when a claim was added.
*
* Specification: MUST be triggered when a claim was successfully added.
*/
event ClaimAdded(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Emitted when a claim was removed.
*
* Specification: MUST be triggered when removeClaim was successfully called.
*/
event ClaimRemoved(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Emitted when a claim was changed.
*
* Specification: MUST be triggered when addClaim was successfully called on an existing claimId.
*/
event ClaimChanged(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Add or update a claim.
*
* Triggers Event: `ClaimAdded`, `ClaimChanged`
*
* Specification: Add or update a claim from an issuer.
*
* _signature is a signed message of the following structure:
* `keccak256(abi.encode(address identityHolder_address, uint256 topic, bytes data))`.
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address + uint256 topic))`.
*/
function addClaim(
uint256 _topic,
uint256 _scheme,
address issuer,
bytes calldata _signature,
bytes calldata _data,
string calldata _uri)
external returns (bytes32 claimRequestId);
/**
* @dev Removes a claim.
*
* Triggers Event: `ClaimRemoved`
*
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address, uint256 topic))`.
*/
function removeClaim(bytes32 _claimId) external returns (bool success);
/**
* @dev Get a claim by its ID.
*
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address, uint256 topic))`.
*/
function getClaim(bytes32 _claimId)
external view returns(
uint256 topic,
uint256 scheme,
address issuer,
bytes memory signature,
bytes memory data,
string memory uri);
/**
* @dev Returns an array of claim IDs by topic.
*/
function getClaimIdsByTopic(uint256 _topic) external view returns(bytes32[] memory claimIds);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../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.
*
* By default, the owner account will be the one that deploys the contract. 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 {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @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) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @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;
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
/**
* @title Roles
* @dev Library for managing addresses assigned to a Role.
*/
library Roles {
struct Role {
mapping(address => bool) bearer;
}
/**
* @dev Give an account access to this role.
*/
function add(Role storage role, address account) internal {
require(!has(role, account), "Roles: account already has role");
role.bearer[account] = true;
}
/**
* @dev Remove an account's access to this role.
*/
function remove(Role storage role, address account) internal {
require(has(role, account), "Roles: account does not have role");
role.bearer[account] = false;
}
/**
* @dev Check if an account has this role.
* @return bool
*/
function has(Role storage role, address account) internal view returns (bool) {
require(account != address(0), "Roles: account is the zero address");
return role.bearer[account];
}
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol";
interface ITrustedIssuersRegistry {
/**
* this event is emitted when a trusted issuer is added in the registry.
* the event is emitted by the addTrustedIssuer function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
* `claimTopics` is the set of claims that the trusted issuer is allowed to emit
*/
event TrustedIssuerAdded(IClaimIssuer indexed trustedIssuer, uint256[] claimTopics);
/**
* this event is emitted when a trusted issuer is removed from the registry.
* the event is emitted by the removeTrustedIssuer function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
*/
event TrustedIssuerRemoved(IClaimIssuer indexed trustedIssuer);
/**
* this event is emitted when the set of claim topics is changed for a given trusted issuer.
* the event is emitted by the updateIssuerClaimTopics function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
* `claimTopics` is the set of claims that the trusted issuer is allowed to emit
*/
event ClaimTopicsUpdated(IClaimIssuer indexed trustedIssuer, uint256[] claimTopics);
/**
* @dev registers a ClaimIssuer contract as trusted claim issuer.
* Requires that a ClaimIssuer contract doesn't already exist
* Requires that the claimTopics set is not empty
* Requires that there is no more than 15 claimTopics
* Requires that there is no more than 50 Trusted issuers
* @param _trustedIssuer The ClaimIssuer contract address of the trusted claim issuer.
* @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `TrustedIssuerAdded` event
*/
function addTrustedIssuer(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external;
/**
* @dev Removes the ClaimIssuer contract of a trusted claim issuer.
* Requires that the claim issuer contract to be registered first
* @param _trustedIssuer the claim issuer to remove.
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `TrustedIssuerRemoved` event
*/
function removeTrustedIssuer(IClaimIssuer _trustedIssuer) external;
/**
* @dev Updates the set of claim topics that a trusted issuer is allowed to emit.
* Requires that this ClaimIssuer contract already exists in the registry
* Requires that the provided claimTopics set is not empty
* Requires that there is no more than 15 claimTopics
* @param _trustedIssuer the claim issuer to update.
* @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `ClaimTopicsUpdated` event
*/
function updateIssuerClaimTopics(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external;
/**
* @dev Function for getting all the trusted claim issuers stored.
* @return array of all claim issuers registered.
*/
function getTrustedIssuers() external view returns (IClaimIssuer[] memory);
/**
* @dev Function for getting all the trusted issuer allowed for a given claim topic.
* @param claimTopic the claim topic to get the trusted issuers for.
* @return array of all claim issuer addresses that are allowed for the given claim topic.
*/
function getTrustedIssuersForClaimTopic(uint256 claimTopic) external view returns (IClaimIssuer[] memory);
/**
* @dev Checks if the ClaimIssuer contract is trusted
* @param _issuer the address of the ClaimIssuer contract
* @return true if the issuer is trusted, false otherwise.
*/
function isTrustedIssuer(address _issuer) external view returns (bool);
/**
* @dev Function for getting all the claim topic of trusted claim issuer
* Requires the provided ClaimIssuer contract to be registered in the trusted issuers registry.
* @param _trustedIssuer the trusted issuer concerned.
* @return The set of claim topics that the trusted issuer is allowed to emit
*/
function getTrustedIssuerClaimTopics(IClaimIssuer _trustedIssuer) external view returns (uint256[] memory);
/**
* @dev Function for checking if the trusted claim issuer is allowed
* to emit a certain claim topic
* @param _issuer the address of the trusted issuer's ClaimIssuer contract
* @param _claimTopic the Claim Topic that has to be checked to know if the `issuer` is allowed to emit it
* @return true if the issuer is trusted for this claim topic.
*/
function hasClaimTopic(address _issuer, uint256 _claimTopic) external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
interface IClaimTopicsRegistry {
/**
* this event is emitted when a claim topic has been added to the ClaimTopicsRegistry
* the event is emitted by the 'addClaimTopic' function
* `claimTopic` is the required claim added to the Claim Topics Registry
*/
event ClaimTopicAdded(uint256 indexed claimTopic);
/**
* this event is emitted when a claim topic has been removed from the ClaimTopicsRegistry
* the event is emitted by the 'removeClaimTopic' function
* `claimTopic` is the required claim removed from the Claim Topics Registry
*/
event ClaimTopicRemoved(uint256 indexed claimTopic);
/**
* @dev Add a trusted claim topic (For example: KYC=1, AML=2).
* Only owner can call.
* emits `ClaimTopicAdded` event
* cannot add more than 15 topics for 1 token as adding more could create gas issues
* @param _claimTopic The claim topic index
*/
function addClaimTopic(uint256 _claimTopic) external;
/**
* @dev Remove a trusted claim topic (For example: KYC=1, AML=2).
* Only owner can call.
* emits `ClaimTopicRemoved` event
* @param _claimTopic The claim topic index
*/
function removeClaimTopic(uint256 _claimTopic) external;
/**
* @dev Get the trusted claim topics for the security token
* @return Array of trusted claim topics
*/
function getClaimTopics() external view returns (uint256[] memory);
}// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@onchain-id/solidity/contracts/interface/IIdentity.sol";
interface IIdentityRegistryStorage {
/// events
/**
* this event is emitted when an Identity is registered into the storage contract.
* the event is emitted by the 'registerIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityStored(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity is removed from the storage contract.
* the event is emitted by the 'deleteIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityUnstored(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity has been updated
* the event is emitted by the 'updateIdentity' function
* `oldIdentity` is the old Identity contract's address to update
* `newIdentity` is the new Identity contract's
*/
event IdentityModified(IIdentity indexed oldIdentity, IIdentity indexed newIdentity);
/**
* this event is emitted when an Identity's country has been updated
* the event is emitted by the 'updateCountry' function
* `investorAddress` is the address on which the country has been updated
* `country` is the numeric code (ISO 3166-1) of the new country
*/
event CountryModified(address indexed investorAddress, uint16 indexed country);
/**
* this event is emitted when an Identity Registry is bound to the storage contract
* the event is emitted by the 'addIdentityRegistry' function
* `identityRegistry` is the address of the identity registry added
*/
event IdentityRegistryBound(address indexed identityRegistry);
/**
* this event is emitted when an Identity Registry is unbound from the storage contract
* the event is emitted by the 'removeIdentityRegistry' function
* `identityRegistry` is the address of the identity registry removed
*/
event IdentityRegistryUnbound(address indexed identityRegistry);
/// functions
/**
* @dev adds an identity contract corresponding to a user address in the storage.
* Requires that the user doesn't have an identity contract already registered.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's identity contract
* @param _country The country of the investor
* emits `IdentityStored` event
*/
function addIdentityToStorage(
address _userAddress,
IIdentity _identity,
uint16 _country
) external;
/**
* @dev Removes an user from the storage.
* Requires that the user have an identity contract already deployed that will be deleted.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user to be removed
* emits `IdentityUnstored` event
*/
function removeIdentityFromStorage(address _userAddress) external;
/**
* @dev Updates the country corresponding to a user address.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _country The new country of the user
* emits `CountryModified` event
*/
function modifyStoredInvestorCountry(address _userAddress, uint16 _country) external;
/**
* @dev Updates an identity contract corresponding to a user address.
* Requires that the user address should be the owner of the identity contract.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's new identity contract
* emits `IdentityModified` event
*/
function modifyStoredIdentity(address _userAddress, IIdentity _identity) external;
/**
* @notice Adds an identity registry as agent of the Identity Registry Storage Contract.
* This function can only be called by the wallet set as owner of the smart contract
* This function adds the identity registry to the list of identityRegistries linked to the storage contract
* cannot bind more than 300 IR to 1 IRS
* @param _identityRegistry The identity registry address to add.
*/
function bindIdentityRegistry(address _identityRegistry) external;
/**
* @notice Removes an identity registry from being agent of the Identity Registry Storage Contract.
* This function can only be called by the wallet set as owner of the smart contract
* This function removes the identity registry from the list of identityRegistries linked to the storage contract
* @param _identityRegistry The identity registry address to remove.
*/
function unbindIdentityRegistry(address _identityRegistry) external;
/**
* @dev Returns the identity registries linked to the storage contract
*/
function linkedIdentityRegistries() external view returns (address[] memory);
/**
* @dev Returns the onchainID of an investor.
* @param _userAddress The wallet of the investor
*/
function storedIdentity(address _userAddress) external view returns (IIdentity);
/**
* @dev Returns the country code of an investor.
* @param _userAddress The wallet of the investor
*/
function storedInvestorCountry(address _userAddress) external view returns (uint16);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import "./IIdentity.sol";
interface IClaimIssuer is IIdentity {
/**
* @dev Emitted when a claim is revoked.
*
* Specification: MUST be triggered when revoking a claim.
*/
event ClaimRevoked(bytes indexed signature);
/**
* @dev Revoke a claim previously issued, the claim is no longer considered as valid after revocation.
* @notice will fetch the claim from the identity contract (unsafe).
* @param _claimId the id of the claim
* @param _identity the address of the identity contract
* @return isRevoked true when the claim is revoked
*/
function revokeClaim(bytes32 _claimId, address _identity) external returns(bool);
/**
* @dev Revoke a claim previously issued, the claim is no longer considered as valid after revocation.
* @param signature the signature of the claim
*/
function revokeClaimBySignature(bytes calldata signature) external;
/**
* @dev Returns revocation status of a claim.
* @param _sig the signature of the claim
* @return isRevoked true if the claim is revoked and false otherwise
*/
function isClaimRevoked(bytes calldata _sig) external view returns (bool);
/**
* @dev Checks if a claim is valid.
* @param _identity the identity contract related to the claim
* @param claimTopic the claim topic of the claim
* @param sig the signature of the claim
* @param data the data field of the claim
* @return claimValid true if the claim is valid, false otherwise
*/
function isClaimValid(
IIdentity _identity,
uint256 claimTopic,
bytes calldata sig,
bytes calldata data)
external view returns (bool);
/**
* @dev returns the address that signed the given data
* @param sig the signature of the data
* @param dataHash the data that was signed
* returns the address that signed dataHash and created the signature sig
*/
function getRecoveredAddress(bytes calldata sig, bytes32 dataHash) external pure returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../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;
}
/**
* @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[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_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 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_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() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @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 {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@solady/=lib/solady/src/",
"@solidity-lib/=lib/solidity-lib/contracts/",
"@forge-std/=lib/forge-std/src/",
"@onchain-id/solidity/=lib/solidity/",
"@ERC-3643/=lib/ERC-3643/contracts/",
"@core/=contracts/core/",
"@modules/=contracts/modules/",
"@rules/=contracts/rules/",
"@interface/=contracts/interface/",
"@abstract/=contracts/abstract/",
"@mock/=tests/mock/",
"@chainlink/=node_modules/@chainlink/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@onchain-id/solidity/=lib/solidity/",
"@core/=contracts/core/",
"@modules/=contracts/modules/",
"@rules/=contracts/rules/",
"@interface/=contracts/interface/",
"@abstract/=contracts/abstract/",
"@mock/=tests/mock/",
"ERC-3643/=lib/ERC-3643/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"solady/=lib/solady/src/",
"solidity-lib/=lib/solidity-lib/contracts/",
"solidity/=lib/solidity/contracts/",
"solmate/=lib/solady/lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType","type":"error"},{"inputs":[],"name":"FrictionlessOnChainAssetTokenUnableToUpdateData","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"_isFrozen","type":"bool"},{"indexed":true,"internalType":"address","name":"_owner","type":"address"}],"name":"AddressFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_agent","type":"address"}],"name":"AgentAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_agent","type":"address"}],"name":"AgentRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_compliance","type":"address"}],"name":"ComplianceAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_identityRegistry","type":"address"}],"name":"IdentityRegistryAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"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":"_userAddress","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_lostWallet","type":"address"},{"indexed":true,"internalType":"address","name":"_newWallet","type":"address"},{"indexed":true,"internalType":"address","name":"_investorOnchainID","type":"address"}],"name":"RecoverySuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokensFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokensUnfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_userAddress","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"_newName","type":"string"},{"indexed":true,"internalType":"string","name":"_newSymbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"_newDecimals","type":"uint8"},{"indexed":false,"internalType":"string","name":"_newVersion","type":"string"},{"indexed":true,"internalType":"address","name":"_newOnchainID","type":"address"}],"name":"UpdatedTokenInformation","type":"event"},{"inputs":[{"internalType":"address","name":"_agent","type":"address"}],"name":"addAgent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_userAddresses","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_fromList","type":"address[]"},{"internalType":"address[]","name":"_toList","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchForcedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_userAddresses","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchFreezePartialTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_toList","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_userAddresses","type":"address[]"},{"internalType":"bool[]","name":"_freeze","type":"bool[]"}],"name":"batchSetAddressFrozen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_toList","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_userAddresses","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchUnfreezePartialTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compliance","outputs":[{"internalType":"contract IModularCompliance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"forcedTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"freezePartialTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrency","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFrictionlessTokenType","outputs":[{"internalType":"enum IBasicFrictionlessToken.FrictionlessTokenTypes","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"getFrozenTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIssuanceData","outputs":[{"components":[{"internalType":"uint256","name":"auctionedOn","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPriceStatus","name":"priceQuoteStatus","type":"uint8"},{"internalType":"string","name":"onChainAssetUUID","type":"string"},{"internalType":"string","name":"issuerUUID","type":"string"},{"internalType":"string","name":"isin","type":"string"},{"internalType":"string","name":"issuanceDocs","type":"string"},{"internalType":"string","name":"assetClass","type":"string"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCAIssuanceData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSpecificationData","outputs":[{"components":[{"internalType":"uint256","name":"issuedOn","type":"uint256"},{"internalType":"uint256","name":"maturityDays","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetSchedule","name":"schedule","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPaymentFrequency","name":"paymentFrequency","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetYieldType","name":"yieldType","type":"uint8"},{"internalType":"string","name":"baseCurrency","type":"string"},{"internalType":"uint256","name":"stripTotal","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCASpecData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUpdateData","outputs":[{"components":[{"internalType":"uint256","name":"maturesOn","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"yield","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetRiskGrade","name":"riskGrade","type":"uint8"},{"internalType":"uint256","name":"pullToParValue","type":"uint256"},{"internalType":"address","name":"custodianAddress","type":"address"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCAUpdateData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"identityRegistry","outputs":[{"internalType":"contract IIdentityRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_identityRegistry","type":"address"},{"internalType":"address","name":"_compliance","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"_onchainID","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_agent","type":"address"}],"name":"isAgent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"isFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"issuanceData","outputs":[{"internalType":"uint256","name":"auctionedOn","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPriceStatus","name":"priceQuoteStatus","type":"uint8"},{"internalType":"string","name":"onChainAssetUUID","type":"string"},{"internalType":"string","name":"issuerUUID","type":"string"},{"internalType":"string","name":"isin","type":"string"},{"internalType":"string","name":"issuanceDocs","type":"string"},{"internalType":"string","name":"assetClass","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"onchainID","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":[{"internalType":"address","name":"_lostWallet","type":"address"},{"internalType":"address","name":"_newWallet","type":"address"},{"internalType":"address","name":"_investorOnchainID","type":"address"}],"name":"recoveryAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_agent","type":"address"}],"name":"removeAgent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"bool","name":"_freeze","type":"bool"}],"name":"setAddressFrozen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_compliance","type":"address"}],"name":"setCompliance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IBasicFrictionlessToken.FrictionlessTokenTypes","name":"newTokenType_","type":"uint8"}],"name":"setFrictionlessTokenType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_identityRegistry","type":"address"}],"name":"setIdentityRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"auctionedOn","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPriceStatus","name":"priceQuoteStatus","type":"uint8"},{"internalType":"string","name":"onChainAssetUUID","type":"string"},{"internalType":"string","name":"issuerUUID","type":"string"},{"internalType":"string","name":"isin","type":"string"},{"internalType":"string","name":"issuanceDocs","type":"string"},{"internalType":"string","name":"assetClass","type":"string"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCAIssuanceData","name":"issuanceData_","type":"tuple"}],"name":"setIssuanceData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_onchainID","type":"address"}],"name":"setOnchainID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"issuedOn","type":"uint256"},{"internalType":"uint256","name":"maturityDays","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetSchedule","name":"schedule","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPaymentFrequency","name":"paymentFrequency","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetYieldType","name":"yieldType","type":"uint8"},{"internalType":"string","name":"baseCurrency","type":"string"},{"internalType":"uint256","name":"stripTotal","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCASpecData","name":"specificationData_","type":"tuple"}],"name":"setSpecificationData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"setSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"maturesOn","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"yield","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetRiskGrade","name":"riskGrade","type":"uint8"},{"internalType":"uint256","name":"pullToParValue","type":"uint256"},{"internalType":"address","name":"custodianAddress","type":"address"}],"internalType":"struct IFrictionlessOnChainAssetToken.FOCAUpdateData","name":"updateData_","type":"tuple"}],"name":"setUpdateData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"specificationData","outputs":[{"internalType":"uint256","name":"issuedOn","type":"uint256"},{"internalType":"uint256","name":"maturityDays","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetSchedule","name":"schedule","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetPaymentFrequency","name":"paymentFrequency","type":"uint8"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetYieldType","name":"yieldType","type":"uint8"},{"internalType":"string","name":"baseCurrency","type":"string"},{"internalType":"uint256","name":"stripTotal","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unfreezePartialTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateData","outputs":[{"internalType":"uint256","name":"maturesOn","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"yield","type":"uint256"},{"internalType":"enum IFrictionlessOnChainAssetToken.FrictionlessOnChainAssetRiskGrade","name":"riskGrade","type":"uint8"},{"internalType":"uint256","name":"pullToParValue","type":"uint256"},{"internalType":"address","name":"custodianAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
6080604052606e805460ff1916905534801561001a57600080fd5b5061542f8061002a6000396000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80637de4fba9116101de578063a9059cbb1161010f578063e5839836116100ad578063f8333bfa1161007c578063f8333bfa14610850578063f898178914610863578063f91b619c14610876578063fc7e5fa81461088957600080fd5b8063e5839836146107df578063e9bb84671461080b578063f14d540614610820578063f2fde38b1461083d57600080fd5b8063c47f0027116100e9578063c47f00271461076d578063c69c09cf14610780578063cbf3f86114610793578063dd62ed3e146107a657600080fd5b8063a9059cbb14610731578063aba6370514610744578063b84c82461461075a57600080fd5b806395d89b411161017c5780639dc29fac116101565780639dc29fac146106e55780639fc1d0e7146106f8578063a1e4b7861461070b578063a457c2d71461071e57600080fd5b806395d89b41146106b557806397a6278e146106bd57806399d09c69146106d057600080fd5b806388d695b2116101b857806388d695b21461063a5780638da5cb5b1461064d5780638e00a2bb1461065e5780639285948a146106a257600080fd5b80637de4fba91461060c5780638456cb591461061f57806384e798421461062757600080fd5b80633d1ddc5b116102c35780634a6cc67711610261578063685731071161023057806368573107146105c05780636945c1fd146105d357806370a08231146105db578063715018a61461060457600080fd5b80634a6cc6771461057057806354fd4d50146105835780635c975abb146105a45780636290865d146105af57600080fd5b806342a47abc1161029d57806342a47abc1461051c57806344ed4f891461052f5780634710362d146105425780634946b76b1461055557600080fd5b80633d1ddc5b146104ee5780633f4ba83a1461050157806340c10f191461050957600080fd5b80631a7af3791161033057806323b872dd1161030a57806323b872dd1461049e5780632d095a58146104b1578063313ce567146104c657806339509351146104db57600080fd5b80631a7af379146104655780631fe56f7d146104785780631ffbb0641461048b57600080fd5b8063125c4a331161036c578063125c4a33146103e9578063134e18f4146103fc578063158b1a571461042657806318160ddd1461045d57600080fd5b806306fdde0314610393578063095ea7b3146103b15780630b9fff74146103d4575b600080fd5b61039b61089c565b6040516103a89190614444565b60405180910390f35b6103c46103bf36600461446c565b61092e565b60405190151581526020016103a8565b6103e76103e2366004614498565b610945565b005b6103e76103f736600461446c565b610a12565b606e5461010090046001600160a01b03165b6040516001600160a01b0390911681526020016103a8565b61044f6104343660046144d4565b6001600160a01b03166000908152606d602052604090205490565b6040519081526020016103a8565b60685461044f565b6103e761047336600461453d565b610b82565b6103e761048636600461446c565b610bf7565b6103c46104993660046144d4565b610d70565b6103c46104ac3660046145a9565b610d7d565b6104b96110db565b6040516103a8919061462d565b606b5460405160ff90911681526020016103a8565b6103c46104e936600461446c565b611367565b6103e76104fc3660046144d4565b61139e565b6103e7611469565b6103e761051736600461446c565b611567565b6103e761052a3660046146e9565b6117e8565b6103e761053d36600461479b565b61187e565b6103e761055036600461453d565b611893565b61055d6118f8565b6040516103a897969594939291906147c7565b6103e761057e36600461453d565b611bcf565b604080518082019091526005815264342e302e3160d81b602082015261039b565b606e5460ff166103c4565b606f546001600160a01b031661040e565b6103e76105ce36600461453d565b611c34565b61039b611c99565b61044f6105e93660046144d4565b6001600160a01b031660009081526066602052604090205490565b6103e7611cab565b6103e761061a366004614858565b611cbf565b6103e7611d3e565b6103e76106353660046144d4565b611e2d565b6103e761064836600461453d565b611ecd565b6033546001600160a01b031661040e565b60b05460b15460b25460b35460b45460b55460b65461068f96959460ff90811694931691906001600160a01b031687565b6040516103a89796959493929190614895565b6103c46106b03660046148e4565b611f33565b61039b61236e565b6103e76106cb3660046144d4565b61237d565b6106d861241d565b6040516103a8919061492f565b6103e76106f336600461446c565b6124cf565b6103c46107063660046145a9565b6126f2565b6103e7610719366004614998565b61298e565b6103c461072c36600461446c565b6129d3565b6103c461073f36600461446c565b612a0a565b606b5461010090046001600160a01b031661040e565b6103e76107683660046149d5565b612cc8565b6103e761077b3660046149d5565b612e24565b6103e761078e366004614a55565b612ee0565b6103e76107a13660046144d4565b612fa1565b61044f6107b4366004614a8e565b6001600160a01b03918216600090815260676020908152604080832093909416825291909152205490565b6103c46107ed3660046144d4565b6001600160a01b03166000908152606c602052604090205460ff1690565b610813613008565b6040516103a89190614abc565b610828613251565b6040516103a899989796959493929190614b77565b6103e761084b3660046144d4565b61342b565b60a15460ff166040516103a89190614c01565b6103e76108713660046144d4565b6134bb565b6103e7610884366004614cb7565b613614565b6103e761089736600461453d565b613a7d565b6060606980546108ab90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546108d790614d6c565b80156109245780601f106108f957610100808354040283529160200191610924565b820191906000526020600020905b81548152906001019060200180831161090757829003601f168201915b5050505050905090565b600061093b338484613ae2565b5060015b92915050565b61094d613c20565b6109e360a2600301805461096090614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461098c90614d6c565b80156109d95780601f106109ae576101008083540402835291602001916109d9565b820191906000526020600020905b8154815290600101906020018083116109bc57829003601f168201915b5050505050613c7a565b610a00576040516345f9481360e01b815260040160405180910390fd5b8060a2610a0d8282614f76565b505050565b610a1b33610d70565b610a835760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260666020908152604080832054606d90925290912054610ab3908390615044565b811015610b025760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206578636565647320617661696c61626c652062616c616e63656044820152606401610a7a565b6001600160a01b0383166000908152606d6020526040902054610b26908390615044565b6001600160a01b0384166000818152606d6020526040908190209290925590517fa065e63c631c86f1b9f66a4a2f63f2093bf1c2168d23290259dbd969e0222a4590610b759085815260200190565b60405180910390a2505050565b60005b83811015610bf057610bde858583818110610ba257610ba2615057565b9050602002016020810190610bb791906144d4565b848484818110610bc957610bc9615057565b905060200201602081019061078e919061506d565b80610be88161508a565b915050610b85565b5050505050565b610c0033610d70565b610c635760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0382166000908152606d6020526040902054811115610cf15760405162461bcd60e51b815260206004820152603460248201527f416d6f756e742073686f756c64206265206c657373207468616e206f7220657160448201527f75616c20746f2066726f7a656e20746f6b656e730000000000000000000000006064820152608401610a7a565b6001600160a01b0382166000908152606d6020526040902054610d159082906150a3565b6001600160a01b0383166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d690610d649084815260200190565b60405180910390a25050565b600061093f606583613cd4565b606e5460009060ff1615610dc65760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b6001600160a01b0383166000908152606c602052604090205460ff16158015610e0857506001600160a01b0384166000908152606c602052604090205460ff16155b610e545760405162461bcd60e51b815260206004820152601060248201527f77616c6c65742069732066726f7a656e000000000000000000000000000000006044820152606401610a7a565b6001600160a01b0384166000908152606d6020908152604080832054606690925290912054610e8391906150a3565b821115610ed25760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742042616c616e63650000000000000000000000006044820152606401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0385811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015610f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906150b6565b8015610fca5750606f546040516372331c7360e11b81526001600160a01b0386811660048301528581166024830152604482018590529091169063e46638e690606401602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca91906150b6565b1561108c576001600160a01b03841660009081526067602090815260408083203380855292529091205461100a9186916110059086906150a3565b613ae2565b611015848484613d57565b606f546040516322ebca6d60e21b81526001600160a01b03868116600483015285811660248301526044820185905290911690638baf29b490606401600060405180830381600087803b15801561106b57600080fd5b505af115801561107f573d6000803e3d6000fd5b50505050600190506110d4565b60405162461bcd60e51b815260206004820152601560248201527f5472616e73666572206e6f7420706f737369626c6500000000000000000000006044820152606401610a7a565b9392505050565b6110e3614342565b604080516101208101825260a28054825260a354602083015260a454919290919083019060ff16600181111561111b5761111b6145ea565b600181111561112c5761112c6145ea565b81526020016002820160019054906101000a900460ff166006811115611154576111546145ea565b6006811115611165576111656145ea565b81526020016002820160029054906101000a900460ff16600181111561118d5761118d6145ea565b600181111561119e5761119e6145ea565b81526020016003820180546111b290614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546111de90614d6c565b801561122b5780601f106112005761010080835404028352916020019161122b565b820191906000526020600020905b81548152906001019060200180831161120e57829003601f168201915b505050505081526020016004820154815260200160058201805461124e90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461127a90614d6c565b80156112c75780601f1061129c576101008083540402835291602001916112c7565b820191906000526020600020905b8154815290600101906020018083116112aa57829003601f168201915b505050505081526020016006820180546112e090614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461130c90614d6c565b80156113595780601f1061132e57610100808354040283529160200191611359565b820191906000526020600020905b81548152906001019060200180831161133c57829003601f168201915b505050505081525050905090565b3360008181526067602090815260408083206001600160a01b0387168452909152812054909161093b918590611005908690615044565b6113a6613c20565b606b805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b0384811682029290921792839055604051920416906113ed90606a906150d3565b6040518091039020606960405161140491906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d19261145e9260ff9091169190615149565b60405180910390a450565b61147233610d70565b6114d55760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460ff166115275760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a7a565b606e805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b61157033610d70565b6115d35760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0384811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015611623573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164791906150b6565b6116935760405162461bcd60e51b815260206004820152601960248201527f4964656e74697479206973206e6f742076657269666965642e000000000000006044820152606401610a7a565b606f546040516372331c7360e11b8152600060048201526001600160a01b038481166024830152604482018490529091169063e46638e690606401602060405180830381865afa1580156116eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170f91906150b6565b61175b5760405162461bcd60e51b815260206004820152601760248201527f436f6d706c69616e6365206e6f7420666f6c6c6f7765640000000000000000006044820152606401610a7a565b6117658282613ef7565b606f546040517f5f8dead30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905290911690635f8dead390604401600060405180830381600087803b1580156117cc57600080fd5b505af11580156117e0573d6000803e3d6000fd5b505050505050565b60005b858110156118755761186287878381811061180857611808615057565b905060200201602081019061181d91906144d4565b86868481811061182f5761182f615057565b905060200201602081019061184491906144d4565b85858581811061185657611856615057565b905060200201356126f2565b508061186d8161508a565b9150506117eb565b50505050505050565b611886613c20565b8060b0610a0d8282615193565b60005b83811015610bf0576118e68585838181106118b3576118b3615057565b90506020020160208101906118c891906144d4565b8484848181106118da576118da615057565b90506020020135610bf7565b806118f08161508a565b915050611896565b60a9805460aa5460ab8054929360ff9092169261191490614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461194090614d6c565b801561198d5780601f106119625761010080835404028352916020019161198d565b820191906000526020600020905b81548152906001019060200180831161197057829003601f168201915b5050505050908060030180546119a290614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546119ce90614d6c565b8015611a1b5780601f106119f057610100808354040283529160200191611a1b565b820191906000526020600020905b8154815290600101906020018083116119fe57829003601f168201915b505050505090806004018054611a3090614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611a5c90614d6c565b8015611aa95780601f10611a7e57610100808354040283529160200191611aa9565b820191906000526020600020905b815481529060010190602001808311611a8c57829003601f168201915b505050505090806005018054611abe90614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611aea90614d6c565b8015611b375780601f10611b0c57610100808354040283529160200191611b37565b820191906000526020600020905b815481529060010190602001808311611b1a57829003601f168201915b505050505090806006018054611b4c90614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611b7890614d6c565b8015611bc55780601f10611b9a57610100808354040283529160200191611bc5565b820191906000526020600020905b815481529060010190602001808311611ba857829003601f168201915b5050505050905087565b60005b83811015610bf057611c22858583818110611bef57611bef615057565b9050602002016020810190611c0491906144d4565b848484818110611c1657611c16615057565b905060200201356124cf565b80611c2c8161508a565b915050611bd2565b60005b83811015610bf057611c87858583818110611c5457611c54615057565b9050602002016020810190611c6991906144d4565b848484818110611c7b57611c7b615057565b90506020020135611567565b80611c918161508a565b915050611c37565b606060a260030180546108ab90614d6c565b611cb3613c20565b611cbd6000613fdf565b565b611cc7613c20565b600060a15460ff166003811115611ce057611ce06145ea565b14611d17576040517f4b2a71e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a1805482919060ff19166001836003811115611d3657611d366145ea565b021790555050565b611d4733610d70565b611daa5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460ff1615611df05760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b606e805460ff191660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161155d565b611e35613c20565b6001600160a01b038116611e8b5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b611e9660658261403e565b6040516001600160a01b038216907ff68e73cec97f2d70aa641fb26e87a4383686e2efacb648f2165aeb02ac562ec590600090a250565b60005b83811015610bf057611f20858583818110611eed57611eed615057565b9050602002016020810190611f0291906144d4565b848484818110611f1457611f14615057565b90506020020135612a0a565b5080611f2b8161508a565b915050611ed0565b6000611f3e33610d70565b611fa15760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0384166000908152606660205260409020546000036120095760405162461bcd60e51b815260206004820152601460248201527f6e6f20746f6b656e7320746f207265636f7665720000000000000000000000006044820152606401610a7a565b604080516001600160a01b038516602082015283916000910160408051808303601f190181529082905280516020909101207fd202158d000000000000000000000000000000000000000000000000000000008252600482018190526001602483015291506001600160a01b0383169063d202158d90604401602060405180830381865afa15801561209f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c391906150b6565b15612326576001600160a01b03868116600081815260666020908152604080832054606d83529281902054606e5482517f7e42683b0000000000000000000000000000000000000000000000000000000081526004810196909652915193959094610100909204169263454a03e0928b9289928692637e42683b92602480820193918290030181865afa15801561215e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121829190615235565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015261ffff166044820152606401600060405180830381600087803b1580156121ed57600080fd5b505af1158015612201573d6000803e3d6000fd5b505050506122108888846126f2565b508015612221576122218782610a12565b6001600160a01b0388166000908152606c602052604090205460ff16151560010361225157612251876001612ee0565b606e546040517fa8d29d1d0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301526101009092049091169063a8d29d1d90602401600060405180830381600087803b1580156122b757600080fd5b505af11580156122cb573d6000803e3d6000fd5b50505050856001600160a01b0316876001600160a01b0316896001600160a01b03167ff0c9129a94f30f1caaceb63e44b9811d0a3edf1d6c23757f346093af5553fed060405160405180910390a460019450505050506110d4565b60405162461bcd60e51b815260206004820152601560248201527f5265636f76657279206e6f7420706f737369626c6500000000000000000000006044820152606401610a7a565b6060606a80546108ab90614d6c565b612385613c20565b6001600160a01b0381166123db5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b6123e66065826140ba565b6040516001600160a01b038216907fed9c8ad8d5a0a66898ea49d2956929c93ae2e8bd50281b2ed897c5d1a6737e0b90600090a250565b61242561439f565b6040805160e08101825260b08054825260b154602083015260b254919290919083019060ff16600481111561245c5761245c6145ea565b600481111561246d5761246d6145ea565b815260038201546020820152600482015460409091019060ff16600a811115612498576124986145ea565b600a8111156124a9576124a96145ea565b8152600582015460208201526006909101546001600160a01b0316604090910152919050565b6124d833610d70565b61253b5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b8061255b836001600160a01b031660009081526066602052604090205490565b10156125a95760405162461bcd60e51b815260206004820152601d60248201527f63616e6e6f74206275726e206d6f7265207468616e2062616c616e63650000006044820152606401610a7a565b6001600160a01b0382166000908152606d602090815260408083205460669092528220546125d791906150a3565b90508082111561266d5760006125ed82846150a3565b6001600160a01b0385166000908152606d60205260409020549091506126149082906150a3565b6001600160a01b0385166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d6906126639084815260200190565b60405180910390a2505b6126778383614158565b606f546040517f8d2ea7720000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526024820185905290911690638d2ea77290604401600060405180830381600087803b1580156126de57600080fd5b505af1158015611875573d6000803e3d6000fd5b60006126fd33610d70565b6127605760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b81612780856001600160a01b031660009081526066602052604090205490565b10156127ce5760405162461bcd60e51b815260206004820152601660248201527f73656e6465722062616c616e636520746f6f206c6f77000000000000000000006044820152606401610a7a565b6001600160a01b0384166000908152606d602090815260408083205460669092528220546127fc91906150a3565b90508083111561289257600061281282856150a3565b6001600160a01b0387166000908152606d60205260409020549091506128399082906150a3565b6001600160a01b0387166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d6906128889084815260200190565b60405180910390a2505b606e5460405163b9209e3360e01b81526001600160a01b0386811660048301526101009092049091169063b9209e3390602401602060405180830381865afa1580156128e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290691906150b6565b1561108c57612916858585613d57565b606f546040516322ebca6d60e21b81526001600160a01b03878116600483015286811660248301526044820186905290911690638baf29b490606401600060405180830381600087803b15801561296c57600080fd5b505af1158015612980573d6000803e3d6000fd5b5050505060019150506110d4565b612996613c20565b6129a960a9600201805461096090614d6c565b6129c6576040516345f9481360e01b815260040160405180910390fd5b8060a9610a0d8282615259565b3360008181526067602090815260408083206001600160a01b0387168452909152812054909161093b9185906110059086906150a3565b606e5460009060ff1615612a535760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b6001600160a01b0383166000908152606c602052604090205460ff16158015612a8c5750336000908152606c602052604090205460ff16155b612ad85760405162461bcd60e51b815260206004820152601060248201527f77616c6c65742069732066726f7a656e000000000000000000000000000000006044820152606401610a7a565b336000908152606d6020908152604080832054606690925290912054612afe91906150a3565b821115612b4d5760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742042616c616e63650000000000000000000000006044820152606401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0385811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015612b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc191906150b6565b8015612c435750606f546040516372331c7360e11b81523360048201526001600160a01b038581166024830152604482018590529091169063e46638e690606401602060405180830381865afa158015612c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4391906150b6565b1561108c57612c53338484613d57565b606f546040516322ebca6d60e21b81523360048201526001600160a01b0385811660248301526044820185905290911690638baf29b490606401600060405180830381600087803b158015612ca757600080fd5b505af1158015612cbb573d6000803e3d6000fd5b505050506001905061093f565b612cd0613c20565b604051602001612ceb90602080825260009082015260400190565b604051602081830303815290604052805190602001208282604051602001612d1492919061530a565b6040516020818303038152906040528051906020012003612d775760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b606a612d84828483614eb6565b50606b546040516101009091046001600160a01b031690612da790606a906150d3565b60405180910390206069604051612dbe91906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d192612e189260ff9091169190615149565b60405180910390a45050565b612e2c613c20565b604051602001612e4790602080825260009082015260400190565b604051602081830303815290604052805190602001208282604051602001612e7092919061530a565b6040516020818303038152906040528051906020012003612ed35760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b6069612d84828483614eb6565b612ee933610d70565b612f4c5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0382166000818152606c6020526040808220805460ff19168515159081179091559051339391927f7fa523c84ab8d7fc5b72f08b9e46dbbf10c39e119a075b3e317002d14bc9f43691a45050565b612fa9613c20565b606e805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b038416908102919091179091556040517fd2be862d755bca7e0d39772b2cab3a5578da9c285f69199f4c063c2294a7f36c90600090a250565b6130496040805160e0810190915260008082526020820190815260200160608152602001606081526020016060815260200160608152602001606081525090565b6040805160e0810190915260a98054825260aa54602083019060ff166003811115613076576130766145ea565b6003811115613087576130876145ea565b815260200160028201805461309b90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546130c790614d6c565b80156131145780601f106130e957610100808354040283529160200191613114565b820191906000526020600020905b8154815290600101906020018083116130f757829003601f168201915b5050505050815260200160038201805461312d90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461315990614d6c565b80156131a65780601f1061317b576101008083540402835291602001916131a6565b820191906000526020600020905b81548152906001019060200180831161318957829003601f168201915b505050505081526020016004820180546131bf90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546131eb90614d6c565b80156132385780601f1061320d57610100808354040283529160200191613238565b820191906000526020600020905b81548152906001019060200180831161321b57829003601f168201915b5050505050815260200160058201805461124e90614d6c565b60a2805460a35460a45460a580549394929360ff80841694610100850482169462010000900490911692909161328690614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546132b290614d6c565b80156132ff5780601f106132d4576101008083540402835291602001916132ff565b820191906000526020600020905b8154815290600101906020018083116132e257829003601f168201915b50505050509080600401549080600501805461331a90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461334690614d6c565b80156133935780601f1061336857610100808354040283529160200191613393565b820191906000526020600020905b81548152906001019060200180831161337657829003601f168201915b5050505050908060060180546133a890614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546133d490614d6c565b80156134215780601f106133f657610100808354040283529160200191613421565b820191906000526020600020905b81548152906001019060200180831161340457829003601f168201915b5050505050905089565b613433613c20565b6001600160a01b0381166134af5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a7a565b6134b881613fdf565b50565b6134c3613c20565b606f546001600160a01b03161561354b57606f546040517f40db3b500000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906340db3b5090602401600060405180830381600087803b15801561353257600080fd5b505af1158015613546573d6000803e3d6000fd5b505050505b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f3ff5aa02000000000000000000000000000000000000000000000000000000008152306004820152633ff5aa0290602401600060405180830381600087803b1580156135c557600080fd5b505af11580156135d9573d6000803e3d6000fd5b50506040516001600160a01b03841692507f7f3a888862559648ec01d97deb7b5012bff86dc91e654a1de397170db40e35b69150600090a250565b600054610100900460ff16158080156136345750600054600160ff909116105b8061364e5750303b15801561364e575060005460ff166001145b6136c05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a7a565b6000805460ff1916600117905580156136e3576000805461ff0019166101001790555b60006136f76033546001600160a01b031690565b6001600160a01b03161461374d5760405162461bcd60e51b815260206004820152601360248201527f616c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610a7a565b6001600160a01b0387161580159061376d57506001600160a01b03861615155b6137b95760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b6040516020016137d490602080825260009082015260400190565b60405160208183030381529060405280519060200120856040516020016137fb9190614444565b6040516020818303038152906040528051906020012014158015613875575060405160200161383590602080825260009082015260400190565b604051602081830303815290604052805190602001208460405160200161385c9190614444565b6040516020818303038152906040528051906020012014155b6138c15760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b60128360ff1611156139155760405162461bcd60e51b815260206004820152601960248201527f646563696d616c73206265747765656e203020616e64203138000000000000006044820152606401610a7a565b61391d614260565b60696139298682615339565b50606a6139368582615339565b50606b80546001600160a01b038416610100027fffffffffffffffffffffff00000000000000000000000000000000000000000090911660ff861617179055606e805460ff1916600117905561398b87612fa1565b613994866134bb565b606b546040516101009091046001600160a01b0316906139b690606a906150d3565b604051809103902060696040516139cd91906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d192613a279260ff9091169190615149565b60405180910390a48015611875576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b60005b83811015610bf057613ad0858583818110613a9d57613a9d615057565b9050602002016020810190613ab291906144d4565b848484818110613ac457613ac4615057565b90506020020135610a12565b80613ada8161508a565b915050613a80565b6001600160a01b038316613b5d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038216613bbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a7a565b6001600160a01b0383811660008181526067602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6033546001600160a01b03163314611cbd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7a565b6040805160208082015260009181018290526060016040516020818303038152906040528051906020012082604051602001613cb69190614444565b60405160208183030381529060405280519060200120149050919050565b60006001600160a01b038216613d375760405162461bcd60e51b815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f206164647265604482015261737360f01b6064820152608401610a7a565b506001600160a01b03166000908152602091909152604090205460ff1690565b6001600160a01b038316613dd35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038216613e4f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038316600090815260666020526040902054613e739082906150a3565b6001600160a01b038085166000908152606660205260408082209390935590841681522054613ea3908290615044565b6001600160a01b0380841660008181526066602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613c139085815260200190565b6001600160a01b038216613f4d5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a7a565b80606854613f5b9190615044565b6068556001600160a01b038216600090815260666020526040902054613f82908290615044565b6001600160a01b0383166000818152606660205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613fd39085815260200190565b60405180910390a35050565b603380546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6140488282613cd4565b156140955760405162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c65006044820152606401610a7a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6140c48282613cd4565b6141365760405162461bcd60e51b815260206004820152602160248201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c60448201527f65000000000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6001600160a01b0382166141d45760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b0382166000908152606660205260409020546141f89082906150a3565b6001600160a01b03831660009081526066602052604090205560685461421f9082906150a3565b6068556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001613fd3565b600054610100900460ff166142cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610a7a565b611cbd600054610100900460ff166143395760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610a7a565b611cbd33613fdf565b60405180610120016040528060008152602001600081526020016000600181111561436f5761436f6145ea565b81526020016000815260200160008152602001606081526020016000815260200160608152602001606081525090565b6040518060e001604052806000815260200160008152602001600060048111156143cb576143cb6145ea565b8152602001600081526020016000600a8111156143ea576143ea6145ea565b815260006020820181905260409091015290565b6000815180845260005b8181101561442457602081850181015186830182015201614408565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110d460208301846143fe565b6001600160a01b03811681146134b857600080fd5b6000806040838503121561447f57600080fd5b823561448a81614457565b946020939093013593505050565b6000602082840312156144aa57600080fd5b813567ffffffffffffffff8111156144c157600080fd5b820161012081850312156110d457600080fd5b6000602082840312156144e657600080fd5b81356110d481614457565b60008083601f84011261450357600080fd5b50813567ffffffffffffffff81111561451b57600080fd5b6020830191508360208260051b850101111561453657600080fd5b9250929050565b6000806000806040858703121561455357600080fd5b843567ffffffffffffffff8082111561456b57600080fd5b614577888389016144f1565b9096509450602087013591508082111561459057600080fd5b5061459d878288016144f1565b95989497509550505050565b6000806000606084860312156145be57600080fd5b83356145c981614457565b925060208401356145d981614457565b929592945050506040919091013590565b634e487b7160e01b600052602160045260246000fd5b600281106134b8576134b86145ea565b61461981614600565b9052565b60078110614619576146196145ea565b602081528151602082015260208201516040820152600060408301516146566060840182614610565b506060830151614669608084018261461d565b50608083015161467c60a0840182614610565b5060a08301516101208060c08501526146996101408501836143fe565b915060c085015160e085015260e0850151601f196101008187860301818801526146c385846143fe565b9088015187820390920184880152935090506146df83826143fe565b9695505050505050565b6000806000806000806060878903121561470257600080fd5b863567ffffffffffffffff8082111561471a57600080fd5b6147268a838b016144f1565b9098509650602089013591508082111561473f57600080fd5b61474b8a838b016144f1565b9096509450604089013591508082111561476457600080fd5b5061477189828a016144f1565b979a9699509497509295939492505050565b600060e0828403121561479557600080fd5b50919050565b600060e082840312156147ad57600080fd5b6110d48383614783565b600481106134b8576134b86145ea565b8781526147d3876147b7565b86602082015260e0604082015260006147ef60e08301886143fe565b828103606084015261480181886143fe565b9050828103608084015261481581876143fe565b905082810360a084015261482981866143fe565b905082810360c084015261483d81856143fe565b9a9950505050505050505050565b600481106134b857600080fd5b60006020828403121561486a57600080fd5b81356110d48161484b565b60058110614619576146196145ea565b600b8110614619576146196145ea565b8781526020810187905260e081016148b06040830188614875565b8560608301526148c36080830186614885565b8360a08301526001600160a01b03831660c083015298975050505050505050565b6000806000606084860312156148f957600080fd5b833561490481614457565b9250602084013561491481614457565b9150604084013561492481614457565b809150509250925092565b600060e082019050825182526020830151602083015260408301516149576040840182614875565b506060830151606083015260808301516149746080840182614885565b5060a083015160a08301526001600160a01b0360c08401511660c083015292915050565b6000602082840312156149aa57600080fd5b813567ffffffffffffffff8111156149c157600080fd5b6149cd84828501614783565b949350505050565b600080602083850312156149e857600080fd5b823567ffffffffffffffff80821115614a0057600080fd5b818501915085601f830112614a1457600080fd5b813581811115614a2357600080fd5b866020828501011115614a3557600080fd5b60209290920196919550909350505050565b80151581146134b857600080fd5b60008060408385031215614a6857600080fd5b8235614a7381614457565b91506020830135614a8381614a47565b809150509250929050565b60008060408385031215614aa157600080fd5b8235614aac81614457565b91506020830135614a8381614457565b602081528151602082015260006020830151614ad7816147b7565b80604084015250604083015160e06060840152614af86101008401826143fe565b90506060840151601f1980858403016080860152614b1683836143fe565b925060808601519150808584030160a0860152614b3383836143fe565b925060a08601519150808584030160c0860152614b5083836143fe565b925060c08601519150808584030160e086015250614b6e82826143fe565b95945050505050565b60006101208b83528a6020840152614b8e8a614600565b896040840152614ba1606084018a61461d565b614baa88614600565b8760808401528060a0840152614bc2818401886143fe565b90508560c084015282810360e0840152614bdc81866143fe565b9050828103610100840152614bf181856143fe565b9c9b505050505050505050505050565b60208101614c0e836147b7565b91905290565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614c3b57600080fd5b813567ffffffffffffffff80821115614c5657614c56614c14565b604051601f8301601f19908116603f01168101908282118183101715614c7e57614c7e614c14565b81604052838152866020858801011115614c9757600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c08789031215614cd057600080fd5b8635614cdb81614457565b95506020870135614ceb81614457565b9450604087013567ffffffffffffffff80821115614d0857600080fd5b614d148a838b01614c2a565b95506060890135915080821115614d2a57600080fd5b50614d3789828a01614c2a565b935050608087013560ff81168114614d4e57600080fd5b915060a0870135614d5e81614457565b809150509295509295509295565b600181811c90821680614d8057607f821691505b60208210810361479557634e487b7160e01b600052602260045260246000fd5b600081356002811061093f57600080fd5b614dba82614600565b60ff1981541660ff831681178255505050565b600081356007811061093f57600080fd5b60078210614dee57614dee6145ea565b805461ff008360081b1661ff00198216178255505050565b614e0f82614600565b805462ff00008360101b1662ff0000198216178255505050565b6000808335601e19843603018112614e4057600080fd5b83018035915067ffffffffffffffff821115614e5b57600080fd5b60200191503681900382131561453657600080fd5b601f821115610a0d57600081815260208120601f850160051c81016020861015614e975750805b601f850160051c820191505b818110156117e057828155600101614ea3565b67ffffffffffffffff831115614ece57614ece614c14565b614ee283614edc8354614d6c565b83614e70565b6000601f841160018114614f165760008515614efe5750838201355b600019600387901b1c1916600186901b178355610bf0565b600083815260209020601f19861690835b82811015614f475786850135825560209485019460019092019101614f27565b5086821015614f645760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b813581556020820135600182015560028101614f9d614f9760408501614da0565b82614db1565b614fb2614fac60608501614dcd565b82614dde565b614fc7614fc160808501614da0565b82614e06565b50614fd560a0830183614e29565b614fe3818360038601614eb6565b505060c08201356004820155614ffc60e0830183614e29565b61500a818360058601614eb6565b505061501a610100830183614e29565b615028818360068601614eb6565b50505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561093f5761093f61502e565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561507f57600080fd5b81356110d481614a47565b60006001820161509c5761509c61502e565b5060010190565b8181038181111561093f5761093f61502e565b6000602082840312156150c857600080fd5b81516110d481614a47565b60008083546150e181614d6c565b600182811680156150f9576001811461510e5761513d565b60ff198416875282151583028701945061513d565b8760005260208060002060005b858110156151345781548a82015290840190820161511b565b50505082870194505b50929695505050505050565b60ff831681526040602082015260006149cd60408301846143fe565b60008135600b811061093f57600080fd5b600b8210614dba57614dba6145ea565b6000813561093f81614457565b8135815560208201356001820155600281016040830135600581106151b757600080fd5b60ff1982541660ff821681178355505050606082013560038201556151ea6151e160808401615165565b60048301615176565b60a0820135600582015561523161520360c08401615186565b600683016001600160a01b03821673ffffffffffffffffffffffffffffffffffffffff198254161781555050565b5050565b60006020828403121561524757600080fd5b815161ffff811681146110d457600080fd5b8135815560018101602083013561526f8161484b565b615278816147b7565b60ff1982541660ff8216811783555050506152966040830183614e29565b6152a4818360028601614eb6565b50506152b36060830183614e29565b6152c1818360038601614eb6565b50506152d06080830183614e29565b6152de818360048601614eb6565b50506152ed60a0830183614e29565b6152fb818360058601614eb6565b505061501a60c0830183614e29565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b815167ffffffffffffffff81111561535357615353614c14565b615367816153618454614d6c565b84614e70565b602080601f83116001811461539c57600084156153845750858301515b600019600386901b1c1916600185901b1785556117e0565b600085815260208120601f198616915b828110156153cb578886015182559484019460019091019084016153ac565b50858210156153e95787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220765b6772de28e3157b3108f224b33688412944d803ec365f79ac1011973f0c6964736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80637de4fba9116101de578063a9059cbb1161010f578063e5839836116100ad578063f8333bfa1161007c578063f8333bfa14610850578063f898178914610863578063f91b619c14610876578063fc7e5fa81461088957600080fd5b8063e5839836146107df578063e9bb84671461080b578063f14d540614610820578063f2fde38b1461083d57600080fd5b8063c47f0027116100e9578063c47f00271461076d578063c69c09cf14610780578063cbf3f86114610793578063dd62ed3e146107a657600080fd5b8063a9059cbb14610731578063aba6370514610744578063b84c82461461075a57600080fd5b806395d89b411161017c5780639dc29fac116101565780639dc29fac146106e55780639fc1d0e7146106f8578063a1e4b7861461070b578063a457c2d71461071e57600080fd5b806395d89b41146106b557806397a6278e146106bd57806399d09c69146106d057600080fd5b806388d695b2116101b857806388d695b21461063a5780638da5cb5b1461064d5780638e00a2bb1461065e5780639285948a146106a257600080fd5b80637de4fba91461060c5780638456cb591461061f57806384e798421461062757600080fd5b80633d1ddc5b116102c35780634a6cc67711610261578063685731071161023057806368573107146105c05780636945c1fd146105d357806370a08231146105db578063715018a61461060457600080fd5b80634a6cc6771461057057806354fd4d50146105835780635c975abb146105a45780636290865d146105af57600080fd5b806342a47abc1161029d57806342a47abc1461051c57806344ed4f891461052f5780634710362d146105425780634946b76b1461055557600080fd5b80633d1ddc5b146104ee5780633f4ba83a1461050157806340c10f191461050957600080fd5b80631a7af3791161033057806323b872dd1161030a57806323b872dd1461049e5780632d095a58146104b1578063313ce567146104c657806339509351146104db57600080fd5b80631a7af379146104655780631fe56f7d146104785780631ffbb0641461048b57600080fd5b8063125c4a331161036c578063125c4a33146103e9578063134e18f4146103fc578063158b1a571461042657806318160ddd1461045d57600080fd5b806306fdde0314610393578063095ea7b3146103b15780630b9fff74146103d4575b600080fd5b61039b61089c565b6040516103a89190614444565b60405180910390f35b6103c46103bf36600461446c565b61092e565b60405190151581526020016103a8565b6103e76103e2366004614498565b610945565b005b6103e76103f736600461446c565b610a12565b606e5461010090046001600160a01b03165b6040516001600160a01b0390911681526020016103a8565b61044f6104343660046144d4565b6001600160a01b03166000908152606d602052604090205490565b6040519081526020016103a8565b60685461044f565b6103e761047336600461453d565b610b82565b6103e761048636600461446c565b610bf7565b6103c46104993660046144d4565b610d70565b6103c46104ac3660046145a9565b610d7d565b6104b96110db565b6040516103a8919061462d565b606b5460405160ff90911681526020016103a8565b6103c46104e936600461446c565b611367565b6103e76104fc3660046144d4565b61139e565b6103e7611469565b6103e761051736600461446c565b611567565b6103e761052a3660046146e9565b6117e8565b6103e761053d36600461479b565b61187e565b6103e761055036600461453d565b611893565b61055d6118f8565b6040516103a897969594939291906147c7565b6103e761057e36600461453d565b611bcf565b604080518082019091526005815264342e302e3160d81b602082015261039b565b606e5460ff166103c4565b606f546001600160a01b031661040e565b6103e76105ce36600461453d565b611c34565b61039b611c99565b61044f6105e93660046144d4565b6001600160a01b031660009081526066602052604090205490565b6103e7611cab565b6103e761061a366004614858565b611cbf565b6103e7611d3e565b6103e76106353660046144d4565b611e2d565b6103e761064836600461453d565b611ecd565b6033546001600160a01b031661040e565b60b05460b15460b25460b35460b45460b55460b65461068f96959460ff90811694931691906001600160a01b031687565b6040516103a89796959493929190614895565b6103c46106b03660046148e4565b611f33565b61039b61236e565b6103e76106cb3660046144d4565b61237d565b6106d861241d565b6040516103a8919061492f565b6103e76106f336600461446c565b6124cf565b6103c46107063660046145a9565b6126f2565b6103e7610719366004614998565b61298e565b6103c461072c36600461446c565b6129d3565b6103c461073f36600461446c565b612a0a565b606b5461010090046001600160a01b031661040e565b6103e76107683660046149d5565b612cc8565b6103e761077b3660046149d5565b612e24565b6103e761078e366004614a55565b612ee0565b6103e76107a13660046144d4565b612fa1565b61044f6107b4366004614a8e565b6001600160a01b03918216600090815260676020908152604080832093909416825291909152205490565b6103c46107ed3660046144d4565b6001600160a01b03166000908152606c602052604090205460ff1690565b610813613008565b6040516103a89190614abc565b610828613251565b6040516103a899989796959493929190614b77565b6103e761084b3660046144d4565b61342b565b60a15460ff166040516103a89190614c01565b6103e76108713660046144d4565b6134bb565b6103e7610884366004614cb7565b613614565b6103e761089736600461453d565b613a7d565b6060606980546108ab90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546108d790614d6c565b80156109245780601f106108f957610100808354040283529160200191610924565b820191906000526020600020905b81548152906001019060200180831161090757829003601f168201915b5050505050905090565b600061093b338484613ae2565b5060015b92915050565b61094d613c20565b6109e360a2600301805461096090614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461098c90614d6c565b80156109d95780601f106109ae576101008083540402835291602001916109d9565b820191906000526020600020905b8154815290600101906020018083116109bc57829003601f168201915b5050505050613c7a565b610a00576040516345f9481360e01b815260040160405180910390fd5b8060a2610a0d8282614f76565b505050565b610a1b33610d70565b610a835760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b60648201526084015b60405180910390fd5b6001600160a01b038216600090815260666020908152604080832054606d90925290912054610ab3908390615044565b811015610b025760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206578636565647320617661696c61626c652062616c616e63656044820152606401610a7a565b6001600160a01b0383166000908152606d6020526040902054610b26908390615044565b6001600160a01b0384166000818152606d6020526040908190209290925590517fa065e63c631c86f1b9f66a4a2f63f2093bf1c2168d23290259dbd969e0222a4590610b759085815260200190565b60405180910390a2505050565b60005b83811015610bf057610bde858583818110610ba257610ba2615057565b9050602002016020810190610bb791906144d4565b848484818110610bc957610bc9615057565b905060200201602081019061078e919061506d565b80610be88161508a565b915050610b85565b5050505050565b610c0033610d70565b610c635760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0382166000908152606d6020526040902054811115610cf15760405162461bcd60e51b815260206004820152603460248201527f416d6f756e742073686f756c64206265206c657373207468616e206f7220657160448201527f75616c20746f2066726f7a656e20746f6b656e730000000000000000000000006064820152608401610a7a565b6001600160a01b0382166000908152606d6020526040902054610d159082906150a3565b6001600160a01b0383166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d690610d649084815260200190565b60405180910390a25050565b600061093f606583613cd4565b606e5460009060ff1615610dc65760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b6001600160a01b0383166000908152606c602052604090205460ff16158015610e0857506001600160a01b0384166000908152606c602052604090205460ff16155b610e545760405162461bcd60e51b815260206004820152601060248201527f77616c6c65742069732066726f7a656e000000000000000000000000000000006044820152606401610a7a565b6001600160a01b0384166000908152606d6020908152604080832054606690925290912054610e8391906150a3565b821115610ed25760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742042616c616e63650000000000000000000000006044820152606401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0385811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015610f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906150b6565b8015610fca5750606f546040516372331c7360e11b81526001600160a01b0386811660048301528581166024830152604482018590529091169063e46638e690606401602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca91906150b6565b1561108c576001600160a01b03841660009081526067602090815260408083203380855292529091205461100a9186916110059086906150a3565b613ae2565b611015848484613d57565b606f546040516322ebca6d60e21b81526001600160a01b03868116600483015285811660248301526044820185905290911690638baf29b490606401600060405180830381600087803b15801561106b57600080fd5b505af115801561107f573d6000803e3d6000fd5b50505050600190506110d4565b60405162461bcd60e51b815260206004820152601560248201527f5472616e73666572206e6f7420706f737369626c6500000000000000000000006044820152606401610a7a565b9392505050565b6110e3614342565b604080516101208101825260a28054825260a354602083015260a454919290919083019060ff16600181111561111b5761111b6145ea565b600181111561112c5761112c6145ea565b81526020016002820160019054906101000a900460ff166006811115611154576111546145ea565b6006811115611165576111656145ea565b81526020016002820160029054906101000a900460ff16600181111561118d5761118d6145ea565b600181111561119e5761119e6145ea565b81526020016003820180546111b290614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546111de90614d6c565b801561122b5780601f106112005761010080835404028352916020019161122b565b820191906000526020600020905b81548152906001019060200180831161120e57829003601f168201915b505050505081526020016004820154815260200160058201805461124e90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461127a90614d6c565b80156112c75780601f1061129c576101008083540402835291602001916112c7565b820191906000526020600020905b8154815290600101906020018083116112aa57829003601f168201915b505050505081526020016006820180546112e090614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461130c90614d6c565b80156113595780601f1061132e57610100808354040283529160200191611359565b820191906000526020600020905b81548152906001019060200180831161133c57829003601f168201915b505050505081525050905090565b3360008181526067602090815260408083206001600160a01b0387168452909152812054909161093b918590611005908690615044565b6113a6613c20565b606b805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b0384811682029290921792839055604051920416906113ed90606a906150d3565b6040518091039020606960405161140491906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d19261145e9260ff9091169190615149565b60405180910390a450565b61147233610d70565b6114d55760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460ff166115275760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a7a565b606e805460ff191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b61157033610d70565b6115d35760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0384811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015611623573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164791906150b6565b6116935760405162461bcd60e51b815260206004820152601960248201527f4964656e74697479206973206e6f742076657269666965642e000000000000006044820152606401610a7a565b606f546040516372331c7360e11b8152600060048201526001600160a01b038481166024830152604482018490529091169063e46638e690606401602060405180830381865afa1580156116eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170f91906150b6565b61175b5760405162461bcd60e51b815260206004820152601760248201527f436f6d706c69616e6365206e6f7420666f6c6c6f7765640000000000000000006044820152606401610a7a565b6117658282613ef7565b606f546040517f5f8dead30000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526024820184905290911690635f8dead390604401600060405180830381600087803b1580156117cc57600080fd5b505af11580156117e0573d6000803e3d6000fd5b505050505050565b60005b858110156118755761186287878381811061180857611808615057565b905060200201602081019061181d91906144d4565b86868481811061182f5761182f615057565b905060200201602081019061184491906144d4565b85858581811061185657611856615057565b905060200201356126f2565b508061186d8161508a565b9150506117eb565b50505050505050565b611886613c20565b8060b0610a0d8282615193565b60005b83811015610bf0576118e68585838181106118b3576118b3615057565b90506020020160208101906118c891906144d4565b8484848181106118da576118da615057565b90506020020135610bf7565b806118f08161508a565b915050611896565b60a9805460aa5460ab8054929360ff9092169261191490614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461194090614d6c565b801561198d5780601f106119625761010080835404028352916020019161198d565b820191906000526020600020905b81548152906001019060200180831161197057829003601f168201915b5050505050908060030180546119a290614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546119ce90614d6c565b8015611a1b5780601f106119f057610100808354040283529160200191611a1b565b820191906000526020600020905b8154815290600101906020018083116119fe57829003601f168201915b505050505090806004018054611a3090614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611a5c90614d6c565b8015611aa95780601f10611a7e57610100808354040283529160200191611aa9565b820191906000526020600020905b815481529060010190602001808311611a8c57829003601f168201915b505050505090806005018054611abe90614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611aea90614d6c565b8015611b375780601f10611b0c57610100808354040283529160200191611b37565b820191906000526020600020905b815481529060010190602001808311611b1a57829003601f168201915b505050505090806006018054611b4c90614d6c565b80601f0160208091040260200160405190810160405280929190818152602001828054611b7890614d6c565b8015611bc55780601f10611b9a57610100808354040283529160200191611bc5565b820191906000526020600020905b815481529060010190602001808311611ba857829003601f168201915b5050505050905087565b60005b83811015610bf057611c22858583818110611bef57611bef615057565b9050602002016020810190611c0491906144d4565b848484818110611c1657611c16615057565b905060200201356124cf565b80611c2c8161508a565b915050611bd2565b60005b83811015610bf057611c87858583818110611c5457611c54615057565b9050602002016020810190611c6991906144d4565b848484818110611c7b57611c7b615057565b90506020020135611567565b80611c918161508a565b915050611c37565b606060a260030180546108ab90614d6c565b611cb3613c20565b611cbd6000613fdf565b565b611cc7613c20565b600060a15460ff166003811115611ce057611ce06145ea565b14611d17576040517f4b2a71e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a1805482919060ff19166001836003811115611d3657611d366145ea565b021790555050565b611d4733610d70565b611daa5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b606e5460ff1615611df05760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b606e805460ff191660011790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161155d565b611e35613c20565b6001600160a01b038116611e8b5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b611e9660658261403e565b6040516001600160a01b038216907ff68e73cec97f2d70aa641fb26e87a4383686e2efacb648f2165aeb02ac562ec590600090a250565b60005b83811015610bf057611f20858583818110611eed57611eed615057565b9050602002016020810190611f0291906144d4565b848484818110611f1457611f14615057565b90506020020135612a0a565b5080611f2b8161508a565b915050611ed0565b6000611f3e33610d70565b611fa15760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0384166000908152606660205260409020546000036120095760405162461bcd60e51b815260206004820152601460248201527f6e6f20746f6b656e7320746f207265636f7665720000000000000000000000006044820152606401610a7a565b604080516001600160a01b038516602082015283916000910160408051808303601f190181529082905280516020909101207fd202158d000000000000000000000000000000000000000000000000000000008252600482018190526001602483015291506001600160a01b0383169063d202158d90604401602060405180830381865afa15801561209f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c391906150b6565b15612326576001600160a01b03868116600081815260666020908152604080832054606d83529281902054606e5482517f7e42683b0000000000000000000000000000000000000000000000000000000081526004810196909652915193959094610100909204169263454a03e0928b9289928692637e42683b92602480820193918290030181865afa15801561215e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121829190615235565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015261ffff166044820152606401600060405180830381600087803b1580156121ed57600080fd5b505af1158015612201573d6000803e3d6000fd5b505050506122108888846126f2565b508015612221576122218782610a12565b6001600160a01b0388166000908152606c602052604090205460ff16151560010361225157612251876001612ee0565b606e546040517fa8d29d1d0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301526101009092049091169063a8d29d1d90602401600060405180830381600087803b1580156122b757600080fd5b505af11580156122cb573d6000803e3d6000fd5b50505050856001600160a01b0316876001600160a01b0316896001600160a01b03167ff0c9129a94f30f1caaceb63e44b9811d0a3edf1d6c23757f346093af5553fed060405160405180910390a460019450505050506110d4565b60405162461bcd60e51b815260206004820152601560248201527f5265636f76657279206e6f7420706f737369626c6500000000000000000000006044820152606401610a7a565b6060606a80546108ab90614d6c565b612385613c20565b6001600160a01b0381166123db5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b6123e66065826140ba565b6040516001600160a01b038216907fed9c8ad8d5a0a66898ea49d2956929c93ae2e8bd50281b2ed897c5d1a6737e0b90600090a250565b61242561439f565b6040805160e08101825260b08054825260b154602083015260b254919290919083019060ff16600481111561245c5761245c6145ea565b600481111561246d5761246d6145ea565b815260038201546020820152600482015460409091019060ff16600a811115612498576124986145ea565b600a8111156124a9576124a96145ea565b8152600582015460208201526006909101546001600160a01b0316604090910152919050565b6124d833610d70565b61253b5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b8061255b836001600160a01b031660009081526066602052604090205490565b10156125a95760405162461bcd60e51b815260206004820152601d60248201527f63616e6e6f74206275726e206d6f7265207468616e2062616c616e63650000006044820152606401610a7a565b6001600160a01b0382166000908152606d602090815260408083205460669092528220546125d791906150a3565b90508082111561266d5760006125ed82846150a3565b6001600160a01b0385166000908152606d60205260409020549091506126149082906150a3565b6001600160a01b0385166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d6906126639084815260200190565b60405180910390a2505b6126778383614158565b606f546040517f8d2ea7720000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301526024820185905290911690638d2ea77290604401600060405180830381600087803b1580156126de57600080fd5b505af1158015611875573d6000803e3d6000fd5b60006126fd33610d70565b6127605760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b81612780856001600160a01b031660009081526066602052604090205490565b10156127ce5760405162461bcd60e51b815260206004820152601660248201527f73656e6465722062616c616e636520746f6f206c6f77000000000000000000006044820152606401610a7a565b6001600160a01b0384166000908152606d602090815260408083205460669092528220546127fc91906150a3565b90508083111561289257600061281282856150a3565b6001600160a01b0387166000908152606d60205260409020549091506128399082906150a3565b6001600160a01b0387166000818152606d6020526040908190209290925590517f9bed35cb62ad0dba04f9d5bfee4b5bc91443e77da8a65c4c84834c51bb08b0d6906128889084815260200190565b60405180910390a2505b606e5460405163b9209e3360e01b81526001600160a01b0386811660048301526101009092049091169063b9209e3390602401602060405180830381865afa1580156128e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290691906150b6565b1561108c57612916858585613d57565b606f546040516322ebca6d60e21b81526001600160a01b03878116600483015286811660248301526044820186905290911690638baf29b490606401600060405180830381600087803b15801561296c57600080fd5b505af1158015612980573d6000803e3d6000fd5b5050505060019150506110d4565b612996613c20565b6129a960a9600201805461096090614d6c565b6129c6576040516345f9481360e01b815260040160405180910390fd5b8060a9610a0d8282615259565b3360008181526067602090815260408083206001600160a01b0387168452909152812054909161093b9185906110059086906150a3565b606e5460009060ff1615612a535760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a7a565b6001600160a01b0383166000908152606c602052604090205460ff16158015612a8c5750336000908152606c602052604090205460ff16155b612ad85760405162461bcd60e51b815260206004820152601060248201527f77616c6c65742069732066726f7a656e000000000000000000000000000000006044820152606401610a7a565b336000908152606d6020908152604080832054606690925290912054612afe91906150a3565b821115612b4d5760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742042616c616e63650000000000000000000000006044820152606401610a7a565b606e5460405163b9209e3360e01b81526001600160a01b0385811660048301526101009092049091169063b9209e3390602401602060405180830381865afa158015612b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc191906150b6565b8015612c435750606f546040516372331c7360e11b81523360048201526001600160a01b038581166024830152604482018590529091169063e46638e690606401602060405180830381865afa158015612c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4391906150b6565b1561108c57612c53338484613d57565b606f546040516322ebca6d60e21b81523360048201526001600160a01b0385811660248301526044820185905290911690638baf29b490606401600060405180830381600087803b158015612ca757600080fd5b505af1158015612cbb573d6000803e3d6000fd5b505050506001905061093f565b612cd0613c20565b604051602001612ceb90602080825260009082015260400190565b604051602081830303815290604052805190602001208282604051602001612d1492919061530a565b6040516020818303038152906040528051906020012003612d775760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b606a612d84828483614eb6565b50606b546040516101009091046001600160a01b031690612da790606a906150d3565b60405180910390206069604051612dbe91906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d192612e189260ff9091169190615149565b60405180910390a45050565b612e2c613c20565b604051602001612e4790602080825260009082015260400190565b604051602081830303815290604052805190602001208282604051602001612e7092919061530a565b6040516020818303038152906040528051906020012003612ed35760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b6069612d84828483614eb6565b612ee933610d70565b612f4c5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b6064820152608401610a7a565b6001600160a01b0382166000818152606c6020526040808220805460ff19168515159081179091559051339391927f7fa523c84ab8d7fc5b72f08b9e46dbbf10c39e119a075b3e317002d14bc9f43691a45050565b612fa9613c20565b606e805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b038416908102919091179091556040517fd2be862d755bca7e0d39772b2cab3a5578da9c285f69199f4c063c2294a7f36c90600090a250565b6130496040805160e0810190915260008082526020820190815260200160608152602001606081526020016060815260200160608152602001606081525090565b6040805160e0810190915260a98054825260aa54602083019060ff166003811115613076576130766145ea565b6003811115613087576130876145ea565b815260200160028201805461309b90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546130c790614d6c565b80156131145780601f106130e957610100808354040283529160200191613114565b820191906000526020600020905b8154815290600101906020018083116130f757829003601f168201915b5050505050815260200160038201805461312d90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461315990614d6c565b80156131a65780601f1061317b576101008083540402835291602001916131a6565b820191906000526020600020905b81548152906001019060200180831161318957829003601f168201915b505050505081526020016004820180546131bf90614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546131eb90614d6c565b80156132385780601f1061320d57610100808354040283529160200191613238565b820191906000526020600020905b81548152906001019060200180831161321b57829003601f168201915b5050505050815260200160058201805461124e90614d6c565b60a2805460a35460a45460a580549394929360ff80841694610100850482169462010000900490911692909161328690614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546132b290614d6c565b80156132ff5780601f106132d4576101008083540402835291602001916132ff565b820191906000526020600020905b8154815290600101906020018083116132e257829003601f168201915b50505050509080600401549080600501805461331a90614d6c565b80601f016020809104026020016040519081016040528092919081815260200182805461334690614d6c565b80156133935780601f1061336857610100808354040283529160200191613393565b820191906000526020600020905b81548152906001019060200180831161337657829003601f168201915b5050505050908060060180546133a890614d6c565b80601f01602080910402602001604051908101604052809291908181526020018280546133d490614d6c565b80156134215780601f106133f657610100808354040283529160200191613421565b820191906000526020600020905b81548152906001019060200180831161340457829003601f168201915b5050505050905089565b613433613c20565b6001600160a01b0381166134af5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a7a565b6134b881613fdf565b50565b6134c3613c20565b606f546001600160a01b03161561354b57606f546040517f40db3b500000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906340db3b5090602401600060405180830381600087803b15801561353257600080fd5b505af1158015613546573d6000803e3d6000fd5b505050505b606f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517f3ff5aa02000000000000000000000000000000000000000000000000000000008152306004820152633ff5aa0290602401600060405180830381600087803b1580156135c557600080fd5b505af11580156135d9573d6000803e3d6000fd5b50506040516001600160a01b03841692507f7f3a888862559648ec01d97deb7b5012bff86dc91e654a1de397170db40e35b69150600090a250565b600054610100900460ff16158080156136345750600054600160ff909116105b8061364e5750303b15801561364e575060005460ff166001145b6136c05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a7a565b6000805460ff1916600117905580156136e3576000805461ff0019166101001790555b60006136f76033546001600160a01b031690565b6001600160a01b03161461374d5760405162461bcd60e51b815260206004820152601360248201527f616c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610a7a565b6001600160a01b0387161580159061376d57506001600160a01b03861615155b6137b95760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f2061646472657373006044820152606401610a7a565b6040516020016137d490602080825260009082015260400190565b60405160208183030381529060405280519060200120856040516020016137fb9190614444565b6040516020818303038152906040528051906020012014158015613875575060405160200161383590602080825260009082015260400190565b604051602081830303815290604052805190602001208460405160200161385c9190614444565b6040516020818303038152906040528051906020012014155b6138c15760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d20656d70747920737472696e67006044820152606401610a7a565b60128360ff1611156139155760405162461bcd60e51b815260206004820152601960248201527f646563696d616c73206265747765656e203020616e64203138000000000000006044820152606401610a7a565b61391d614260565b60696139298682615339565b50606a6139368582615339565b50606b80546001600160a01b038416610100027fffffffffffffffffffffff00000000000000000000000000000000000000000090911660ff861617179055606e805460ff1916600117905561398b87612fa1565b613994866134bb565b606b546040516101009091046001600160a01b0316906139b690606a906150d3565b604051809103902060696040516139cd91906150d3565b60408051918290038220606b5483830183526005845264342e302e3160d81b6020850152915190927f6a1105ac8148a3c319adbc369f9072573e8a11d3a3d195e067e7c40767ec54d192613a279260ff9091169190615149565b60405180910390a48015611875576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150505050505050565b60005b83811015610bf057613ad0858583818110613a9d57613a9d615057565b9050602002016020810190613ab291906144d4565b848484818110613ac457613ac4615057565b90506020020135610a12565b80613ada8161508a565b915050613a80565b6001600160a01b038316613b5d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038216613bbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a7a565b6001600160a01b0383811660008181526067602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6033546001600160a01b03163314611cbd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a7a565b6040805160208082015260009181018290526060016040516020818303038152906040528051906020012082604051602001613cb69190614444565b60405160208183030381529060405280519060200120149050919050565b60006001600160a01b038216613d375760405162461bcd60e51b815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f206164647265604482015261737360f01b6064820152608401610a7a565b506001600160a01b03166000908152602091909152604090205460ff1690565b6001600160a01b038316613dd35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038216613e4f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b038316600090815260666020526040902054613e739082906150a3565b6001600160a01b038085166000908152606660205260408082209390935590841681522054613ea3908290615044565b6001600160a01b0380841660008181526066602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613c139085815260200190565b6001600160a01b038216613f4d5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a7a565b80606854613f5b9190615044565b6068556001600160a01b038216600090815260666020526040902054613f82908290615044565b6001600160a01b0383166000818152606660205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613fd39085815260200190565b60405180910390a35050565b603380546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6140488282613cd4565b156140955760405162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c65006044820152606401610a7a565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6140c48282613cd4565b6141365760405162461bcd60e51b815260206004820152602160248201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c60448201527f65000000000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b0316600090815260209190915260409020805460ff19169055565b6001600160a01b0382166141d45760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610a7a565b6001600160a01b0382166000908152606660205260409020546141f89082906150a3565b6001600160a01b03831660009081526066602052604090205560685461421f9082906150a3565b6068556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001613fd3565b600054610100900460ff166142cb5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610a7a565b611cbd600054610100900460ff166143395760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610a7a565b611cbd33613fdf565b60405180610120016040528060008152602001600081526020016000600181111561436f5761436f6145ea565b81526020016000815260200160008152602001606081526020016000815260200160608152602001606081525090565b6040518060e001604052806000815260200160008152602001600060048111156143cb576143cb6145ea565b8152602001600081526020016000600a8111156143ea576143ea6145ea565b815260006020820181905260409091015290565b6000815180845260005b8181101561442457602081850181015186830182015201614408565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110d460208301846143fe565b6001600160a01b03811681146134b857600080fd5b6000806040838503121561447f57600080fd5b823561448a81614457565b946020939093013593505050565b6000602082840312156144aa57600080fd5b813567ffffffffffffffff8111156144c157600080fd5b820161012081850312156110d457600080fd5b6000602082840312156144e657600080fd5b81356110d481614457565b60008083601f84011261450357600080fd5b50813567ffffffffffffffff81111561451b57600080fd5b6020830191508360208260051b850101111561453657600080fd5b9250929050565b6000806000806040858703121561455357600080fd5b843567ffffffffffffffff8082111561456b57600080fd5b614577888389016144f1565b9096509450602087013591508082111561459057600080fd5b5061459d878288016144f1565b95989497509550505050565b6000806000606084860312156145be57600080fd5b83356145c981614457565b925060208401356145d981614457565b929592945050506040919091013590565b634e487b7160e01b600052602160045260246000fd5b600281106134b8576134b86145ea565b61461981614600565b9052565b60078110614619576146196145ea565b602081528151602082015260208201516040820152600060408301516146566060840182614610565b506060830151614669608084018261461d565b50608083015161467c60a0840182614610565b5060a08301516101208060c08501526146996101408501836143fe565b915060c085015160e085015260e0850151601f196101008187860301818801526146c385846143fe565b9088015187820390920184880152935090506146df83826143fe565b9695505050505050565b6000806000806000806060878903121561470257600080fd5b863567ffffffffffffffff8082111561471a57600080fd5b6147268a838b016144f1565b9098509650602089013591508082111561473f57600080fd5b61474b8a838b016144f1565b9096509450604089013591508082111561476457600080fd5b5061477189828a016144f1565b979a9699509497509295939492505050565b600060e0828403121561479557600080fd5b50919050565b600060e082840312156147ad57600080fd5b6110d48383614783565b600481106134b8576134b86145ea565b8781526147d3876147b7565b86602082015260e0604082015260006147ef60e08301886143fe565b828103606084015261480181886143fe565b9050828103608084015261481581876143fe565b905082810360a084015261482981866143fe565b905082810360c084015261483d81856143fe565b9a9950505050505050505050565b600481106134b857600080fd5b60006020828403121561486a57600080fd5b81356110d48161484b565b60058110614619576146196145ea565b600b8110614619576146196145ea565b8781526020810187905260e081016148b06040830188614875565b8560608301526148c36080830186614885565b8360a08301526001600160a01b03831660c083015298975050505050505050565b6000806000606084860312156148f957600080fd5b833561490481614457565b9250602084013561491481614457565b9150604084013561492481614457565b809150509250925092565b600060e082019050825182526020830151602083015260408301516149576040840182614875565b506060830151606083015260808301516149746080840182614885565b5060a083015160a08301526001600160a01b0360c08401511660c083015292915050565b6000602082840312156149aa57600080fd5b813567ffffffffffffffff8111156149c157600080fd5b6149cd84828501614783565b949350505050565b600080602083850312156149e857600080fd5b823567ffffffffffffffff80821115614a0057600080fd5b818501915085601f830112614a1457600080fd5b813581811115614a2357600080fd5b866020828501011115614a3557600080fd5b60209290920196919550909350505050565b80151581146134b857600080fd5b60008060408385031215614a6857600080fd5b8235614a7381614457565b91506020830135614a8381614a47565b809150509250929050565b60008060408385031215614aa157600080fd5b8235614aac81614457565b91506020830135614a8381614457565b602081528151602082015260006020830151614ad7816147b7565b80604084015250604083015160e06060840152614af86101008401826143fe565b90506060840151601f1980858403016080860152614b1683836143fe565b925060808601519150808584030160a0860152614b3383836143fe565b925060a08601519150808584030160c0860152614b5083836143fe565b925060c08601519150808584030160e086015250614b6e82826143fe565b95945050505050565b60006101208b83528a6020840152614b8e8a614600565b896040840152614ba1606084018a61461d565b614baa88614600565b8760808401528060a0840152614bc2818401886143fe565b90508560c084015282810360e0840152614bdc81866143fe565b9050828103610100840152614bf181856143fe565b9c9b505050505050505050505050565b60208101614c0e836147b7565b91905290565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614c3b57600080fd5b813567ffffffffffffffff80821115614c5657614c56614c14565b604051601f8301601f19908116603f01168101908282118183101715614c7e57614c7e614c14565b81604052838152866020858801011115614c9757600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c08789031215614cd057600080fd5b8635614cdb81614457565b95506020870135614ceb81614457565b9450604087013567ffffffffffffffff80821115614d0857600080fd5b614d148a838b01614c2a565b95506060890135915080821115614d2a57600080fd5b50614d3789828a01614c2a565b935050608087013560ff81168114614d4e57600080fd5b915060a0870135614d5e81614457565b809150509295509295509295565b600181811c90821680614d8057607f821691505b60208210810361479557634e487b7160e01b600052602260045260246000fd5b600081356002811061093f57600080fd5b614dba82614600565b60ff1981541660ff831681178255505050565b600081356007811061093f57600080fd5b60078210614dee57614dee6145ea565b805461ff008360081b1661ff00198216178255505050565b614e0f82614600565b805462ff00008360101b1662ff0000198216178255505050565b6000808335601e19843603018112614e4057600080fd5b83018035915067ffffffffffffffff821115614e5b57600080fd5b60200191503681900382131561453657600080fd5b601f821115610a0d57600081815260208120601f850160051c81016020861015614e975750805b601f850160051c820191505b818110156117e057828155600101614ea3565b67ffffffffffffffff831115614ece57614ece614c14565b614ee283614edc8354614d6c565b83614e70565b6000601f841160018114614f165760008515614efe5750838201355b600019600387901b1c1916600186901b178355610bf0565b600083815260209020601f19861690835b82811015614f475786850135825560209485019460019092019101614f27565b5086821015614f645760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b813581556020820135600182015560028101614f9d614f9760408501614da0565b82614db1565b614fb2614fac60608501614dcd565b82614dde565b614fc7614fc160808501614da0565b82614e06565b50614fd560a0830183614e29565b614fe3818360038601614eb6565b505060c08201356004820155614ffc60e0830183614e29565b61500a818360058601614eb6565b505061501a610100830183614e29565b615028818360068601614eb6565b50505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561093f5761093f61502e565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561507f57600080fd5b81356110d481614a47565b60006001820161509c5761509c61502e565b5060010190565b8181038181111561093f5761093f61502e565b6000602082840312156150c857600080fd5b81516110d481614a47565b60008083546150e181614d6c565b600182811680156150f9576001811461510e5761513d565b60ff198416875282151583028701945061513d565b8760005260208060002060005b858110156151345781548a82015290840190820161511b565b50505082870194505b50929695505050505050565b60ff831681526040602082015260006149cd60408301846143fe565b60008135600b811061093f57600080fd5b600b8210614dba57614dba6145ea565b6000813561093f81614457565b8135815560208201356001820155600281016040830135600581106151b757600080fd5b60ff1982541660ff821681178355505050606082013560038201556151ea6151e160808401615165565b60048301615176565b60a0820135600582015561523161520360c08401615186565b600683016001600160a01b03821673ffffffffffffffffffffffffffffffffffffffff198254161781555050565b5050565b60006020828403121561524757600080fd5b815161ffff811681146110d457600080fd5b8135815560018101602083013561526f8161484b565b615278816147b7565b60ff1982541660ff8216811783555050506152966040830183614e29565b6152a4818360028601614eb6565b50506152b36060830183614e29565b6152c1818360038601614eb6565b50506152d06080830183614e29565b6152de818360048601614eb6565b50506152ed60a0830183614e29565b6152fb818360058601614eb6565b505061501a60c0830183614e29565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b815167ffffffffffffffff81111561535357615353614c14565b615367816153618454614d6c565b84614e70565b602080601f83116001811461539c57600084156153845750858301515b600019600386901b1c1916600185901b1785556117e0565b600085815260208120601f198616915b828110156153cb578886015182559484019460019091019084016153ac565b50858210156153e95787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220765b6772de28e3157b3108f224b33688412944d803ec365f79ac1011973f0c6964736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.