ETH Price: $3,613.86 (-3.00%)

Contract

0x4280B1Fd47e5573b66008A5F307C0cf82D9D95CF
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Confirm Payment ...186853312023-11-30 15:32:23368 days ago1701358343IN
0x4280B1Fd...82D9D95CF
0 ETH0.0031178457.45588713
Confirm Payment ...186853302023-11-30 15:32:11368 days ago1701358331IN
0x4280B1Fd...82D9D95CF
0 ETH0.0084212757.40982389
Confirm Payment ...186853292023-11-30 15:31:59368 days ago1701358319IN
0x4280B1Fd...82D9D95CF
0 ETH0.0031407657.87829379
Confirm Payment ...186853282023-11-30 15:31:47368 days ago1701358307IN
0x4280B1Fd...82D9D95CF
0 ETH0.0092897459.44026774
Confirm Payment ...186853262023-11-30 15:31:23368 days ago1701358283IN
0x4280B1Fd...82D9D95CF
0 ETH0.0032846960.53063681
Confirm Payment ...186853252023-11-30 15:31:11368 days ago1701358271IN
0x4280B1Fd...82D9D95CF
0 ETH0.0090618357.9820018
Confirm Payment ...186853242023-11-30 15:30:59368 days ago1701358259IN
0x4280B1Fd...82D9D95CF
0 ETH0.0031597758.22866533
Confirm Payment ...186853222023-11-30 15:30:35368 days ago1701358235IN
0x4280B1Fd...82D9D95CF
0 ETH0.0091921858.81603255
Confirm Payment ...186853212023-11-30 15:30:23368 days ago1701358223IN
0x4280B1Fd...82D9D95CF
0 ETH0.0032160859.26629192
Confirm Payment ...186853202023-11-30 15:30:11368 days ago1701358211IN
0x4280B1Fd...82D9D95CF
0 ETH0.0090582357.95898094
Initiate Trade186852952023-11-30 15:24:59368 days ago1701357899IN
0x4280B1Fd...82D9D95CF
0 ETH0.0159646462.6285672
Initiate Trade186852912023-11-30 15:24:11368 days ago1701357851IN
0x4280B1Fd...82D9D95CF
0 ETH0.0165028764.74001586
Initiate Trade186852872023-11-30 15:23:23368 days ago1701357803IN
0x4280B1Fd...82D9D95CF
0 ETH0.0158196462.05972994
Initiate Trade186852832023-11-30 15:22:35368 days ago1701357755IN
0x4280B1Fd...82D9D95CF
0 ETH0.0145631857.13070192
Initiate Trade186852792023-11-30 15:21:47368 days ago1701357707IN
0x4280B1Fd...82D9D95CF
0 ETH0.0152337856.00451483
Confirm Payment ...186852422023-11-30 15:14:23368 days ago1701357263IN
0x4280B1Fd...82D9D95CF
0 ETH0.0028425952.38364393
Confirm Payment ...186852392023-11-30 15:13:47368 days ago1701357227IN
0x4280B1Fd...82D9D95CF
0 ETH0.0076835352.380496
Initiate Subscri...186852342023-11-30 15:12:47368 days ago1701357167IN
0x4280B1Fd...82D9D95CF
0 ETH0.014728153.60665839

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
186851372023-11-30 14:53:23368 days ago1701356003  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Product

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 17 : Product.sol
pragma solidity 0.8.17;

import "./libraries/SecurityTokenBalancesLibrary.sol";
import "./libraries/IterableBalances.sol";
import "./libraries/SettlementRepositoryLibrary.sol";
import "./libraries/SettlementWorkflowLibrary.sol";
import "./libraries/TransferAdapterLibrary.sol";
import "./libraries/ApproveAdapterLibrary.sol";
import "./interfaces/IProduct.sol";
import "./interfaces/ISettlement.sol";
import "./interfaces/IERC20Adapter.sol";
import "../registry/interfaces/IProductRegistry.sol";
import "../utils/Ownable.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../utils/ProductErrorReporter.sol";

error InvalidRegistryAddress();


/**
 * @dev This contract represents a CAST-compatible financial product
 * It includes a number of basic financial information about the product (common to all products)
 * It also contains extended information specific to this product, as a JSON string in field extendedDataJson
 * It also includes the methods needed to handle Settlement Transactions on this instrument(subscriptions on primary market, secondary
 * market trades as well as coupons and redemption) -> see ISettlement interface
 * It also includes the methods needed to interact (almost) as an ERC20 token, enable to interact with DeFi protocols. -> see IERC20Adapter 
 * interface
 * Supports ERC165
 */
contract Product is
    ISettlement,
    IProduct,
    IERC20Adapter,
    ERC165,
    Ownable
{
    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;
    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;
    using TransferAdapterLibrary for TransferAdapterLibrary.OngoingTransfers;
    using ApproveAdapterLibrary for ApproveAdapterLibrary.OngoingApproves;
    // Basic Informations
    /**
     * @dev The product's currency
     */
    string public currency;
    /**
     * @dev The product's denomination in cents
     */
    uint256 public denominationCent;
    /**
     * @dev The product's maturity date (unix timestamp)
     */
    uint256 public maturityDate;
    /**
     * @dev The product's governing law
     */
    string public governingLaw;
    /**
     * @dev The product's guarantor legal entity
     */
    LegalEntity public guarantor;
    /**
     * @dev The product's isin code
     */
    string public isinCode;
    /**
     * @dev The product's issuer legal entity
     */
    LegalEntity public issuer;
    /**
     * @dev The product's quotation market
     */
    string public listing;
    /**
     * @dev The product's name
     */
    string public name;
    /**
     * @dev The product's paying agent legal entity
     */
    LegalEntity public payingAgent;
    /**
     * @dev The product's type code (e.g. sgforge.com/bond/V1)
     */
    string public productType;
    /**
     * @dev The product's registrar legal entity
     */
    LegalEntity public registrar;
    /**
     * @dev The product's settlement agent legal entity
     */
    LegalEntity public settlementAgent;
    /**
     * @dev The product's symbol
     */
    string public symbol;
    /**
     * @dev The product's state
     */
    ProductState public state;
    /**
     * @dev This URL where the Settlement Transaction Repository can be reached
     * The STR can provided the confidential part of the Settlement Transactions to the counterparts (authentication with ethereum private key)
     */
    string public strUrl;
    /**
     * @dev The issuer's issuance program this product is part of
     */
    string public program;
    /**
     * @dev This product's series number
     */
    string public series;
    /**
     * @dev This product's note status
     */
    string public noteStatus;
    /**
     * @dev JSON string of extended information about the product. Can be roughly anything.
     * Will be used to hold financial information specific to a some products.
     */
    string public extendedDataJson;
    /**
     * @dev String holding ESG information about the product (JSON format)
     */
    string public esg;
    /**
     * @dev This product's form of the node (e.g. Registered)
     */
    string public formOfNote;
    /**
     * @dev This product's FIGI code
     */
    string public figi;
    /**
     * @dev The address of a previous contract that is replaced with this one (allows to keep track of successive contract migrations)
     */
    address public previousContract;

    /**
     * @dev Extended data(JSON string) associated with specific business operations
     */
    mapping(uint256 => string) public operationExtendedDataJson;

    /**
     * @dev The product's balances. Handles total and locked balance.
     */
    SecurityTokenBalancesLibrary.SecurityTokenBalances
        private securityTokenBalances;

    /**
     * @dev The product's settlement transaction repository
     * Contains all Settlement Transactions involving this product.
     */
    SettlementRepositoryLibrary.SettlementTransactionRepository
        private settlementTransactionRepository;

    /**
     * @dev Ongoing two-steps transfers.
     * See IERC20Adapter
     */
    TransferAdapterLibrary.OngoingTransfers private ongoingTransfers;
    /**
     * @dev Ongoing two-steps approves
     * See IERC20Adapter
     */
    ApproveAdapterLibrary.OngoingApproves private ongoingApproves;

    /**
     * @dev The version number of this smart contract.
     */
    string public constant version = "1.1";

    // Tranches related informations
    Tranche[] public tranches;
    /**
     * @dev The product total issued nominal amount(includes all tranches)
     */
    uint256 public seriesNominalAmountCent;
    /**
     * @dev The product outstanding nominal amount(includes all not-burnt tokens)
     */
    uint256 public seriesOutstandingNominalAmountCent;
    /**
     * @dev The product redeemed amount(i.e. burnt tokens)
     */
    uint256 public seriesRedeemedAmountCent;
    /**
     * @dev The total number of (not burnt) tokens
     */
    uint256 public totalSupply;

    /**
     * @dev The different states a product can have
     * Product are initially in the `Created` state.
     * Once at list one subscription operation has been initiated, they move to the `Running` state.
     * Once a redemption operation has been initiated, they move to the `Redeemed` state, which is the product's final state.
     * Once a product is in the `Redeemed` state, no more Settlement Transaction may be initiated on this product.
     * 
     */
    enum ProductState {
        Undefined,
        Created,
        Running,
        Redeemed
    }

    constructor(BasicProductInput memory basicProductInput) Ownable(basicProductInput.registrar.account){
        
        isinCode = basicProductInput.isinCode;
        name = basicProductInput.name;
        symbol = basicProductInput.symbol;
        denominationCent = basicProductInput.denominationCent;
        maturityDate = basicProductInput.maturityDate;
        governingLaw = basicProductInput.governingLaw;
        listing = basicProductInput.listing;
        state = ProductState.Created;
        currency = basicProductInput.currency;
        registrar = LegalEntity(
            basicProductInput.registrar.lei,
            basicProductInput.registrar.account
        );
        if(basicProductInput.settlementAgent.account == address(0))
            revert ZeroAddressCheck();
        settlementAgent = LegalEntity(
            basicProductInput.settlementAgent.lei,
            basicProductInput.settlementAgent.account
        );
        payingAgent = LegalEntity(
            basicProductInput.payingAgent.lei,
            basicProductInput.payingAgent.account
        );
        issuer = LegalEntity(
            basicProductInput.issuer.lei,
            basicProductInput.issuer.account
        );
        securityTokenBalances.setIssuer(issuer.account);
        guarantor = LegalEntity(
            basicProductInput.guarantor.lei,
            basicProductInput.guarantor.account
        );
        strUrl = basicProductInput.strUrl;
        productType = basicProductInput.productType;
        program = basicProductInput.program;
        series = basicProductInput.series;
        noteStatus = basicProductInput.noteStatus;
        formOfNote = basicProductInput.formOfNote;
        extendedDataJson = basicProductInput.extendedDataJson;
        esg = basicProductInput.esg;
        figi = basicProductInput.figi;
        previousContract = basicProductInput.previousContract;

        for (uint256 i = 0; i < basicProductInput.initialTranches.length; i++) {
            internalCreateTranche(basicProductInput.initialTranches[i]);
        }

        if (basicProductInput.initialBalances.length > 0) {
            uint256 balanceSupply = 0;
            for (
                uint256 i = 0;
                i < basicProductInput.initialBalances.length;
                i++
            ) {
                uint256 value = basicProductInput.initialBalances[i].balance;
                address to = basicProductInput.initialBalances[i].account;

                securityTokenBalances.mint(to, value);
                balanceSupply += value;
            }
            if (balanceSupply != totalSupply)
                revert TotalSupplyNotMatchTotalInitialSupply();
        } else {
            securityTokenBalances.mint(issuer.account, totalSupply);
        }
    }

    /**
     * @dev ERC165. Indicates that the product implements the ISettlement,IERC20Adapter and IProduct interfaces.
     */
    function supportsInterface(bytes4 interfaceId)
        override
        public
        view
        returns (bool)
    {
        return
            interfaceId == type(ISettlement).interfaceId ||
            interfaceId == type(IERC20Adapter).interfaceId ||
            interfaceId == type(IProduct).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    // Basic Token
    /**
     * @dev Shortcut to the account of the issuer legal entity
     */
    function issuerAccount() external view returns (address) {
        return issuer.account;
    }

    /**
     * @dev Shortcut to the Legal Entity ID of the issuer legal entity
     */
    function issuerLEI() external view returns (string memory) {
        return issuer.lei;
    }

    /**
     * @dev Shortcut to the account of the settlement agent legal entity
     */
    function settlementAgentAccount() external view returns (address) {
        return settlementAgent.account;
    }

    /**
     * @dev Shortcut to the Legal Entity ID of the settlement agent legal entity
     */
    function settlementAgentLEI() external view returns (string memory) {
        return settlementAgent.lei;
    }

    /**
     * @dev Shortcut to the account of the paying agent legal entity
     */
    function payingAgentAccount() external view returns (address) {
        if (payingAgent.account == address(0)) revert PayingAgentNotSet();
        return payingAgent.account;
    }

    /**
     * @dev Shortcut to the Legal Entity ID of the paying agent legal entity
     */
    function payingAgentLEI() external view returns (string memory) {
        if (bytes(payingAgent.lei).length == 0) revert PayingAgentNotSet();
        return payingAgent.lei;
    }

    /**
     * @dev Shortcut to the account of the registrar legal entity
     */
    function registrarAccount() external view returns (address) {
        return registrar.account;
    }

    /**
     * @dev Shortcut to the Legal Entity ID of the registrar legal entity
     */
    function registrarLEI() external view returns (string memory) {
        return registrar.lei;
    }

    /**
     * @dev Shortcut to the account of the guarantor legal entity
     */
    function guarantorAccount() external view returns (address) {
        if (guarantor.account == address(0)) revert GuarantorNotSet();
        return guarantor.account;
    }

    /**
     * @dev Shortcut to the Legal Entity ID of the guarantor legal entity
     */
    function guarantorLEI() external view returns (string memory) {
        if (bytes(guarantor.lei).length == 0) revert GuarantorNotSet();
        return guarantor.lei;
    }

    /**
     * @dev Return details of all tranches
     */
    function getTranches() external view returns (Tranche[] memory) {
        return tranches;
    }

    // Modifiers
    /**
     * @dev Checks the product is not redeemed yet
     */
    modifier onlyNotRedeemedProduct() {
        if (state >= ProductState.Redeemed) revert ProductIsFullyRedeemed();
        _;
    }
    /**
     * @dev Checks there is no ongoing approve request for the same spender
     */
    modifier onlyOnAvailableSpender(address spender) {
        if (ongoingApproves.hasOngoingApprove[msg.sender][spender])
            revert OwnerHasOngoingApprove();
        _;
    }

    /**
     * @dev Used to protect methods that only the product's settlement agent can call
     */
    modifier settlerOnly() {
        if (msg.sender != settlementAgent.account) revert UnauthorizedSettler();
        _;
    }

    /**
     * @dev Allows to change the product's extended data descriptor
     * NB: Only the registrar can call this method
     */
    function setExtendeDataJson(string memory _extendedDataJson)
        external
        onlyRegistrar
    {
        extendedDataJson = _extendedDataJson;
    }

    /**
     * @dev Allows to change the product's ESG data descriptor
     * NB: Only the registrar can call this method
     */
    function setEsg(string memory _esg) external onlyRegistrar {
        esg = _esg;
    }

    // [ERC-20] Only
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return securityTokenBalances.getBalance(_owner);
    }

    /**
     * @dev Initiates two-step simple transfer(cf IERC20Adapter) and sends corresponding `TransferRequest` event
     */
    function transfer(address _to, uint256 _value)
        external
        virtual
        override
        returns (bool)
    {
        if (_value == 0) revert ZeroValueCheck();
        if (_to == msg.sender) revert InvalidReceiver();
        bytes32 transferHash = ongoingTransfers.addTransfer(
            securityTokenBalances,
            msg.sender,
            _to,
            _value,
            false,
            address(0)
        );
        emit Transfer(msg.sender, _to, 0); // Required by https://eips.ethereum.org/EIPS/eip-20#transfer
        emit TransferRequest(transferHash, msg.sender, _to, _value);
        return true;
    }

    /**
     * @dev Initiates two-step approve(cf IERC20Adapter) and sends corresponding `ApproveRequest` event
     */
    function approve(address _spender, uint256 _value)
        external
        virtual
        override
        onlyOnAvailableSpender(_spender)
        returns (bool)
    {
        bytes32 approveHash = ongoingApproves.addApprove(
            securityTokenBalances,
            msg.sender,
            _spender,
            _value
        );
        emit ApproveRequest(approveHash, msg.sender, _spender, _value);
        return true;
    }

    /**
     * @dev Validates two-step transfer(cf IERC20Adapter) and sends corresponding `TransferValidated` event
     * NB: Only the registrar can call this method
     */
    function validateTransfer(bytes32 transferHash)
        external
        override
        onlyRegistrar
        returns (bool)
    {
        ongoingTransfers.validateTransfer(securityTokenBalances, transferHash);
        emit TransferValidated(transferHash);
        return true;
    }

    /**
     * @dev Rejects two-step transfer(cf IERC20Adapter) and sends corresponding `TransferRejected` event
     * Unlocks token if simple transfer
     * Restore allowance if tranferFrom
     * NB: Only the registrar can call this method
     */
    function rejectTransfer(bytes32 transferHash)
        external
        override
        onlyRegistrar
        returns (bool)
    {
        ongoingTransfers.rejectTransfer(transferHash);
        TransferAdapterLibrary.Transfer
            memory transferRequest = ongoingTransfers.transfers[transferHash];
        if (transferRequest.isTransferFrom) {
            ongoingApproves.allowances[transferRequest.from][
                transferRequest.spender
            ] += transferRequest.value;
        } else {
            securityTokenBalances.unlock(
                transferRequest.from,
                transferRequest.value
            );
        }
        emit TransferRejected(transferHash);
        return true;
    }

    /**
     * @dev Validates two-step approve(cf IERC20Adapter) and sends corresponding `ApproveValidated` event
     * NB: Only the registrar can call this method
     */
    function validateApprove(bytes32 approveHash)
        external
        override
        onlyRegistrar
        returns (bool)
    {
        ongoingApproves.validateApprove(approveHash);
        ApproveAdapterLibrary.Approve memory approveRequest = ongoingApproves
            .approves[approveHash];
        emit Approval(
            approveRequest.owner,
            approveRequest.spender,
            approveRequest.value
        );
        emit ApproveValidated(approveHash);
        return true;
    }


    /**
     * @dev Rejects two-step transfer(cf IERC20Adapter) and sends corresponding `ApproveRejected` event
     * NB: Only the registrar can call this method
     */
    function rejectApprove(bytes32 approveHash)
        external
        override
        onlyRegistrar
        returns (bool)
    {
        ongoingApproves.rejectApprove(securityTokenBalances, approveHash);
        emit ApproveRejected(approveHash);
        return true;
    }

    /**
     * @dev Returns current allowance for provided `owner` and `spender`
     */
    function allowance(address owner, address spender)
        external
        view
        override
        returns (uint256)
    {
        return ongoingApproves.allowance(owner, spender);
    }

    /**
     * @dev Initiates two-step transferFrom(cf IERC20Adapter) and sends corresponding `TransferRequest` event
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        bytes32 transferHash = ongoingApproves.transferFrom(
            securityTokenBalances,
            ongoingTransfers,
            msg.sender,
            from,
            to,
            amount
        );
        emit TransferRequest(transferHash, msg.sender, to, amount);
        return true;
    }

    /**
     * @dev Security tokens are not divisible.
     * Only an integer number of tokens can be manipulated
     */
    function decimals() public pure returns (uint8) {
        return 0;
    }

    /**
     * @dev Burn the given `quantity` of tokens
     * The product's totalSupply is updated accordingly.
     * NB : only the product's registrar can call this method
     */
    function burn(uint256 quantity) public onlyRegistrar {
        internalBurn(issuer.account, quantity);        
    }

    function internalBurn(address account, uint256 quantity) internal {
        securityTokenBalances.burn(account, quantity);
        seriesRedeemedAmountCent += quantity * denominationCent;
        recomputeTotalSupply();
    }

    // IBasicToken
    /**
     * @dev Returns all balances as an array of Balance structures(including total and locked balance)
     */
    function getFullBalances()
        public
        view
        returns (SecurityTokenBalancesLibrary.Balance[] memory value)
    {
        return securityTokenBalances.getFullBalances();
    }

    /**
     * @dev Returns balance of `owner` as a Balance structures(including total and locked balance)
     */
    function getFullBalance(address owner)
        public
        view
        returns (SecurityTokenBalancesLibrary.Balance memory value)
    {
        return securityTokenBalances.getFullBalance(owner);
    }

    /**
     * @dev Returns balance of `owner` (this is the total balance, which includes locked tokens)
     */
    function getBalance(address _address) public view returns (uint256 value) {
        return securityTokenBalances.getBalance(_address);
    }

    /**
     * @dev Allows to update the STR's URL
     * NB : only the product's registrar can call this method
     */
    function setStrUrl(string memory _strUrl) public onlyRegistrar {
        strUrl = _strUrl;
    }

    // ISettlement
    /**
     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)
     * and sends the corresponding `SubscriptionInitiated` event
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     * NB : only the product's registrar can call this method
     * NB : the call fails if the product has previously been redeemed
     */
    function initiateSubscription(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) public override onlyRegistrar onlyNotRedeemedProduct {
        SettlementWorkflowLibrary.initiateSubscription(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransaction
        );
        state = ProductState.Running;
        emit SubscriptionInitiated(partialSettlementTransaction.txId);
    }

    /**
     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)
     * and sends the corresponding `TradeInitiated` event
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     * NB : only the product's registrar can call this method
     * NB : the call fails if the product has previously been redeemed
     */
    function initiateTrade(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) public override onlyRegistrar onlyNotRedeemedProduct {
        SettlementWorkflowLibrary.initiateTrade(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransaction
        );
        state = ProductState.Running;
        emit TradeInitiated(partialSettlementTransaction.txId);
    }

    /**
     * @dev Execute unilateral Transfer Settlement Transactions 
     * and sends the corresponding `TransferExecuted` event
     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled
     * NB : only the product's registrar can call this method
     */
    function executeTransfer(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) external override onlyRegistrar onlyNotRedeemedProduct{
        SettlementWorkflowLibrary.executeTransfer(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransaction
        );
        settlementTransactionRepository.setSettlementTransactionStatus(
            partialSettlementTransaction.txId,
            SettlementRepositoryLibrary.SettlementTransactionStatus.Settled
        );
        emit TransferExecuted(partialSettlementTransaction.txId);
    }

    /**
     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)
     * and sends the corresponding `RedemptionInitiated` event
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     * NB : only the product's registrar can call this method
     * NB : the call fails if the product has previously been redeemed
     * NB : extended data in the form of JSON string can be associated with this operation
     */
    function initiateRedemption(
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            memory partialSettlementTransactions,
        string memory extendedData
    ) public override onlyRegistrar onlyNotRedeemedProduct {
        uint256[] memory ids = new uint256[](
            partialSettlementTransactions.length
        );

        SettlementWorkflowLibrary.initiateRedemption(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransactions
        );

        uint256 operationId = partialSettlementTransactions[0].operationId;
        operationExtendedDataJson[operationId] = extendedData;

        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {
            ids[i] = partialSettlementTransactions[i].txId;
        }
        state = ProductState.Redeemed;
        emit RedemptionInitiated(ids);
    }

    /**
     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)
     * and sends the corresponding `CouponInitiated` event
     * NB: the tokens are not locked for this kind of transaction
     * NB : only the product's registrar can call this method
     * NB : the call fails if the product has previously been redeemed
     * NB : extended data in the form of JSON string can be associated with this operation
     */
    function initiateCoupon(
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            memory partialSettlementTransactions,
        string memory extendedData
    ) public override onlyRegistrar onlyNotRedeemedProduct {
        uint256[] memory ids = new uint256[](
            partialSettlementTransactions.length
        );

        SettlementWorkflowLibrary.initiateCoupon(
            settlementTransactionRepository,
            partialSettlementTransactions
        );

        uint256 operationId = partialSettlementTransactions[0].operationId;
        operationExtendedDataJson[operationId] = extendedData;

        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {
            ids[i] = partialSettlementTransactions[i].txId;
        }
        emit CouponInitiated(ids);
    }

    /**
     * @dev Confirms that the payment for Settlement Transaction with id `_settlementTransactionId` was received
     * and sends the corresponding `PaymentReceived` event
     * The tokens are actually transferred to the recipient (except for Coupon where no token is exchanged)
     * If the Settlement Transaction is part of a Redemption operation, the tokens are burnt right after being transferred back to the issuer.
     * The Settlement Transaction state moves to Processed
     * The call fails if the Settlement Transaction with id `_settlementTransactionId` is not found in the repository
     * The call fails if the Settlement Transaction is not in the Acknowledged state.
     * NB : only the product's settlement agent can call this method
     */
    function confirmPaymentReceived(uint256 _settlementTransactionId)
        external
        override
        settlerOnly
    {
        SettlementRepositoryLibrary.SettlementTransaction
            memory settlementTransaction = settlementTransactionRepository
                .getSettlementTransactionById(_settlementTransactionId);
        if (
            settlementTransaction.operationType ==
            SettlementRepositoryLibrary.OperationType.Undefined
        ) revert InvalidOperationType();
        _handleConfirmPaymentReceived(_settlementTransactionId);
    }

    /**
     * @dev Internal method that does the actual job of `confirmPaymentReceived`
     */
    function _handleConfirmPaymentReceived(uint256 settlementTransactionId)
        internal
    {
        SettlementRepositoryLibrary.SettlementTransaction
            memory st = settlementTransactionRepository
                .getSettlementTransactionById(settlementTransactionId);

        if (
            st.status !=
            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged
        ) revert SettlementTransactionNotInAcknowledgedState();

        if (
            st.operationType != SettlementRepositoryLibrary.OperationType.Coupon
        ) {
            securityTokenBalances.transferLocked(
                st.deliverySenderAccountNumber,
                st.deliveryReceiverAccountNumber,
                st.deliveryQuantity
            );
        }

        if (
            st.operationType ==
            SettlementRepositoryLibrary.OperationType.Redemption
        ) {
            internalBurn(
                st.deliveryReceiverAccountNumber,
                st.deliveryQuantity
            );
        }

        settlementTransactionRepository.setSettlementTransactionStatus(
            settlementTransactionId,
            SettlementRepositoryLibrary.SettlementTransactionStatus.Processed
        );
        emit PaymentReceived(settlementTransactionId, st.operationType);
    }

    /**
     * @dev Confirms that the payment for Settlement Transaction with id `_settlementTransactionId` was transferred to the recipient
     * and sends the corresponding `PaymentTransferred` event
     * The Settlement Transaction state moves to Settled
     * The call fails if the Settlement Transaction with id `_settlementTransactionId` is not found in the repository
     * The call fails if the Settlement Transaction is not in the Processed state.
     * NB : only the product's settlement agent can call this method
     */
    function confirmPaymentTransferred(uint256 _settlementTransactionId)
        external
        override
        settlerOnly
    {
        _handleConfirmPaymentTransferred(_settlementTransactionId);
    }

    /**
     * @dev Internal method that does the actual job of `confirmPaymentTransferred`
     */
    function _handleConfirmPaymentTransferred(uint256 _settlementTransactionId)
        internal
    {
        SettlementRepositoryLibrary.SettlementTransaction
            memory st = settlementTransactionRepository
                .getSettlementTransactionById(_settlementTransactionId);
        if (
            st.operationType ==
            SettlementRepositoryLibrary.OperationType.Undefined
        ) revert InvalidOperationType();
        if (
            st.status !=
            SettlementRepositoryLibrary.SettlementTransactionStatus.Processed
        ) revert SettlementTransactionNotInProcessedState();

        settlementTransactionRepository.setSettlementTransactionStatus(
            _settlementTransactionId,
            SettlementRepositoryLibrary.SettlementTransactionStatus.Settled
        );

        emit PaymentTransferred(_settlementTransactionId, st.operationType);
    }

    
    /**
     * @dev Returns the details of Settlement Transaction with id `_settlementTransactionId`
     */
    function getSettlementTransaction(uint256 _settlementTransactionId)
        external
        view
        returns (SettlementRepositoryLibrary.SettlementTransaction memory)
    {
        return
            settlementTransactionRepository.getSettlementTransactionById(
                _settlementTransactionId
            );
    }

    /**
     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`
     * and sends the corresponding `SettlementTransactionCancelled` event
     * Unlocks tokens
     * Fails if the settlement transaction is not in the Acknowledged state.
     * NB : only the product's registrar can call this method     *  
     */
    function cancelSettlementTransaction(uint256 settlementTransactionId)
        public
        override
        onlyRegistrar
    {
        SettlementWorkflowLibrary.cancelSettlementTransaction(
            settlementTransactionRepository,
            securityTokenBalances,
            settlementTransactionId
        );

        emit SettlementTransactionCancelled(settlementTransactionId);
    }

    /**
     * @dev Internal function that recomputes the totalSupply when it changes (mint/burn)
     * 
     */
    function recomputeTotalSupply() internal {
        seriesOutstandingNominalAmountCent =
            seriesNominalAmountCent -
            seriesRedeemedAmountCent;
        totalSupply = seriesOutstandingNominalAmountCent / denominationCent;
    }

    /**
     * @dev Internal function that adds a new tranche and updates aggregated amounts accordingly.
     * 
     */
    function internalCreateTranche(Tranche memory newTranche) internal {
        tranches.push(newTranche);
        seriesNominalAmountCent += newTranche.nominalAmountCent;
        recomputeTotalSupply();
    }

    /**
     * @dev Issue a new tranche of tokens for the same product
     * Mints the corresponding number of tokens
     * The product's totalSupply is updated accordingly.
     * NB : only the product's registrar can call this method
     */
    function createTranche(Tranche memory newTranche) public onlyRegistrar {
        securityTokenBalances.mint(issuer.account, newTranche.nominalAmountCent / denominationCent);
        internalCreateTranche(newTranche);
    }
}

File 2 of 17 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 3 of 17 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 4 of 17 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 5 of 17 : IERC20Adapter.sol
pragma solidity 0.8.17;

/**
 * @dev IERC20Adapter is an interface allowing to (mostly) comply with the ERC20 standard while remaining compliant with 
 * the financial regulations(mostly KYC and due dilligence obligations).
 * Each call to transfer()/transferFrom() or approve() has to be reviewed by *some* validator authority before either proceeding (by calling validateTransfer()
 * /validateApprove()) or cancelling (by calling rejectTransfer()/rejectApprove())
 * see TransferAdapterLibrary and ApproveAdapteLibrary for implementation.
 */
interface IERC20Adapter {
    /**
     * @dev Initiate a transfer request. Same semantic as ERC20's transfer function although the transfer
     * will only actually occur once reviewed by validator(who will call validateTransfer)
     */
    function transfer(address _to, uint256 _value) external returns (bool);

    /**
     * @dev Actually performs the transfer request corresponding to the given `transferHash`
     * Called by the validator authority
     */
    function validateTransfer(bytes32 transferHash) external returns (bool);

    /**
     * @dev Rejects(and thus, actually cancels) the transfer request corresponding to the given `transferHash`
     * Called by the validator authority
     */
    function rejectTransfer(bytes32 transferHash) external returns (bool);

    /**
     * @dev Initiate an approve request. Same semantic as ERC20's approve function although the approve
     * will only actually occur once reviewed by validator(who will call validateApprove)
     */
    function approve(address _spender, uint256 _value) external returns (bool);

    /**
     * @dev Same semantic as ERC20's allowance function
     */
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    /**
     * @dev Initiate a transferFrom request. Same semantic as ERC20's transferFrom function although the transferFrom
     * will only actually occur once reviewed by validator(who will call validateTransfer)
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Actually performs the approve request corresponding to the given `transferHash`
     * Called by the validator authority
     */
    function validateApprove(bytes32 approveHash) external returns (bool);

    /**
     * @dev Rejects(and thus, actually cancels) the approve request corresponding to the given `transferHash`
     * Called by the validator authority
     */
    function rejectApprove(bytes32 approveHash) external returns (bool);

    /**
     * @dev Emitted when a transfer actuelly occurs(that is, when validateTransfer() is called by the validator authority
     */
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    /**
     * @dev Emitted when an approve request is initiated
     */
    event ApproveRequest(
        bytes32 approveHash,
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    /**
     * @dev Emitted when an approve request is rejected
     */
    event ApproveRejected(bytes32 approveHash);
    /**
     * @dev Emitted when an approve request is validated
     */
    event ApproveValidated(bytes32 approveHash);
    /**
     * @dev Emitted when an approve actually occurs(that is, when validateApprove() is called by the validator authority
     */
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
    /**
     * @dev Emitted when a transfer request is initiated
     */
    event TransferRequest(
        bytes32 transferHash,
        address indexed from,
        address indexed to,
        uint256 value
    );
    /**
     * @dev Emitted when a transfer request is rejected
     */
    event TransferRejected(bytes32 transferHash);
    /**
     * @dev Emitted when a transfer request is validated
     */
    event TransferValidated(bytes32 transferHash);
}

File 6 of 17 : IProduct.sol
pragma solidity 0.8.17;

/**
 * @dev This interface mostly lists all structures used by the Product contract
 */

// Maybe add common functions for products
interface IProduct {
    /**
     * @dev Details of a legal entity
     */
    struct LegalEntity {
        /**
         * @dev Legal Entity Identifier of the legal entity
        */
        string lei;
        /**
         * @dev Account address of the legal entity
         */
        address account;
    }

    /**
     * @dev Describes an issuance tranche
    */
    struct Tranche {
        uint256 nominalAmountCent;
        uint256 issueDate;
    }

    /**
     * @dev Represents a simple balance with value `balance` for address `account`
     */
    struct InitBalance {
        address account;
        uint256 balance;
    }
    // pourquoi pas dans ISettlement ?
    event TransferExecuted(uint256 settlementTransactionId);

    /**
     * @dev This structure describes the parameters of the product to create/issue
     * Most parameters are financial characteristics of the product
     */
    struct BasicProductInput {
        /**
         * @dev The balances to setup at the contract's creation
         * Used when migrating from an existing contract with existing balances
         */
        InitBalance[] initialBalances;
        /**
         * @dev The details of the initial issuance tranches
         */
        Tranche[] initialTranches;
        /**
         * @dev The address of a previous contract that is replaced with this one (allows to keep track of successive contract migrations)
         */
        address previousContract;
        /**
         * @dev FIGI code of the product(optional)
         */
        string figi;
        /**
         * @dev JSON string of extended information about the product. Can be roughly anything.
         * Will be used to hold financial information specific to a some products.
         */
        string extendedDataJson;
        /**
         * @dev String holding ESG information about the product (JSON format)
         */
        string esg;
        /**
         * @dev This product's note status
         */
        string noteStatus;
        /**
         * @dev This product's form of the node (e.g. Registered)
         */
        string formOfNote;
        /**
         * @dev Name of the issuance series (a group of tranches)
         */
        string series;
        /**
         * @dev The issuer's issuance program this product is part of
         */
        string program;
        /**
         * @dev The URL of the Settlement Transaction Repository that gives access to confidential information in the Settlement Transactions
         */
        string strUrl;
        /**
         * @dev The type of the financial product
         */
        string productType;
        /**
         * @dev Details of the product's guarantor legal entity
         */
        LegalEntity guarantor;
        /**
         * @dev Details of the product's issuer legal entity
         */
        LegalEntity issuer;
        /**
         * @dev Details of the product's paying agent legal entity
         */
        LegalEntity payingAgent;
        /**
         * @dev Details of the product's settlement agent legal entity
         */
        LegalEntity settlementAgent;
        /**
         * @dev Details of the product's registrar legal entity
         */
        LegalEntity registrar;
        /**
         * @dev The product's currency
         */
        string currency;
        /**
         * @dev The address of the IProductRegistry where the product should be listed
         */
        address registryAddress;
        /**
         * @dev String describing the market places where the product is listed
         */
        string listing;
        /**
         * @dev The governing law of the product
         */
        string governingLaw;
        /**
         * @dev The product's maturity date
         */
        uint256 maturityDate;
        /**
         * @dev The product's denomination in cents
         */
        uint256 denominationCent;
        /**
         * @dev The product's symbol
         */
        string symbol;
        /**
         * @dev The product's name
         */
        string name;
        /**
         * @dev The product's ISIN code
         */
        string isinCode;
    }
}

File 7 of 17 : ISettlement.sol
pragma solidity 0.8.17;

import "../libraries/SettlementRepositoryLibrary.sol";

/**
 * @dev This interface lists the methods allowing to initiate and settle so-called Settlement Transaction.
 * Please refer to CAST framework's whitepaper for details about what Settlement Transactions are
 */
interface ISettlement {
    /**
     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateSubscription(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            calldata partialSettlementTransaction
    ) external;

    /**
     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateTrade(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            calldata partialSettlementTransaction
    ) external;

    /**
     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateRedemption(
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            calldata settlementTransaction,
        string calldata extendedData
    ) external;

    /**
     * @dev Execute unilateral Transfer Settlement Transactions 
     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled
     */
    function executeTransfer(
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) external;

    /**
     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)
     * NB: the tokens are not locked for this kind of transaction
     */
    function initiateCoupon(
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            calldata settlementTransaction,
        string calldata extendedData
    ) external;

    /**
     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`
     */
    function cancelSettlementTransaction(uint256 settlementTransactionId)
        external;

    /**
     * @dev Confirms that the payment for Settlement Transaction with id `settlementTransactionId` was correctly received
     * (by the settlement agent). The tokens are unlocked and transferred to the buyer. Settlement Transaction's status moves to Processed
     */
    function confirmPaymentReceived(uint256 settlementTransactionId) external;

    /**
     * @dev Confirms that the payment for Settlement Transaction with id `settlementTransactionId` was correctly transferred to the seller
     * (by the settlement agent). Settlement Transaction's status moves to Settled
     */
    function confirmPaymentTransferred(uint256 settlementTransactionId)
        external;

    /**
     * @dev Emitted when Subscription Settlement Transaction with id `settlementTransactionId` was initiated.
     */
    event SubscriptionInitiated(uint256 settlementTransactionId);
    /**
     * @dev Emitted when Trade Settlement Transaction with id `settlementTransactionId` was initiated.
     */
    event TradeInitiated(uint256 settlementTransactionId);
    /**
     * @dev Emitted when Redemption Settlement Transactions with ids `settlementTransactionIds` were initiated.
     */
    event RedemptionInitiated(uint256[] settlementTransactionIds);
    /**
     * @dev Emitted when Coupon Settlement Transactions with ids `settlementTransactionId`s were initiated.
     */
    event CouponInitiated(uint256[] settlementTransactionIds);
    /**
     * @dev Emitted when payment for Settlement Transaction with id `settlementTransactionId` was reported as received
     */
    event PaymentReceived(
        uint256 settlementTransactionId,
        SettlementRepositoryLibrary.OperationType settlementTransactionOperationType
    );
    /**
     * @dev Emitted when payment for Settlement Transaction with id `settlementTransactionId` was reported as transferred
     */
    event PaymentTransferred(
        uint256 settlementTransactionId,
        SettlementRepositoryLibrary.OperationType settlementTransactionOperationType
    );
    /**
     * @dev Emitted when Settlement Transaction with id `settlementTransactionId` was cancelled
     */
    event SettlementTransactionCancelled(uint256 settlementTransactionId);
}

File 8 of 17 : ApproveAdapterLibrary.sol
pragma solidity 0.8.17;

import "./EncodingUtils.sol";
import "./SecurityTokenBalancesLibrary.sol";
import "./TransferAdapterLibrary.sol";

import { ZeroAddressCheck, InvalidApproveStatus, OwnerHasOngoingApprove, ApproveDoesNotExists, InsufficientAllowance } from "../../utils/ProductErrorReporter.sol";

/**
 * @dev This library allows to handle two-step approves as described in IERC20Adapter
 */
library ApproveAdapterLibrary {
    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;
    using TransferAdapterLibrary for TransferAdapterLibrary.OngoingTransfers;

    /**
     * @dev The different status an approve request can have
     * Approve requests are initially in the `Created` state
     * If validated by the validator authority they move to the `Validated` state, which is a final state
     * If rejected by the validator authority they move to the `Rejected` state, which is a final state
     * 
     */
    enum ApproveStatus {
        Undefined,
        Created,
        Validated,
        Rejected
    }

    /**
     * @dev The details of an approve request
     */
    struct Approve {
        /**
        * @dev The address of the owner 
        */
        address owner;
        /**
        * @dev The address of the spender 
        */
        address spender;
        /**
        * @dev The number of tokens that the spender is allowed to spend
        */
        uint256 value;
        /**
        * @dev The status of the approve request
        */
        ApproveStatus status;
    }

    /**
     * @dev Structure containing all ongoing approve requests
     * Requests are indexed by the hash of their content
    */
    struct OngoingApproves {
        mapping(bytes32 => Approve) approves;
        /**
        * @dev Counter of requests, allowing all request to be unique
        */
        uint256 counter;
        /**
        * @dev Current allowances indexed by owner address, then by spender address
        */
        mapping(address => mapping(address => uint256)) allowances;
        /**
        * @dev Boolean indicating for a couple (owner,spender) whether there is an ongoing approve request
        * This enables to reject approve request really if there is already an ongoing approve request for the same (owner, spender), thus
        * avoiding complex issues
        */
        mapping(address => mapping(address => bool)) hasOngoingApprove;
    }

    /**
     * @dev Initiates an approve request
     * If the requested allowance is less than current allowance, the excess tokens are unlocked
     * If the requested allowance is more than current allowance, the excess tokens are locked
     * NB : as the allowance is first reset to 0, the allowance will stay 0 is the request is rejected.
     * This is by design and not a bug.
    */
    function addApprove(
        OngoingApproves storage self,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        address owner,
        address spender,
        uint256 value
    ) public returns (bytes32) {
        if (owner == address(0)) revert ZeroAddressCheck();
        if (spender == address(0)) revert ZeroAddressCheck();
        uint256 currentAllowedAmount = self.allowances[owner][spender];
        if (currentAllowedAmount > value) {
            securityTokenBalances.unlock(owner, (currentAllowedAmount - value));
        } else if (currentAllowedAmount < value) {
            securityTokenBalances.lock(owner, (value - currentAllowedAmount));
        }
        self.allowances[owner][spender] = 0; // reset allowance
        bytes32 approveHash = EncodingUtils.encodeRequest(
            owner,
            spender,
            value,
            self.counter
        );
        self.approves[approveHash] = Approve(
            owner,
            spender,
            value,
            ApproveStatus.Created
        );
        self.hasOngoingApprove[owner][spender] = true;
        self.counter += 1;

        return approveHash;
    }

    /**
     * @dev Validates an approve request
     * Provided there is a matching approve request in state Created, the approve is performed (that is, the allowance is set to the target
     * value, and the approve request status moves to Validated)
    */
    function validateApprove(OngoingApproves storage self, bytes32 approveHash)
        public
    {
        Approve storage approve = self.approves[approveHash];
        if (approve.status == ApproveStatus.Undefined)
            revert ApproveDoesNotExists();
        if (approve.status != ApproveStatus.Created)
            revert InvalidApproveStatus();
        self.allowances[approve.owner][approve.spender] = approve.value;
        self.hasOngoingApprove[approve.owner][approve.spender] = false;
        self.approves[approveHash].status = ApproveStatus.Validated;
    }

    /**
     * @dev Rejects an approve request
     * Provided there is a matching approve request in state Created, the approve is cancelled (that is, the tokens are unlocked
     * , and the approve request status moves to Validated)
     * NB: after the request has be rejected, the allowance is 0 (and not the allowance that existed before the request was sent), this
     * is by design and not a bug
    */
    function rejectApprove(
        OngoingApproves storage self,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        bytes32 approveHash
    ) public {
        Approve memory approve = self.approves[approveHash];
        if (approve.status == ApproveStatus.Undefined)
            revert ApproveDoesNotExists();
        if (approve.status != ApproveStatus.Created)
            revert InvalidApproveStatus();
        securityTokenBalances.unlock(approve.owner, approve.value);
        self.hasOngoingApprove[approve.owner][approve.spender] = false;
        self.approves[approveHash].status = ApproveStatus.Rejected;
    }

    /**
     * @dev Initiates a transferFrom request
     * This code is here to enable checking the allowance before accepting request
    */
    function transferFrom(
        OngoingApproves storage self,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        TransferAdapterLibrary.OngoingTransfers storage ongoingTransfers,
        address spender,
        address from,
        address to,
        uint256 value
    ) public returns (bytes32) {
        uint256 currentAmount = self.allowances[from][spender];
        if (currentAmount < value) revert InsufficientAllowance();
        self.allowances[from][spender] -= value;
        bytes32 transferHash = ongoingTransfers.addTransfer(
            securityTokenBalances,
            from,
            to,
            value,
            true, // isTransferFrom
            spender
        );
        return transferHash;
    }

    /**
     * @dev Returns current allowance for `owner` and `spender`
    */
    function allowance(
        OngoingApproves storage self,
        address owner,
        address spender
    ) public view returns (uint256) {
        return self.allowances[owner][spender];
    }
}

File 9 of 17 : EncodingUtils.sol
pragma solidity 0.8.17;

library EncodingUtils {
    /**
     * @dev Computes the hash of a tranfer or approve request
     * Enables to index requests in mappings
     */
    function encodeRequest(
        address _from,
        address _to,
        uint256 _value,
        uint256 counter
    ) internal view returns (bytes32) {
        return
            keccak256(abi.encode(block.timestamp, _from, _to, _value, counter));
    }
}

File 10 of 17 : IterableBalances.sol
pragma solidity 0.8.17;

error KeyNotInBalances();

/**
 * @dev An iterable mapping of security token balances.
 * Handles total and locked balances (locked balance corresponds to tokens that are reserved for an ongoing Settlement Transaction)
 */
library IterableBalances {
    struct iterableBalances {
        mapping(address => Balance) balances;
        KeyFlag[] keys;
        uint256 size;
    }

    struct Balance {
        uint256 keyIndex;
        uint256 total;
        uint256 locked;
    }
    struct KeyFlag {
        address key;
        bool deleted;
    }

    function insert(
        iterableBalances storage self,
        address key,
        uint256 total
    ) public {
        uint256 keyIndex = self.balances[key].keyIndex;
        self.balances[key].total = total;

        if (keyIndex == 0) {
            keyIndex = self.keys.length;
            self.keys.push();
            self.balances[key].keyIndex = keyIndex + 1;
            self.keys[keyIndex].key = key;
            self.size++;
        }
    }

    function remove(iterableBalances storage self, address key) public {
        uint256 keyIndex = self.balances[key].keyIndex;

        if (keyIndex == 0) revert KeyNotInBalances();

        delete self.balances[key];
        self.keys[keyIndex - 1].deleted = true;
        self.size--;
    }

    function contains(iterableBalances storage self, address key)
        public
        view
        returns (bool)
    {
        return self.balances[key].keyIndex > 0;
    }

    function iterate_start(iterableBalances storage self)
        public
        view
        returns (uint256 keyIndex)
    {
        return iterate_next(self, type(uint256).max);
    }

    function iterate_valid(iterableBalances storage self, uint256 keyIndex)
        public
        view
        returns (bool)
    {
        return keyIndex < self.keys.length;
    }

    function iterate_next(iterableBalances storage self, uint256 keyIndex)
        public
        view
        returns (uint256 r_keyIndex)
    {
        unchecked {
            keyIndex++;
        }

        while (keyIndex < self.keys.length && self.keys[keyIndex].deleted) {
            keyIndex++;
        }

        return keyIndex;
    }

    function iterate_get(iterableBalances storage self, uint256 keyIndex)
        public
        view
        returns (
            address key,
            uint256 total,
            uint256 locked
        )
    {
        key = self.keys[keyIndex].key;
        total = self.balances[key].total;
        locked = self.balances[key].locked;
    }

}

File 11 of 17 : SecurityTokenBalancesLibrary.sol
pragma solidity 0.8.17;
import "./IterableBalances.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

import { InsufficientDisposableBalance, InsufficientBalance, InsufficientLockedBalance } from "../../utils/ProductErrorReporter.sol";

/// @dev Models a address -> uint mapping where it is possible to iterate over all keys.
library SecurityTokenBalancesLibrary {
    using IterableBalances for IterableBalances.iterableBalances;
    using SafeMath for uint256;

    struct SecurityTokenBalances {
        address issuer;
        IterableBalances.iterableBalances iterableBalances;
    }
    modifier onlyWhenBalanceDisposable(
        SecurityTokenBalances storage self,
        address _from,
        uint256 _value
    ) {
        if (
            self.iterableBalances.balances[_from].total -
                self.iterableBalances.balances[_from].locked <
            _value
        ) revert InsufficientDisposableBalance();
        _;
    }
    struct Balance {
        address account;
        uint256 total;
        uint256 locked;
    }

    event Transfer(address indexed _from, address indexed _to, uint256 _value); // Only for erc20 explorer

    function setIssuer(SecurityTokenBalances storage self, address key) public {
        self.issuer = key;
    }

    function mint(
        SecurityTokenBalances storage self,
        address key,
        uint256 balance
    ) public {
        self.iterableBalances.insert(key, balance);
        emit Transfer(0x0000000000000000000000000000000000000000, key, balance);
    }

    function lock(
        SecurityTokenBalances storage self,
        address key,
        uint256 valueToLock
    ) public onlyWhenBalanceDisposable(self, key, valueToLock) {
        self.iterableBalances.balances[key].locked += valueToLock;
    }

    function unlock(
        SecurityTokenBalances storage self,
        address key,
        uint256 valueToUnlock
    ) public {
        if (self.iterableBalances.balances[key].total < valueToUnlock)
            revert InsufficientBalance();
        if (self.iterableBalances.balances[key].locked < valueToUnlock)
            revert InsufficientLockedBalance();

        self.iterableBalances.balances[key].locked -= valueToUnlock;
    }

    function burn(
        SecurityTokenBalances storage self,
        address _from,
        uint256 _value
    ) public onlyWhenBalanceDisposable(self, _from, _value) {
        self.iterableBalances.balances[_from].total -= _value;

        emit Transfer(_from, address(0), _value);
    }

    function transferLocked(
        SecurityTokenBalances storage self,
        address _from,
        address _to,
        uint256 _value
    ) external {
        unlock(self, _from, _value);

        self.iterableBalances.balances[_from].total -= _value;

        self.iterableBalances.insert(
            _to,
            self.iterableBalances.balances[_to].total + _value
        );

        emit Transfer(_from, _to, _value);
    }

    // should check this of any security issue?
    function transfer(
        SecurityTokenBalances storage self,
        address _from,
        address _to,
        uint256 _value
    ) external onlyWhenBalanceDisposable(self, _from, _value) {
        self.iterableBalances.balances[_from].total -= _value;

        self.iterableBalances.insert(
            _to,
            self.iterableBalances.balances[_to].total + _value
        );

        emit Transfer(_from, _to, _value);
    }

    // rename to getTotalBalance()
    function getBalance(SecurityTokenBalances storage self, address _address)
        external
        view
        returns (uint256 balance)
    {
        return self.iterableBalances.balances[_address].total;
    }

    function getAvailableBalance(
        SecurityTokenBalances storage self,
        address _address
    ) external view returns (uint256 balance) {
        return
            self.iterableBalances.balances[_address].total -
            self.iterableBalances.balances[_address].locked;
    }

    function getFullBalance(
        SecurityTokenBalances storage self,
        address _address
    ) external view returns (Balance memory value) {
        return
            Balance(
                _address,
                self.iterableBalances.balances[_address].total,
                self.iterableBalances.balances[_address].locked
            );
    }

    function getFullBalances(SecurityTokenBalances storage self)
        public
        view
        returns (Balance[] memory value)
    {
        address tokenHolder = address(0);
        uint256 balance;
        uint256 locked;
        uint256 balancesSize = self.iterableBalances.size;
        Balance[] memory addressBalanceArray = new Balance[](balancesSize);
        for (
            uint256 index = self.iterableBalances.iterate_start();
            self.iterableBalances.iterate_valid(index);
            index = self.iterableBalances.iterate_next(index)
        ) {
            (tokenHolder, balance, locked) = self.iterableBalances.iterate_get(
                index
            );
            addressBalanceArray[index] = Balance(tokenHolder, balance, locked);
        }

        return addressBalanceArray;
    }
}

File 12 of 17 : SettlementRepositoryLibrary.sol
pragma solidity 0.8.17;

import "./SecurityTokenBalancesLibrary.sol";

import { NotSupportedTrustedToken, InvalidSettlementTransactionStatus, SettlementTransactionAlreadyExists } from "../../utils/ProductErrorReporter.sol";


/**
 * @dev This library handles the Settlement Transaction Repository which is the container for all
 * Settlement Transactions for a given product
 */
library SettlementRepositoryLibrary {
    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;
    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;

    /**
     * @dev The different status a Settlement Transaction can have
     * Settlement Transactions are initially in the `Created` state.
     * Once correctly initiated they move to the Acknowledged state.
     * When the payment of the cash leg (if any) is received by the settlement agent, they move to the Processed state
     * When the payment of the cash leg is transferred to the receiving end, they move to the Settled state, which is a final state.
     * Whenever a Settlement Transaction is cancelled, it moves to the Cancelled state, which is a final state
     */
    enum SettlementTransactionStatus {
        Undefined,
        Created,
        Acknowledged,
        Processed,
        Settled,
        Cancelled
    }

    /**
     * @dev The different operation types
     * Operation types is used to keep track of the type of business operation that a Settlement Transaction is part of.
     * Some business operations(e.g. Redemption) lead to several Settlement Transactions
     */
    enum OperationType {
        Undefined,
        Subscription,
        Redemption,
        Trade,
        Coupon,
        ExecuteTransfer
    }

    /**
     * @dev The actual Settlement Transaction Repository, which maps Settlement Transaction ids to Settlement Transaction details
     */
    struct SettlementTransactionRepository {
        mapping(uint256 => SettlementTransaction) settlementTransactionById; // mapping ( settlementtransactionId => settlementtransaction)
    }

    /**
     * @dev The details of a Settlement Transaction
     * NB: actually these are only the details that can be publicly disclosed on the blockchain
     * The confidential details are available on a public server called the STR, which URL is available in the strUrl field of the products
     */
    struct SettlementTransaction {
        /**
         * @dev The UUID of the Settlement Transaction(as an integer)
        */
        uint256 txId;
        /**
         * @dev Optional id of the business operation this Settlement Transaction is part of.
        */
        uint256 operationId;
        /**
         * @dev The address of counterparty that delivers the security tokens(a.k.a product)
        */
        address deliverySenderAccountNumber;
        /**
         * @dev The address of counterparty that receives the security tokens(a.k.a product)
        */
        address deliveryReceiverAccountNumber;
        /**
         * @dev The quantity of security tokens(a.k.a product) that should be delivered
        */
        uint256 deliveryQuantity;
        /**
         * @dev Hash of the Settlement Transaction details
        */
        string txHash;
        /**
         * @dev Current status of the Settlement Transaction
        */
        SettlementTransactionStatus status;
        /**
         * @dev The type of the business operation this Settlement Transaction is part of.
        */
        OperationType operationType;
    }

    /**
     * @dev Partial details of a Settlement Transaction that are passed when initiating the transaction
     */
    struct PartialSettlementTransaction {
        /**
         * @dev The UUID of the Settlement Transaction(as an integer)
        */
        uint256 txId;
        /**
         * @dev Optional id of the business operation this Settlement Transaction is part of.
        */
        uint256 operationId;
        /**
         * @dev The address of counterparty that delivers the security tokens(a.k.a product)
         * e.g the issuer for a Subscription operation, the investor for a Redemption operation, the seller for a Trade operation
        */
        address deliverySenderAccountNumber;
        /**
         * @dev The address of counterparty that receives the security tokens(a.k.a product)
         *  e.g the investor for a Subscription operation, the issuer for a Redemption operation, the buyer for a Trade operation
        */
        address deliveryReceiverAccountNumber;
        /**
         * @dev The quantity of security tokens(a.k.a product) that should be delivered
        */
        uint256 deliveryQuantity;
        /**
         * @dev Hash of the Settlement Transaction details
        */
        string txHash;
    }

    /**
     * @dev Returns the details of the Settlement Transaction with id `id`
     */
    function getSettlementTransactionById(
        SettlementTransactionRepository storage settlementTransactionRepository,
        uint256 id
    ) public view returns (SettlementTransaction memory) {
        SettlementTransaction
            memory settlementTransaction = settlementTransactionRepository
                .settlementTransactionById[id];

        return settlementTransaction;
    }

    /**
     * @dev Updates the status of Settlement Transaction with id `txId`
     */
    function setSettlementTransactionStatus(
        SettlementTransactionRepository storage settlementTransactionRepository,
        uint256 txId,
        SettlementTransactionStatus status
    ) internal {
        if (status == SettlementTransactionStatus.Undefined)
            revert InvalidSettlementTransactionStatus();

        SettlementTransaction
            storage settlementTransaction = settlementTransactionRepository
                .settlementTransactionById[txId];
        settlementTransaction.status = status;
    }

    /**
     * @dev Adds Settlement Transaction with given details to the repository.
     * NB : status is initialized to `Created`
     */
    function createSettlementTransaction(
        SettlementTransactionRepository storage settlementTransactionRepository,
        PartialSettlementTransaction memory partialSettlementTransaction,
        OperationType operationType
    )
        internal
    {
        if (
            settlementTransactionRepository
                .settlementTransactionById[partialSettlementTransaction.txId]
                .txId == partialSettlementTransaction.txId
        ) revert SettlementTransactionAlreadyExists();

        SettlementTransaction
            memory newSettlementTransaction = SettlementTransaction({
                txId: partialSettlementTransaction.txId,
                operationId: partialSettlementTransaction.operationId,
                deliverySenderAccountNumber: partialSettlementTransaction
                    .deliverySenderAccountNumber,
                deliveryReceiverAccountNumber: partialSettlementTransaction
                    .deliveryReceiverAccountNumber,
                deliveryQuantity: partialSettlementTransaction.deliveryQuantity,
                txHash: partialSettlementTransaction.txHash,
                status: SettlementTransactionStatus.Created,
                operationType: operationType
            });
        settlementTransactionRepository.settlementTransactionById[
            partialSettlementTransaction.txId
        ] = newSettlementTransaction;
    }
}

File 13 of 17 : SettlementWorkflowLibrary.sol
pragma solidity 0.8.17;

import "./SettlementRepositoryLibrary.sol";
import "./SecurityTokenBalancesLibrary.sol";

import { SettlementTransactionNotInAcknowledgedState, DeliveryReceiverAccountNumberNotMatchTokenIssuer, InvalidSettlementTransactionStatus } from "../../utils/ProductErrorReporter.sol";

/**
 * @dev This library handles the details of the different Settlement Transaction workflows
 */
library SettlementWorkflowLibrary {
    using SettlementRepositoryLibrary for SettlementRepositoryLibrary.SettlementTransactionRepository;
    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;

    /**
     * @dev Mutualizes code for initializing DVP-type Settlement Transactions.
     * DVP means Delivery Versus Payment, meaning that there are both a token leg and a cash leg
     * In this case the tokens have to be locked while awaiting payment confirmation by the settlement agent
     */
    function initiateDVP(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        uint256 settlementTransactionId
    ) public {
        SettlementRepositoryLibrary.SettlementTransaction
            memory st = settlementTransactionRepository
                .getSettlementTransactionById(settlementTransactionId);

        securityTokenBalances.lock(
            st.deliverySenderAccountNumber,
            st.deliveryQuantity
        );

        settlementTransactionRepository.setSettlementTransactionStatus(
            settlementTransactionId,
            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged
        );
    }

    /**
     * @dev Initiate a Subscription Settlement Transaction (counterparty buys product on primary market from the product's issuer)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateSubscription(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) public {
        settlementTransactionRepository.createSettlementTransaction(
            partialSettlementTransaction,
            SettlementRepositoryLibrary.OperationType.Subscription
        );

        initiateDVP(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransaction.txId
        );
    }

    /**
     * @dev Execute unilateral Transfer Settlement Transactions 
     * As there is no cash leg to settle, the tokens are transfered right away and the Settlement Transaction is marked as Settled
     */
    function executeTransfer(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) public {
        settlementTransactionRepository.createSettlementTransaction(
            partialSettlementTransaction,
            SettlementRepositoryLibrary.OperationType.ExecuteTransfer
        );
        securityTokenBalances.transfer(
            partialSettlementTransaction.deliverySenderAccountNumber,
            partialSettlementTransaction.deliveryReceiverAccountNumber,
            partialSettlementTransaction.deliveryQuantity
        );
    }

    /**
     * @dev Initiate a Trade Settlement Transaction (one counterparty buys, the other sells)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateTrade(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        SettlementRepositoryLibrary.PartialSettlementTransaction
            memory partialSettlementTransaction
    ) public {
        settlementTransactionRepository.createSettlementTransaction(
            partialSettlementTransaction,
            SettlementRepositoryLibrary.OperationType.Trade
        );

        initiateDVP(
            settlementTransactionRepository,
            securityTokenBalances,
            partialSettlementTransaction.txId
        );
    }

    /**
     * @dev Initiate a Redemption Settlement Transactions (issuer redeems product to all holders and gets the tokens back)
     * The tokens are locked waiting for the cash leg to settle (see functions confirmPaymentReceived/confirmPaymentTransferred)
     */
    function initiateRedemption(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            memory partialSettlementTransactions
    ) public {
        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {
            if (
                securityTokenBalances.issuer !=
                partialSettlementTransactions[i].deliveryReceiverAccountNumber
            ) revert DeliveryReceiverAccountNumberNotMatchTokenIssuer();

            settlementTransactionRepository.createSettlementTransaction(
                partialSettlementTransactions[i],
                SettlementRepositoryLibrary.OperationType.Redemption
            );

            initiateDVP(
                settlementTransactionRepository,
                securityTokenBalances,
                partialSettlementTransactions[i].txId
            );
        }
    }

    /**
     * @dev Initiate a Coupon Settlement Transactions (issuer pays coupon to all holders)
     * NB: the tokens are not locked for this kind of transaction
     */
    function initiateCoupon(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SettlementRepositoryLibrary.PartialSettlementTransaction[]
            memory partialSettlementTransactions
    ) public {
        for (uint256 i = 0; i < partialSettlementTransactions.length; i++) {
            settlementTransactionRepository.createSettlementTransaction(
                partialSettlementTransactions[i],
                SettlementRepositoryLibrary.OperationType.Coupon
            );
            settlementTransactionRepository.setSettlementTransactionStatus(
                partialSettlementTransactions[i].txId,
                SettlementRepositoryLibrary
                    .SettlementTransactionStatus
                    .Acknowledged
            );
        }
    }

    /**
     * @dev Cancels ongoing settlement transaction with id `settlementTransactionId`
     * Unlocks tokens
     * Fails if the settlement transaction is not in the Acknowledged state.
     */
    function cancelSettlementTransaction(
        SettlementRepositoryLibrary.SettlementTransactionRepository
            storage settlementTransactionRepository,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        uint256 settlementTransactionId
    ) public {
        SettlementRepositoryLibrary.SettlementTransaction
            memory settlementTransaction = settlementTransactionRepository
                .settlementTransactionById[settlementTransactionId];

        if (
            settlementTransaction.status !=
            SettlementRepositoryLibrary.SettlementTransactionStatus.Acknowledged
        ) revert SettlementTransactionNotInAcknowledgedState();

        securityTokenBalances.unlock(
            settlementTransaction.deliverySenderAccountNumber,
            settlementTransaction.deliveryQuantity
        );
        settlementTransactionRepository.setSettlementTransactionStatus(
            settlementTransactionId,
            SettlementRepositoryLibrary.SettlementTransactionStatus.Cancelled
        );
    }
}

File 14 of 17 : TransferAdapterLibrary.sol
pragma solidity 0.8.17;

import "./EncodingUtils.sol";
import "./SecurityTokenBalancesLibrary.sol";

import { ZeroAddressCheck, TransferRequestNotFound, InvalidTransferRequestStatus } from "../../utils/ProductErrorReporter.sol";

/**
 * @dev This library allows to handle two-step transfers as described in IERC20Adapter
 */
library TransferAdapterLibrary {
    using SecurityTokenBalancesLibrary for SecurityTokenBalancesLibrary.SecurityTokenBalances;

    /**
     * @dev The different status a transfer request can have
     * Transfer requests are initially in the `Created` state
     * If validated by the validator authority they move to the `Validated` state, which is a final state
     * If rejected by the validator authority they move to the `Rejected` state, which is a final state
     * 
     */
    enum TransferStatus {
        Undefined,
        Created,
        Validated,
        Rejected
    }

    /**
     * @dev The details of a transfer request
     */
    struct Transfer {
        /**
        * @dev The source address of the transfer 
        */
        address from;
        /**
        * @dev The destination address of the transfer 
        */
        address to;
        /**
        * @dev The number of tokens to transfer
        */
        uint256 value;
        /**
        * @dev The status of the transfer request
        */
        TransferStatus status;
        /**
        * @dev Whether this is a transferFrom request (i.e. allowance will be consumed)
        */
        bool isTransferFrom;
        /**
        * @dev Address of the spender address, in case of transferFrom request
        */
        address spender;
    }

    /**
     * @dev Structure containing all ongoing transfer requests
     * Requests are indexed by the hash of their content
    */
    struct OngoingTransfers {
        mapping(bytes32 => Transfer) transfers;
        uint256 counter;
    }

    /**
     * @dev Initiates a transfer request
     * If simple transfer request, the tokens are locked, awaiting either validation or rejection by the validator authority
     * If transferFrom, the tockens where already locked when the approve request was done
    */
    function addTransfer(
        OngoingTransfers storage self,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        address from,
        address to,
        uint256 value,
        bool isTransferFrom,
        address spender
    ) public returns (bytes32) {
        if (from == address(0)) revert ZeroAddressCheck();
        if (to == address(0)) revert ZeroAddressCheck();
        if (!isTransferFrom) {
            securityTokenBalances.lock(from, value);
        }
        bytes32 transferHash = EncodingUtils.encodeRequest(
            from,
            to,
            value,
            self.counter
        );
        self.transfers[transferHash] = Transfer(
            from,
            to,
            value,
            TransferStatus.Created,
            isTransferFrom,
            spender
        );
        self.counter += 1;
        return transferHash;
    }

    /**
     * @dev Validates a transfer request
     * Provided there is a matching transfer request in state Created, the transfer is performed (that is, the tokens are
     * transferred to the destination address, and unlocked, and the transfer request status moves to Validated)
    */
    function validateTransfer(
        OngoingTransfers storage self,
        SecurityTokenBalancesLibrary.SecurityTokenBalances
            storage securityTokenBalances,
        bytes32 transferHash
    ) public {
        Transfer storage transfer = self.transfers[transferHash];
        if (transfer.status == TransferStatus.Undefined)
            revert TransferRequestNotFound();
        if (transfer.status != TransferStatus.Created)
            revert InvalidTransferRequestStatus();
        securityTokenBalances.transferLocked(
            transfer.from,
            transfer.to,
            transfer.value
        );
        transfer.status = TransferStatus.Validated;
    }

    /**
     * @dev Rejects a transfer request
     * Provided there is a matching transfer request in state Created, the transfer is cancelled (that is, the transfer request staus moves 
     * to Rejected)
     * NB : due to the complexity of the token unlocking logic (depending on whether the transfer request was a transferFrom or not, either
     * the tokens should be unlocked (simple transfer) or the previous allowance should be restored (transferFrom)) and to avoid complex 
     * inter-dependency between ApproveAdapterLibrary and TransferAdapterLibrary, this logic is perform directly in Product.rejectTransfer
    */
    function rejectTransfer(OngoingTransfers storage self, bytes32 transferHash)
        public
    {
        Transfer storage transfer = self.transfers[transferHash];
        if (transfer.status == TransferStatus.Undefined)
            revert TransferRequestNotFound();
        if (transfer.status != TransferStatus.Created)
            revert InvalidTransferRequestStatus();
        transfer.status = TransferStatus.Rejected;
    }
}

File 15 of 17 : IProductRegistry.sol
pragma solidity 0.8.17;

/**
 * @title The product registry
 * @dev The registry listing all financial products handled by a given registrar(the owner of the registry).
 */
interface IProductRegistry {
    /** 
     * @dev Add a new product to the registry
     * @param name The name of the product
     * @param isinCode The ISIN code of the product
     * @param productAddress The adress of the product's contract
     */
    function listProduct(
        string calldata name,
        string calldata isinCode,
        address productAddress
    ) external;

    /** 
     * @dev Get the address of a product by providing its name
     * @param name The name of the product
     * @return product The found product's contract address
     */
    function getProductByName(string calldata name)
        external
        view
        returns (address product);

    /**
     * @dev Get the address of a product by providing its ISIN code
     * @param isin The ISIN code of the product
     * @return product The found product's contract address
     */
    function getProductByIsinCode(string calldata isin)
        external
        view
        returns (address product);

    /**
     * @dev Get all products' addresses at once
     * @return product An array of all producs' addresses
     */
    function getAllProducts() external view returns (address[] memory product);

    /// @dev Remove a product from the registry
    /// @param isin The ISIN code of the product
    function unListProduct(string calldata isin) external;
}

File 16 of 17 : Ownable.sol
pragma solidity 0.8.17;

/**
 * @dev Used when a function reserved to the registrar is called by some other account
 */
import { UnauthorizedRegistrar, ZeroAddressCheck } from "./ProductErrorReporter.sol";

/**
 * @dev The Ownable contract handles an owner, called the registrar, and a modifier used to protect methods reserved to the registrar.
 */
abstract contract Ownable {
    address private registrarAgent;

    /**
     * @dev `_registrar` will be the owner of the contract
     */
    constructor(address _registrar) {
        if(_registrar == address(0))
            revert ZeroAddressCheck();
        registrarAgent = _registrar;
    }
    /**
     * @dev Throws an error if the caller is not the contract's owner(a.k.a. registrar)
     */
    modifier onlyRegistrar() {
        if (msg.sender != registrarAgent) revert UnauthorizedRegistrar();
        _;
    }
}

File 17 of 17 : ProductErrorReporter.sol
pragma solidity 0.8.17;

error TotalSupplyNotMatchTotalInitialSupply();

error PayingAgentNotSet();
error GuarantorNotSet();

error UnauthorizedIssuer();
error UnauthorizedSettler();

error ProductIsFullyRedeemed();

error SettlementTransactionNotInProcessedState();
error SettlementTransactionNotInAcknowledgedState();
error SettlementTransactionAlreadyExists();
error InvalidSettlementTransactionStatus();
error DeliveryReceiverAccountNumberNotMatchTokenIssuer();

error InvalidOperationType();

error InvalidTrustedToken();
error NotSupportedTrustedToken();

error InsufficientDisposableBalance();
error InsufficientBalance();
error InsufficientLockedBalance();

error TransferRequestNotFound();
error InvalidTransferRequestStatus();

error ZeroAddressCheck();
error OwnerHasOngoingApprove();
error ApproveDoesNotExists();
error InvalidApproveStatus();
error InsufficientAllowance();
error UnauthorizedRegistrar();

error ZeroValueCheck();
error InvalidReceiver();

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {
    "contracts/product/libraries/ApproveAdapterLibrary.sol": {
      "ApproveAdapterLibrary": "0x783c952feeb792aa63908c9b85c83ab46b0bf2fd"
    },
    "contracts/product/libraries/SecurityTokenBalancesLibrary.sol": {
      "SecurityTokenBalancesLibrary": "0xe320252f58d744a09584c79ac4f3629fca3798cb"
    },
    "contracts/product/libraries/SettlementRepositoryLibrary.sol": {
      "SettlementRepositoryLibrary": "0xc21b38fffc1bbe9cd95e7d9be962ad0dc5593e16"
    },
    "contracts/product/libraries/SettlementWorkflowLibrary.sol": {
      "SettlementWorkflowLibrary": "0x7dac013c0caa344f7086ae3f06419be9208d6e89"
    },
    "contracts/product/libraries/TransferAdapterLibrary.sol": {
      "TransferAdapterLibrary": "0x128d1485f8feb919100fcddd0571df2975010acd"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"components":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct IProduct.InitBalance[]","name":"initialBalances","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"nominalAmountCent","type":"uint256"},{"internalType":"uint256","name":"issueDate","type":"uint256"}],"internalType":"struct IProduct.Tranche[]","name":"initialTranches","type":"tuple[]"},{"internalType":"address","name":"previousContract","type":"address"},{"internalType":"string","name":"figi","type":"string"},{"internalType":"string","name":"extendedDataJson","type":"string"},{"internalType":"string","name":"esg","type":"string"},{"internalType":"string","name":"noteStatus","type":"string"},{"internalType":"string","name":"formOfNote","type":"string"},{"internalType":"string","name":"series","type":"string"},{"internalType":"string","name":"program","type":"string"},{"internalType":"string","name":"strUrl","type":"string"},{"internalType":"string","name":"productType","type":"string"},{"components":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IProduct.LegalEntity","name":"guarantor","type":"tuple"},{"components":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IProduct.LegalEntity","name":"issuer","type":"tuple"},{"components":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IProduct.LegalEntity","name":"payingAgent","type":"tuple"},{"components":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IProduct.LegalEntity","name":"settlementAgent","type":"tuple"},{"components":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"internalType":"struct IProduct.LegalEntity","name":"registrar","type":"tuple"},{"internalType":"string","name":"currency","type":"string"},{"internalType":"address","name":"registryAddress","type":"address"},{"internalType":"string","name":"listing","type":"string"},{"internalType":"string","name":"governingLaw","type":"string"},{"internalType":"uint256","name":"maturityDate","type":"uint256"},{"internalType":"uint256","name":"denominationCent","type":"uint256"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"isinCode","type":"string"}],"internalType":"struct IProduct.BasicProductInput","name":"basicProductInput","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"GuarantorNotSet","type":"error"},{"inputs":[],"name":"InvalidOperationType","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"InvalidSettlementTransactionStatus","type":"error"},{"inputs":[],"name":"OwnerHasOngoingApprove","type":"error"},{"inputs":[],"name":"PayingAgentNotSet","type":"error"},{"inputs":[],"name":"ProductIsFullyRedeemed","type":"error"},{"inputs":[],"name":"SettlementTransactionNotInAcknowledgedState","type":"error"},{"inputs":[],"name":"SettlementTransactionNotInProcessedState","type":"error"},{"inputs":[],"name":"TotalSupplyNotMatchTotalInitialSupply","type":"error"},{"inputs":[],"name":"UnauthorizedRegistrar","type":"error"},{"inputs":[],"name":"UnauthorizedSettler","type":"error"},{"inputs":[],"name":"ZeroAddressCheck","type":"error"},{"inputs":[],"name":"ZeroValueCheck","type":"error"},{"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":false,"internalType":"bytes32","name":"approveHash","type":"bytes32"}],"name":"ApproveRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"approveHash","type":"bytes32"},{"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":"ApproveRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"approveHash","type":"bytes32"}],"name":"ApproveValidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"settlementTransactionIds","type":"uint256[]"}],"name":"CouponInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementTransactionId","type":"uint256"},{"indexed":false,"internalType":"enum SettlementRepositoryLibrary.OperationType","name":"settlementTransactionOperationType","type":"uint8"}],"name":"PaymentReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementTransactionId","type":"uint256"},{"indexed":false,"internalType":"enum SettlementRepositoryLibrary.OperationType","name":"settlementTransactionOperationType","type":"uint8"}],"name":"PaymentTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"settlementTransactionIds","type":"uint256[]"}],"name":"RedemptionInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementTransactionId","type":"uint256"}],"name":"SettlementTransactionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementTransactionId","type":"uint256"}],"name":"SubscriptionInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"settlementTransactionId","type":"uint256"}],"name":"TradeInitiated","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":"uint256","name":"settlementTransactionId","type":"uint256"}],"name":"TransferExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"transferHash","type":"bytes32"}],"name":"TransferRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"transferHash","type":"bytes32"},{"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":"TransferRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"transferHash","type":"bytes32"}],"name":"TransferValidated","type":"event"},{"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":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"settlementTransactionId","type":"uint256"}],"name":"cancelSettlementTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_settlementTransactionId","type":"uint256"}],"name":"confirmPaymentReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_settlementTransactionId","type":"uint256"}],"name":"confirmPaymentTransferred","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nominalAmountCent","type":"uint256"},{"internalType":"uint256","name":"issueDate","type":"uint256"}],"internalType":"struct IProduct.Tranche","name":"newTranche","type":"tuple"}],"name":"createTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"denominationCent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"esg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"}],"internalType":"struct SettlementRepositoryLibrary.PartialSettlementTransaction","name":"partialSettlementTransaction","type":"tuple"}],"name":"executeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"extendedDataJson","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"figi","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"formOfNote","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getFullBalance","outputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"locked","type":"uint256"}],"internalType":"struct SecurityTokenBalancesLibrary.Balance","name":"value","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFullBalances","outputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"locked","type":"uint256"}],"internalType":"struct SecurityTokenBalancesLibrary.Balance[]","name":"value","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_settlementTransactionId","type":"uint256"}],"name":"getSettlementTransaction","outputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"},{"internalType":"enum SettlementRepositoryLibrary.SettlementTransactionStatus","name":"status","type":"uint8"},{"internalType":"enum SettlementRepositoryLibrary.OperationType","name":"operationType","type":"uint8"}],"internalType":"struct SettlementRepositoryLibrary.SettlementTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTranches","outputs":[{"components":[{"internalType":"uint256","name":"nominalAmountCent","type":"uint256"},{"internalType":"uint256","name":"issueDate","type":"uint256"}],"internalType":"struct IProduct.Tranche[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governingLaw","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guarantor","outputs":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guarantorAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guarantorLEI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"}],"internalType":"struct SettlementRepositoryLibrary.PartialSettlementTransaction[]","name":"partialSettlementTransactions","type":"tuple[]"},{"internalType":"string","name":"extendedData","type":"string"}],"name":"initiateCoupon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"}],"internalType":"struct SettlementRepositoryLibrary.PartialSettlementTransaction[]","name":"partialSettlementTransactions","type":"tuple[]"},{"internalType":"string","name":"extendedData","type":"string"}],"name":"initiateRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"}],"internalType":"struct SettlementRepositoryLibrary.PartialSettlementTransaction","name":"partialSettlementTransaction","type":"tuple"}],"name":"initiateSubscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"txId","type":"uint256"},{"internalType":"uint256","name":"operationId","type":"uint256"},{"internalType":"address","name":"deliverySenderAccountNumber","type":"address"},{"internalType":"address","name":"deliveryReceiverAccountNumber","type":"address"},{"internalType":"uint256","name":"deliveryQuantity","type":"uint256"},{"internalType":"string","name":"txHash","type":"string"}],"internalType":"struct SettlementRepositoryLibrary.PartialSettlementTransaction","name":"partialSettlementTransaction","type":"tuple"}],"name":"initiateTrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isinCode","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"issuer","outputs":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"issuerAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"issuerLEI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listing","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturityDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"noteStatus","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"operationExtendedDataJson","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payingAgent","outputs":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payingAgentAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payingAgentLEI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previousContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"productType","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"program","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrar","outputs":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrarAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registrarLEI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"approveHash","type":"bytes32"}],"name":"rejectApprove","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferHash","type":"bytes32"}],"name":"rejectTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"series","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seriesNominalAmountCent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seriesOutstandingNominalAmountCent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seriesRedeemedAmountCent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_esg","type":"string"}],"name":"setEsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_extendedDataJson","type":"string"}],"name":"setExtendeDataJson","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_strUrl","type":"string"}],"name":"setStrUrl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settlementAgent","outputs":[{"internalType":"string","name":"lei","type":"string"},{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"settlementAgentAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"settlementAgentLEI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum Product.ProductState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strUrl","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"uint256","name":"","type":"uint256"}],"name":"tranches","outputs":[{"internalType":"uint256","name":"nominalAmountCent","type":"uint256"},{"internalType":"uint256","name":"issueDate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","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":"bytes32","name":"approveHash","type":"bytes32"}],"name":"validateApprove","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferHash","type":"bytes32"}],"name":"validateTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b50604051620049b8380380620049b8833981016040819052620000349162000a51565b610200810151602001516001600160a01b03811662000066576040516399676b1160e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03929092169190911790556103208101516007906200009b908262000ee7565b50610300810151600b90620000b1908262000ee7565b506102e0810151601390620000c7908262000ee7565b506102c08101516002556102a0810151600355610280810151600490620000ef908262000ee7565b50610260810151600a9062000105908262000ee7565b506014805460ff1916600190811790915561022082015162000128908262000ee7565b5060408051808201909152610200820180515180835290516020908101516001600160a01b031690830152600f90819062000164908262000ee7565b5060209182015160019190910180546001600160a01b0319166001600160a01b039283161790556101e08301519091015116620001b4576040516399676b1160e01b815260040160405180910390fd5b604080518082019091526101e0820180515180835290516020908101516001600160a01b0316908301526011908190620001ef908262000ee7565b5060209182015160019190910180546001600160a01b0319166001600160a01b03928316179055604080518082019091526101c08401805151808352905184015190921692810192909252600c9081906200024b908262000ee7565b5060209182015160019190910180546001600160a01b0319166001600160a01b03928316179055604080518082019091526101a084018051518083529051840151909216928101929092526008908190620002a7908262000ee7565b5060209190910151600190910180546001600160a01b0319166001600160a01b0392831617905560095460405163d29dde5760e01b8152601f60048201529116602482015273e320252f58d744a09584c79ac4f3629fca3798cb9063d29dde579060440160006040518083038186803b1580156200032457600080fd5b505af415801562000339573d6000803e3d6000fd5b505060408051808201909152610180840180515180835290516020908101516001600160a01b0316908301529092506005915081906200037a908262000ee7565b5060209190910151600190910180546001600160a01b0319166001600160a01b03909216919091179055610140810151601590620003b9908262000ee7565b50610160810151600e90620003cf908262000ee7565b50610120810151601690620003e5908262000ee7565b50610100810151601790620003fb908262000ee7565b5060c081015160189062000410908262000ee7565b5060e0810151601b9062000425908262000ee7565b5060808101516019906200043a908262000ee7565b5060a0810151601a906200044f908262000ee7565b506060810151601c9062000464908262000ee7565b506040810151601d80546001600160a01b0319166001600160a01b0390921691909117905560005b816020015151811015620004e057620004cb82602001518281518110620004b757620004b762000fb3565b6020026020010151620006a260201b60201c565b80620004d78162000fdf565b9150506200048c565b50805151156200061a576000805b825151811015620005ef5760008360000151828151811062000514576200051462000fb3565b60200260200101516020015190506000846000015183815181106200053d576200053d62000fb3565b60209081029190910101515160405163ec2a214f60e01b8152601f60048201526001600160a01b03821660248201526044810184905290915073e320252f58d744a09584c79ac4f3629fca3798cb9063ec2a214f9060640160006040518083038186803b158015620005ae57600080fd5b505af4158015620005c3573d6000803e3d6000fd5b505050508184620005d5919062000ffb565b935050508080620005e69062000fdf565b915050620004ee565b50602e5481146200061357604051633b47470b60e21b815260040160405180910390fd5b506200069b565b600954602e5460405163ec2a214f60e01b8152601f60048201526001600160a01b039092166024830152604482015273e320252f58d744a09584c79ac4f3629fca3798cb9063ec2a214f9060640160006040518083038186803b1580156200068157600080fd5b505af415801562000696573d6000803e3d6000fd5b505050505b5062001050565b602a80546001810182556000918252825160029091027fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2810182905560208401517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390910155602b8054919290916200071d90849062000ffb565b909155506200072d905062000730565b50565b602d54602b5462000742919062001017565b602c81905560025462000755916200102d565b602e55565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156200079557620007956200075a565b60405290565b60405161034081016001600160401b03811182821017156200079557620007956200075a565b604051601f8201601f191681016001600160401b0381118282101715620007ec57620007ec6200075a565b604052919050565b60006001600160401b038211156200081057620008106200075a565b5060051b60200190565b80516001600160a01b03811681146200083257600080fd5b919050565b600082601f8301126200084957600080fd5b81516020620008626200085c83620007f4565b620007c1565b82815260069290921b840181019181810190868411156200088257600080fd5b8286015b84811015620008cf5760408189031215620008a15760008081fd5b620008ab62000770565b620008b6826200081a565b8152818501518582015283529183019160400162000886565b509695505050505050565b600082601f830112620008ec57600080fd5b81516020620008ff6200085c83620007f4565b82815260069290921b840181019181810190868411156200091f57600080fd5b8286015b84811015620008cf57604081890312156200093e5760008081fd5b6200094862000770565b81518152848201518582015283529183019160400162000923565b600082601f8301126200097557600080fd5b81516001600160401b038111156200099157620009916200075a565b6020620009a7601f8301601f19168201620007c1565b8281528582848701011115620009bc57600080fd5b60005b83811015620009dc578581018301518282018401528201620009bf565b506000928101909101919091529392505050565b60006040828403121562000a0357600080fd5b62000a0d62000770565b82519091506001600160401b0381111562000a2757600080fd5b62000a358482850162000963565b82525062000a46602083016200081a565b602082015292915050565b60006020828403121562000a6457600080fd5b81516001600160401b038082111562000a7c57600080fd5b90830190610340828603121562000a9257600080fd5b62000a9c6200079b565b82518281111562000aac57600080fd5b62000aba8782860162000837565b82525060208301518281111562000ad057600080fd5b62000ade87828601620008da565b60208301525062000af2604084016200081a565b604082015260608301518281111562000b0a57600080fd5b62000b188782860162000963565b60608301525060808301518281111562000b3157600080fd5b62000b3f8782860162000963565b60808301525060a08301518281111562000b5857600080fd5b62000b668782860162000963565b60a08301525060c08301518281111562000b7f57600080fd5b62000b8d8782860162000963565b60c08301525060e08301518281111562000ba657600080fd5b62000bb48782860162000963565b60e083015250610100808401518381111562000bcf57600080fd5b62000bdd8882870162000963565b828401525050610120808401518381111562000bf857600080fd5b62000c068882870162000963565b828401525050610140808401518381111562000c2157600080fd5b62000c2f8882870162000963565b828401525050610160808401518381111562000c4a57600080fd5b62000c588882870162000963565b828401525050610180808401518381111562000c7357600080fd5b62000c8188828701620009f0565b8284015250506101a0808401518381111562000c9c57600080fd5b62000caa88828701620009f0565b8284015250506101c0808401518381111562000cc557600080fd5b62000cd388828701620009f0565b8284015250506101e0808401518381111562000cee57600080fd5b62000cfc88828701620009f0565b828401525050610200808401518381111562000d1757600080fd5b62000d2588828701620009f0565b828401525050610220808401518381111562000d4057600080fd5b62000d4e8882870162000963565b82840152505061024062000d648185016200081a565b90820152610260838101518381111562000d7d57600080fd5b62000d8b8882870162000963565b828401525050610280808401518381111562000da657600080fd5b62000db48882870162000963565b8284015250506102a08084015181830152506102c08084015181830152506102e0808401518381111562000de757600080fd5b62000df58882870162000963565b828401525050610300808401518381111562000e1057600080fd5b62000e1e8882870162000963565b828401525050610320808401518381111562000e3957600080fd5b62000e478882870162000963565b918301919091525095945050505050565b600181811c9082168062000e6d57607f821691505b60208210810362000e8e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000ee257600081815260208120601f850160051c8101602086101562000ebd5750805b601f850160051c820191505b8181101562000ede5782815560010162000ec9565b5050505b505050565b81516001600160401b0381111562000f035762000f036200075a565b62000f1b8162000f14845462000e58565b8462000e94565b602080601f83116001811462000f53576000841562000f3a5750858301515b600019600386901b1c1916600185901b17855562000ede565b600085815260208120601f198616915b8281101562000f845788860151825594840194600190910190840162000f63565b508582101562000fa35787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000ff45762000ff462000fc9565b5060010190565b8082018082111562001011576200101162000fc9565b92915050565b8181038181111562001011576200101162000fc9565b6000826200104b57634e487b7160e01b600052601260045260246000fd5b500490565b61395880620010606000396000f3fe608060405234801561001057600080fd5b50600436106104725760003560e01c80638876678d11610250578063cac0652211610150578063dd62ed3e116100c8578063e4ae852911610097578063e96b38281161007c578063e96b3828146108c3578063f12d870f146108d6578063f8b2cb4f146106a557600080fd5b8063e4ae8529146108a8578063e5a6b10f146108bb57600080fd5b8063dd62ed3e14610867578063e109ca7a1461087a578063e3406ff61461088d578063e46871f1146108a057600080fd5b8063d9474b2c1161011f578063dc2f511b11610104578063dc2f511b14610837578063dc9c8aa81461084c578063dcc59ec21461085f57600080fd5b8063d9474b2c14610827578063da15ff911461082f57600080fd5b8063cac06522146107d6578063d1eac5cc146107de578063d497ec04146107fe578063d59624b41461081e57600080fd5b8063b9f534c0116101e3578063c19d93fb116101b2578063c62c564711610197578063c62c5647146107be578063c76b9527146107c6578063c860ebc6146107ce57600080fd5b8063c19d93fb14610791578063c4842b6c146107ab57600080fd5b8063b9f534c01461075b578063bc7c55ed14610763578063bf554b9f1461076b578063c1136a291461077e57600080fd5b80639e2c91371161021f5780639e2c913714610724578063a5462be71461072d578063a9059cbb14610735578063b71f31f31461074857600080fd5b80638876678d146106f65780638c8d0ce01461070b578063942a05161461071357806395d89b411461071c57600080fd5b806342966c68116103765780636121c61d116102ee57806371cf516b116102bd57806378954b3b116102a257806378954b3b146106c85780637fbeb89c146106db57806381aa632c146106ee57600080fd5b806371cf516b146106b8578063781d219a146106c057600080fd5b80636121c61d1461067957806362d103361461068157806362f4774c1461069257806370a08231146106a557600080fd5b8063524f7f761161034557806357786f711161032a57806357786f71146106605780635962e266146106695780635e4795a91461067157600080fd5b8063524f7f761461061c57806354fd4d501461062457600080fd5b806342966c68146105d25780634493b8f3146105e55780634ec3714c146105f65780634ec4928e1461060957600080fd5b80631fce02201161040957806326c25962116103d85780632b20e397116103bd5780632b20e397146105b2578063313ce567146105ba57806334356674146105c957600080fd5b806326c259621461058257806326fa713b146105aa57600080fd5b80631fce02201461052457806323b872dd14610537578063255f6a9b1461054a578063266a85c21461055d57600080fd5b8063095ea7b311610445578063095ea7b3146104df5780630a720745146104f257806318160ddd146105055780631d1438481461051c57600080fd5b806301ffc9a714610477578063053576ad1461049f5780630665d994146104b557806306fdde03146104ca575b600080fd5b61048a610485366004612cbc565b6108de565b60405190151581526020015b60405180910390f35b6104a761098e565b604051610496929190612d36565b6104c86104c3366004612e50565b610a2f565b005b6104d2610a6a565b6040516104969190612e8d565b61048a6104ed366004612eb5565b610af8565b61048a610500366004612ee1565b610c5f565b61050e602e5481565b604051908152602001610496565b6104a7610e22565b61048a610532366004612ee1565b610e31565b61048a610545366004612efa565b610f28565b6104c861055836600461300e565b611042565b6010546001600160a01b03165b6040516001600160a01b039091168152602001610496565b610595610590366004612ee1565b61124b565b60408051928352602083019190915201610496565b6104d2611279565b6104a761130e565b60405160008152602001610496565b61050e60025481565b6104c86105e0366004612ee1565b61131d565b6012546001600160a01b031661056a565b6104c86106043660046130e2565b611361565b6104c861061736600461300e565b611492565b6104d261169e565b6104d26040518060400160405280600381526020017f312e31000000000000000000000000000000000000000000000000000000000081525081565b61050e602b5481565b6104d26116df565b6104a76116ec565b6104d26116fb565b6009546001600160a01b031661056a565b6104c86106a0366004612e50565b611708565b61050e6106b3366004613117565b61173f565b6104a76117de565b6104d26117ed565b601d5461056a906001600160a01b031681565b61048a6106e9366004612ee1565b6117ff565b6104d2611a76565b6106fe611ab7565b6040516104969190613134565b6104d2611b50565b61050e602d5481565b6104d2611b5d565b61050e602c5481565b6104d2611b6a565b61048a610743366004612eb5565b611b77565b6104c861075636600461319f565b611d57565b6104d2611e2c565b6104d2611e39565b6104c8610779366004612ee1565b611e46565b6104d261078c366004612ee1565b611f2c565b60145461079e9060ff1681565b6040516104969190613204565b6104c86107b93660046130e2565b611f45565b6104d261206c565b61056a61207e565b6104d26120ba565b6104d26120c7565b6107f16107ec366004613117565b6120d4565b604051610496919061321e565b61081161080c366004612ee1565b61219d565b6040516104969190613265565b61050e60035481565b6104d2612262565b61056a61226f565b61083f6122ab565b60405161049691906132f5565b61048a61085a366004612ee1565b61231e565b6104d2612406565b61050e610875366004613344565b612413565b6104c86108883660046130e2565b6124c1565b6104c861089b366004612ee1565b6125e8565b6104d26126d6565b6104c86108b6366004612e50565b6126e3565b6104d261271a565b6104c86108d1366004612ee1565b612727565b6104d261275b565b60006001600160e01b031982167fb5ab740e00000000000000000000000000000000000000000000000000000000148061094157506001600160e01b031982167fe81f93ba00000000000000000000000000000000000000000000000000000000145b8061095457506001600160e01b03198216155b8061098857507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b60118054819061099d9061337d565b80601f01602080910402602001604051908101604052809291908181526020018280546109c99061337d565b8015610a165780601f106109eb57610100808354040283529160200191610a16565b820191906000526020600020905b8154815290600101906020018083116109f957829003601f168201915b505050600190930154919250506001600160a01b031682565b6000546001600160a01b03163314610a5a57604051631a88efbf60e11b815260040160405180910390fd5b6019610a668282613406565b5050565b600b8054610a779061337d565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa39061337d565b8015610af05780601f10610ac557610100808354040283529160200191610af0565b820191906000526020600020905b815481529060010190602001808311610ad357829003601f168201915b505050505081565b3360009081526029602090815260408083206001600160a01b0386168452909152812054839060ff1615610b58576040517f4714a5f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f3498e56c00000000000000000000000000000000000000000000000000000000815260266004820152601f60248201523360448201526001600160a01b03851660648201526084810184905260009073783c952feeb792aa63908c9b85c83ab46b0bf2fd90633498e56c9060a401602060405180830381865af4158015610be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0b91906134c6565b60408051828152602081018790529192506001600160a01b0387169133917f57d1524865ded40de243246267aece0a56c052311c9ce71c4d0cbbed21249eb3910160405180910390a3506001949350505050565b600080546001600160a01b03163314610c8b57604051631a88efbf60e11b815260040160405180910390fd5b6040517f7d674945000000000000000000000000000000000000000000000000000000008152602660048201526024810183905273783c952feeb792aa63908c9b85c83ab46b0bf2fd90637d6749459060440160006040518083038186803b158015610cf657600080fd5b505af4158015610d0a573d6000803e3d6000fd5b5050506000838152602660209081526040808320815160808101835281546001600160a01b0390811682526001830154169381019390935260028101549183019190915260038082015493945091929091606084019160ff1690811115610d7357610d736131ee565b6003811115610d8457610d846131ee565b81525050905080602001516001600160a01b031681600001516001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360400151604051610ddb91815260200190565b60405180910390a36040518381527f1cd3564f5a2b43649814052b7428dc0ba155f5d18f8f5fcf50bd32cc88359fb4906020015b60405180910390a160019150505b919050565b60088054819061099d9061337d565b600080546001600160a01b03163314610e5d57604051631a88efbf60e11b815260040160405180910390fd5b6040517fcdb4242e00000000000000000000000000000000000000000000000000000000815260266004820152601f60248201526044810183905273783c952feeb792aa63908c9b85c83ab46b0bf2fd9063cdb4242e9060640160006040518083038186803b158015610ecf57600080fd5b505af4158015610ee3573d6000803e3d6000fd5b505050507f891e5cbb521c74b11f09b9a17b9f0fab0c8cdd158908914196b5d9f1e741dd7582604051610f1891815260200190565b60405180910390a1506001919050565b6040517f1c64d94700000000000000000000000000000000000000000000000000000000815260266004820152601f60248083019190915260448201523360648201526001600160a01b038085166084830152831660a482015260c48101829052600090819073783c952feeb792aa63908c9b85c83ab46b0bf2fd90631c64d9479060e401602060405180830381865af4158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee91906134c6565b60408051828152602081018690529192506001600160a01b0386169133917f957db550c8482e0e40d923e90c7e1c7388a338f015b090168eae3a7dd36903c7910160405180910390a3506001949350505050565b6000546001600160a01b0316331461106d57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115611086576110866131ee565b106110a4576040516383b3712f60e01b815260040160405180910390fd5b6000825167ffffffffffffffff8111156110c0576110c0612d61565b6040519080825280602002602001820160405280156110e9578160200160208202803683370190505b506040517f1f5263e9000000000000000000000000000000000000000000000000000000008152909150737dac013c0caa344f7086ae3f06419be9208d6e8990631f5263e99061114090602390879060040161357d565b60006040518083038186803b15801561115857600080fd5b505af415801561116c573d6000803e3d6000fd5b5050505060008360008151811061118557611185613596565b602002602001015160200151905082601e600083815260200190815260200160002090816111b39190613406565b5060005b845181101561120d578481815181106111d2576111d2613596565b6020026020010151600001518382815181106111f0576111f0613596565b602090810291909101015280611205816135c2565b9150506111b7565b507f354e5f2b05309441ea51dd05db8e29f7a5e5341858336b8d4a1466ab7deef5ba8260405161123d91906135db565b60405180910390a150505050565b602a818154811061125b57600080fd5b60009182526020909120600290910201805460019091015490915082565b6060600f600001805461128b9061337d565b80601f01602080910402602001604051908101604052809291908181526020018280546112b79061337d565b80156113045780601f106112d957610100808354040283529160200191611304565b820191906000526020600020905b8154815290600101906020018083116112e757829003601f168201915b5050505050905090565b600f8054819061099d9061337d565b6000546001600160a01b0316331461134857604051631a88efbf60e11b815260040160405180910390fd5b60095461135e906001600160a01b031682612768565b50565b6000546001600160a01b0316331461138c57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff1660038111156113a5576113a56131ee565b106113c3576040516383b3712f60e01b815260040160405180910390fd5b6040517fbfc9867b000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e899063bfc9867b9061141990602390601f908690600401613613565b60006040518083038186803b15801561143157600080fd5b505af4158015611445573d6000803e3d6000fd5b505082516114599250602391506004612827565b80516040519081527ff49c7151a34f944c290bea0b71e18d61f02bfd24115ac372517b6ba94ebd9546906020015b60405180910390a150565b6000546001600160a01b031633146114bd57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff1660038111156114d6576114d66131ee565b106114f4576040516383b3712f60e01b815260040160405180910390fd5b6000825167ffffffffffffffff81111561151057611510612d61565b604051908082528060200260200182016040528015611539578160200160208202803683370190505b506040517f56d10ebd000000000000000000000000000000000000000000000000000000008152909150737dac013c0caa344f7086ae3f06419be9208d6e89906356d10ebd9061159390602390601f90889060040161363b565b60006040518083038186803b1580156115ab57600080fd5b505af41580156115bf573d6000803e3d6000fd5b505050506000836000815181106115d8576115d8613596565b602002602001015160200151905082601e600083815260200190815260200160002090816116069190613406565b5060005b84518110156116605784818151811061162557611625613596565b60200260200101516000015183828151811061164357611643613596565b602090810291909101015280611658816135c2565b91505061160a565b506014805460ff191660031790556040517f1d13bbc19c4b8f9e6a70801e6ff012075a3f608962f7374206a6b0dafc1992719061123d9084906135db565b6060600c60000180546116b09061337d565b90506000036116d257604051631f950c7960e11b815260040160405180910390fd5b600c805461128b9061337d565b601b8054610a779061337d565b600c8054819061099d9061337d565b600e8054610a779061337d565b6000546001600160a01b0316331461173357604051631a88efbf60e11b815260040160405180910390fd5b6015610a668282613406565b6040517f75ac38c2000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b038216602482015260009073e320252f58d744a09584c79ac4f3629fca3798cb906375ac38c290604401602060405180830381865af41580156117ba573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098891906134c6565b60058054819061099d9061337d565b60606011600001805461128b9061337d565b600080546001600160a01b0316331461182b57604051631a88efbf60e11b815260040160405180910390fd5b6040517f5c226beb000000000000000000000000000000000000000000000000000000008152602460048201819052810183905273128d1485f8feb919100fcddd0571df2975010acd90635c226beb9060440160006040518083038186803b15801561189657600080fd5b505af41580156118aa573d6000803e3d6000fd5b5050506000838152602460209081526040808320815160c08101835281546001600160a01b0390811682526001830154169381019390935260028101549183019190915260038082015493945091929091606084019160ff1690811115611913576119136131ee565b6003811115611924576119246131ee565b815260039190910154610100810460ff16151560208301526201000090046001600160a01b03166040909101526080810151909150156119ad5760408082015182516001600160a01b0390811660009081526028602090815284822060a08701519093168252919091529182208054919290916119a290849061365a565b90915550611a469050565b805160408083015190517f580e2c44000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b039092166024830152604482015273e320252f58d744a09584c79ac4f3629fca3798cb9063580e2c449060640160006040518083038186803b158015611a2d57600080fd5b505af4158015611a41573d6000803e3d6000fd5b505050505b6040518381527f6a9eda23525b3a9b3aa9326b05e25ca9af576996fa0ae91c62afbc835839b0cb90602001610e0f565b606060056000018054611a889061337d565b9050600003611aaa576040516373aba56b60e01b815260040160405180910390fd5b6005805461128b9061337d565b6040517f4bb4caef000000000000000000000000000000000000000000000000000000008152601f600482015260609073e320252f58d744a09584c79ac4f3629fca3798cb90634bb4caef90602401600060405180830381865af4158015611b23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b4b91908101906136df565b905090565b60078054610a779061337d565b60138054610a779061337d565b60158054610a779061337d565b600081600003611bb3576040517fbabd61a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03841603611bf5576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f84a04370000000000000000000000000000000000000000000000000000000008152602460048201819052601f908201523360448201526001600160a01b038416606482015260848101839052600060a4820181905260c482018190529073128d1485f8feb919100fcddd0571df2975010acd906384a043709060e401602060405180830381865af4158015611c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb791906134c6565b9050836001600160a01b0316336001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6000604051611cff91815260200190565b60405180910390a360408051828152602081018590526001600160a01b0386169133917f957db550c8482e0e40d923e90c7e1c7388a338f015b090168eae3a7dd36903c7910160405180910390a35060019392505050565b6000546001600160a01b03163314611d8257604051631a88efbf60e11b815260040160405180910390fd5b600954600254825173e320252f58d744a09584c79ac4f3629fca3798cb9263ec2a214f92601f926001600160a01b0390921691611dbf9190613779565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b039091166024830152604482015260640160006040518083038186803b158015611e0b57600080fd5b505af4158015611e1f573d6000803e3d6000fd5b5050505061135e816128ac565b601c8054610a779061337d565b600a8054610a779061337d565b6000546001600160a01b03163314611e7157604051631a88efbf60e11b815260040160405180910390fd5b6040517fd9ea7a0600000000000000000000000000000000000000000000000000000000815260236004820152601f602482015260448101829052737dac013c0caa344f7086ae3f06419be9208d6e899063d9ea7a069060640160006040518083038186803b158015611ee357600080fd5b505af4158015611ef7573d6000803e3d6000fd5b505050507f5ac1d96566a8d80ac0b7c75ce8ad501255fb99929aa34a2328f9b192b1d0c0a98160405161148791815260200190565b601e6020526000908152604090208054610a779061337d565b6000546001600160a01b03163314611f7057604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115611f8957611f896131ee565b10611fa7576040516383b3712f60e01b815260040160405180910390fd5b6040517fcd2002fd000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e899063cd2002fd90611ffd90602390601f908690600401613613565b60006040518083038186803b15801561201557600080fd5b505af4158015612029573d6000803e3d6000fd5b50506014805460ff19166002179055505080516040519081527fc40a4f74d715da2ee96119fbf8d8da1df0f5b79e92c3fd855f1ddc102d51d04790602001611487565b60606008600001805461128b9061337d565b6006546000906001600160a01b03166120aa576040516373aba56b60e01b815260040160405180910390fd5b506006546001600160a01b031690565b60168054610a779061337d565b601a8054610a779061337d565b612101604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6040517f5d1605b3000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b038316602482015273e320252f58d744a09584c79ac4f3629fca3798cb90635d1605b390604401606060405180830381865af4158015612179573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610988919061379b565b6121e3604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a08201529060c082019081526020016000905290565b6040516318366f3560e21b8152602360048201526024810183905273c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561223a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610988919081019061380b565b60188054610a779061337d565b600d546000906001600160a01b031661229b57604051631f950c7960e11b815260040160405180910390fd5b50600d546001600160a01b031690565b6060602a805480602002602001604051908101604052809291908181526020016000905b82821015612315578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906122cf565b50505050905090565b600080546001600160a01b0316331461234a57604051631a88efbf60e11b815260040160405180910390fd5b6040517f284d9c96000000000000000000000000000000000000000000000000000000008152602460048201819052601f908201526044810183905273128d1485f8feb919100fcddd0571df2975010acd9063284d9c969060640160006040518083038186803b1580156123bd57600080fd5b505af41580156123d1573d6000803e3d6000fd5b505050507ff293a19d8e1c857cb5b75138774de0ea944b21327ae79db4cb55296627b5237182604051610f1891815260200190565b60198054610a779061337d565b6040517fd8e9cf03000000000000000000000000000000000000000000000000000000008152602660048201526001600160a01b0380841660248301528216604482015260009073783c952feeb792aa63908c9b85c83ab46b0bf2fd9063d8e9cf0390606401602060405180830381865af4158015612496573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ba91906134c6565b9392505050565b6000546001600160a01b031633146124ec57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115612505576125056131ee565b10612523576040516383b3712f60e01b815260040160405180910390fd5b6040517f06846dce000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e89906306846dce9061257990602390601f908690600401613613565b60006040518083038186803b15801561259157600080fd5b505af41580156125a5573d6000803e3d6000fd5b50506014805460ff19166002179055505080516040519081527f0bed382b9aad3b5629da3f0660006b5b0ebaf727367204f573a175544a0f930d90602001611487565b6012546001600160a01b0316331461261357604051631de3f8c960e21b815260040160405180910390fd5b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561266d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612695919081019061380b565b905060008160e0015160058111156126af576126af6131ee565b036126cd57604051630ead561960e11b815260040160405180910390fd5b610a6682612933565b60048054610a779061337d565b6000546001600160a01b0316331461270e57604051631a88efbf60e11b815260040160405180910390fd5b601a610a668282613406565b60018054610a779061337d565b6012546001600160a01b0316331461275257604051631de3f8c960e21b815260040160405180910390fd5b61135e81612b4b565b60178054610a779061337d565b6040517f51a0cf48000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b03831660248201526044810182905273e320252f58d744a09584c79ac4f3629fca3798cb906351a0cf489060640160006040518083038186803b1580156127e257600080fd5b505af41580156127f6573d6000803e3d6000fd5b505050506002548161280891906138db565b602d6000828254612819919061365a565b90915550610a669050612c96565b600081600581111561283b5761283b6131ee565b03612872576040517f7ec04df100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208490526040902060068101805483919060ff191660018360058111156128a1576128a16131ee565b021790555050505050565b602a80546001810182556000918252825160029091027fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2810182905560208401517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390910155602b80549192909161292590849061365a565b9091555061135e9050612c96565b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561298d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129b5919081019061380b565b905060028160c0015160058111156129cf576129cf6131ee565b14612a06576040517f6b67159000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048160e001516005811115612a1e57612a1e6131ee565b14612ace576040818101516060830151608084015192517f9030099a000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b03928316602482015291166044820152606481019190915273e320252f58d744a09584c79ac4f3629fca3798cb90639030099a9060840160006040518083038186803b158015612ab557600080fd5b505af4158015612ac9573d6000803e3d6000fd5b505050505b60028160e001516005811115612ae657612ae66131ee565b03612afd57612afd81606001518260800151612768565b612b0a6023836003612827565b7f9bbe037a1a1faac87c3e07d5beed35ad6d3c54fbbc21637447918822abb04583828260e00151604051612b3f9291906138f2565b60405180910390a15050565b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af4158015612ba5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bcd919081019061380b565b905060008160e001516005811115612be757612be76131ee565b03612c0557604051630ead561960e11b815260040160405180910390fd5b60038160c001516005811115612c1d57612c1d6131ee565b14612c54576040517f1109e7ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612c616023836004612827565b7fa86580040b7b220b796aa9b66b3eede5540d9130c21f31e27b6667458720f3f8828260e00151604051612b3f9291906138f2565b602d54602b54612ca6919061390f565b602c819055600254612cb791613779565b602e55565b600060208284031215612cce57600080fd5b81356001600160e01b0319811681146124ba57600080fd5b60005b83811015612d01578181015183820152602001612ce9565b50506000910152565b60008151808452612d22816020860160208601612ce6565b601f01601f19169290920160200192915050565b604081526000612d496040830185612d0a565b90506001600160a01b03831660208301529392505050565b634e487b7160e01b600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612d9b57612d9b612d61565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612dca57612dca612d61565b604052919050565b600067ffffffffffffffff821115612dec57612dec612d61565b50601f01601f191660200190565b600082601f830112612e0b57600080fd5b8135612e1e612e1982612dd2565b612da1565b818152846020838601011115612e3357600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215612e6257600080fd5b813567ffffffffffffffff811115612e7957600080fd5b612e8584828501612dfa565b949350505050565b6020815260006124ba6020830184612d0a565b6001600160a01b038116811461135e57600080fd5b60008060408385031215612ec857600080fd5b8235612ed381612ea0565b946020939093013593505050565b600060208284031215612ef357600080fd5b5035919050565b600080600060608486031215612f0f57600080fd5b8335612f1a81612ea0565b92506020840135612f2a81612ea0565b929592945050506040919091013590565b600067ffffffffffffffff821115612f5557612f55612d61565b5060051b60200190565b600060c08284031215612f7157600080fd5b60405160c0810167ffffffffffffffff8282108183111715612f9557612f95612d61565b81604052829350843583526020850135602084015260408501359150612fba82612ea0565b81604084015260608501359150612fd082612ea0565b8160608401526080850135608084015260a0850135915080821115612ff457600080fd5b5061300185828601612dfa565b60a0830152505092915050565b6000806040838503121561302157600080fd5b823567ffffffffffffffff8082111561303957600080fd5b818501915085601f83011261304d57600080fd5b8135602061305d612e1983612f3b565b82815260059290921b8401810191818101908984111561307c57600080fd5b8286015b848110156130b4578035868111156130985760008081fd5b6130a68c86838b0101612f5f565b845250918301918301613080565b50965050860135925050808211156130cb57600080fd5b506130d885828601612dfa565b9150509250929050565b6000602082840312156130f457600080fd5b813567ffffffffffffffff81111561310b57600080fd5b612e8584828501612f5f565b60006020828403121561312957600080fd5b81356124ba81612ea0565b6020808252825182820181905260009190848201906040850190845b818110156131935761318083855180516001600160a01b0316825260208082015190830152604090810151910152565b9284019260609290920191600101613150565b50909695505050505050565b6000604082840312156131b157600080fd5b6040516040810181811067ffffffffffffffff821117156131d4576131d4612d61565b604052823581526020928301359281019290925250919050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310613218576132186131ee565b91905290565b81516001600160a01b03168152602080830151908201526040808301519082015260608101610988565b6006811061135e5761135e6131ee565b61326181613248565b9052565b602081528151602082015260208201516040820152600060408301516001600160a01b0380821660608501528060608601511660808501525050608083015160a083015260a08301516101008060c08501526132c5610120850183612d0a565b915060c08501516132d960e0860182613258565b5060e08501516132eb82860182613258565b5090949350505050565b602080825282518282018190526000919060409081850190868401855b8281101561333757815180518552860151868501529284019290850190600101613312565b5091979650505050505050565b6000806040838503121561335757600080fd5b823561336281612ea0565b9150602083013561337281612ea0565b809150509250929050565b600181811c9082168061339157607f821691505b6020821081036133b157634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561340157600081815260208120601f850160051c810160208610156133de5750805b601f850160051c820191505b818110156133fd578281556001016133ea565b5050505b505050565b815167ffffffffffffffff81111561342057613420612d61565b6134348161342e845461337d565b846133b7565b602080601f83116001811461346957600084156134515750858301515b600019600386901b1c1916600185901b1785556133fd565b600085815260208120601f198616915b8281101561349857888601518255948401946001909101908401613479565b50858210156134b65787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156134d857600080fd5b5051919050565b8051825260208101516020830152600060408201516001600160a01b03808216604086015280606085015116606086015250506080820151608084015260a082015160c060a0850152612e8560c0850182612d0a565b600081518084526020808501808196508360051b8101915082860160005b8581101561333757828403895261356b8483516134df565b98850198935090840190600101613553565b828152604060208201526000612e856040830184613535565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016135d4576135d46135ac565b5060010190565b6020808252825182820181905260009190848201906040850190845b81811015613193578351835292840192918401916001016135f7565b83815282602082015260606040820152600061363260608301846134df565b95945050505050565b8381528260208201526060604082015260006136326060830184613535565b80820180821115610988576109886135ac565b8051610e1d81612ea0565b60006060828403121561368a57600080fd5b6040516060810181811067ffffffffffffffff821117156136ad576136ad612d61565b806040525080915082516136c081612ea0565b8082525060208301516020820152604083015160408201525092915050565b600060208083850312156136f257600080fd5b825167ffffffffffffffff81111561370957600080fd5b8301601f8101851361371a57600080fd5b8051613728612e1982612f3b565b8181526060918202830184019184820191908884111561374757600080fd5b938501935b8385101561376d5761375e8986613678565b8352938401939185019161374c565b50979650505050505050565b60008261379657634e487b7160e01b600052601260045260246000fd5b500490565b6000606082840312156137ad57600080fd5b6124ba8383613678565b600082601f8301126137c857600080fd5b81516137d6612e1982612dd2565b8181528460208386010111156137eb57600080fd5b612e85826020830160208701612ce6565b805160068110610e1d57600080fd5b60006020828403121561381d57600080fd5b815167ffffffffffffffff8082111561383557600080fd5b90830190610100828603121561384a57600080fd5b613852612d77565b825181526020830151602082015261386c6040840161366d565b604082015261387d6060840161366d565b60608201526080830151608082015260a08301518281111561389e57600080fd5b6138aa878286016137b7565b60a0830152506138bc60c084016137fc565b60c08201526138cd60e084016137fc565b60e082015295945050505050565b8082028115828204841417610988576109886135ac565b8281526040810161390283613248565b8260208301529392505050565b81810381811115610988576109886135ac56fea26469706673582212206b14e1154ef6f2ad60e97f357f0e3f3018b51011d5f6cfc870fed9abac6e424564736f6c63430008110033000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000980000000000000000000000000a72cd393790f4d85da4d348d7a6cc7de05d0f68100000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000006b0cbc8000000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006567d08000000000000000000000000000000000000000000000000000000000000000034e2f41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000717b22696e74657265737452617465223a3430312c22636f75706f6e7061796d656e74416d6f756e7463656e74223a343031352c2266696e616c526564656d7074696f6e416d6f756e7450657263656e74223a31303030302c22696e7465726573745061796d656e7444617465223a5b5d7d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000867b2273656375726974794f6e636861696e436172626f6e466f6f747072696e74457374696d6174654b67434f326571756976616c656e74427959656172223a22302e3634222c22657374696d61746544617465223a22323032332d31312d3330222c227265706f7274223a22687474703a2f2f7777772e7367666f7267652e636f6d2f227d2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009556e736563757265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002253454355524954595f544f4b454e535f494e5f5245474953545245445f464f524d5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e2f4100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007454d544e205347000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017687474703a2f2f7374723a363636302f6772617068716c0000000000000000000000000000000000000000000000000000000000000000000000000000000006626f6e64563100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a400000000000000000000000000000000000000000000000000000000000000194f32524e453849425850345230544438505534312d4446494e000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a400000000000000000000000000000000000000000000000000000000000000194f32524e453849425850345230544438505534312d4446494e00000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000065980908e77b276c3e6cd73f609da62d1fc8e062000000000000000000000000000000000000000000000000000000000000001a4f32524e453849425850345230544438505534312d20534753530000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000e08106fad4add8dbffbbd0813027625a57c06fbd000000000000000000000000000000000000000000000000000000000000000d464f5247455f534554544c455200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000089ace546613b2cbb4510eab030a61bcdd11c8b8500000000000000000000000000000000000000000000000000000000000000143936393530304658384b34305a4457344633373700000000000000000000000000000000000000000000000000000000000000000000000000000000000000034555520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4c5558454d424f55524700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000246520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040534f43494554452047454e4552414c45204555522031304d203359204449474954414c20475245454e2053454e494f5220505245464552524544204e4f5445530000000000000000000000000000000000000000000000000000000000000040534f43494554452047454e4552414c45204555522031304d203359204449474954414c20475245454e2053454e494f5220505245464552524544204e4f544553000000000000000000000000000000000000000000000000000000000000000c46523030313430304d4447350000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104725760003560e01c80638876678d11610250578063cac0652211610150578063dd62ed3e116100c8578063e4ae852911610097578063e96b38281161007c578063e96b3828146108c3578063f12d870f146108d6578063f8b2cb4f146106a557600080fd5b8063e4ae8529146108a8578063e5a6b10f146108bb57600080fd5b8063dd62ed3e14610867578063e109ca7a1461087a578063e3406ff61461088d578063e46871f1146108a057600080fd5b8063d9474b2c1161011f578063dc2f511b11610104578063dc2f511b14610837578063dc9c8aa81461084c578063dcc59ec21461085f57600080fd5b8063d9474b2c14610827578063da15ff911461082f57600080fd5b8063cac06522146107d6578063d1eac5cc146107de578063d497ec04146107fe578063d59624b41461081e57600080fd5b8063b9f534c0116101e3578063c19d93fb116101b2578063c62c564711610197578063c62c5647146107be578063c76b9527146107c6578063c860ebc6146107ce57600080fd5b8063c19d93fb14610791578063c4842b6c146107ab57600080fd5b8063b9f534c01461075b578063bc7c55ed14610763578063bf554b9f1461076b578063c1136a291461077e57600080fd5b80639e2c91371161021f5780639e2c913714610724578063a5462be71461072d578063a9059cbb14610735578063b71f31f31461074857600080fd5b80638876678d146106f65780638c8d0ce01461070b578063942a05161461071357806395d89b411461071c57600080fd5b806342966c68116103765780636121c61d116102ee57806371cf516b116102bd57806378954b3b116102a257806378954b3b146106c85780637fbeb89c146106db57806381aa632c146106ee57600080fd5b806371cf516b146106b8578063781d219a146106c057600080fd5b80636121c61d1461067957806362d103361461068157806362f4774c1461069257806370a08231146106a557600080fd5b8063524f7f761161034557806357786f711161032a57806357786f71146106605780635962e266146106695780635e4795a91461067157600080fd5b8063524f7f761461061c57806354fd4d501461062457600080fd5b806342966c68146105d25780634493b8f3146105e55780634ec3714c146105f65780634ec4928e1461060957600080fd5b80631fce02201161040957806326c25962116103d85780632b20e397116103bd5780632b20e397146105b2578063313ce567146105ba57806334356674146105c957600080fd5b806326c259621461058257806326fa713b146105aa57600080fd5b80631fce02201461052457806323b872dd14610537578063255f6a9b1461054a578063266a85c21461055d57600080fd5b8063095ea7b311610445578063095ea7b3146104df5780630a720745146104f257806318160ddd146105055780631d1438481461051c57600080fd5b806301ffc9a714610477578063053576ad1461049f5780630665d994146104b557806306fdde03146104ca575b600080fd5b61048a610485366004612cbc565b6108de565b60405190151581526020015b60405180910390f35b6104a761098e565b604051610496929190612d36565b6104c86104c3366004612e50565b610a2f565b005b6104d2610a6a565b6040516104969190612e8d565b61048a6104ed366004612eb5565b610af8565b61048a610500366004612ee1565b610c5f565b61050e602e5481565b604051908152602001610496565b6104a7610e22565b61048a610532366004612ee1565b610e31565b61048a610545366004612efa565b610f28565b6104c861055836600461300e565b611042565b6010546001600160a01b03165b6040516001600160a01b039091168152602001610496565b610595610590366004612ee1565b61124b565b60408051928352602083019190915201610496565b6104d2611279565b6104a761130e565b60405160008152602001610496565b61050e60025481565b6104c86105e0366004612ee1565b61131d565b6012546001600160a01b031661056a565b6104c86106043660046130e2565b611361565b6104c861061736600461300e565b611492565b6104d261169e565b6104d26040518060400160405280600381526020017f312e31000000000000000000000000000000000000000000000000000000000081525081565b61050e602b5481565b6104d26116df565b6104a76116ec565b6104d26116fb565b6009546001600160a01b031661056a565b6104c86106a0366004612e50565b611708565b61050e6106b3366004613117565b61173f565b6104a76117de565b6104d26117ed565b601d5461056a906001600160a01b031681565b61048a6106e9366004612ee1565b6117ff565b6104d2611a76565b6106fe611ab7565b6040516104969190613134565b6104d2611b50565b61050e602d5481565b6104d2611b5d565b61050e602c5481565b6104d2611b6a565b61048a610743366004612eb5565b611b77565b6104c861075636600461319f565b611d57565b6104d2611e2c565b6104d2611e39565b6104c8610779366004612ee1565b611e46565b6104d261078c366004612ee1565b611f2c565b60145461079e9060ff1681565b6040516104969190613204565b6104c86107b93660046130e2565b611f45565b6104d261206c565b61056a61207e565b6104d26120ba565b6104d26120c7565b6107f16107ec366004613117565b6120d4565b604051610496919061321e565b61081161080c366004612ee1565b61219d565b6040516104969190613265565b61050e60035481565b6104d2612262565b61056a61226f565b61083f6122ab565b60405161049691906132f5565b61048a61085a366004612ee1565b61231e565b6104d2612406565b61050e610875366004613344565b612413565b6104c86108883660046130e2565b6124c1565b6104c861089b366004612ee1565b6125e8565b6104d26126d6565b6104c86108b6366004612e50565b6126e3565b6104d261271a565b6104c86108d1366004612ee1565b612727565b6104d261275b565b60006001600160e01b031982167fb5ab740e00000000000000000000000000000000000000000000000000000000148061094157506001600160e01b031982167fe81f93ba00000000000000000000000000000000000000000000000000000000145b8061095457506001600160e01b03198216155b8061098857507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b60118054819061099d9061337d565b80601f01602080910402602001604051908101604052809291908181526020018280546109c99061337d565b8015610a165780601f106109eb57610100808354040283529160200191610a16565b820191906000526020600020905b8154815290600101906020018083116109f957829003601f168201915b505050600190930154919250506001600160a01b031682565b6000546001600160a01b03163314610a5a57604051631a88efbf60e11b815260040160405180910390fd5b6019610a668282613406565b5050565b600b8054610a779061337d565b80601f0160208091040260200160405190810160405280929190818152602001828054610aa39061337d565b8015610af05780601f10610ac557610100808354040283529160200191610af0565b820191906000526020600020905b815481529060010190602001808311610ad357829003601f168201915b505050505081565b3360009081526029602090815260408083206001600160a01b0386168452909152812054839060ff1615610b58576040517f4714a5f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f3498e56c00000000000000000000000000000000000000000000000000000000815260266004820152601f60248201523360448201526001600160a01b03851660648201526084810184905260009073783c952feeb792aa63908c9b85c83ab46b0bf2fd90633498e56c9060a401602060405180830381865af4158015610be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0b91906134c6565b60408051828152602081018790529192506001600160a01b0387169133917f57d1524865ded40de243246267aece0a56c052311c9ce71c4d0cbbed21249eb3910160405180910390a3506001949350505050565b600080546001600160a01b03163314610c8b57604051631a88efbf60e11b815260040160405180910390fd5b6040517f7d674945000000000000000000000000000000000000000000000000000000008152602660048201526024810183905273783c952feeb792aa63908c9b85c83ab46b0bf2fd90637d6749459060440160006040518083038186803b158015610cf657600080fd5b505af4158015610d0a573d6000803e3d6000fd5b5050506000838152602660209081526040808320815160808101835281546001600160a01b0390811682526001830154169381019390935260028101549183019190915260038082015493945091929091606084019160ff1690811115610d7357610d736131ee565b6003811115610d8457610d846131ee565b81525050905080602001516001600160a01b031681600001516001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360400151604051610ddb91815260200190565b60405180910390a36040518381527f1cd3564f5a2b43649814052b7428dc0ba155f5d18f8f5fcf50bd32cc88359fb4906020015b60405180910390a160019150505b919050565b60088054819061099d9061337d565b600080546001600160a01b03163314610e5d57604051631a88efbf60e11b815260040160405180910390fd5b6040517fcdb4242e00000000000000000000000000000000000000000000000000000000815260266004820152601f60248201526044810183905273783c952feeb792aa63908c9b85c83ab46b0bf2fd9063cdb4242e9060640160006040518083038186803b158015610ecf57600080fd5b505af4158015610ee3573d6000803e3d6000fd5b505050507f891e5cbb521c74b11f09b9a17b9f0fab0c8cdd158908914196b5d9f1e741dd7582604051610f1891815260200190565b60405180910390a1506001919050565b6040517f1c64d94700000000000000000000000000000000000000000000000000000000815260266004820152601f60248083019190915260448201523360648201526001600160a01b038085166084830152831660a482015260c48101829052600090819073783c952feeb792aa63908c9b85c83ab46b0bf2fd90631c64d9479060e401602060405180830381865af4158015610fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fee91906134c6565b60408051828152602081018690529192506001600160a01b0386169133917f957db550c8482e0e40d923e90c7e1c7388a338f015b090168eae3a7dd36903c7910160405180910390a3506001949350505050565b6000546001600160a01b0316331461106d57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115611086576110866131ee565b106110a4576040516383b3712f60e01b815260040160405180910390fd5b6000825167ffffffffffffffff8111156110c0576110c0612d61565b6040519080825280602002602001820160405280156110e9578160200160208202803683370190505b506040517f1f5263e9000000000000000000000000000000000000000000000000000000008152909150737dac013c0caa344f7086ae3f06419be9208d6e8990631f5263e99061114090602390879060040161357d565b60006040518083038186803b15801561115857600080fd5b505af415801561116c573d6000803e3d6000fd5b5050505060008360008151811061118557611185613596565b602002602001015160200151905082601e600083815260200190815260200160002090816111b39190613406565b5060005b845181101561120d578481815181106111d2576111d2613596565b6020026020010151600001518382815181106111f0576111f0613596565b602090810291909101015280611205816135c2565b9150506111b7565b507f354e5f2b05309441ea51dd05db8e29f7a5e5341858336b8d4a1466ab7deef5ba8260405161123d91906135db565b60405180910390a150505050565b602a818154811061125b57600080fd5b60009182526020909120600290910201805460019091015490915082565b6060600f600001805461128b9061337d565b80601f01602080910402602001604051908101604052809291908181526020018280546112b79061337d565b80156113045780601f106112d957610100808354040283529160200191611304565b820191906000526020600020905b8154815290600101906020018083116112e757829003601f168201915b5050505050905090565b600f8054819061099d9061337d565b6000546001600160a01b0316331461134857604051631a88efbf60e11b815260040160405180910390fd5b60095461135e906001600160a01b031682612768565b50565b6000546001600160a01b0316331461138c57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff1660038111156113a5576113a56131ee565b106113c3576040516383b3712f60e01b815260040160405180910390fd5b6040517fbfc9867b000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e899063bfc9867b9061141990602390601f908690600401613613565b60006040518083038186803b15801561143157600080fd5b505af4158015611445573d6000803e3d6000fd5b505082516114599250602391506004612827565b80516040519081527ff49c7151a34f944c290bea0b71e18d61f02bfd24115ac372517b6ba94ebd9546906020015b60405180910390a150565b6000546001600160a01b031633146114bd57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff1660038111156114d6576114d66131ee565b106114f4576040516383b3712f60e01b815260040160405180910390fd5b6000825167ffffffffffffffff81111561151057611510612d61565b604051908082528060200260200182016040528015611539578160200160208202803683370190505b506040517f56d10ebd000000000000000000000000000000000000000000000000000000008152909150737dac013c0caa344f7086ae3f06419be9208d6e89906356d10ebd9061159390602390601f90889060040161363b565b60006040518083038186803b1580156115ab57600080fd5b505af41580156115bf573d6000803e3d6000fd5b505050506000836000815181106115d8576115d8613596565b602002602001015160200151905082601e600083815260200190815260200160002090816116069190613406565b5060005b84518110156116605784818151811061162557611625613596565b60200260200101516000015183828151811061164357611643613596565b602090810291909101015280611658816135c2565b91505061160a565b506014805460ff191660031790556040517f1d13bbc19c4b8f9e6a70801e6ff012075a3f608962f7374206a6b0dafc1992719061123d9084906135db565b6060600c60000180546116b09061337d565b90506000036116d257604051631f950c7960e11b815260040160405180910390fd5b600c805461128b9061337d565b601b8054610a779061337d565b600c8054819061099d9061337d565b600e8054610a779061337d565b6000546001600160a01b0316331461173357604051631a88efbf60e11b815260040160405180910390fd5b6015610a668282613406565b6040517f75ac38c2000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b038216602482015260009073e320252f58d744a09584c79ac4f3629fca3798cb906375ac38c290604401602060405180830381865af41580156117ba573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098891906134c6565b60058054819061099d9061337d565b60606011600001805461128b9061337d565b600080546001600160a01b0316331461182b57604051631a88efbf60e11b815260040160405180910390fd5b6040517f5c226beb000000000000000000000000000000000000000000000000000000008152602460048201819052810183905273128d1485f8feb919100fcddd0571df2975010acd90635c226beb9060440160006040518083038186803b15801561189657600080fd5b505af41580156118aa573d6000803e3d6000fd5b5050506000838152602460209081526040808320815160c08101835281546001600160a01b0390811682526001830154169381019390935260028101549183019190915260038082015493945091929091606084019160ff1690811115611913576119136131ee565b6003811115611924576119246131ee565b815260039190910154610100810460ff16151560208301526201000090046001600160a01b03166040909101526080810151909150156119ad5760408082015182516001600160a01b0390811660009081526028602090815284822060a08701519093168252919091529182208054919290916119a290849061365a565b90915550611a469050565b805160408083015190517f580e2c44000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b039092166024830152604482015273e320252f58d744a09584c79ac4f3629fca3798cb9063580e2c449060640160006040518083038186803b158015611a2d57600080fd5b505af4158015611a41573d6000803e3d6000fd5b505050505b6040518381527f6a9eda23525b3a9b3aa9326b05e25ca9af576996fa0ae91c62afbc835839b0cb90602001610e0f565b606060056000018054611a889061337d565b9050600003611aaa576040516373aba56b60e01b815260040160405180910390fd5b6005805461128b9061337d565b6040517f4bb4caef000000000000000000000000000000000000000000000000000000008152601f600482015260609073e320252f58d744a09584c79ac4f3629fca3798cb90634bb4caef90602401600060405180830381865af4158015611b23573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b4b91908101906136df565b905090565b60078054610a779061337d565b60138054610a779061337d565b60158054610a779061337d565b600081600003611bb3576040517fbabd61a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03841603611bf5576040517f1e4ec46b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f84a04370000000000000000000000000000000000000000000000000000000008152602460048201819052601f908201523360448201526001600160a01b038416606482015260848101839052600060a4820181905260c482018190529073128d1485f8feb919100fcddd0571df2975010acd906384a043709060e401602060405180830381865af4158015611c93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb791906134c6565b9050836001600160a01b0316336001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6000604051611cff91815260200190565b60405180910390a360408051828152602081018590526001600160a01b0386169133917f957db550c8482e0e40d923e90c7e1c7388a338f015b090168eae3a7dd36903c7910160405180910390a35060019392505050565b6000546001600160a01b03163314611d8257604051631a88efbf60e11b815260040160405180910390fd5b600954600254825173e320252f58d744a09584c79ac4f3629fca3798cb9263ec2a214f92601f926001600160a01b0390921691611dbf9190613779565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b039091166024830152604482015260640160006040518083038186803b158015611e0b57600080fd5b505af4158015611e1f573d6000803e3d6000fd5b5050505061135e816128ac565b601c8054610a779061337d565b600a8054610a779061337d565b6000546001600160a01b03163314611e7157604051631a88efbf60e11b815260040160405180910390fd5b6040517fd9ea7a0600000000000000000000000000000000000000000000000000000000815260236004820152601f602482015260448101829052737dac013c0caa344f7086ae3f06419be9208d6e899063d9ea7a069060640160006040518083038186803b158015611ee357600080fd5b505af4158015611ef7573d6000803e3d6000fd5b505050507f5ac1d96566a8d80ac0b7c75ce8ad501255fb99929aa34a2328f9b192b1d0c0a98160405161148791815260200190565b601e6020526000908152604090208054610a779061337d565b6000546001600160a01b03163314611f7057604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115611f8957611f896131ee565b10611fa7576040516383b3712f60e01b815260040160405180910390fd5b6040517fcd2002fd000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e899063cd2002fd90611ffd90602390601f908690600401613613565b60006040518083038186803b15801561201557600080fd5b505af4158015612029573d6000803e3d6000fd5b50506014805460ff19166002179055505080516040519081527fc40a4f74d715da2ee96119fbf8d8da1df0f5b79e92c3fd855f1ddc102d51d04790602001611487565b60606008600001805461128b9061337d565b6006546000906001600160a01b03166120aa576040516373aba56b60e01b815260040160405180910390fd5b506006546001600160a01b031690565b60168054610a779061337d565b601a8054610a779061337d565b612101604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6040517f5d1605b3000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b038316602482015273e320252f58d744a09584c79ac4f3629fca3798cb90635d1605b390604401606060405180830381865af4158015612179573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610988919061379b565b6121e3604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a08201529060c082019081526020016000905290565b6040516318366f3560e21b8152602360048201526024810183905273c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561223a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610988919081019061380b565b60188054610a779061337d565b600d546000906001600160a01b031661229b57604051631f950c7960e11b815260040160405180910390fd5b50600d546001600160a01b031690565b6060602a805480602002602001604051908101604052809291908181526020016000905b82821015612315578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906122cf565b50505050905090565b600080546001600160a01b0316331461234a57604051631a88efbf60e11b815260040160405180910390fd5b6040517f284d9c96000000000000000000000000000000000000000000000000000000008152602460048201819052601f908201526044810183905273128d1485f8feb919100fcddd0571df2975010acd9063284d9c969060640160006040518083038186803b1580156123bd57600080fd5b505af41580156123d1573d6000803e3d6000fd5b505050507ff293a19d8e1c857cb5b75138774de0ea944b21327ae79db4cb55296627b5237182604051610f1891815260200190565b60198054610a779061337d565b6040517fd8e9cf03000000000000000000000000000000000000000000000000000000008152602660048201526001600160a01b0380841660248301528216604482015260009073783c952feeb792aa63908c9b85c83ab46b0bf2fd9063d8e9cf0390606401602060405180830381865af4158015612496573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ba91906134c6565b9392505050565b6000546001600160a01b031633146124ec57604051631a88efbf60e11b815260040160405180910390fd5b600360145460ff166003811115612505576125056131ee565b10612523576040516383b3712f60e01b815260040160405180910390fd5b6040517f06846dce000000000000000000000000000000000000000000000000000000008152737dac013c0caa344f7086ae3f06419be9208d6e89906306846dce9061257990602390601f908690600401613613565b60006040518083038186803b15801561259157600080fd5b505af41580156125a5573d6000803e3d6000fd5b50506014805460ff19166002179055505080516040519081527f0bed382b9aad3b5629da3f0660006b5b0ebaf727367204f573a175544a0f930d90602001611487565b6012546001600160a01b0316331461261357604051631de3f8c960e21b815260040160405180910390fd5b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561266d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612695919081019061380b565b905060008160e0015160058111156126af576126af6131ee565b036126cd57604051630ead561960e11b815260040160405180910390fd5b610a6682612933565b60048054610a779061337d565b6000546001600160a01b0316331461270e57604051631a88efbf60e11b815260040160405180910390fd5b601a610a668282613406565b60018054610a779061337d565b6012546001600160a01b0316331461275257604051631de3f8c960e21b815260040160405180910390fd5b61135e81612b4b565b60178054610a779061337d565b6040517f51a0cf48000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b03831660248201526044810182905273e320252f58d744a09584c79ac4f3629fca3798cb906351a0cf489060640160006040518083038186803b1580156127e257600080fd5b505af41580156127f6573d6000803e3d6000fd5b505050506002548161280891906138db565b602d6000828254612819919061365a565b90915550610a669050612c96565b600081600581111561283b5761283b6131ee565b03612872576040517f7ec04df100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260208490526040902060068101805483919060ff191660018360058111156128a1576128a16131ee565b021790555050505050565b602a80546001810182556000918252825160029091027fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2810182905560208401517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390910155602b80549192909161292590849061365a565b9091555061135e9050612c96565b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af415801561298d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129b5919081019061380b565b905060028160c0015160058111156129cf576129cf6131ee565b14612a06576040517f6b67159000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048160e001516005811115612a1e57612a1e6131ee565b14612ace576040818101516060830151608084015192517f9030099a000000000000000000000000000000000000000000000000000000008152601f60048201526001600160a01b03928316602482015291166044820152606481019190915273e320252f58d744a09584c79ac4f3629fca3798cb90639030099a9060840160006040518083038186803b158015612ab557600080fd5b505af4158015612ac9573d6000803e3d6000fd5b505050505b60028160e001516005811115612ae657612ae66131ee565b03612afd57612afd81606001518260800151612768565b612b0a6023836003612827565b7f9bbe037a1a1faac87c3e07d5beed35ad6d3c54fbbc21637447918822abb04583828260e00151604051612b3f9291906138f2565b60405180910390a15050565b6040516318366f3560e21b8152602360048201526024810182905260009073c21b38fffc1bbe9cd95e7d9be962ad0dc5593e16906360d9bcd490604401600060405180830381865af4158015612ba5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612bcd919081019061380b565b905060008160e001516005811115612be757612be76131ee565b03612c0557604051630ead561960e11b815260040160405180910390fd5b60038160c001516005811115612c1d57612c1d6131ee565b14612c54576040517f1109e7ce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612c616023836004612827565b7fa86580040b7b220b796aa9b66b3eede5540d9130c21f31e27b6667458720f3f8828260e00151604051612b3f9291906138f2565b602d54602b54612ca6919061390f565b602c819055600254612cb791613779565b602e55565b600060208284031215612cce57600080fd5b81356001600160e01b0319811681146124ba57600080fd5b60005b83811015612d01578181015183820152602001612ce9565b50506000910152565b60008151808452612d22816020860160208601612ce6565b601f01601f19169290920160200192915050565b604081526000612d496040830185612d0a565b90506001600160a01b03831660208301529392505050565b634e487b7160e01b600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612d9b57612d9b612d61565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715612dca57612dca612d61565b604052919050565b600067ffffffffffffffff821115612dec57612dec612d61565b50601f01601f191660200190565b600082601f830112612e0b57600080fd5b8135612e1e612e1982612dd2565b612da1565b818152846020838601011115612e3357600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215612e6257600080fd5b813567ffffffffffffffff811115612e7957600080fd5b612e8584828501612dfa565b949350505050565b6020815260006124ba6020830184612d0a565b6001600160a01b038116811461135e57600080fd5b60008060408385031215612ec857600080fd5b8235612ed381612ea0565b946020939093013593505050565b600060208284031215612ef357600080fd5b5035919050565b600080600060608486031215612f0f57600080fd5b8335612f1a81612ea0565b92506020840135612f2a81612ea0565b929592945050506040919091013590565b600067ffffffffffffffff821115612f5557612f55612d61565b5060051b60200190565b600060c08284031215612f7157600080fd5b60405160c0810167ffffffffffffffff8282108183111715612f9557612f95612d61565b81604052829350843583526020850135602084015260408501359150612fba82612ea0565b81604084015260608501359150612fd082612ea0565b8160608401526080850135608084015260a0850135915080821115612ff457600080fd5b5061300185828601612dfa565b60a0830152505092915050565b6000806040838503121561302157600080fd5b823567ffffffffffffffff8082111561303957600080fd5b818501915085601f83011261304d57600080fd5b8135602061305d612e1983612f3b565b82815260059290921b8401810191818101908984111561307c57600080fd5b8286015b848110156130b4578035868111156130985760008081fd5b6130a68c86838b0101612f5f565b845250918301918301613080565b50965050860135925050808211156130cb57600080fd5b506130d885828601612dfa565b9150509250929050565b6000602082840312156130f457600080fd5b813567ffffffffffffffff81111561310b57600080fd5b612e8584828501612f5f565b60006020828403121561312957600080fd5b81356124ba81612ea0565b6020808252825182820181905260009190848201906040850190845b818110156131935761318083855180516001600160a01b0316825260208082015190830152604090810151910152565b9284019260609290920191600101613150565b50909695505050505050565b6000604082840312156131b157600080fd5b6040516040810181811067ffffffffffffffff821117156131d4576131d4612d61565b604052823581526020928301359281019290925250919050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310613218576132186131ee565b91905290565b81516001600160a01b03168152602080830151908201526040808301519082015260608101610988565b6006811061135e5761135e6131ee565b61326181613248565b9052565b602081528151602082015260208201516040820152600060408301516001600160a01b0380821660608501528060608601511660808501525050608083015160a083015260a08301516101008060c08501526132c5610120850183612d0a565b915060c08501516132d960e0860182613258565b5060e08501516132eb82860182613258565b5090949350505050565b602080825282518282018190526000919060409081850190868401855b8281101561333757815180518552860151868501529284019290850190600101613312565b5091979650505050505050565b6000806040838503121561335757600080fd5b823561336281612ea0565b9150602083013561337281612ea0565b809150509250929050565b600181811c9082168061339157607f821691505b6020821081036133b157634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561340157600081815260208120601f850160051c810160208610156133de5750805b601f850160051c820191505b818110156133fd578281556001016133ea565b5050505b505050565b815167ffffffffffffffff81111561342057613420612d61565b6134348161342e845461337d565b846133b7565b602080601f83116001811461346957600084156134515750858301515b600019600386901b1c1916600185901b1785556133fd565b600085815260208120601f198616915b8281101561349857888601518255948401946001909101908401613479565b50858210156134b65787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156134d857600080fd5b5051919050565b8051825260208101516020830152600060408201516001600160a01b03808216604086015280606085015116606086015250506080820151608084015260a082015160c060a0850152612e8560c0850182612d0a565b600081518084526020808501808196508360051b8101915082860160005b8581101561333757828403895261356b8483516134df565b98850198935090840190600101613553565b828152604060208201526000612e856040830184613535565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016135d4576135d46135ac565b5060010190565b6020808252825182820181905260009190848201906040850190845b81811015613193578351835292840192918401916001016135f7565b83815282602082015260606040820152600061363260608301846134df565b95945050505050565b8381528260208201526060604082015260006136326060830184613535565b80820180821115610988576109886135ac565b8051610e1d81612ea0565b60006060828403121561368a57600080fd5b6040516060810181811067ffffffffffffffff821117156136ad576136ad612d61565b806040525080915082516136c081612ea0565b8082525060208301516020820152604083015160408201525092915050565b600060208083850312156136f257600080fd5b825167ffffffffffffffff81111561370957600080fd5b8301601f8101851361371a57600080fd5b8051613728612e1982612f3b565b8181526060918202830184019184820191908884111561374757600080fd5b938501935b8385101561376d5761375e8986613678565b8352938401939185019161374c565b50979650505050505050565b60008261379657634e487b7160e01b600052601260045260246000fd5b500490565b6000606082840312156137ad57600080fd5b6124ba8383613678565b600082601f8301126137c857600080fd5b81516137d6612e1982612dd2565b8181528460208386010111156137eb57600080fd5b612e85826020830160208701612ce6565b805160068110610e1d57600080fd5b60006020828403121561381d57600080fd5b815167ffffffffffffffff8082111561383557600080fd5b90830190610100828603121561384a57600080fd5b613852612d77565b825181526020830151602082015261386c6040840161366d565b604082015261387d6060840161366d565b60608201526080830151608082015260a08301518281111561389e57600080fd5b6138aa878286016137b7565b60a0830152506138bc60c084016137fc565b60c08201526138cd60e084016137fc565b60e082015295945050505050565b8082028115828204841417610988576109886135ac565b8281526040810161390283613248565b8260208301529392505050565b81810381811115610988576109886135ac56fea26469706673582212206b14e1154ef6f2ad60e97f357f0e3f3018b51011d5f6cfc870fed9abac6e424564736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000006c0000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000980000000000000000000000000a72cd393790f4d85da4d348d7a6cc7de05d0f68100000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000006b0cbc8000000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006567d08000000000000000000000000000000000000000000000000000000000000000034e2f41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000717b22696e74657265737452617465223a3430312c22636f75706f6e7061796d656e74416d6f756e7463656e74223a343031352c2266696e616c526564656d7074696f6e416d6f756e7450657263656e74223a31303030302c22696e7465726573745061796d656e7444617465223a5b5d7d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000867b2273656375726974794f6e636861696e436172626f6e466f6f747072696e74457374696d6174654b67434f326571756976616c656e74427959656172223a22302e3634222c22657374696d61746544617465223a22323032332d31312d3330222c227265706f7274223a22687474703a2f2f7777772e7367666f7267652e636f6d2f227d2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009556e736563757265640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002253454355524954595f544f4b454e535f494e5f5245474953545245445f464f524d5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e2f4100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007454d544e205347000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017687474703a2f2f7374723a363636302f6772617068716c0000000000000000000000000000000000000000000000000000000000000000000000000000000006626f6e64563100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a400000000000000000000000000000000000000000000000000000000000000194f32524e453849425850345230544438505534312d4446494e000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a400000000000000000000000000000000000000000000000000000000000000194f32524e453849425850345230544438505534312d4446494e00000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000065980908e77b276c3e6cd73f609da62d1fc8e062000000000000000000000000000000000000000000000000000000000000001a4f32524e453849425850345230544438505534312d20534753530000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000e08106fad4add8dbffbbd0813027625a57c06fbd000000000000000000000000000000000000000000000000000000000000000d464f5247455f534554544c455200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000089ace546613b2cbb4510eab030a61bcdd11c8b8500000000000000000000000000000000000000000000000000000000000000143936393530304658384b34305a4457344633373700000000000000000000000000000000000000000000000000000000000000000000000000000000000000034555520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4c5558454d424f55524700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000246520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040534f43494554452047454e4552414c45204555522031304d203359204449474954414c20475245454e2053454e494f5220505245464552524544204e4f5445530000000000000000000000000000000000000000000000000000000000000040534f43494554452047454e4552414c45204555522031304d203359204449474954414c20475245454e2053454e494f5220505245464552524544204e4f544553000000000000000000000000000000000000000000000000000000000000000c46523030313430304d4447350000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : basicProductInput (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
91 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000340
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000360
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 00000000000000000000000000000000000000000000000000000000000003c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000400
Arg [6] : 00000000000000000000000000000000000000000000000000000000000004a0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000560
Arg [8] : 00000000000000000000000000000000000000000000000000000000000005a0
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000600
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000640
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000680
Arg [12] : 00000000000000000000000000000000000000000000000000000000000006c0
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000700
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000780
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000800
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000880
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000900
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000980
Arg [19] : 000000000000000000000000a72cd393790f4d85da4d348d7a6cc7de05d0f681
Arg [20] : 00000000000000000000000000000000000000000000000000000000000009c0
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000a00
Arg [22] : 000000000000000000000000000000000000000000000000000000006b0cbc80
Arg [23] : 0000000000000000000000000000000000000000000000000000000000989680
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000a40
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000aa0
Arg [26] : 0000000000000000000000000000000000000000000000000000000000000b00
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [29] : 000000000000000000000000000000000000000000000000000000003b9aca00
Arg [30] : 000000000000000000000000000000000000000000000000000000006567d080
Arg [31] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [32] : 4e2f410000000000000000000000000000000000000000000000000000000000
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000071
Arg [34] : 7b22696e74657265737452617465223a3430312c22636f75706f6e7061796d65
Arg [35] : 6e74416d6f756e7463656e74223a343031352c2266696e616c526564656d7074
Arg [36] : 696f6e416d6f756e7450657263656e74223a31303030302c22696e7465726573
Arg [37] : 745061796d656e7444617465223a5b5d7d000000000000000000000000000000
Arg [38] : 0000000000000000000000000000000000000000000000000000000000000086
Arg [39] : 7b2273656375726974794f6e636861696e436172626f6e466f6f747072696e74
Arg [40] : 457374696d6174654b67434f326571756976616c656e74427959656172223a22
Arg [41] : 302e3634222c22657374696d61746544617465223a22323032332d31312d3330
Arg [42] : 222c227265706f7274223a22687474703a2f2f7777772e7367666f7267652e63
Arg [43] : 6f6d2f227d200000000000000000000000000000000000000000000000000000
Arg [44] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [45] : 556e736563757265640000000000000000000000000000000000000000000000
Arg [46] : 0000000000000000000000000000000000000000000000000000000000000022
Arg [47] : 53454355524954595f544f4b454e535f494e5f5245474953545245445f464f52
Arg [48] : 4d53000000000000000000000000000000000000000000000000000000000000
Arg [49] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [50] : 4e2f410000000000000000000000000000000000000000000000000000000000
Arg [51] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [52] : 454d544e20534700000000000000000000000000000000000000000000000000
Arg [53] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [54] : 687474703a2f2f7374723a363636302f6772617068716c000000000000000000
Arg [55] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [56] : 626f6e6456310000000000000000000000000000000000000000000000000000
Arg [57] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [58] : 000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a4
Arg [59] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [60] : 4f32524e453849425850345230544438505534312d4446494e00000000000000
Arg [61] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [62] : 000000000000000000000000dc03823bbccc2fe2a6cea8976ab803709c1be0a4
Arg [63] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [64] : 4f32524e453849425850345230544438505534312d4446494e00000000000000
Arg [65] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [66] : 00000000000000000000000065980908e77b276c3e6cd73f609da62d1fc8e062
Arg [67] : 000000000000000000000000000000000000000000000000000000000000001a
Arg [68] : 4f32524e453849425850345230544438505534312d2053475353000000000000
Arg [69] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [70] : 000000000000000000000000e08106fad4add8dbffbbd0813027625a57c06fbd
Arg [71] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [72] : 464f5247455f534554544c455200000000000000000000000000000000000000
Arg [73] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [74] : 00000000000000000000000089ace546613b2cbb4510eab030a61bcdd11c8b85
Arg [75] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [76] : 3936393530304658384b34305a44573446333737000000000000000000000000
Arg [77] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [78] : 4555520000000000000000000000000000000000000000000000000000000000
Arg [79] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [80] : 4c5558454d424f55524700000000000000000000000000000000000000000000
Arg [81] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [82] : 4652000000000000000000000000000000000000000000000000000000000000
Arg [83] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [84] : 534f43494554452047454e4552414c45204555522031304d2033592044494749
Arg [85] : 54414c20475245454e2053454e494f5220505245464552524544204e4f544553
Arg [86] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [87] : 534f43494554452047454e4552414c45204555522031304d2033592044494749
Arg [88] : 54414c20475245454e2053454e494f5220505245464552524544204e4f544553
Arg [89] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [90] : 46523030313430304d4447350000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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.