Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 18 from a total of 18 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Confirm Payment ... | 18685331 | 799 days ago | IN | 0 ETH | 0.00311784 | ||||
| Confirm Payment ... | 18685330 | 799 days ago | IN | 0 ETH | 0.00842127 | ||||
| Confirm Payment ... | 18685329 | 799 days ago | IN | 0 ETH | 0.00314076 | ||||
| Confirm Payment ... | 18685328 | 799 days ago | IN | 0 ETH | 0.00928974 | ||||
| Confirm Payment ... | 18685326 | 799 days ago | IN | 0 ETH | 0.00328469 | ||||
| Confirm Payment ... | 18685325 | 799 days ago | IN | 0 ETH | 0.00906183 | ||||
| Confirm Payment ... | 18685324 | 799 days ago | IN | 0 ETH | 0.00315977 | ||||
| Confirm Payment ... | 18685322 | 799 days ago | IN | 0 ETH | 0.00919218 | ||||
| Confirm Payment ... | 18685321 | 799 days ago | IN | 0 ETH | 0.00321608 | ||||
| Confirm Payment ... | 18685320 | 799 days ago | IN | 0 ETH | 0.00905823 | ||||
| Initiate Trade | 18685295 | 799 days ago | IN | 0 ETH | 0.01596464 | ||||
| Initiate Trade | 18685291 | 799 days ago | IN | 0 ETH | 0.01650287 | ||||
| Initiate Trade | 18685287 | 799 days ago | IN | 0 ETH | 0.01581964 | ||||
| Initiate Trade | 18685283 | 799 days ago | IN | 0 ETH | 0.01456318 | ||||
| Initiate Trade | 18685279 | 799 days ago | IN | 0 ETH | 0.01523378 | ||||
| Confirm Payment ... | 18685242 | 799 days ago | IN | 0 ETH | 0.00284259 | ||||
| Confirm Payment ... | 18685239 | 799 days ago | IN | 0 ETH | 0.00768353 | ||||
| Initiate Subscri... | 18685234 | 799 days ago | IN | 0 ETH | 0.0147281 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60806040 | 18685137 | 799 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract contains unverified libraries: ApproveAdapterLibrary, SecurityTokenBalancesLibrary, SettlementRepositoryLibrary, SettlementWorkflowLibrary, TransferAdapterLibrary
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Product
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
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);
}
}// 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;
}
}// 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);
}// 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;
}
}
}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);
}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;
}
}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);
}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];
}
}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));
}
}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;
}
}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;
}
}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;
}
}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
);
}
}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;
}
}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;
}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();
_;
}
}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();
{
"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
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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"}]Contract Creation Code
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):
-----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
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.