Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 71 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Multicall | 24649583 | 29 hrs ago | IN | 0 ETH | 0.00019557 | ||||
| Approve Deposits | 24649232 | 31 hrs ago | IN | 0 ETH | 0.00019303 | ||||
| Multicall | 24649163 | 31 hrs ago | IN | 0 ETH | 0.00029806 | ||||
| Multicall | 24643537 | 2 days ago | IN | 0.00065707 ETH | 0.00006334 | ||||
| Multicall | 24643318 | 2 days ago | IN | 0.00065707 ETH | 0.00013108 | ||||
| Approve Deposits | 24643317 | 2 days ago | IN | 0.00052673 ETH | 0.00011694 | ||||
| Approve Deposits | 24642845 | 2 days ago | IN | 0.00052673 ETH | 0.00016485 | ||||
| Approve Deposits | 24642845 | 2 days ago | IN | 0 ETH | 0.00005631 | ||||
| Multicall | 24642607 | 2 days ago | IN | 0 ETH | 0.00007783 | ||||
| Approve Deposits | 24636415 | 3 days ago | IN | 0.00016397 ETH | 0.00007214 | ||||
| Approve Deposits | 24635221 | 3 days ago | IN | 0 ETH | 0.00007128 | ||||
| Multicall | 24635181 | 3 days ago | IN | 0 ETH | 0.00016332 | ||||
| Multicall | 24634180 | 3 days ago | IN | 0.00065707 ETH | 0.00019458 | ||||
| Multicall | 24634137 | 3 days ago | IN | 0 ETH | 0.00022666 | ||||
| Approve Deposits | 24627655 | 4 days ago | IN | 0 ETH | 0.00008264 | ||||
| Multicall | 24627654 | 4 days ago | IN | 0.00065707 ETH | 0.00020673 | ||||
| Multicall | 24627654 | 4 days ago | IN | 0.00065707 ETH | 0.0002049 | ||||
| Approve Deposits | 24627302 | 4 days ago | IN | 0.00052673 ETH | 0.0000448 | ||||
| Approve Redeems | 24627301 | 4 days ago | IN | 0 ETH | 0.00000608 | ||||
| Approve Redeems | 24627300 | 4 days ago | IN | 0 ETH | 0.00000618 | ||||
| Multicall | 24622574 | 5 days ago | IN | 0.00002217 ETH | 0.00003723 | ||||
| Approve Deposits | 24622547 | 5 days ago | IN | 0.00001985 ETH | 0.00003632 | ||||
| Multicall | 24621644 | 5 days ago | IN | 0 ETH | 0.00005189 | ||||
| Approve Redeems | 24621596 | 5 days ago | IN | 0 ETH | 0.00001226 | ||||
| Approve Redeems | 24621459 | 5 days ago | IN | 0 ETH | 0.00001128 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| With Batch | 24650133 | 28 hrs ago | 0.00016892 ETH | ||||
| Multicall | 24650133 | 28 hrs ago | 0.00016892 ETH | ||||
| With Batch | 24643537 | 2 days ago | 0.00065707 ETH | ||||
| With Batch | 24643318 | 2 days ago | 0.00065707 ETH | ||||
| Request Callback | 24643317 | 2 days ago | 0.00052673 ETH | ||||
| Request Callback | 24642845 | 2 days ago | 0.00052673 ETH | ||||
| Request Callback | 24636415 | 3 days ago | 0.00016397 ETH | ||||
| Request Callback | 24636029 | 3 days ago | 0.00016397 ETH | ||||
| Approve Deposits | 24636029 | 3 days ago | 0.00016397 ETH | ||||
| With Batch | 24634180 | 3 days ago | 0.00065707 ETH | ||||
| With Batch | 24627654 | 4 days ago | 0.00065707 ETH | ||||
| With Batch | 24627654 | 4 days ago | 0.00065707 ETH | ||||
| Request Callback | 24627302 | 4 days ago | 0.00052673 ETH | ||||
| With Batch | 24622574 | 5 days ago | 0.00002217 ETH | ||||
| Request Callback | 24622547 | 5 days ago | 0.00001985 ETH | ||||
| With Batch | 24599448 | 8 days ago | 0.00014952 ETH | ||||
| Multicall | 24599448 | 8 days ago | 0.00014952 ETH | ||||
| With Batch | 24599348 | 8 days ago | 0.00016851 ETH | ||||
| Multicall | 24599348 | 8 days ago | 0.00016851 ETH | ||||
| Request Callback | 24599268 | 8 days ago | 0.000162 ETH | ||||
| Approve Deposits | 24599268 | 8 days ago | 0.000162 ETH | ||||
| With Batch | 24585579 | 10 days ago | 0.00022756 ETH | ||||
| Multicall | 24585579 | 10 days ago | 0.00022756 ETH | ||||
| Request Callback | 24585311 | 10 days ago | 0.00021339 ETH | ||||
| Approve Deposits | 24585311 | 10 days ago | 0.00021339 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BatchRequestManager
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {RequestCallbackMessageLib} from "./libraries/RequestCallbackMessageLib.sol";
import {RequestMessageLib, RequestType as RequestMessageType} from "./libraries/RequestMessageLib.sol";
import {
IBatchRequestManager,
EpochInvestAmounts,
EpochRedeemAmounts,
UserOrder,
QueuedOrder,
RequestType,
EpochId
} from "./interfaces/IBatchRequestManager.sol";
import {Auth} from "../misc/Auth.sol";
import {D18, d18} from "../misc/types/D18.sol";
import {IAuth} from "../misc/interfaces/IAuth.sol";
import {CastLib} from "../misc/libraries/CastLib.sol";
import {MathLib} from "../misc/libraries/MathLib.sol";
import {IERC165} from "../misc/interfaces/IERC165.sol";
import {BytesLib} from "../misc/libraries/BytesLib.sol";
import {PoolId} from "../core/types/PoolId.sol";
import {AssetId} from "../core/types/AssetId.sol";
import {PricingLib} from "../core/libraries/PricingLib.sol";
import {ShareClassId} from "../core/types/ShareClassId.sol";
import {IGateway} from "../core/messaging/interfaces/IGateway.sol";
import {BatchedMulticall} from "../core/utils/BatchedMulticall.sol";
import {IHubRegistry} from "../core/hub/interfaces/IHubRegistry.sol";
import {IHubRequestManagerCallback} from "../core/hub/interfaces/IHubRequestManagerCallback.sol";
import {IHubRequestManager, IHubRequestManagerNotifications} from "../core/hub/interfaces/IHubRequestManager.sol";
/// @title Batch Request Manager
/// @notice Manager for handling deposit/redeem requests, epochs, and fulfillment logic for share classes
contract BatchRequestManager is Auth, BatchedMulticall, IBatchRequestManager {
using MathLib for *;
using CastLib for *;
using BytesLib for bytes;
using RequestMessageLib for *;
using RequestCallbackMessageLib for *;
IHubRequestManagerCallback public hub;
IHubRegistry public immutable hubRegistry;
// Epochs
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => EpochId))) public epochId;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint32 epochId_ => EpochInvestAmounts))))
public epochInvestAmounts;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(uint32 epochId_ => EpochRedeemAmounts))))
public epochRedeemAmounts;
// Pending requests
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => uint128))) public pendingRedeem;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => uint128))) public pendingDeposit;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => UserOrder)))) public
redeemRequest;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => UserOrder)))) public
depositRequest;
// Queued requests
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => QueuedOrder)))) public
queuedRedeemRequest;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => QueuedOrder)))) public
queuedDepositRequest;
// Force cancel request safeguards
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => bool)))) public
allowForceDepositCancel;
mapping(PoolId => mapping(ShareClassId => mapping(AssetId => mapping(bytes32 investor => bool)))) public
allowForceRedeemCancel;
constructor(IHubRegistry hubRegistry_, IGateway gateway_, address deployer)
Auth(deployer)
BatchedMulticall(gateway_)
{
hubRegistry = hubRegistry_;
}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
/// Accepts a `bytes32` representation of 'hub'
function file(bytes32 what, address data) external auth {
if (what == "hub") hub = IHubRequestManagerCallback(data);
else revert FileUnrecognizedParam();
emit File(what, data);
}
modifier isManager(PoolId poolId) {
require(hubRegistry.manager(poolId, msgSender()), IAuth.NotAuthorized());
_;
}
/// @dev used only for migrations
function setEpochIds(PoolId poolId, ShareClassId scId, AssetId assetId, EpochId memory epochIdData) external auth {
epochId[poolId][scId][assetId] = epochIdData;
emit EpochIdModified(poolId, scId, assetId, epochIdData);
}
//----------------------------------------------------------------------------------------------
// Incoming requests
//----------------------------------------------------------------------------------------------
/// @inheritdoc IHubRequestManager
function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external auth {
uint8 kind = uint8(RequestMessageLib.requestType(payload));
if (kind == uint8(RequestMessageType.DepositRequest)) {
RequestMessageLib.DepositRequest memory m = payload.deserializeDepositRequest();
requestDeposit(poolId, scId, m.amount, m.investor, assetId);
} else if (kind == uint8(RequestMessageType.RedeemRequest)) {
RequestMessageLib.RedeemRequest memory m = payload.deserializeRedeemRequest();
requestRedeem(poolId, scId, m.amount, m.investor, assetId);
} else if (kind == uint8(RequestMessageType.CancelDepositRequest)) {
RequestMessageLib.CancelDepositRequest memory m = payload.deserializeCancelDepositRequest();
uint128 cancelledAssetAmount = cancelDepositRequest(poolId, scId, m.investor, assetId);
// Cancellation might have been queued such that it will be executed in the future during claiming
if (cancelledAssetAmount > 0) {
hub.requestCallback(
poolId,
scId,
assetId,
RequestCallbackMessageLib.FulfilledDepositRequest(m.investor, 0, 0, cancelledAssetAmount)
.serialize(),
0,
true,
address(0) // Refund is not used because we're in unpaid mode with no payment
);
}
} else if (kind == uint8(RequestMessageType.CancelRedeemRequest)) {
RequestMessageLib.CancelRedeemRequest memory m = payload.deserializeCancelRedeemRequest();
uint128 cancelledShareAmount = cancelRedeemRequest(poolId, scId, m.investor, assetId);
// Cancellation might have been queued such that it will be executed in the future during claiming
if (cancelledShareAmount > 0) {
hub.requestCallback(
poolId,
scId,
assetId,
RequestCallbackMessageLib.FulfilledRedeemRequest(m.investor, 0, 0, cancelledShareAmount)
.serialize(),
0,
true,
address(0) // Refund is not used because we're in unpaid mode with no payment
);
}
} else {
revert UnknownRequestType();
}
}
/// @inheritdoc IBatchRequestManager
function requestDeposit(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId depositAssetId)
public
auth
{
// NOTE: Vaults ensure amount > 0
_updatePending(poolId, scId_, amount, true, investor, depositAssetId, RequestType.Deposit);
}
/// @inheritdoc IBatchRequestManager
function cancelDepositRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
public
auth
returns (uint128 cancelledAssetAmount)
{
allowForceDepositCancel[poolId][scId_][depositAssetId][investor] = true;
uint128 cancellingAmount = depositRequest[poolId][scId_][depositAssetId][investor].pending;
return _updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);
}
/// @inheritdoc IBatchRequestManager
function requestRedeem(PoolId poolId, ShareClassId scId_, uint128 amount, bytes32 investor, AssetId payoutAssetId)
public
auth
{
// NOTE: Vaults ensure amount > 0
_updatePending(poolId, scId_, amount, true, investor, payoutAssetId, RequestType.Redeem);
}
/// @inheritdoc IBatchRequestManager
function cancelRedeemRequest(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
public
auth
returns (uint128 cancelledShareAmount)
{
allowForceRedeemCancel[poolId][scId_][payoutAssetId][investor] = true;
uint128 cancellingAmount = redeemRequest[poolId][scId_][payoutAssetId][investor].pending;
return _updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);
}
//----------------------------------------------------------------------------------------------
// Manager actions
//----------------------------------------------------------------------------------------------
/// @inheritdoc IBatchRequestManager
function approveDeposits(
PoolId poolId,
ShareClassId scId_,
AssetId depositAssetId,
uint32 nowDepositEpochId,
uint128 approvedAssetAmount,
D18 pricePoolPerAsset,
address refund
) external payable isManager(poolId) {
require(
nowDepositEpochId == nowDepositEpoch(poolId, scId_, depositAssetId),
EpochNotInSequence(nowDepositEpochId, nowDepositEpoch(poolId, scId_, depositAssetId))
);
// Limit in case approved > pending due to race condition of FM approval and async incoming requests
uint128 pendingAssetAmount = pendingDeposit[poolId][scId_][depositAssetId];
require(approvedAssetAmount <= pendingAssetAmount, InsufficientPending());
require(approvedAssetAmount > 0, ZeroApprovalAmount());
uint128 approvedPoolAmount = PricingLib.convertWithPrice(
approvedAssetAmount, hubRegistry.decimals(depositAssetId), hubRegistry.decimals(poolId), pricePoolPerAsset
);
// Update epoch data
EpochInvestAmounts storage epochAmounts = epochInvestAmounts[poolId][scId_][depositAssetId][nowDepositEpochId];
epochAmounts.approvedAssetAmount = approvedAssetAmount;
epochAmounts.approvedPoolAmount = approvedPoolAmount;
epochAmounts.pendingAssetAmount = pendingAssetAmount;
epochAmounts.pricePoolPerAsset = pricePoolPerAsset;
// Reduce pending
pendingDeposit[poolId][scId_][depositAssetId] -= approvedAssetAmount;
pendingAssetAmount -= approvedAssetAmount;
epochId[poolId][scId_][depositAssetId].deposit = nowDepositEpochId;
emit ApproveDeposits(
poolId,
scId_,
depositAssetId,
nowDepositEpochId,
approvedPoolAmount,
approvedAssetAmount,
pendingAssetAmount
);
bytes memory callback =
RequestCallbackMessageLib.ApprovedDeposits(approvedAssetAmount, pricePoolPerAsset.raw()).serialize();
hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, 0, false, refund);
}
/// @inheritdoc IBatchRequestManager
function approveRedeems(
PoolId poolId,
ShareClassId scId_,
AssetId payoutAssetId,
uint32 nowRedeemEpochId,
uint128 approvedShareAmount,
D18 pricePoolPerAsset
) external payable isManager(poolId) {
require(
nowRedeemEpochId == nowRedeemEpoch(poolId, scId_, payoutAssetId),
EpochNotInSequence(nowRedeemEpochId, nowRedeemEpoch(poolId, scId_, payoutAssetId))
);
// Limit in case approved > pending due to race condition of FM approval and async incoming requests
uint128 pendingShareAmount = pendingRedeem[poolId][scId_][payoutAssetId];
require(approvedShareAmount <= pendingShareAmount, InsufficientPending());
require(approvedShareAmount > 0, ZeroApprovalAmount());
// Update epoch data
EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][nowRedeemEpochId];
epochAmounts.approvedShareAmount = approvedShareAmount;
epochAmounts.pendingShareAmount = pendingShareAmount;
epochAmounts.pricePoolPerAsset = pricePoolPerAsset;
// Reduce pending
pendingRedeem[poolId][scId_][payoutAssetId] -= approvedShareAmount;
pendingShareAmount -= approvedShareAmount;
epochId[poolId][scId_][payoutAssetId].redeem = nowRedeemEpochId;
emit ApproveRedeems(poolId, scId_, payoutAssetId, nowRedeemEpochId, approvedShareAmount, pendingShareAmount);
}
/// @inheritdoc IBatchRequestManager
function issueShares(
PoolId poolId,
ShareClassId scId_,
AssetId depositAssetId,
uint32 nowIssueEpochId,
D18 pricePoolPerShare,
uint128 extraGasLimit,
address refund
) external payable isManager(poolId) {
require(nowIssueEpochId <= epochId[poolId][scId_][depositAssetId].deposit, EpochNotFound());
require(
nowIssueEpochId == nowIssueEpoch(poolId, scId_, depositAssetId),
EpochNotInSequence(nowIssueEpochId, nowIssueEpoch(poolId, scId_, depositAssetId))
);
EpochInvestAmounts storage epochAmounts = epochInvestAmounts[poolId][scId_][depositAssetId][nowIssueEpochId];
epochAmounts.pricePoolPerShare = pricePoolPerShare;
uint128 issuedShareAmount = pricePoolPerShare.isNotZero()
? PricingLib.assetToShareAmount(
epochAmounts.approvedAssetAmount,
hubRegistry.decimals(depositAssetId),
hubRegistry.decimals(poolId),
epochAmounts.pricePoolPerAsset,
pricePoolPerShare,
MathLib.Rounding.Down
)
: 0;
epochAmounts.issuedAt = block.timestamp.toUint64();
epochId[poolId][scId_][depositAssetId].issue = nowIssueEpochId;
emit IssueShares(
poolId,
scId_,
depositAssetId,
nowIssueEpochId,
pricePoolPerShare,
epochAmounts.pricePoolPerAsset.isNotZero()
? PricingLib.priceAssetPerShare(epochAmounts.pricePoolPerShare, epochAmounts.pricePoolPerAsset)
: d18(0),
issuedShareAmount
);
bytes memory callback =
RequestCallbackMessageLib.IssuedShares(issuedShareAmount, pricePoolPerShare.raw()).serialize();
hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, extraGasLimit, false, refund);
}
/// @inheritdoc IBatchRequestManager
function revokeShares(
PoolId poolId,
ShareClassId scId_,
AssetId payoutAssetId,
uint32 nowRevokeEpochId,
D18 pricePoolPerShare,
uint128 extraGasLimit,
address refund
) external payable isManager(poolId) {
(uint128 payoutAssetAmount, uint128 revokedShareAmount) =
_revokeShares(poolId, scId_, payoutAssetId, nowRevokeEpochId, pricePoolPerShare);
bytes memory callback = RequestCallbackMessageLib.RevokedShares(
payoutAssetAmount, revokedShareAmount, pricePoolPerShare.raw()
).serialize();
hub.requestCallback{value: msgValue()}(poolId, scId_, payoutAssetId, callback, extraGasLimit, false, refund);
}
function _revokeShares(
PoolId poolId,
ShareClassId scId_,
AssetId payoutAssetId,
uint32 nowRevokeEpochId,
D18 pricePoolPerShare
) internal returns (uint128 payoutAssetAmount, uint128 revokedShareAmount) {
require(nowRevokeEpochId <= epochId[poolId][scId_][payoutAssetId].redeem, EpochNotFound());
require(
nowRevokeEpochId == nowRevokeEpoch(poolId, scId_, payoutAssetId),
EpochNotInSequence(nowRevokeEpochId, nowRevokeEpoch(poolId, scId_, payoutAssetId))
);
EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][nowRevokeEpochId];
epochAmounts.pricePoolPerShare = pricePoolPerShare;
// NOTE: shares and pool currency have the same decimals - no conversion needed!
uint128 payoutPoolAmount = pricePoolPerShare.mulUint128(epochAmounts.approvedShareAmount, MathLib.Rounding.Down);
payoutAssetAmount = epochAmounts.pricePoolPerAsset.isNotZero()
? PricingLib.shareToAssetAmount(
epochAmounts.approvedShareAmount,
hubRegistry.decimals(poolId),
hubRegistry.decimals(payoutAssetId),
epochAmounts.pricePoolPerShare,
epochAmounts.pricePoolPerAsset,
MathLib.Rounding.Down
)
: 0;
revokedShareAmount = epochAmounts.approvedShareAmount;
epochAmounts.payoutAssetAmount = payoutAssetAmount;
epochAmounts.revokedAt = block.timestamp.toUint64();
epochId[poolId][scId_][payoutAssetId].revoke = nowRevokeEpochId;
emit RevokeShares(
poolId,
scId_,
payoutAssetId,
nowRevokeEpochId,
pricePoolPerShare,
epochAmounts.pricePoolPerAsset.isNotZero()
? PricingLib.priceAssetPerShare(epochAmounts.pricePoolPerShare, epochAmounts.pricePoolPerAsset)
: d18(0),
epochAmounts.approvedShareAmount,
payoutAssetAmount,
payoutPoolAmount
);
}
/// @inheritdoc IBatchRequestManager
function forceCancelDepositRequest(
PoolId poolId,
ShareClassId scId_,
bytes32 investor,
AssetId depositAssetId,
address refund
) external payable isManager(poolId) {
require(allowForceDepositCancel[poolId][scId_][depositAssetId][investor], CancellationInitializationRequired());
uint128 cancellingAmount = depositRequest[poolId][scId_][depositAssetId][investor].pending;
uint128 cancelledAssetAmount =
_updatePending(poolId, scId_, cancellingAmount, false, investor, depositAssetId, RequestType.Deposit);
// Cancellation might have been queued such that it will be executed in the future during claiming
if (cancelledAssetAmount > 0) {
bytes memory callback =
RequestCallbackMessageLib.FulfilledDepositRequest(investor, 0, 0, cancelledAssetAmount).serialize();
hub.requestCallback{value: msgValue()}(poolId, scId_, depositAssetId, callback, 0, false, refund);
}
}
/// @inheritdoc IBatchRequestManager
function forceCancelRedeemRequest(
PoolId poolId,
ShareClassId scId_,
bytes32 investor,
AssetId payoutAssetId,
address refund
) external payable isManager(poolId) {
require(allowForceRedeemCancel[poolId][scId_][payoutAssetId][investor], CancellationInitializationRequired());
uint128 cancellingAmount = redeemRequest[poolId][scId_][payoutAssetId][investor].pending;
uint128 cancelledShareAmount =
_updatePending(poolId, scId_, cancellingAmount, false, investor, payoutAssetId, RequestType.Redeem);
// Cancellation might have been queued such that it will be executed in the future during claiming
if (cancelledShareAmount > 0) {
bytes memory callback =
RequestCallbackMessageLib.FulfilledRedeemRequest(investor, 0, 0, cancelledShareAmount).serialize();
hub.requestCallback{value: msgValue()}(poolId, scId_, payoutAssetId, callback, 0, false, refund);
}
}
//----------------------------------------------------------------------------------------------
// Claiming methods
//----------------------------------------------------------------------------------------------
/// @inheritdoc IHubRequestManagerNotifications
function notifyDeposit(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
bytes32 investor,
uint32 maxClaims,
address refund
) external payable protected {
uint128 totalPayoutShareAmount;
uint128 totalPaymentAssetAmount;
uint128 cancelledAssetAmount;
for (uint32 i = 0; i < maxClaims; i++) {
(uint128 payoutShareAmount, uint128 paymentAssetAmount, uint128 cancelled, bool canClaimAgain) =
_claimDeposit(poolId, scId, investor, assetId);
totalPayoutShareAmount += payoutShareAmount;
totalPaymentAssetAmount += paymentAssetAmount;
// Should be written at most once with non-zero amount iff the last claimable epoch was processed and
// the user had a pending cancellation
// NOTE: Purposely delaying corresponding message dispatch after deposit fulfillment message
if (cancelled > 0) {
cancelledAssetAmount = cancelled;
}
if (!canClaimAgain) {
break;
}
}
if (totalPaymentAssetAmount > 0 || cancelledAssetAmount > 0) {
hub.requestCallback{value: msgValue()}(
poolId,
scId,
assetId,
RequestCallbackMessageLib.FulfilledDepositRequest(
investor, totalPaymentAssetAmount, totalPayoutShareAmount, cancelledAssetAmount
).serialize(),
0,
false,
refund
);
}
}
function _claimDeposit(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
internal
returns (
uint128 payoutShareAmount,
uint128 paymentAssetAmount,
uint128 cancelledAssetAmount,
bool canClaimAgain
)
{
UserOrder storage userOrder = depositRequest[poolId][scId_][depositAssetId][investor];
require(userOrder.pending > 0, NoOrderFound());
require(userOrder.lastUpdate <= epochId[poolId][scId_][depositAssetId].issue, IssuanceRequired());
canClaimAgain = userOrder.lastUpdate < epochId[poolId][scId_][depositAssetId].issue;
EpochInvestAmounts storage epochAmounts =
epochInvestAmounts[poolId][scId_][depositAssetId][userOrder.lastUpdate];
// Calculate ceiling for pending reduction (ensures sum(user.pending) <= pendingTotal)
paymentAssetAmount = epochAmounts.approvedAssetAmount == 0
? 0
: userOrder.pending
.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount, MathLib.Rounding.Up)
.toUint128();
// NOTE: To ensure sum(user.pending) <= pendingTotal, we reduce pending by ceiling of the
// proportional share. Payout amounts use floor to ensure sum(claimed) <= sum(issued).
// This means users may lose up to 1 wei per claim, but prevents unbounded drift.
if (paymentAssetAmount > 0) {
// Calculate floor for share payout (ensures sum(shares claimed) <= shares issued)
uint128 paymentAssetFloor = userOrder.pending
.mulDiv(epochAmounts.approvedAssetAmount, epochAmounts.pendingAssetAmount, MathLib.Rounding.Down)
.toUint128();
if (paymentAssetFloor > 0) {
payoutShareAmount = epochAmounts.pricePoolPerShare.isNotZero()
? PricingLib.assetToShareAmount(
paymentAssetFloor,
hubRegistry.decimals(depositAssetId),
hubRegistry.decimals(poolId),
epochAmounts.pricePoolPerAsset,
epochAmounts.pricePoolPerShare,
MathLib.Rounding.Down
)
: 0;
}
userOrder.pending -= paymentAssetAmount;
}
emit ClaimDeposit(
poolId,
scId_,
userOrder.lastUpdate,
investor,
depositAssetId,
paymentAssetAmount,
userOrder.pending,
payoutShareAmount,
epochAmounts.issuedAt
);
// If there is nothing to claim anymore we can short circuit to the latest epoch
if (userOrder.pending == 0) {
// The current epoch is always one step ahead of the stored one
userOrder.lastUpdate = nowDepositEpoch(poolId, scId_, depositAssetId);
canClaimAgain = false;
} else {
userOrder.lastUpdate += 1;
}
// If user claimed up to latest approval epoch, move queued to pending
if (userOrder.lastUpdate == nowDepositEpoch(poolId, scId_, depositAssetId)) {
cancelledAssetAmount =
_postClaimUpdateQueued(poolId, scId_, investor, depositAssetId, userOrder, RequestType.Deposit);
}
}
/// @inheritdoc IHubRequestManagerNotifications
function notifyRedeem(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
bytes32 investor,
uint32 maxClaims,
address refund
) external payable protected {
uint128 totalPayoutAssetAmount;
uint128 totalPaymentShareAmount;
uint128 cancelledShareAmount;
for (uint32 i = 0; i < maxClaims; i++) {
(uint128 payoutAssetAmount, uint128 paymentShareAmount, uint128 cancelled, bool canClaimAgain) =
_claimRedeem(poolId, scId, investor, assetId);
totalPayoutAssetAmount += payoutAssetAmount;
totalPaymentShareAmount += paymentShareAmount;
// Should be written at most once with non-zero amount iff the last claimable epoch was processed and
// the user had a pending cancellation
// NOTE: Purposely delaying corresponding message dispatch after redemption fulfillment message
if (cancelled > 0) {
cancelledShareAmount = cancelled;
}
if (!canClaimAgain) {
break;
}
}
if (totalPaymentShareAmount > 0 || cancelledShareAmount > 0) {
hub.requestCallback{value: msgValue()}(
poolId,
scId,
assetId,
RequestCallbackMessageLib.FulfilledRedeemRequest(
investor, totalPayoutAssetAmount, totalPaymentShareAmount, cancelledShareAmount
).serialize(),
0,
false,
refund
);
}
}
function _claimRedeem(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
internal
returns (
uint128 payoutAssetAmount,
uint128 paymentShareAmount,
uint128 cancelledShareAmount,
bool canClaimAgain
)
{
UserOrder storage userOrder = redeemRequest[poolId][scId_][payoutAssetId][investor];
require(userOrder.pending > 0, NoOrderFound());
require(userOrder.lastUpdate <= epochId[poolId][scId_][payoutAssetId].revoke, RevocationRequired());
canClaimAgain = userOrder.lastUpdate < epochId[poolId][scId_][payoutAssetId].revoke;
EpochRedeemAmounts storage epochAmounts = epochRedeemAmounts[poolId][scId_][payoutAssetId][userOrder.lastUpdate];
// Calculate ceiling for pending reduction (ensures sum(user.pending) <= pendingTotal)
paymentShareAmount = epochAmounts.approvedShareAmount == 0
? 0
: userOrder.pending
.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount, MathLib.Rounding.Up)
.toUint128();
// NOTE: To ensure sum(user.pending) <= pendingTotal, we reduce pending by ceiling of the
// proportional share. Payout amounts use floor to ensure sum(claimed) <= sum(issued).
// This means users may lose up to 1 wei per claim, but prevents unbounded drift.
if (paymentShareAmount > 0) {
// Calculate floor for asset payout (ensures sum(assets claimed) <= assets available)
uint128 paymentShareFloor = userOrder.pending
.mulDiv(epochAmounts.approvedShareAmount, epochAmounts.pendingShareAmount, MathLib.Rounding.Down)
.toUint128();
if (paymentShareFloor > 0) {
payoutAssetAmount = epochAmounts.pricePoolPerAsset.isNotZero()
? PricingLib.shareToAssetAmount(
paymentShareFloor,
hubRegistry.decimals(poolId),
hubRegistry.decimals(payoutAssetId),
epochAmounts.pricePoolPerShare,
epochAmounts.pricePoolPerAsset,
MathLib.Rounding.Down
)
: 0;
}
userOrder.pending -= paymentShareAmount;
}
emit ClaimRedeem(
poolId,
scId_,
userOrder.lastUpdate,
investor,
payoutAssetId,
paymentShareAmount,
userOrder.pending,
payoutAssetAmount,
epochAmounts.revokedAt
);
// If there is nothing to claim anymore we can short circuit the in between epochs
if (userOrder.pending == 0) {
// The current epoch is always one step ahead of the stored one
userOrder.lastUpdate = nowRedeemEpoch(poolId, scId_, payoutAssetId);
canClaimAgain = false;
} else {
userOrder.lastUpdate += 1;
}
if (userOrder.lastUpdate == nowRedeemEpoch(poolId, scId_, payoutAssetId)) {
cancelledShareAmount =
_postClaimUpdateQueued(poolId, scId_, investor, payoutAssetId, userOrder, RequestType.Redeem);
}
}
//----------------------------------------------------------------------------------------------
// ERC-165
//----------------------------------------------------------------------------------------------
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
return interfaceId == type(IBatchRequestManager).interfaceId
|| interfaceId == type(IHubRequestManager).interfaceId
|| interfaceId == type(IHubRequestManagerNotifications).interfaceId
|| interfaceId == type(IERC165).interfaceId;
}
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @inheritdoc IBatchRequestManager
function nowDepositEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
return epochId[poolId][scId_][depositAssetId].deposit + 1;
}
/// @inheritdoc IBatchRequestManager
function nowIssueEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
return epochId[poolId][scId_][depositAssetId].issue + 1;
}
/// @inheritdoc IBatchRequestManager
function nowRedeemEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
return epochId[poolId][scId_][depositAssetId].redeem + 1;
}
/// @inheritdoc IBatchRequestManager
function nowRevokeEpoch(PoolId poolId, ShareClassId scId_, AssetId depositAssetId) public view returns (uint32) {
return epochId[poolId][scId_][depositAssetId].revoke + 1;
}
/// @inheritdoc IBatchRequestManager
function maxDepositClaims(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId depositAssetId)
public
view
returns (uint32)
{
return _maxClaims(
depositRequest[poolId][scId_][depositAssetId][investor], epochId[poolId][scId_][depositAssetId].issue
);
}
/// @inheritdoc IBatchRequestManager
function maxRedeemClaims(PoolId poolId, ShareClassId scId_, bytes32 investor, AssetId payoutAssetId)
public
view
returns (uint32)
{
return _maxClaims(
redeemRequest[poolId][scId_][payoutAssetId][investor], epochId[poolId][scId_][payoutAssetId].revoke
);
}
function _maxClaims(UserOrder memory userOrder, uint32 lastEpoch) internal pure returns (uint32) {
// User order either not set or not processed
if (userOrder.pending == 0 || userOrder.lastUpdate > lastEpoch) {
return 0;
}
return lastEpoch - userOrder.lastUpdate + 1;
}
//----------------------------------------------------------------------------------------------
// Internal methods
//----------------------------------------------------------------------------------------------
function _postClaimUpdateQueued(
PoolId poolId,
ShareClassId scId_,
bytes32 investor,
AssetId assetId,
UserOrder storage userOrder,
RequestType requestType
) internal returns (uint128 cancelledAmount) {
QueuedOrder storage queued = requestType == RequestType.Deposit
? queuedDepositRequest[poolId][scId_][assetId][investor]
: queuedRedeemRequest[poolId][scId_][assetId][investor];
// Increment pending by queued or cancel everything
uint128 updatePendingAmount = queued.isCancelling ? userOrder.pending : queued.amount;
if (queued.isCancelling) {
cancelledAmount = userOrder.pending + queued.amount;
userOrder.pending = 0;
} else {
userOrder.pending += queued.amount;
}
if (requestType == RequestType.Deposit) {
_updatePendingDeposit(
poolId,
scId_,
updatePendingAmount,
!queued.isCancelling,
investor,
assetId,
userOrder,
QueuedOrder(false, 0)
);
} else {
_updatePendingRedeem(
poolId,
scId_,
updatePendingAmount,
!queued.isCancelling,
investor,
assetId,
userOrder,
QueuedOrder(false, 0)
);
}
// Clear queued
queued.isCancelling = false;
queued.amount = 0;
}
/// @notice Updates the amount of a deposit or redeem request.
///
/// @param poolId Identifier of the pool
/// @param scId_ Identifier of the share class
/// @param amount Amount which is updated
/// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)
/// @param investor Address of the entity which is depositing
/// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to
/// @param requestType Flag indicating whether the request is a deposit or redeem request
/// @return cancelledAmount Pending amount which was cancelled
function _updatePending(
PoolId poolId,
ShareClassId scId_,
uint128 amount,
bool isIncrement,
bytes32 investor,
AssetId assetId,
RequestType requestType
) internal returns (uint128 cancelledAmount) {
UserOrder storage userOrder = requestType == RequestType.Deposit
? depositRequest[poolId][scId_][assetId][investor]
: redeemRequest[poolId][scId_][assetId][investor];
QueuedOrder storage queued = requestType == RequestType.Deposit
? queuedDepositRequest[poolId][scId_][assetId][investor]
: queuedRedeemRequest[poolId][scId_][assetId][investor];
// We must only update either queued or pending
if (_updateQueued(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued, requestType)) {
return 0;
}
cancelledAmount = isIncrement ? 0 : amount;
// NOTE: If we decrease the pending, we decrease usually by the full amount
// We keep subtraction of amount over setting to zero on purpose to not limit future higher level logic
userOrder.pending = isIncrement ? userOrder.pending + amount : userOrder.pending - amount;
userOrder.lastUpdate = requestType == RequestType.Deposit
? nowDepositEpoch(poolId, scId_, assetId)
: nowRedeemEpoch(poolId, scId_, assetId);
if (requestType == RequestType.Deposit) {
_updatePendingDeposit(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);
} else {
_updatePendingRedeem(poolId, scId_, amount, isIncrement, investor, assetId, userOrder, queued);
}
}
/// @notice Checks whether the pending amount can be updated. If not, it updates the queued amount.
///
/// @param poolId Identifier of the pool
/// @param scId_ Identifier of the share class
/// @param amount Amount which is updated
/// @param isIncrement Whether the amount is positive (additional request) or negative (cancellation)
/// @param investor Address of the entity which is depositing
/// @param assetId Identifier of the asset which the investor either used as deposit or wants to redeem to
/// @param userOrder User order storage for the deposit or redeem request
/// @param requestType Flag indicating whether the request is a deposit or redeem request
/// @return skipPendingUpdate Flag indicating whether the pending amount can be updated which is true if the user
/// does not need to claim
function _updateQueued(
PoolId poolId,
ShareClassId scId_,
uint128 amount,
bool isIncrement,
bytes32 investor,
AssetId assetId,
UserOrder storage userOrder,
QueuedOrder storage queued,
RequestType requestType
) internal returns (bool skipPendingUpdate) {
uint32 currentEpoch = requestType == RequestType.Deposit
? nowDepositEpoch(poolId, scId_, assetId)
: nowRedeemEpoch(poolId, scId_, assetId);
// Short circuit if user can mutate pending, i.e. last update happened after latest approval or is first update
if (_canMutatePending(userOrder, currentEpoch)) {
return false;
}
// Block increasing queued amount if cancelling is already queued
// NOTE: Can only happen due to race condition as Vaults blocks requests if cancellation is in progress
require(!(queued.isCancelling && amount > 0), CancellationQueued());
if (!isIncrement) {
queued.isCancelling = true;
} else {
queued.amount += amount;
}
if (requestType == RequestType.Deposit) {
uint128 pendingTotal = pendingDeposit[poolId][scId_][assetId];
emit UpdateDepositRequest(
poolId,
scId_,
assetId,
currentEpoch,
investor,
userOrder.pending,
pendingTotal,
queued.amount,
queued.isCancelling
);
} else {
uint128 pendingTotal = pendingRedeem[poolId][scId_][assetId];
emit UpdateRedeemRequest(
poolId,
scId_,
assetId,
currentEpoch,
investor,
userOrder.pending,
pendingTotal,
queued.amount,
queued.isCancelling
);
}
return true;
}
function _updatePendingDeposit(
PoolId poolId,
ShareClassId scId_,
uint128 amount,
bool isIncrement,
bytes32 investor,
AssetId assetId,
UserOrder storage userOrder,
QueuedOrder memory queued
) internal {
uint128 pendingTotal = pendingDeposit[poolId][scId_][assetId];
pendingTotal = isIncrement ? pendingTotal + amount : amount > pendingTotal ? 0 : pendingTotal - amount;
pendingDeposit[poolId][scId_][assetId] = pendingTotal;
emit UpdateDepositRequest(
poolId,
scId_,
assetId,
nowDepositEpoch(poolId, scId_, assetId),
investor,
userOrder.pending,
pendingTotal,
queued.amount,
queued.isCancelling
);
}
function _updatePendingRedeem(
PoolId poolId,
ShareClassId scId_,
uint128 amount,
bool isIncrement,
bytes32 investor,
AssetId assetId,
UserOrder storage userOrder,
QueuedOrder memory queued
) internal {
uint128 pendingTotal = pendingRedeem[poolId][scId_][assetId];
pendingTotal = isIncrement ? pendingTotal + amount : amount > pendingTotal ? 0 : pendingTotal - amount;
pendingRedeem[poolId][scId_][assetId] = pendingTotal;
emit UpdateRedeemRequest(
poolId,
scId_,
assetId,
nowRedeemEpoch(poolId, scId_, assetId),
investor,
userOrder.pending,
pendingTotal,
queued.amount,
queued.isCancelling
);
}
/// @dev A user cannot mutate their pending amount at all times because it affects the total pending amount. It is
/// restricted to the following three conditions:
/// 1. It's the first epoch (currentEpoch <= 1), which implies userOrder.lastUpdate == 0
/// 2. User has no pending amount (userOrder.pending == 0)
/// 3. User's last update is not behind the current epoch (userOrder.lastUpdate >= currentEpoch)
function _canMutatePending(UserOrder memory userOrder, uint32 currentEpoch) internal pure returns (bool) {
return currentEpoch <= 1 || userOrder.pending == 0 || userOrder.lastUpdate >= currentEpoch;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "../../misc/libraries/CastLib.sol";
import {BytesLib} from "../../misc/libraries/BytesLib.sol";
enum RequestCallbackType {
/// @dev Placeholder for null request callback type
Invalid,
ApprovedDeposits,
IssuedShares,
RevokedShares,
FulfilledDepositRequest,
FulfilledRedeemRequest
}
library RequestCallbackMessageLib {
using RequestCallbackMessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownRequestCallbackType();
function requestCallbackType(bytes memory message) internal pure returns (RequestCallbackType) {
return RequestCallbackType(message.toUint8(0));
}
//---------------------------------------
// RequestCallback.ApprovedDeposits (submsg)
//---------------------------------------
struct ApprovedDeposits {
uint128 assetAmount;
uint128 pricePoolPerAsset;
}
function deserializeApprovedDeposits(bytes memory data) internal pure returns (ApprovedDeposits memory) {
require(requestCallbackType(data) == RequestCallbackType.ApprovedDeposits, UnknownRequestCallbackType());
return ApprovedDeposits({assetAmount: data.toUint128(1), pricePoolPerAsset: data.toUint128(17)});
}
function serialize(ApprovedDeposits memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestCallbackType.ApprovedDeposits, t.assetAmount, t.pricePoolPerAsset);
}
//---------------------------------------
// RequestCallback.IssuedShares (submsg)
//---------------------------------------
struct IssuedShares {
uint128 shareAmount;
uint128 pricePoolPerShare;
}
function deserializeIssuedShares(bytes memory data) internal pure returns (IssuedShares memory) {
require(requestCallbackType(data) == RequestCallbackType.IssuedShares, UnknownRequestCallbackType());
return IssuedShares({shareAmount: data.toUint128(1), pricePoolPerShare: data.toUint128(17)});
}
function serialize(IssuedShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestCallbackType.IssuedShares, t.shareAmount, t.pricePoolPerShare);
}
//---------------------------------------
// RequestCallback.RevokedShares (submsg)
//---------------------------------------
struct RevokedShares {
uint128 assetAmount;
uint128 shareAmount;
uint128 pricePoolPerShare;
}
function deserializeRevokedShares(bytes memory data) internal pure returns (RevokedShares memory) {
require(requestCallbackType(data) == RequestCallbackType.RevokedShares, UnknownRequestCallbackType());
return RevokedShares({
assetAmount: data.toUint128(1), shareAmount: data.toUint128(17), pricePoolPerShare: data.toUint128(33)
});
}
function serialize(RevokedShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestCallbackType.RevokedShares, t.assetAmount, t.shareAmount, t.pricePoolPerShare);
}
//---------------------------------------
// RequestCallback.FulfilledDepositRequest (submsg)
//---------------------------------------
struct FulfilledDepositRequest {
bytes32 investor;
uint128 fulfilledAssetAmount;
uint128 fulfilledShareAmount;
uint128 cancelledAssetAmount;
}
function deserializeFulfilledDepositRequest(bytes memory data)
internal
pure
returns (FulfilledDepositRequest memory)
{
require(requestCallbackType(data) == RequestCallbackType.FulfilledDepositRequest, UnknownRequestCallbackType());
return FulfilledDepositRequest({
investor: data.toBytes32(1),
fulfilledAssetAmount: data.toUint128(33),
fulfilledShareAmount: data.toUint128(49),
cancelledAssetAmount: data.toUint128(65)
});
}
function serialize(FulfilledDepositRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
RequestCallbackType.FulfilledDepositRequest,
t.investor,
t.fulfilledAssetAmount,
t.fulfilledShareAmount,
t.cancelledAssetAmount
);
}
//---------------------------------------
// RequestCallback.FulfilledRedeemRequest (submsg)
//---------------------------------------
struct FulfilledRedeemRequest {
bytes32 investor;
uint128 fulfilledAssetAmount;
uint128 fulfilledShareAmount;
uint128 cancelledShareAmount;
}
function deserializeFulfilledRedeemRequest(bytes memory data)
internal
pure
returns (FulfilledRedeemRequest memory)
{
require(requestCallbackType(data) == RequestCallbackType.FulfilledRedeemRequest, UnknownRequestCallbackType());
return FulfilledRedeemRequest({
investor: data.toBytes32(1),
fulfilledAssetAmount: data.toUint128(33),
fulfilledShareAmount: data.toUint128(49),
cancelledShareAmount: data.toUint128(65)
});
}
function serialize(FulfilledRedeemRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
RequestCallbackType.FulfilledRedeemRequest,
t.investor,
t.fulfilledAssetAmount,
t.fulfilledShareAmount,
t.cancelledShareAmount
);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "../../misc/libraries/CastLib.sol";
import {BytesLib} from "../../misc/libraries/BytesLib.sol";
enum RequestType {
/// @dev Placeholder for null request type
Invalid,
DepositRequest,
RedeemRequest,
CancelDepositRequest,
CancelRedeemRequest
}
library RequestMessageLib {
using RequestMessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownRequestType();
function requestType(bytes memory message) internal pure returns (RequestType) {
return RequestType(message.toUint8(0));
}
//---------------------------------------
// Request.DepositRequest (submsg)
//---------------------------------------
struct DepositRequest {
bytes32 investor;
uint128 amount;
}
function deserializeDepositRequest(bytes memory data) internal pure returns (DepositRequest memory) {
require(requestType(data) == RequestType.DepositRequest, UnknownRequestType());
return DepositRequest({investor: data.toBytes32(1), amount: data.toUint128(33)});
}
function serialize(DepositRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestType.DepositRequest, t.investor, t.amount);
}
//---------------------------------------
// Request.RedeemRequest (submsg)
//---------------------------------------
struct RedeemRequest {
bytes32 investor;
uint128 amount;
}
function deserializeRedeemRequest(bytes memory data) internal pure returns (RedeemRequest memory) {
require(requestType(data) == RequestType.RedeemRequest, UnknownRequestType());
return RedeemRequest({investor: data.toBytes32(1), amount: data.toUint128(33)});
}
function serialize(RedeemRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestType.RedeemRequest, t.investor, t.amount);
}
//---------------------------------------
// Request.CancelDepositRequest (submsg)
//---------------------------------------
struct CancelDepositRequest {
bytes32 investor;
}
function deserializeCancelDepositRequest(bytes memory data) internal pure returns (CancelDepositRequest memory) {
require(requestType(data) == RequestType.CancelDepositRequest, UnknownRequestType());
return CancelDepositRequest({investor: data.toBytes32(1)});
}
function serialize(CancelDepositRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestType.CancelDepositRequest, t.investor);
}
//---------------------------------------
// Request.CancelRedeemRequest (submsg)
//---------------------------------------
struct CancelRedeemRequest {
bytes32 investor;
}
function deserializeCancelRedeemRequest(bytes memory data) internal pure returns (CancelRedeemRequest memory) {
require(requestType(data) == RequestType.CancelRedeemRequest, UnknownRequestType());
return CancelRedeemRequest({investor: data.toBytes32(1)});
}
function serialize(CancelRedeemRequest memory t) internal pure returns (bytes memory) {
return abi.encodePacked(RequestType.CancelRedeemRequest, t.investor);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {D18} from "../../misc/types/D18.sol";
import {PoolId} from "../../core/types/PoolId.sol";
import {AssetId} from "../../core/types/AssetId.sol";
import {ShareClassId} from "../../core/types/ShareClassId.sol";
import {IHubRequestManager, IHubRequestManagerNotifications} from "../../core/hub/interfaces/IHubRequestManager.sol";
/// @notice Struct containing the epoch data for issuing share class tokens
/// @param approvedPoolAmount The amount of pool currency which was approved by the Fund Manager
/// @param approvedAssetAmount The amount of assets which was approved by the Fund Manager
/// @param pendingAssetAmount The amount of assets for which issuance was pending by the Fund Manager
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency at the time of approval
/// @param pricePoolPerShare The price of 1 pool currency token in terms of share class tokens at the time of issuance
/// @param issuedAt The timestamp when shares were issued
struct EpochInvestAmounts {
uint128 approvedPoolAmount;
uint128 approvedAssetAmount;
uint128 pendingAssetAmount;
D18 pricePoolPerAsset;
D18 pricePoolPerShare;
uint64 issuedAt;
}
/// @notice Struct containing the epoch data for paying out assets of a share class token
/// @param approvedShareAmount The amount of share class tokens which was approved by the Fund Manager for payout
/// @param pendingShareAmount The amount of share class tokens for which payout was pending by the Fund Manager
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency at the time of approval
/// @param pricePoolPerShare The price of 1 pool currency token in terms of share class tokens at the time of revocation
/// @param payoutAssetAmount The amount of payout assets to claim by redeeming share class tokens
/// @param revokedAt The timestamp when shares were revoked
struct EpochRedeemAmounts {
uint128 approvedShareAmount;
uint128 pendingShareAmount;
D18 pricePoolPerAsset;
D18 pricePoolPerShare;
uint128 payoutAssetAmount;
uint64 revokedAt;
}
/// @notice Struct containing the user's deposit or redeem request data
/// @param pending The amount of assets or shares which is pending for a user
/// @param lastUpdate The epoch at which the user most recently deposited or redeemed
struct UserOrder {
uint128 pending;
uint32 lastUpdate;
}
/// @notice Struct containing the user's queued deposit or redeem request data
/// @param isCancelling Whether the user is cancelling their pending requests
/// @param amount The amount of assets or shares which is queued for a user
struct QueuedOrder {
bool isCancelling;
uint128 amount;
}
/// @notice Enum indicating the type of request, either deposit or redeem
enum RequestType {
Deposit,
Redeem
}
/// @notice Struct containing the epoch IDs for each action
/// @param deposit The epoch ID for deposits
/// @param issue The epoch ID for issuing shares
/// @param redeem The epoch ID for redeems
/// @param revoke The epoch ID for revoking shares
struct EpochId {
uint32 deposit;
uint32 issue;
uint32 redeem;
uint32 revoke;
}
interface IBatchRequestManager is IHubRequestManager, IHubRequestManagerNotifications {
//----------------------------------------------------------------------------------------------
// Events
//----------------------------------------------------------------------------------------------
event ApproveDeposits(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
uint128 approvedPoolAmount,
uint128 approvedAssetAmount,
uint128 pendingAssetAmount
);
event ApproveRedeems(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
uint128 approvedShareAmount,
uint128 pendingShareAmount
);
event IssueShares(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
D18 pricePoolPerShare,
D18 priceAssetPerShare,
uint128 issuedShareAmount
);
event RevokeShares(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
D18 pricePoolPerShare,
D18 priceAssetPerShare,
uint128 approvedShareAmount,
uint128 payoutAssetAmount,
uint128 payoutPoolAmount
);
event ClaimDeposit(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
uint32 indexed epochId,
bytes32 investor,
AssetId assetId,
uint128 paymentAssetAmount,
uint128 pendingAssetAmount,
uint128 payoutShareAmount,
uint64 issuedAt
);
event ClaimRedeem(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
uint32 indexed epochId,
bytes32 investor,
AssetId assetId,
uint128 paymentShareAmount,
uint128 pendingShareAmount,
uint128 payoutAssetAmount,
uint64 revokedAt
);
event UpdateDepositRequest(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
bytes32 investor,
uint128 pendingAmount,
uint128 totalPendingAmount,
uint128 queuedAmount,
bool isQueuedCancellation
);
event UpdateRedeemRequest(
PoolId indexed poolId,
ShareClassId indexed shareClassId,
AssetId indexed assetId,
uint32 epochId,
bytes32 investor,
uint128 pendingAmount,
uint128 totalPendingAmount,
uint128 queuedAmount,
bool isQueuedCancellation
);
//----------------------------------------------------------------------------------------------
// Events
//----------------------------------------------------------------------------------------------
/// @notice Emitted when a call to `file()` was performed.
event File(bytes32 what, address addr);
/// @notice Emitted when epoch IDs are modified via setEpochIds during migration
event EpochIdModified(
PoolId indexed poolId, ShareClassId indexed scId, AssetId indexed assetId, EpochId epochIdData
);
//----------------------------------------------------------------------------------------------
// Errors
//----------------------------------------------------------------------------------------------
/// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.
error FileUnrecognizedParam();
/// @notice Dispatched when unknown request type is encountered.
error UnknownRequestType();
error InsufficientPending();
error ZeroApprovalAmount();
error EpochNotFound();
error EpochNotInSequence(uint32 epochId, uint32 actualEpochId);
error NoOrderFound();
error IssuanceRequired();
error RevocationRequired();
error CancellationInitializationRequired();
error CancellationQueued();
//----------------------------------------------------------------------------------------------
// Incoming requests
//----------------------------------------------------------------------------------------------
/// @notice Submit a deposit request to invest assets into a pool's share class
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param amount The amount of assets to deposit
/// @param investor The investor's address as bytes32
/// @param depositAssetId The asset identifier for the deposit
function requestDeposit(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId depositAssetId)
external;
/// @notice Cancel a pending deposit request and return the deposited assets
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param depositAssetId The asset identifier for the deposit
/// @return cancelledAssetAmount The amount of assets returned to the investor
function cancelDepositRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)
external
returns (uint128 cancelledAssetAmount);
/// @notice Submit a redemption request to redeem shares for assets
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param amount The amount of shares to redeem
/// @param investor The investor's address as bytes32
/// @param payoutAssetId The asset identifier for the payout
function requestRedeem(PoolId poolId, ShareClassId scId, uint128 amount, bytes32 investor, AssetId payoutAssetId)
external;
/// @notice Cancel a pending redemption request and return the shares
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param payoutAssetId The asset identifier for the payout
/// @return cancelledShareAmount The amount of shares returned to the investor
function cancelRedeemRequest(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)
external
returns (uint128 cancelledShareAmount);
//----------------------------------------------------------------------------------------------
// Manager actions
//----------------------------------------------------------------------------------------------
/// @notice Approve pending deposit requests for an epoch
/// @dev This function approves a specific amount of assets from the current deposit epoch
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for deposits
/// @param nowDepositEpochId The current deposit epoch identifier
/// @param approvedAssetAmount The amount of assets approved for this epoch
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency
/// @param refund Address to receive unused gas refund
function approveDeposits(
PoolId poolId,
ShareClassId scId,
AssetId depositAssetId,
uint32 nowDepositEpochId,
uint128 approvedAssetAmount,
D18 pricePoolPerAsset,
address refund
) external payable;
/// @notice Approve pending redemption requests for an epoch
/// @dev This function approves a specific amount of shares from the current redeem epoch
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param payoutAssetId The asset identifier for payouts
/// @param nowRedeemEpochId The current redeem epoch identifier
/// @param approvedShareAmount The amount of shares approved for redemption
/// @param pricePoolPerAsset The price of one asset unit in terms of pool currency
function approveRedeems(
PoolId poolId,
ShareClassId scId,
AssetId payoutAssetId,
uint32 nowRedeemEpochId,
uint128 approvedShareAmount,
D18 pricePoolPerAsset
) external payable;
/// @notice Issue shares to investors based on approved deposits
/// @dev This function mints shares for the approved deposit epoch using the provided share price
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for deposits
/// @param nowIssueEpochId The current issue epoch identifier
/// @param pricePoolPerShare The price of pool currency per share unit
/// @param extraGasLimit Additional gas limit for cross-chain operations
/// @param refund Address to receive unused gas refund
function issueShares(
PoolId poolId,
ShareClassId scId,
AssetId depositAssetId,
uint32 nowIssueEpochId,
D18 pricePoolPerShare,
uint128 extraGasLimit,
address refund
) external payable;
/// @notice Revoke shares and prepare asset payouts for redemptions
/// @dev This function burns shares for the approved redeem epoch and calculates asset payouts
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param payoutAssetId The asset identifier for payouts
/// @param nowRevokeEpochId The current revoke epoch identifier
/// @param pricePoolPerShare The price of pool currency per share unit
/// @param extraGasLimit Additional gas limit for cross-chain operations
/// @param refund Address to receive unused gas refund
function revokeShares(
PoolId poolId,
ShareClassId scId,
AssetId payoutAssetId,
uint32 nowRevokeEpochId,
D18 pricePoolPerShare,
uint128 extraGasLimit,
address refund
) external payable;
/// @notice Force cancel a user's deposit request (manager action)
/// @dev This allows the manager to cancel a deposit request on behalf of a user
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param depositAssetId The asset identifier for the deposit
/// @param refund Address to receive unused gas refund
function forceCancelDepositRequest(
PoolId poolId,
ShareClassId scId,
bytes32 investor,
AssetId depositAssetId,
address refund
) external payable;
/// @notice Force cancel a user's redemption request (manager action)
/// @dev This allows the manager to cancel a redemption request on behalf of a user
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param payoutAssetId The asset identifier for the payout
/// @param refund Address to receive unused gas refund
function forceCancelRedeemRequest(
PoolId poolId,
ShareClassId scId,
bytes32 investor,
AssetId payoutAssetId,
address refund
) external payable;
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @notice Get the current deposit epoch identifier
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for deposits
/// @return The current deposit epoch ID
function nowDepositEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);
/// @notice Get the current issue epoch identifier
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for deposits
/// @return The current issue epoch ID
function nowIssueEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);
/// @notice Get the current redeem epoch identifier
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for payouts
/// @return The current redeem epoch ID
function nowRedeemEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);
/// @notice Get the current revoke epoch identifier
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param depositAssetId The asset identifier for payouts
/// @return The current revoke epoch ID
function nowRevokeEpoch(PoolId poolId, ShareClassId scId, AssetId depositAssetId) external view returns (uint32);
/// @notice Get the maximum number of deposit claims available for an investor
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param depositAssetId The asset identifier for deposits
/// @return The maximum number of claimable deposit epochs
function maxDepositClaims(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId depositAssetId)
external
view
returns (uint32);
/// @notice Get the maximum number of redeem claims available for an investor
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param investor The investor's address as bytes32
/// @param payoutAssetId The asset identifier for payouts
/// @return The maximum number of claimable redeem epochs
function maxRedeemClaims(PoolId poolId, ShareClassId scId, bytes32 investor, AssetId payoutAssetId)
external
view
returns (uint32);
//----------------------------------------------------------------------------------------------
// Epoch data access
//----------------------------------------------------------------------------------------------
/// @notice Get detailed investment amounts and pricing for a specific epoch
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param assetId The asset identifier
/// @param epochId The epoch identifier
/// @return pendingAssetAmount Assets waiting to be approved
/// @return approvedAssetAmount Assets approved for investment
/// @return approvedPoolAmount Pool currency amount after asset-to-pool conversion
/// @return pricePoolPerAsset Price of pool currency per asset unit
/// @return pricePoolPerShare Price of pool currency per share unit
/// @return issuedAt Timestamp when shares were issued
function epochInvestAmounts(PoolId poolId, ShareClassId scId, AssetId assetId, uint32 epochId)
external
view
returns (
uint128 pendingAssetAmount,
uint128 approvedAssetAmount,
uint128 approvedPoolAmount,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
uint64 issuedAt
);
/// @notice Get detailed redemption amounts and pricing for a specific epoch
/// @param poolId The pool identifier
/// @param scId The share class identifier
/// @param assetId The asset identifier
/// @param epochId The epoch identifier
/// @return approvedShareAmount Shares approved for redemption
/// @return pendingShareAmount Shares waiting to be approved
/// @return pricePoolPerAsset Price of pool currency per asset unit
/// @return pricePoolPerShare Price of pool currency per share unit
/// @return payoutAssetAmount Asset amount to be paid out
/// @return revokedAt Timestamp when shares were revoked
function epochRedeemAmounts(PoolId poolId, ShareClassId scId, AssetId assetId, uint32 epochId)
external
view
returns (
uint128 approvedShareAmount,
uint128 pendingShareAmount,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
uint128 payoutAssetAmount,
uint64 revokedAt
);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IAuth} from "./interfaces/IAuth.sol";
/// @title Auth
/// @notice Simple authentication pattern
/// @author Based on code from https://github.com/makerdao/dss
abstract contract Auth is IAuth {
/// @inheritdoc IAuth
mapping(address => uint256) public wards;
constructor(address initialWard) {
wards[initialWard] = 1;
emit Rely(initialWard);
}
/// @dev Check if the msg.sender has permissions
modifier auth() {
require(wards[msg.sender] == 1, NotAuthorized());
_;
}
/// @inheritdoc IAuth
function rely(address user) public auth {
wards[user] = 1;
emit Rely(user);
}
/// @inheritdoc IAuth
function deny(address user) public auth {
wards[user] = 0;
emit Deny(user);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
// Small library to handle fixed point number operations with 18 decimals with static typing support.
import {MathLib} from "../libraries/MathLib.sol";
type D18 is uint128;
error D18_DivisionByZero();
using MathLib for uint256;
/// @dev add two D18 types
function add(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) + D18.unwrap(d2));
}
/// @dev subtract two D18 types
function sub(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(D18.unwrap(d1) - D18.unwrap(d2));
}
/// @dev Divides one D18 by another one while retaining precision:
/// - nominator (decimal): 50e18
/// - denominator (decimal): 2e19
/// - result (decimal): 25e17
function divD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), 1e18, D18.unwrap(d2)).toUint128());
}
/// @dev Multiplies one D18 with another one while retaining precision:
/// - value1 (decimal): 50e18
/// - value2 (decimal): 2e19
/// - result (decimal): 100e19
function mulD18(D18 d1, D18 d2) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(D18.unwrap(d1), D18.unwrap(d2), 1e18).toUint128());
}
/// @dev Returns the reciprocal of a D18 decimal, i.e. 1 / d.
/// Example: if d = 2.0 (2e18 internally), reciprocal(d) = 0.5 (5e17 internally).
function reciprocal(D18 d) pure returns (D18) {
uint128 val = D18.unwrap(d);
require(val != 0, D18_DivisionByZero());
return d18(1e18, val);
}
/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal): 1_500_000_000_000_000_000
/// - value (integer): 4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding).toUint128();
}
/// @dev Multiplies a decimal by an integer. i.e:
/// - d (decimal): 1_500_000_000_000_000_000
/// - value (integer): 4_000_000_000_000_000_000
/// - result (integer): 6_000_000_000_000_000_000
function mulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
return MathLib.mulDiv(D18.unwrap(d), value, 1e18, rounding);
}
/// @dev Divides an integer by a decimal, i.e.
/// @dev Same as mulDiv for integers, i.e:
/// - d (decimal): 2_000_000_000_000_000_000
/// - value (integer): 100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint128(D18 d, uint128 value, MathLib.Rounding rounding) pure returns (uint128) {
return MathLib.mulDiv(value, 1e18, d.raw(), rounding).toUint128();
}
/// @dev Divides an integer by a decimal, i.e.
/// @dev Same as mulDiv for integers, i.e:
/// - d (decimal): 2_000_000_000_000_000_000
/// - value (integer): 100_000_000_000_000_000_000
/// - result (integer): 50_000_000_000_000_000_000
function reciprocalMulUint256(D18 d, uint256 value, MathLib.Rounding rounding) pure returns (uint256) {
return MathLib.mulDiv(value, 1e18, d.raw(), rounding);
}
/// @dev Easy way to construct a decimal number
function d18(uint128 value) pure returns (D18) {
return D18.wrap(value);
}
/// @dev Easy way to construct a decimal number
function d18(uint128 num, uint128 den) pure returns (D18) {
return D18.wrap(MathLib.mulDiv(num, 1e18, den).toUint128());
}
function eq(D18 a, D18 b) pure returns (bool) {
return D18.unwrap(a) == D18.unwrap(b);
}
function isZero(D18 a) pure returns (bool) {
return D18.unwrap(a) == 0;
}
function isNotZero(D18 a) pure returns (bool) {
return D18.unwrap(a) != 0;
}
function raw(D18 d) pure returns (uint128) {
return D18.unwrap(d);
}
using {
add as +,
sub as -,
divD18 as /,
eq,
mulD18 as *,
mulUint128,
mulUint256,
reciprocalMulUint128,
reciprocalMulUint256,
reciprocal,
raw,
isZero,
isNotZero
} for D18 global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IAuth {
event Rely(address indexed user);
event Deny(address indexed user);
error NotAuthorized();
/// @notice Returns whether the target is a ward (has admin access)
/// @param target The address to check for ward status
/// @return The ward status (1 if ward, 0 if not)
function wards(address target) external view returns (uint256);
/// @notice Make user a ward (give them admin access)
/// @param user The address to grant ward status to
function rely(address user) external;
/// @notice Remove user as a ward (remove admin access)
/// @param user The address to remove ward status from
function deny(address user) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title CastLib
library CastLib {
error PrefixNotZero();
error SizeNot128();
function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
require(bytes12(addr) == 0, PrefixNotZero());
return address(uint160(uint256(addr)));
}
function toBytes32LeftPadded(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
function toAddress(bytes32 addr) internal pure returns (address) {
require(uint96(uint256(addr)) == 0, PrefixNotZero());
return address(bytes20(addr));
}
function toBytes32(address addr) internal pure returns (bytes32) {
return bytes32(bytes20(addr));
}
/// @dev Adds zero padding
function toBytes32(string memory source) internal pure returns (bytes32) {
return bytes32(bytes(source));
}
/// @dev Removes zero padding
function bytes128ToString(bytes memory _bytes128) internal pure returns (string memory) {
require(_bytes128.length == 128, SizeNot128());
uint8 i = 0;
while (i < 128 && _bytes128[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (uint8 j; j < i; j++) {
bytesArray[j] = _bytes128[j];
}
return string(bytesArray);
}
function toString(bytes32 _bytes32) internal pure returns (string memory) {
uint8 i = 0;
while (i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
library MathLib {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
error MulDiv_Overflow();
error Uint8_Overflow();
error Uint16_Overflow();
error Uint32_Overflow();
error Uint64_Overflow();
error Uint96_Overflow();
error Uint128_Overflow();
error Int128_Overflow();
uint256 public constant One27 = 10 ** 27;
/// @notice Returns x^n with rounding precision of base
///
/// @dev Source: https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/jug.sol#L62
///
/// @param x The base value which should be exponentiated
/// @param n The exponent
/// @param base The scaling base, typically used for fix-point calculations
function rpow(uint256 x, uint256 n, uint256 base) public pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 { z := base }
default { z := 0 }
}
default {
switch mod(n, 2)
case 0 { z := base }
default { z := x }
let half := div(base, 2) // for rounding.
for { n := div(n, 2) } n { n := div(n, 2) } {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) { revert(0, 0) }
let xxRound := add(xx, half)
if lt(xxRound, xx) { revert(0, 0) }
x := div(xxRound, base)
if mod(n, 2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0, 0) }
let zxRound := add(zx, half)
if lt(zxRound, zx) { revert(0, 0) }
z := div(zxRound, base)
}
}
}
}
}
/// @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
/// denominator == 0
/// @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
/// with further edits by Uniswap Labs also under MIT license.
// slither-disable-start divide-before-multiply
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, MulDiv_Overflow());
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
// slither-disable-end divide-before-multiply
/// @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/// @notice Safe type conversion from uint256 to uint8.
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, Uint8_Overflow());
return uint8(value);
}
/// @notice Safe type conversion from uint256 to uint16.
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, Uint16_Overflow());
return uint16(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, Uint32_Overflow());
return uint32(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, Uint64_Overflow());
return uint64(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, Uint96_Overflow());
return uint96(value);
}
/// @notice Safe type conversion from uint256 to uint128.
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, Uint128_Overflow());
return uint128(value);
}
/// @notice Returns the smallest of two numbers.
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? b : a;
}
/// @notice Returns the largest of two numbers.
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.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.
*/
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: GPL-2.0-or-later
pragma solidity 0.8.28;
/// @title Bytes Lib
/// @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
/// The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
/// @author Modified from Solidity Bytes Arrays Utils v0.8.0
library BytesLib {
error SliceOverflow();
error SliceOutOfBounds();
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
unchecked {
require(_length + 31 >= _length, SliceOverflow());
}
require(_bytes.length >= _start + _length, SliceOutOfBounds());
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
//zero out the 32 bytes slice we are about to return
//we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function sliceZeroPadded(bytes memory _bytes, uint256 _start, uint256 _length)
internal
pure
returns (bytes memory)
{
bool needsPad = _bytes.length < _start + _length;
if (!needsPad) return slice(_bytes, _start, _length);
bytes memory slice_ = slice(_bytes, _start, _bytes.length - _start);
bytes memory padding = new bytes(_length + _start - _bytes.length);
return bytes.concat(slice_, padding);
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start + 20, SliceOutOfBounds());
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= _start + 1, SliceOutOfBounds());
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= _start + 2, SliceOutOfBounds());
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
require(_bytes.length >= _start + 4, SliceOutOfBounds());
uint32 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x4), _start))
}
return tempUint;
}
function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
require(_bytes.length >= _start + 8, SliceOutOfBounds());
uint64 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x8), _start))
}
return tempUint;
}
function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
uint128 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x10), _start))
}
return tempUint;
}
function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= _start + 32, SliceOutOfBounds());
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function toBytes16(bytes memory _bytes, uint256 _start) internal pure returns (bytes16) {
require(_bytes.length >= _start + 16, SliceOutOfBounds());
bytes16 tempBytes16;
assembly {
tempBytes16 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes16;
}
function toBool(bytes memory _bytes, uint256 _start) internal pure returns (bool) {
require(_bytes.length > _start, SliceOutOfBounds());
return _bytes[_start] != 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {MathLib} from "../../misc/libraries/MathLib.sol";
using MathLib for uint256;
type PoolId is uint64;
function centrifugeId(PoolId poolId) pure returns (uint16) {
return uint16(PoolId.unwrap(poolId) >> 48);
}
function newPoolId(uint16 centrifugeId_, uint48 localPoolId) pure returns (PoolId) {
return PoolId.wrap((uint64(centrifugeId_) << 48) | uint64(localPoolId));
}
function isNull(PoolId poolId) pure returns (bool) {
return PoolId.unwrap(poolId) == 0;
}
function isEqual(PoolId a, PoolId b) pure returns (bool) {
return PoolId.unwrap(a) == PoolId.unwrap(b);
}
function raw(PoolId poolId) pure returns (uint64) {
return PoolId.unwrap(poolId);
}
using {centrifugeId, isNull, raw, isEqual as ==} for PoolId global;// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
/// @dev Composite Id of the centrifugeId (uint16) where the asset resides
/// and a local counter (uint64) that is part of the contract that registers the asset.
type AssetId is uint128;
function isNull(AssetId assetId) pure returns (bool) {
return AssetId.unwrap(assetId) == 0;
}
function raw(AssetId assetId) pure returns (uint128) {
return AssetId.unwrap(assetId);
}
function centrifugeId(AssetId assetId) pure returns (uint16) {
return uint16(AssetId.unwrap(assetId) >> 112);
}
function newAssetId(uint16 centrifugeId_, uint64 counter) pure returns (AssetId) {
return AssetId.wrap((uint128(centrifugeId_) << 112) + counter);
}
function newAssetId(uint32 isoCode) pure returns (AssetId) {
return AssetId.wrap(isoCode);
}
function eq(AssetId a, AssetId b) pure returns (bool) {
return a.raw() == b.raw();
}
using {isNull, raw, centrifugeId, eq as ==} for AssetId global;// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {D18, d18} from "../../misc/types/D18.sol";
import {MathLib} from "../../misc/libraries/MathLib.sol";
import {IERC20Metadata} from "../../misc/interfaces/IERC20.sol";
import {IERC6909MetadataExt} from "../../misc/interfaces/IERC6909.sol";
library PricingLib {
using MathLib for *;
error DivisionByZero();
/// @dev Prices are fixed-point integers with 18 decimals
uint8 internal constant PRICE_DECIMALS = 18;
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (priceAssetPerShare_) by consumer.
///
/// NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
/// Fulfilled* message amounts. Any other codepath must use the variant with pricePoolPerAsset
/// and pricePoolPerShare
function assetToShareAmount(
address shareToken,
address asset,
uint256 tokenId,
uint128 assetAmount,
D18 priceAssetPerShare_,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (assetAmount == 0) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.convertWithReciprocalPrice(
assetAmount, assetDecimals, shareDecimals, priceAssetPerShare_, rounding
).toUint128();
}
/// @dev Converts the given asset amount to share amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
function assetToShareAmount(
address shareToken,
address asset,
uint256 tokenId,
uint128 assetAmount,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (assetAmount == 0 || pricePoolPerAsset.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.assetToShareAmount(
assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding
).toUint128();
}
/// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
///
/// NOTE: MUST ONLY be used in AsyncRequestManager which rely on priceAssetPerShare that is derived from
/// Fulfilled* message amounts. Any other codepath must use the variant with pricePoolPerAsset and
/// pricePoolPerShare
function shareToAssetAmount(
address shareToken,
uint128 shareAmount,
address asset,
uint256 tokenId,
D18 priceAssetPerShare_,
MathLib.Rounding rounding
) internal view returns (uint128 assets) {
if (shareAmount == 0 || priceAssetPerShare_.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return PricingLib.convertWithPrice(shareAmount, shareDecimals, assetDecimals, priceAssetPerShare_, rounding);
}
/// @dev Converts the given share amount to asset amount. Returned value is in share decimals.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
function shareToAssetAmount(
address shareToken,
uint128 shareAmount,
address asset,
uint256 tokenId,
D18 pricePoolPerShare,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal view returns (uint128 shares) {
if (shareAmount == 0 || pricePoolPerShare.isZero()) {
return 0;
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
// NOTE: Pool and share denomination are always equal by design
return PricingLib.shareToAssetAmount(
shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding
).toUint128();
}
/// @dev Calculates the asset price per share returns the value in price decimals
/// Denominated in ASSET_UNIT/SHARE_UNIT
/// @dev Assumes handling of zero denominator (shares == 0) by consumer.
function calculatePriceAssetPerShare(
address shareToken,
uint128 shares,
address asset,
uint256 tokenId,
uint128 assets,
MathLib.Rounding rounding
) internal view returns (D18 priceAssetPerShare_) {
if (assets == 0) {
return d18(0);
}
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
// NOTE: More precise than utilizing D18
return d18(
_toPriceDecimals(assets, assetDecimals)
.mulDiv(10 ** PRICE_DECIMALS, _toPriceDecimals(shares, shareDecimals), rounding).toUint128()
);
}
/// @dev Calculates the maximum amount of assets that can be converted to shares without uint128 overflow.
/// Returns the maximum asset amount such that assetToShareAmount(result) <= maxShares.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
/// @param shareToken Address of the share token
/// @param asset Address of the asset
/// @param tokenId Token ID for ERC6909 (0 for ERC20)
/// @param maxShares Maximum allowed shares (typically type(uint128).max)
/// @param pricePoolPerShare Price of share in pool units (numerator)
/// @param pricePoolPerAsset Price of asset in pool units (denominator)
/// @return Maximum asset amount that won't cause overflow, or type(uint256).max if no overflow possible
function maxConvertibleAssetAmount(
address shareToken,
address asset,
uint256 tokenId,
uint256 maxShares,
D18 pricePoolPerShare,
D18 pricePoolPerAsset
) internal view returns (uint256) {
require(pricePoolPerAsset.isNotZero(), DivisionByZero());
uint8 assetDecimals = _getAssetDecimals(asset, tokenId);
uint8 shareDecimals = IERC20Metadata(shareToken).decimals();
return MathLib.mulDiv(
maxShares,
uint256(10 ** assetDecimals) * pricePoolPerShare.raw(),
uint256(10 ** shareDecimals) * pricePoolPerAsset.raw(),
MathLib.Rounding.Down
);
}
//----------------------------------------------------------------------------------------------
// Pure methods
//----------------------------------------------------------------------------------------------
/// @dev Converts an amount using decimals and price with implicit rounding down
function convertWithPrice(uint256 baseAmount, uint8 baseDecimals, uint8 quoteDecimals, D18 priceQuotePerBase)
internal
pure
returns (uint128 quoteAmount)
{
return convertWithPrice(baseAmount, baseDecimals, quoteDecimals, priceQuotePerBase, MathLib.Rounding.Down);
}
/// @dev Converts an amount using decimals and price with explicit rounding.
function convertWithPrice(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceQuotePerBase,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
if (baseDecimals == quoteDecimals) {
return priceQuotePerBase.mulUint256(baseAmount, rounding).toUint128();
}
return MathLib.mulDiv(
priceQuotePerBase.raw(),
baseAmount * 10 ** quoteDecimals,
10 ** (baseDecimals + PRICE_DECIMALS),
rounding
) // cancel out exponentiation from D18 multiplication
.toUint128();
}
/// @dev Converts an amount using decimals and reciprocal price.
/// @dev Assumes handling of zero denominator price (priceBasePerQuote) by consumer.
///
/// NOTE: More precise than convertWithPrice(,,,price.reciprocal,)
function convertWithReciprocalPrice(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceBasePerQuote,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
require(priceBasePerQuote.isNotZero(), DivisionByZero());
if (baseDecimals == quoteDecimals) {
return priceBasePerQuote.reciprocalMulUint256(baseAmount, rounding).toUint128();
}
return MathLib.mulDiv(
10 ** quoteDecimals * baseAmount,
10 ** PRICE_DECIMALS,
10 ** baseDecimals * priceBasePerQuote.raw(),
rounding
).toUint128();
}
/// @dev Converts an amount using decimals and two prices.
/// @dev Assumes handling of zero denominator price (priceDenominator) by consumer.
///
/// NOTE: More precise than custom math with one price and convertWith{Reciprocal}Price for the other
function convertWithPrices(
uint256 baseAmount,
uint8 baseDecimals,
uint8 quoteDecimals,
D18 priceNumerator,
D18 priceDenominator,
MathLib.Rounding rounding
) internal pure returns (uint128 quoteAmount) {
require(priceDenominator.isNotZero(), DivisionByZero());
return MathLib.mulDiv(
priceNumerator.raw(),
10 ** quoteDecimals * baseAmount,
10 ** baseDecimals * priceDenominator.raw(),
rounding
).toUint128();
}
/// @dev Converts asset amount to share amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerShare) by consumer.
///
/// NOTE: Pool and share denomination are always equal by design
function assetToShareAmount(
uint256 assetAmount,
uint8 assetDecimals,
uint8 shareDecimals,
D18 pricePoolPerAsset,
D18 pricePoolPerShare,
MathLib.Rounding rounding
) internal pure returns (uint128 shareAmount) {
return convertWithPrices(
assetAmount, assetDecimals, shareDecimals, pricePoolPerAsset, pricePoolPerShare, rounding
);
}
/// @dev Converts share amount to asset asset amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
///
/// NOTE: Pool and share denomination are always equal by design
function shareToAssetAmount(
uint256 shareAmount,
uint8 shareDecimals,
uint8 assetDecimals,
D18 pricePoolPerShare,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 assetAmount) {
return convertWithPrices(
shareAmount, shareDecimals, assetDecimals, pricePoolPerShare, pricePoolPerAsset, rounding
);
}
/// @dev Converts pool amount to asset amount.
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
function poolToAssetAmount(
uint256 poolAmount,
uint8 poolDecimals,
uint8 assetDecimals,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 assetAmount) {
return convertWithReciprocalPrice(poolAmount, poolDecimals, assetDecimals, pricePoolPerAsset, rounding);
}
/// @dev Converts asset amount to pool amount.
function assetToPoolAmount(
uint128 assetAmount,
uint8 assetDecimals,
uint8 poolDecimals,
D18 pricePoolPerAsset,
MathLib.Rounding rounding
) internal pure returns (uint128 poolAmount) {
return convertWithPrice(assetAmount, assetDecimals, poolDecimals, pricePoolPerAsset, rounding);
}
/// @dev Returns the asset price per share denominated in ASSET_UNIT/SHARE_UNIT
/// @dev Assumes handling of zero denominator price (pricePoolPerAsset) by consumer.
///
/// NOTE: Should never be used for calculating amounts due to precision loss. Instead, please refer to
/// conversion relying on pricePoolPerShare and pricePoolPerAsset.
function priceAssetPerShare(D18 pricePoolPerShare, D18 pricePoolPerAsset)
internal
pure
returns (D18 priceAssetPerShare_)
{
return pricePoolPerShare / pricePoolPerAsset;
}
//----------------------------------------------------------------------------------------------
// Private methods
//----------------------------------------------------------------------------------------------
/// @dev Returns the asset decimals
function _getAssetDecimals(address asset, uint256 tokenId) private view returns (uint8 assetDecimals) {
return tokenId == 0 ? IERC20Metadata(asset).decimals() : IERC6909MetadataExt(asset).decimals(tokenId);
}
/// @dev When converting assets to shares using the price, all values are normalized to PRICE_DECIMALS
/// NOTE: We require all assets to have 2 <= decimals <= 18, see `Spoke.registerAsset`
function _toPriceDecimals(uint128 _value, uint8 decimals) private pure returns (uint256) {
if (PRICE_DECIMALS == decimals) return uint256(_value);
return uint256(_value) * 10 ** (PRICE_DECIMALS - decimals);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "./PoolId.sol";
type ShareClassId is bytes16;
function isNull(ShareClassId scId) pure returns (bool) {
return ShareClassId.unwrap(scId) == 0;
}
function index(ShareClassId scId) pure returns (uint32) {
return uint32(uint128(ShareClassId.unwrap(scId)));
}
function equals(ShareClassId left, ShareClassId right) pure returns (bool) {
return ShareClassId.unwrap(left) == ShareClassId.unwrap(right);
}
function raw(ShareClassId scId) pure returns (bytes16) {
return ShareClassId.unwrap(scId);
}
function newShareClassId(PoolId poolId, uint32 index_) pure returns (ShareClassId scId) {
return ShareClassId.wrap(bytes16((uint128(PoolId.unwrap(poolId)) << 64) + index_));
}
using {isNull, index, raw, equals as ==} for ShareClassId global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IMessageHandler} from "./IMessageHandler.sol";
import {IRecoverable} from "../../../misc/interfaces/IRecoverable.sol";
import {PoolId} from "../../types/PoolId.sol";
// Reserved gas amount for processing a message failure (assuming the worst case)
uint256 constant PROCESS_FAIL_MESSAGE_GAS = 35_000;
// Max length for a supported message. Note that a batch can use several messages with this length.
uint256 constant MESSAGE_MAX_LENGTH = 1_000;
// Max length of an error that happens when processing a message.
uint16 constant ERR_MAX_LENGTH = 32 * 4; // enough for most errors
/// @notice Interface for dispatch-only gateway
interface IGateway is IMessageHandler, IRecoverable {
//----------------------------------------------------------------------------------------------
// Structs
//----------------------------------------------------------------------------------------------
struct Underpaid {
uint128 gasLimit;
uint64 counter;
}
//----------------------------------------------------------------------------------------------
// Events
//----------------------------------------------------------------------------------------------
event File(bytes32 indexed what, address addr);
event UpdateManager(PoolId poolId, address who, bool canManage);
event BlockOutgoing(uint16 centrifugeId, PoolId poolId, bool isBlocked);
event PrepareMessage(uint16 indexed centrifugeId, PoolId poolId, bytes message);
event UnderpaidBatch(uint16 indexed centrifugeId, bytes batch, bytes32 batchHash);
event RepayBatch(uint16 indexed centrifugeId, bytes batch);
event ExecuteMessage(uint16 indexed centrifugeId, bytes32 messageHash);
event FailMessage(uint16 indexed centrifugeId, bytes32 messageHash, bytes error);
event SetRefundAddress(PoolId poolId, IRecoverable refund);
event DepositSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);
event WithdrawSubsidy(PoolId indexed poolId, address indexed sender, uint256 amount);
//----------------------------------------------------------------------------------------------
// Errors
//----------------------------------------------------------------------------------------------
/// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.
error FileUnrecognizedParam();
/// @notice Dispatched when the batch is ended without starting it.
error NoBatched();
/// @notice Dispatched when the gateway is paused.
error Paused();
/// @notice Dispatched when the gateway tries to send an empty message.
error EmptyMessage();
/// @notice Dispatched when the message exceeds MESSAGE_MAX_LENGTH.
error TooLongMessage();
/// @notice Dispatched when a message that has not failed is retried.
error NotFailedMessage();
/// @notice Dispatched when a batch that has not been underpaid is repaid.
error NotUnderpaidBatch();
/// @notice Dispatched when the content of a batch doesn't belong to the same pool
error MalformedBatch();
/// @notice Dispatched when a message is sent but the gateway is blocked for sending messages
error OutgoingBlocked();
/// @notice Dispatched when an account is not valid to withdraw subsidized pool funds
error CannotRefund();
/// @notice Dispatched when there is not enough gas to send the message
error NotEnoughGas();
/// @notice Dispatched when the batch requires more gas than the destination chain can execute in a single transaction
error BatchTooExpensive();
/// @notice Dispatched when a message was batched but there was a payment for it
error NotPayable();
/// @notice Dispatched when the callback fails with no error
error CallFailedWithEmptyRevert();
/// @notice Dispatched when the callback is called inside the callback
error CallbackIsLocked();
/// @notice Dispatched when the user doesn't call lockCallback()
error CallbackWasNotLocked();
/// @notice Dispatched when the callback was not from the sender
error CallbackWasNotFromSender();
/// @notice Dispatched when there is not enough msg.value to send to the callback
error NotEnoughValueForCallback();
/// @notice Dispatched when trying to create a batch during the send loop
error ReentrantBatchCreation();
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
/// @notice Used to update an address (state variable) on very rare occasions
/// @param what The name of the variable to be updated
/// @param data New address
function file(bytes32 what, address data) external;
/// @notice Configures a manager address for a pool
/// @param poolId PoolId associated to the adapters
/// @param who Manager address
/// @param canManage If enabled as manager
function updateManager(PoolId poolId, address who, bool canManage) external;
/// @notice Indicates if the gateway for a determined pool can send messages or not
/// @param centrifugeId Centrifuge ID associated to this block
/// @param poolId PoolId associated to this block
/// @param canSend If can send messages or not
function blockOutgoing(uint16 centrifugeId, PoolId poolId, bool canSend) external;
//----------------------------------------------------------------------------------------------
// Message handling
//----------------------------------------------------------------------------------------------
/// @notice Repay an underpaid batch
/// @param centrifugeId The destination chain
/// @param batch The batch to repay
/// @param refund Address to refund excess payment
function repay(uint16 centrifugeId, bytes memory batch, address refund) external payable;
/// @notice Retry a failed message
/// @param centrifugeId The destination chain
/// @param message The message to retry
function retry(uint16 centrifugeId, bytes memory message) external;
/// @notice Handling outgoing messages
/// @param centrifugeId Destination chain
/// @param message The message to send
/// @param unpaidMode Tells if storing the message as unpaid if not enough funds
/// @param refund Address to refund excess payment
function send(uint16 centrifugeId, bytes calldata message, bool unpaidMode, address refund) external payable;
//----------------------------------------------------------------------------------------------
// Batching
//----------------------------------------------------------------------------------------------
/// @notice Automatic batching of cross-chain transactions through a callback.
/// Any cross-chain transactions triggered in this callback will automatically be batched.
/// @dev Should be used like:
/// ```
/// contract Integration {
/// IGateway gateway;
///
/// function doSomething(PoolId poolId) external {
/// gateway.withBatch(abi.encodeWithSelector(Integration.callback.selector, poolId));
/// }
///
/// function callback(PoolId poolId) external {
/// // Avoid reentrancy to the callback and ensure it's called from withBatch in the same contract:
/// gateway.lockCallback();
///
/// // Call several hub, balance sheet, or spoke methods that trigger cross-chain transactions
/// }
/// }
/// ```
///
/// NOTE: inside callback, `msgSender` should be used instead of msg.sender
/// @param callbackData encoding data for the callback method
/// @param callbackValue msg.value to send to the callback
/// @param refund Address to refund excess payment
function withBatch(bytes memory callbackData, uint256 callbackValue, address refund) external payable;
/// @notice Same as withBatch(..), but without sending any msg.value to the callback
function withBatch(bytes memory callbackData, address refund) external payable;
/// @notice Ensures the callback is called by withBatch in the same contract.
/// @dev calling this at the very beginning inside the multicall means:
/// - The callback is called from the gateway under `withBatch`.
/// - The callback is called from the same contract, because withBatch uses `msg.sender` as target for the callback
/// - The callback that uses this can only be called once inside withBatch scope. No reentrancy.
function lockCallback() external;
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @notice Returns the current gateway batching level
/// @return Whether the gateway is currently batching
function isBatching() external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.28;
import {IBatchedMulticall} from "./interfaces/IBatchedMulticall.sol";
import {Multicall, IMulticall} from "../../misc/Multicall.sol";
import {IGateway} from "../messaging/interfaces/IGateway.sol";
/// @title BatchedMulticall
/// @notice Abstract contract that extends Multicall with gateway batching support, enabling efficient
/// aggregation of multiple cross-chain messages into a single batch to reduce transaction costs
/// while coordinating payment handling across batched operations.
/// @dev IMPORTANT: Integrators MUST replace msg.sender with msgSender() and msg.value with msgValue()
/// for the methods called by the multicall.
/// @dev IMPORTANT: The contract which extends BatchedMulticall must not treat the gateway
/// as a permissioned/authenticated msg.sender to avoid the multicall execution to call auth methods,
/// opening security issues.
abstract contract BatchedMulticall is Multicall, IBatchedMulticall {
IGateway public gateway;
address private transient _sender;
constructor(IGateway gateway_) {
gateway = gateway_;
}
/// @inheritdoc IMulticall
/// @notice With extra support for batching
function multicall(bytes[] calldata data) public payable override {
require(_sender == address(0), AlreadyBatching());
_sender = msg.sender;
gateway.withBatch{value: msg.value}(
abi.encodeWithSelector(BatchedMulticall.executeMulticall.selector, data), msg.sender
);
_sender = address(0);
}
function executeMulticall(bytes[] calldata data) external payable protected {
gateway.lockCallback();
super.multicall(data);
}
/// @dev Integrators MUST use msgSender() instead of msg.sender, since this is replaced
/// by the gateway address inside the multicall.
function msgSender() internal view virtual returns (address) {
return _sender != address(0) && msg.sender == address(gateway) ? _sender : msg.sender;
}
/// @dev Only the call to multicall should pass the msg.value, which is then passed
/// in `gateway.withBatch`. No inner calls should pass any msg.value.
function msgValue() internal view returns (uint256 value) {
return _sender != address(0) ? 0 : msg.value;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IHubRequestManager} from "./IHubRequestManager.sol";
import {IERC6909Decimals} from "../../../misc/interfaces/IERC6909.sol";
import {PoolId} from "../../types/PoolId.sol";
import {AssetId} from "../../types/AssetId.sol";
interface IHubRegistry is IERC6909Decimals {
//----------------------------------------------------------------------------------------------
// Events
//----------------------------------------------------------------------------------------------
event NewAsset(AssetId indexed assetId, uint8 decimals);
event NewPool(PoolId poolId, address indexed manager, AssetId indexed currency);
event UpdateManager(PoolId indexed poolId, address indexed manager, bool canManage);
event SetMetadata(PoolId indexed poolId, bytes metadata);
event UpdateDependency(PoolId indexed poolId, bytes32 indexed what, address dependency);
event UpdateCurrency(PoolId indexed poolId, AssetId currency);
event SetHubRequestManager(PoolId indexed poolId, uint16 indexed centrifugeId, IHubRequestManager manager);
//----------------------------------------------------------------------------------------------
// Errors
//----------------------------------------------------------------------------------------------
error NonExistingPool(PoolId id);
error AssetAlreadyRegistered();
error PoolAlreadyRegistered();
error EmptyAccount();
error EmptyCurrency();
error EmptyShareClassManager();
error AssetNotFound();
//----------------------------------------------------------------------------------------------
// Registration methods
//----------------------------------------------------------------------------------------------
/// @notice Register a new asset
/// @param assetId The asset identifier
/// @param decimals_ The number of decimals for the asset
function registerAsset(AssetId assetId, uint8 decimals_) external;
/// @notice Register a new pool
/// @param poolId The pool identifier
/// @param manager The initial manager address for the pool
/// @param currency The currency asset for the pool
function registerPool(PoolId poolId, address manager, AssetId currency) external;
//----------------------------------------------------------------------------------------------
// Update methods
//----------------------------------------------------------------------------------------------
/// @notice Allow/disallow an address as a manager for the pool
/// @param poolId The pool identifier
/// @param newManager The address to update manager status for
/// @param canManage Whether the address can manage the pool
function updateManager(PoolId poolId, address newManager, bool canManage) external;
/// @notice Set the hub request manager for a pool on a specific network
/// @param poolId The pool identifier
/// @param centrifuge The network identifier
/// @param manager The hub request manager contract
function setHubRequestManager(PoolId poolId, uint16 centrifuge, IHubRequestManager manager) external;
/// @notice Sets metadata for this pool
/// @param poolId The pool identifier
/// @param metadata The metadata to attach
function setMetadata(PoolId poolId, bytes calldata metadata) external;
/// @notice Updates a dependency of the system
/// @param poolId The pool identifier
/// @param what The dependency identifier
/// @param dependency The dependency contract address
function updateDependency(PoolId poolId, bytes32 what, address dependency) external;
/// @notice Updates the currency of the pool
/// @param poolId The pool identifier
/// @param currency The new currency asset
function updateCurrency(PoolId poolId, AssetId currency) external;
//----------------------------------------------------------------------------------------------
// View methods
//----------------------------------------------------------------------------------------------
/// @notice Returns the metadata attached to the pool, if any
/// @param poolId The pool identifier
/// @return The metadata bytes
function metadata(PoolId poolId) external view returns (bytes memory);
/// @notice Returns the currency of the pool
/// @param poolId The pool identifier
/// @return The currency asset identifier
function currency(PoolId poolId) external view returns (AssetId);
/// @notice Returns the dependency used in the system
/// @param poolId The pool identifier
/// @param what The dependency identifier
/// @return The dependency contract address
function dependency(PoolId poolId, bytes32 what) external view returns (address);
/// @notice Returns whether the account is a manager
/// @param poolId The pool identifier
/// @param who The address to check
/// @return Whether the address is a manager
function manager(PoolId poolId, address who) external view returns (bool);
/// @notice Returns the hub request manager for a pool and centrifuge ID
/// @param poolId The pool identifier
/// @param centrifugeId The network identifier
/// @return The hub request manager contract
function hubRequestManager(PoolId poolId, uint16 centrifugeId) external view returns (IHubRequestManager);
/// @notice Compute a pool ID given an ID postfix
/// @param centrifugeId The network identifier
/// @param postfix The pool ID postfix
/// @return poolId The computed pool identifier
function poolId(uint16 centrifugeId, uint48 postfix) external view returns (PoolId poolId);
/// @notice Returns the decimals for an asset
/// @param assetId The asset identifier
/// @return The number of decimals
function decimals(AssetId assetId) external view returns (uint8);
/// @notice Returns the decimals for a pool
/// @param poolId The pool identifier
/// @return The number of decimals
function decimals(PoolId poolId) external view returns (uint8);
/// @notice Checks the existence of a pool
/// @param poolId The pool identifier
/// @return Whether the pool exists
function exists(PoolId poolId) external view returns (bool);
/// @notice Checks the existence of an asset
/// @param assetId The asset identifier
/// @return Whether the asset is registered
function isRegistered(AssetId assetId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "../../types/PoolId.sol";
import {AssetId} from "../../types/AssetId.sol";
import {ShareClassId} from "../../types/ShareClassId.sol";
interface IHubRequestManagerCallback {
/// @notice Handles a request callback originating from a hub request manager.
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param payload The payload to be processed by the request callback
/// @param extraGasLimit Extra gas limit for the callback
/// @param refund address to refund the excedent of the payment
function requestCallback(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
bytes calldata payload,
uint128 extraGasLimit,
bool unpaidMode,
address refund
) external payable;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC165} from "../../../misc/interfaces/IERC165.sol";
import {PoolId} from "../../types/PoolId.sol";
import {AssetId} from "../../types/AssetId.sol";
import {ShareClassId} from "../../types/ShareClassId.sol";
interface IHubRequestManager is IERC165 {
/// @notice Handles a request originating from the Hub side, similar to HubHelpers.request
function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external;
}
interface IHubRequestManagerNotifications is IERC165 {
/// @notice Notify a deposit for an investor address located in the chain where the asset belongs
function notifyDeposit(
PoolId poolId,
ShareClassId scId,
AssetId depositAssetId,
bytes32 investor,
uint32 maxClaims,
address refund
) external payable;
/// @notice Notify a redemption for an investor address located in the chain where the asset belongs
function notifyRedeem(
PoolId poolId,
ShareClassId scId,
AssetId payoutAssetId,
bytes32 investor,
uint32 maxClaims,
address refund
) external payable;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IERC20
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @author Modified from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
interface IERC20 {
error InvalidAddress();
error InsufficientBalance();
error InsufficientAllowance();
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
error PermitExpired();
error InvalidPermit();
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
interface IERC20Wrapper {
/**
* @dev Returns the address of the underlying ERC-20 token that is being wrapped.
*/
function underlying() external view returns (address);
/**
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
*/
function depositFor(address account, uint256 value) external returns (bool);
/**
* @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
*/
function withdrawTo(address account, uint256 value) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IERC165} from "forge-std/interfaces/IERC165.sol";
interface IERC6909 is IERC165 {
error EmptyOwner();
error EmptyAmount();
error InvalidTokenId();
error InsufficientBalance(address owner, uint256 tokenId);
error InsufficientAllowance(address sender, uint256 tokenId);
event OperatorSet(address indexed owner, address indexed operator, bool approved);
event Approval(address indexed owner, address indexed spender, uint256 indexed tokenId, uint256 amount);
event Transfer(address caller, address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
/// @notice Owner balance of a tokenId.
/// @param owner The address of the owner.
/// @param tokenId The id of the token.
/// @return amount The balance of the token.
function balanceOf(address owner, uint256 tokenId) external view returns (uint256 amount);
/// @notice Spender allowance of a tokenId.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @param tokenId The id of the token.
/// @return amount The allowance of the token.
function allowance(address owner, address spender, uint256 tokenId) external view returns (uint256 amount);
/// @notice Checks if a spender is approved by an owner as an operator.
/// @param owner The address of the owner.
/// @param spender The address of the spender.
/// @return approved The approval status.
function isOperator(address owner, address spender) external view returns (bool approved);
/// @notice Transfers an amount of a tokenId from the caller to a receiver.
/// @param receiver The address of the receiver.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always, unless the function reverts.
function transfer(address receiver, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Transfers an amount of a tokenId from a sender to a receiver.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always, unless the function reverts.
function transferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Approves an amount of a tokenId to a spender.
/// @param spender The address of the spender.
/// @param tokenId The id of the token.
/// @param amount The amount of the token.
/// @return bool True, always.
function approve(address spender, uint256 tokenId, uint256 amount) external returns (bool);
/// @notice Sets or removes an operator for the caller.
/// @param operator The address of the operator.
/// @param approved The approval status.
/// @return bool True, always.
function setOperator(address operator, bool approved) external returns (bool);
}
interface IERC6909URIExt {
event TokenURISet(uint256 indexed tokenId, string uri);
event ContractURISet(address indexed target, string uri);
error EmptyURI();
/// @return uri Returns the common token URI.
function contractURI() external view returns (string memory);
/// @dev Returns empty string if tokenId does not exist.
/// MAY implemented to throw MissingURI(tokenId) error.
/// @param tokenId The token to query URI for.
/// @return uri A string representing the uri for the specific tokenId.
function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IERC6909NFT is IERC6909, IERC6909URIExt {
error UnknownTokenId(address owner, uint256 tokenId);
error LessThanMinimalDecimal(uint8 minimal, uint8 actual);
/// @notice Provide URI for a specific tokenId.
/// @param tokenId Token Id.
/// @param URI URI to a document defining the collection as a whole.
function setTokenURI(uint256 tokenId, string memory URI) external;
/// @dev Optional method to set up the contract URI if needed.
/// @param URI URI to a document defining the collection as a whole.
function setContractURI(string memory URI) external;
/// @notice Mint new tokens for a given owner and sets tokenURI.
/// @dev For non-fungible tokens, call with amount = 1, for fungible it could be any amount.
/// TokenId is auto incremented by one.
///
/// @param owner Creates supply of a given tokenId by amount for owner.
/// @param tokenURI URI fortestBurningToken the newly minted token.
/// @return tokenId Id of the newly minted token.
function mint(address owner, string memory tokenURI) external returns (uint256 tokenId);
/// @notice Destroy supply of a given tokenId by amount.
/// @dev The msg.sender MUST be the owner.
///
/// @param tokenId Item which have reduced supply.
function burn(uint256 tokenId) external;
}
/// @notice Extension of ERC6909 Standard for tracking total supply
interface IERC6909TotalSupplyExt {
/// @notice The totalSupply for a token id.
///
/// @param tokenId Id of the token
/// @return supply Total supply for a given `tokenId`
function totalSupply(uint256 tokenId) external returns (uint256 supply);
}
interface IERC6909Decimals {
/// @notice Used to retrieve the decimals of an asset
/// @dev address is used but the value corresponds to a AssetId
function decimals(uint256 assetId) external view returns (uint8);
}
interface IERC6909MetadataExt is IERC6909Decimals {
/// @notice Used to retrieve the decimals of an asset
/// @dev address is used but the value corresponds to a AssetId
function decimals(uint256 assetId) external view returns (uint8);
/// @notice Used to retrieve the name of an asset
/// @dev address is used but the value corresponds to a AssetId
function name(uint256 assetId) external view returns (string memory);
/// @notice Used to retrieve the symbol of an asset
/// @dev address is used but the value corresponds to a AssetId
function symbol(uint256 assetId) external view returns (string memory);
}
interface IERC6909Fungible is IERC6909 {
/// @notice Mint new tokens for a specific tokenid and assign them to an owner
///
/// @param owner Creates supply of a given `tokenId` by `amount` for owner.
/// @param tokenId Id of the item
/// @param amount Adds `amount` to the total supply of the given `tokenId`
function mint(address owner, uint256 tokenId, uint256 amount) external;
/// @notice Destroy supply of a given tokenId by amount.
/// @dev The msg.sender MUST be the owner.
///
/// @param owner Owner of the `tokenId`
/// @param tokenId Id of the item.
/// @param amount Subtract `amount` from the total supply of the given `tokenId`
function burn(address owner, uint256 tokenId, uint256 amount) external;
/// @notice Enforces a transfer from `spender` point of view.
///
///
/// @param sender The owner of the `tokenId`
/// @param receiver Address of the receiving party
/// @param tokenId Token Id
/// @param amount Amount to be transferred
function authTransferFrom(address sender, address receiver, uint256 tokenId, uint256 amount) external returns (bool);
}
/// @dev A factory contract to deploy new collateral contracts implementing IERC6909.
interface IERC6909Factory {
/// Events
event NewTokenDeployment(address indexed owner, address instance);
/// @notice Deploys new install of a contract that implements IERC6909.
/// @dev Factory should deploy deterministically if possible.
///
/// @param owner Owner of the deployed collateral contract which has initial full rights.
/// @param salt Used to make a deterministic deployment.
/// @return An address of the newly deployed contract.
function deploy(address owner, bytes32 salt) external returns (address);
/// @notice Generates a new deterministic address based on the owner and the salt.
///
/// @param owner Owner of the deployed collateral contract which has initial full rights.
/// @param salt Used to make a deterministic deployment.
/// @return An address of the newly deployed contract.
function previewAddress(address owner, bytes32 salt) external returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @notice Generic interface for entities that handle incoming messages
interface IMessageHandler {
//----------------------------------------------------------------------------------------------
// Incoming
//----------------------------------------------------------------------------------------------
/// @notice Handling incoming messages
/// @param centrifugeId Source chain
/// @param message Incoming message
function handle(uint16 centrifugeId, bytes calldata message) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
address constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
interface IRecoverable {
/// @notice Used to recover any ERC-20 token.
/// @dev This method is called only by authorized entities
/// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
/// to recover locked native ETH or token compatible with ERC20.
/// @param to Receiver of the funds
/// @param amount Amount to send to the receiver.
function recoverTokens(address token, address to, uint256 amount) external;
/// @notice Used to recover any ERC-20 or ERC-6909 token.
/// @dev This method is called only by authorized entities
/// @param token It could be 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
/// to recover locked native ETH or token compatible with ERC20 or ERC6909.
/// @param tokenId The token id, i.e. non-zero if the underlying token is ERC6909 and else zero.
/// @param to Receiver of the funds
/// @param amount Amount to send to the receiver.
function recoverTokens(address token, uint256 tokenId, address to, uint256 amount) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IGateway} from "../../messaging/interfaces/IGateway.sol";
/// @notice A multicall that batches the messages using the gateway
interface IBatchedMulticall {
error AlreadyBatching();
/// @notice Returns the gateway contract used for batching messages
/// @return The gateway contract instance
function gateway() external view returns (IGateway);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.28;
// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359
// If perform any change on it, please ensure no other warnings appears
import {IMulticall} from "./interfaces/IMulticall.sol";
import {ReentrancyProtection} from "./ReentrancyProtection.sol";
/// @title Multicall
/// @notice Abstract contract that enables batch execution of multiple function calls in a single transaction.
abstract contract Multicall is ReentrancyProtection, IMulticall {
function multicall(bytes[] calldata data) public payable virtual protected {
uint256 totalBytes = data.length;
for (uint256 i; i < totalBytes; ++i) {
(bool success, bytes memory returnData) = address(this).delegatecall(data[i]);
if (!success) {
uint256 length = returnData.length;
require(length != 0, CallFailedWithEmptyRevert());
assembly ("memory-safe") {
revert(add(32, returnData), length)
}
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface IERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @notice Allows to call several calls of the same contract in a single transaction
interface IMulticall {
/// @notice Dispatched when an empty revert is dispatched in a method in the multicall
error CallFailedWithEmptyRevert();
/// @notice Allows caller to execute multiple (batched) messages calls in one transaction.
/// @param data An array of encoded methods of the same contract.
/// @dev No reentrant execution is allowed.
/// If one call fails, it reverts the whole transaction.
/// In order to provide the correct value for functions that require top up,
/// the caller must estimate separately, in advance, how much each of the message call will cost.
/// The `msg.value` when calling this method must be the sum of all estimates.
function multicall(bytes[] calldata data) external payable;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.28;
// NOTE: This file has warning disabled due https://github.com/ethereum/solidity/issues/14359
// If perform any change on it, please ensure no other warnings appears
/// @title ReentrancyProtection
/// @notice Abstract contract that implements reentrancy protection using transient storage.
abstract contract ReentrancyProtection {
/// @notice Dispatched when there is a re-entrancy issue
error UnauthorizedSender();
address private transient _initiator;
/// @dev The method is protected for reentrancy issues.
modifier protected() {
if (_initiator == address(0)) {
// Single call re-entrancy lock
_initiator = msg.sender;
_;
_initiator = address(0);
} else {
// Multicall re-entrancy lock
require(msg.sender == _initiator, UnauthorizedSender());
_;
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@chimera/=lib/chimera/src/"
],
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": true,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IHubRegistry","name":"hubRegistry_","type":"address"},{"internalType":"contract IGateway","name":"gateway_","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyBatching","type":"error"},{"inputs":[],"name":"CallFailedWithEmptyRevert","type":"error"},{"inputs":[],"name":"CancellationInitializationRequired","type":"error"},{"inputs":[],"name":"CancellationQueued","type":"error"},{"inputs":[],"name":"DivisionByZero","type":"error"},{"inputs":[],"name":"EpochNotFound","type":"error"},{"inputs":[{"internalType":"uint32","name":"epochId","type":"uint32"},{"internalType":"uint32","name":"actualEpochId","type":"uint32"}],"name":"EpochNotInSequence","type":"error"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[],"name":"InsufficientPending","type":"error"},{"inputs":[],"name":"IssuanceRequired","type":"error"},{"inputs":[],"name":"MulDiv_Overflow","type":"error"},{"inputs":[],"name":"NoOrderFound","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"RevocationRequired","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"Uint128_Overflow","type":"error"},{"inputs":[],"name":"Uint64_Overflow","type":"error"},{"inputs":[],"name":"UnauthorizedSender","type":"error"},{"inputs":[],"name":"UnknownRequestType","type":"error"},{"inputs":[],"name":"UnknownRequestType","type":"error"},{"inputs":[],"name":"ZeroApprovalAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"approvedPoolAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"}],"name":"ApproveDeposits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingShareAmount","type":"uint128"}],"name":"ApproveRedeems","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"paymentAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"issuedAt","type":"uint64"}],"name":"ClaimDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"paymentShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"pendingShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint64","name":"revokedAt","type":"uint64"}],"name":"ClaimRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"components":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"indexed":false,"internalType":"struct EpochId","name":"epochIdData","type":"tuple"}],"name":"EpochIdModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"indexed":false,"internalType":"D18","name":"priceAssetPerShare","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"issuedShareAmount","type":"uint128"}],"name":"IssueShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"indexed":false,"internalType":"D18","name":"priceAssetPerShare","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"payoutPoolAmount","type":"uint128"}],"name":"RevokeShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"uint128","name":"pendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalPendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"queuedAmount","type":"uint128"},{"indexed":false,"internalType":"bool","name":"isQueuedCancellation","type":"bool"}],"name":"UpdateDepositRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"PoolId","name":"poolId","type":"uint64"},{"indexed":true,"internalType":"ShareClassId","name":"shareClassId","type":"bytes16"},{"indexed":true,"internalType":"AssetId","name":"assetId","type":"uint128"},{"indexed":false,"internalType":"uint32","name":"epochId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"investor","type":"bytes32"},{"indexed":false,"internalType":"uint128","name":"pendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"totalPendingAmount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"queuedAmount","type":"uint128"},{"indexed":false,"internalType":"bool","name":"isQueuedCancellation","type":"bool"}],"name":"UpdateRedeemRequest","type":"event"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"allowForceDepositCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"allowForceRedeemCancel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"uint32","name":"nowDepositEpochId","type":"uint32"},{"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"approveDeposits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"uint32","name":"nowRedeemEpochId","type":"uint32"},{"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"}],"name":"approveRedeems","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"cancelDepositRequest","outputs":[{"internalType":"uint128","name":"cancelledAssetAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"cancelRedeemRequest","outputs":[{"internalType":"uint128","name":"cancelledShareAmount","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"depositRequest","outputs":[{"internalType":"uint128","name":"pending","type":"uint128"},{"internalType":"uint32","name":"lastUpdate","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"epochId","outputs":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"uint32","name":"epochId_","type":"uint32"}],"name":"epochInvestAmounts","outputs":[{"internalType":"uint128","name":"approvedPoolAmount","type":"uint128"},{"internalType":"uint128","name":"approvedAssetAmount","type":"uint128"},{"internalType":"uint128","name":"pendingAssetAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint64","name":"issuedAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"uint32","name":"epochId_","type":"uint32"}],"name":"epochRedeemAmounts","outputs":[{"internalType":"uint128","name":"approvedShareAmount","type":"uint128"},{"internalType":"uint128","name":"pendingShareAmount","type":"uint128"},{"internalType":"D18","name":"pricePoolPerAsset","type":"uint128"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"payoutAssetAmount","type":"uint128"},{"internalType":"uint64","name":"revokedAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"executeMulticall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"forceCancelDepositRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"forceCancelRedeemRequest","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract IHubRequestManagerCallback","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubRegistry","outputs":[{"internalType":"contract IHubRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"},{"internalType":"uint32","name":"nowIssueEpochId","type":"uint32"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"extraGasLimit","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"issueShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"maxDepositClaims","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"maxRedeemClaims","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"uint32","name":"maxClaims","type":"uint32"},{"internalType":"address","name":"refund","type":"address"}],"name":"notifyDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"uint32","name":"maxClaims","type":"uint32"},{"internalType":"address","name":"refund","type":"address"}],"name":"notifyRedeem","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowDepositEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowIssueEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowRedeemEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"nowRevokeEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"pendingDeposit","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"}],"name":"pendingRedeem","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"queuedDepositRequest","outputs":[{"internalType":"bool","name":"isCancelling","type":"bool"},{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"queuedRedeemRequest","outputs":[{"internalType":"bool","name":"isCancelling","type":"bool"},{"internalType":"uint128","name":"amount","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"PoolId","name":"","type":"uint64"},{"internalType":"ShareClassId","name":"","type":"bytes16"},{"internalType":"AssetId","name":"","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"}],"name":"redeemRequest","outputs":[{"internalType":"uint128","name":"pending","type":"uint128"},{"internalType":"uint32","name":"lastUpdate","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"request","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"depositAssetId","type":"uint128"}],"name":"requestDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bytes32","name":"investor","type":"bytes32"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"}],"name":"requestRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId_","type":"bytes16"},{"internalType":"AssetId","name":"payoutAssetId","type":"uint128"},{"internalType":"uint32","name":"nowRevokeEpochId","type":"uint32"},{"internalType":"D18","name":"pricePoolPerShare","type":"uint128"},{"internalType":"uint128","name":"extraGasLimit","type":"uint128"},{"internalType":"address","name":"refund","type":"address"}],"name":"revokeShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"PoolId","name":"poolId","type":"uint64"},{"internalType":"ShareClassId","name":"scId","type":"bytes16"},{"internalType":"AssetId","name":"assetId","type":"uint128"},{"components":[{"internalType":"uint32","name":"deposit","type":"uint32"},{"internalType":"uint32","name":"issue","type":"uint32"},{"internalType":"uint32","name":"redeem","type":"uint32"},{"internalType":"uint32","name":"revoke","type":"uint32"}],"internalType":"struct EpochId","name":"epochIdData","type":"tuple"}],"name":"setEpochIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b50604051615e23380380615e2383398101604081905261002e916100b8565b6001600160a01b0381165f8181526020819052604080822060019055518492849290917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250600180546001600160a01b0319166001600160a01b0392831617905592909216608052506101029050565b6001600160a01b03811681146100b5575f5ffd5b50565b5f5f5f606084860312156100ca575f5ffd5b83516100d5816100a1565b60208501519093506100e6816100a1565b60408501519092506100f7816100a1565b809150509250925092565b608051615c9961018a5f395f818161086701528181610e7a0152818161173e015281816118db0152818161196601528181611ec7015281816120c301528181612141015281816123bd015281816124cf01528181612de401528181613947015281816139d201528181613e3201528181613ebd0152818161433c01526143dc0152615c995ff3fe6080604052600436106101d5575f3560e01c806301ffc9a7146101d95780630a6670631461020d578063116191b61461024157806328537d06146102785780632f6c33bf14610344578063365a86fc146103655780633f92bf831461038457806342e413391461039757806346bfcc8f146103b65780635eb4d168146103e257806365fae35e1461046357806366e960e31461048257806371c4482614610503578063730316d114610522578063790b56ce146105415780637fe50ab2146105605780638a93ba581461057f5780638baa4083146105925780639b884cd5146105b15780639c52a7f1146105d05780639d26e184146105ef5780639e5d3a7a14610637578063ac9650d81461064a578063ae7275201461065d578063b5eaa51d1461067c578063bcf16c93146106c4578063be3bad4a14610721578063bf353dbb14610734578063c076a59f1461076d578063c3f4d5ed146107fe578063c592045514610811578063c88854a314610856578063d0d4133114610889578063d4e8be831461089c578063da8336ba146108bb578063e0aeab1e146108ce578063e3b304d4146108e1578063e47091c914610926578063ee1cb43d1461099d578063fc689b78146109b0578063fdfa8fe0146109cf575b5f5ffd5b3480156101e4575f5ffd5b506101f86101f3366004615055565b610a27565b60405190151581526020015b60405180910390f35b348015610218575f5ffd5b5061022c6102273660046150c5565b610a93565b60405163ffffffff9091168152602001610204565b34801561024c575f5ffd5b50600154610260906001600160a01b031681565b6040516001600160a01b039091168152602001610204565b348015610283575f5ffd5b506102f9610292366004615124565b600460209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b604080516001600160801b039788168152958716602087015293861693850193909352908416606084015290921660808201526001600160401b0390911660a082015260c001610204565b34801561034f575f5ffd5b5061036361035e366004615177565b610b37565b005b348015610370575f5ffd5b50600254610260906001600160a01b031681565b610363610392366004615229565b610e77565b3480156103a2575f5ffd5b5061022c6103b1366004615285565b6110ac565b3480156103c1575f5ffd5b506103d56103d03660046150c5565b61110c565b60405161020491906152c9565b3480156103ed575f5ffd5b506102f96103fc366004615124565b600560209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b34801561046e575f5ffd5b5061036361047d3660046152dd565b6111d4565b34801561048d575f5ffd5b506104df61049c3660046152f6565b600860209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b604080516001600160801b03909316835263ffffffff909116602083015201610204565b34801561050e575f5ffd5b5061022c61051d366004615285565b611247565b34801561052d575f5ffd5b5061036361053c366004615340565b61129d565b34801561054c575f5ffd5b5061036361055b36600461540c565b6113f8565b34801561056b575f5ffd5b5061022c61057a366004615285565b611437565b61036361058d36600461546c565b61148d565b34801561059d575f5ffd5b506103636105ac36600461540c565b6115c9565b3480156105bc575f5ffd5b506103d56105cb3660046150c5565b611609565b3480156105db575f5ffd5b506103636105ea3660046152dd565b6116c9565b3480156105fa575f5ffd5b506101f86106093660046152f6565b600c60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b6103636106453660046154db565b61173b565b61036361065836600461546c565b611d78565b348015610668575f5ffd5b5061022c610677366004615285565b611e75565b348015610687575f5ffd5b506101f86106963660046152f6565b600d60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b3480156106cf575f5ffd5b506104df6106de3660046152f6565b600960209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b61036361072f3660046154db565b611ec4565b34801561073f575f5ffd5b5061075f61074e3660046152dd565b5f6020819052908152604090205481565b604051908152602001610204565b348015610778575f5ffd5b506107ce610787366004615285565b600360209081525f938452604080852082529284528284209052825290205463ffffffff80821691600160201b8104821691600160401b8204811691600160601b90041684565b6040805163ffffffff95861681529385166020850152918416918301919091529091166060820152608001610204565b61036361080c3660046154db565b6123ba565b34801561081c575f5ffd5b506103d561082b366004615285565b600760209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610861575f5ffd5b506102607f000000000000000000000000000000000000000000000000000000000000000081565b610363610897366004615562565b6124cc565b3480156108a7575f5ffd5b506103636108b63660046155da565b6127ee565b6103636108c9366004615604565b6128a8565b6103636108dc366004615604565b612b93565b3480156108ec575f5ffd5b506103d56108fb366004615285565b600660209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610931575f5ffd5b5061097e6109403660046152f6565b600a60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b6040805192151583526001600160801b03909116602083015201610204565b6103636109ab366004615229565b612de1565b3480156109bb575f5ffd5b5061022c6109ca3660046150c5565b612f96565b3480156109da575f5ffd5b5061097e6109e93660046152f6565b600b60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b5f6001600160e01b0319821663af00afbd60e01b1480610a5757506001600160e01b03198216632f6c33bf60e01b145b80610a7257506001600160e01b03198216630e8b676960e21b145b80610a8d57506001600160e01b031982166301ffc9a760e01b145b92915050565b6001600160401b0384165f8181526008602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160601b90041661302d565b95945050505050565b335f90815260208190526040902054600114610b665760405163ea8e4eb560e01b815260040160405180910390fd5b5f610ba583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061307b92505050565b6004811115610bb657610bb661566f565b90505f1960ff821601610c1e575f610c0284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061309a92505050565b9050610c1887878360200151845f0151896113f8565b50610e6f565b60011960ff821601610c7f575f610c6984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061311f92505050565b9050610c1887878360200151845f0151896115c9565b60021960ff821601610d98575f610cca84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061313992505050565b90505f610cdc8888845f01518961110c565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131a1565b5f60015f6040518863ffffffff1660e01b8152600401610d6397969594939291906156b1565b5f604051808303815f87803b158015610d7a575f5ffd5b505af1158015610d8c573d5f5f3e3d5ffd5b505050505b5050610e6f565b60031960ff821601610e56575f610de384848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506131e292505050565b90505f610df58888845f015189611609565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131f7565b604051638d54989d60e01b815260040160405180910390fd5b505050505050565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82610eb0613222565b6040518363ffffffff1660e01b8152600401610ecd929190615724565b602060405180830381865afa158015610ee8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0c9190615746565b610f295760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600d602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16610f8f57604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526008602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690610fe9888884848a8a6001613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131f7565b6002549091506001600160a01b031663c3ab3924611049613531565b8b8b8a865f5f8d6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b5f604051808303818588803b158015611089575f5ffd5b505af115801561109b573d5f5f3e3d5ffd5b5050505050505b5050505050505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160401b900463ffffffff166001615779565b90505b9392505050565b335f9081526020819052604081205460011461113b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600c602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff19166001179055958552600984528285209185529083528184209084528252808320878452909152812054909116906111ca90879087908490888882613260565b9695505050505050565b335f908152602081905260409020546001146112035760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160201b900463ffffffff166001615779565b335f908152602081905260409020546001146112cc5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0384165f8181526003602090815260408083206001600160801b031988168085529083528184206001600160801b0388168086529084529382902086518154948801518489015160608a015163ffffffff908116600160601b0263ffffffff60601b19928216600160401b0292909216600160401b600160801b0319938216600160201b026001600160401b031990991691909416179690961716179390931790925551919290917f0f7c52086fe372e36e65c8c21cbcc8254ac152ce8c02cd914c162f62ed80237b906113ea9086905f60808201905063ffffffff835116825263ffffffff602084015116602083015263ffffffff604084015116604083015263ffffffff606084015116606083015292915050565b60405180910390a450505050565b335f908152602081905260409020546001146114275760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186865f613260565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160601b900463ffffffff166001615779565b5f5c6001600160a01b031661152f57335f805c6001600160a01b0319168217905d5060015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156114fb575f5ffd5b505af115801561150d573d5f5f3e3d5ffd5b5050505061151b828261354c565b5f6001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461155957604051630101292160e31b815260040160405180910390fd5b60015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156115a5575f5ffd5b505af11580156115b7573d5f5f3e3d5ffd5b505050506115c5828261354c565b5050565b335f908152602081905260409020546001146115f85760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186866001613260565b335f908152602081905260408120546001146116385760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600d602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff1916600190811790915596865260088552838620928652918452828520908552835281842088855290925282205416916111ca9188918891859189908990613260565b335f908152602081905260409020546001146116f85760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82611774613222565b6040518363ffffffff1660e01b8152600401611791929190615724565b602060405180830381865afa1580156117ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d09190615746565b6117ed5760405163ea8e4eb560e01b815260040160405180910390fd5b6117f8888888611e75565b63ffffffff168563ffffffff1614856118128a8a8a611e75565b909161183c57604051632c647e3760e21b8152600401611833929190615795565b60405180910390fd5b50506001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b038a8116855292529091205481169085168110156118a25760405163776a3aa960e11b815260040160405180910390fd5b5f856001600160801b0316116118cb5760405163035a9e4760e11b815260040160405180910390fd5b5f6119f5866001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b815260040161192591906152c9565b602060405180830381865afa158015611940573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196491906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b81526004016119b091906157cc565b602060405180830381865afa1580156119cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ef91906157ac565b88613724565b90505f60045f8c6001600160401b03166001600160401b031681526020019081526020015f205f8b6001600160801b0319166001600160801b03191681526020019081526020015f205f8a6001600160801b03166001600160801b031681526020019081526020015f205f8963ffffffff1663ffffffff1681526020019081526020015f20905086815f0160106101000a8154816001600160801b0302191690836001600160801b0316021790555081815f015f6101000a8154816001600160801b0302191690836001600160801b0316021790555082816001015f6101000a8154816001600160801b0302191690836001600160801b03160217905550858160010160106101000a8154816001600160801b0302191690836001600160801b031602179055508660075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f8282829054906101000a90046001600160801b0316611ba491906157e0565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508683611bd491906157e0565b92508760035f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff160217905550886001600160801b03168a6001600160801b0319168c6001600160401b03167f1785217365be01fea67dbce22680b382886fe6a3a22156830b3cda5823a42a8e8b868c89604051611cb194939291906157ff565b60405180910390a45f611cf760405180604001604052808a6001600160801b03168152602001611ce78a6001600160801b031690565b6001600160801b03169052613732565b6002549091506001600160a01b031663c3ab3924611d13613531565b8e8e8e865f5f8e6040518963ffffffff1660e01b8152600401611d3c97969594939291906156b1565b5f604051808303818588803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b60015c6001600160a01b031615611da257604051631ccdbfa560e21b815260040160405180910390fd5b336001805c6001600160a01b0319168217905d506001546040516001600160a01b03909116906329d43364903490631152774b60e31b90611de99087908790602401615856565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b9092168252611e309133906004016158f4565b5f604051808303818588803b158015611e47575f5ffd5b505af1158015611e59573d5f5f3e3d5ffd5b505f935050506001805c6001600160a01b03191691505d505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b03851684529091528120546111029063ffffffff166001615779565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82611efd613222565b6040518363ffffffff1660e01b8152600401611f1a929190615724565b602060405180830381865afa158015611f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f599190615746565b611f765760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0388165f9081526003602090815260408083206001600160801b03198b16845282528083206001600160801b038a16845290915290205463ffffffff9081169086161115611fde576040516386d1007760e01b815260040160405180910390fd5b611fe9888888611247565b63ffffffff168563ffffffff1614856120038a8a8a611247565b909161202457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0388165f9081526004602090815260408083206001600160801b0319808c1685529083528184206001600160801b038b8116865290845282852063ffffffff8b16865290935290832060028101805493891693909216831790915591906120939061374f565b61209d575f6121e6565b8154604051630274be6d60e21b81526121e691600160801b90046001600160801b0316907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906309d2f9b490612100908d906004016152c9565b602060405180830381865afa15801561211b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213f91906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161218b91906157cc565b602060405180830381865afa1580156121a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ca91906157ac565b6001860154600160801b90046001600160801b03168a5f61375d565b90506121f14261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b03938416810291909117909155908b165f8181526003602090815260408083206001600160801b03198f168085529083528184206001600160801b038f81168087529190945291909320805463ffffffff60201b1916600160201b63ffffffff8f1602179055600187015490949293927f75d54fc68ce51f85af6cc4bc67a5d7d3267296e63539b2d428743a1a8a8380de928d928d926122b29291041661374f565b6122bc575f6122e3565b600288015460018901546122e3916001600160801b0390811691600160801b900416613799565b876040516122f494939291906157ff565b60405180910390a45f61233a6040518060400160405280846001600160801b0316815260200161232a8a6001600160801b031690565b6001600160801b031690526137a4565b6002549091506001600160a01b031663c3ab3924612356613531565b8d8d8d868c5f8d6040518963ffffffff1660e01b815260040161237f97969594939291906156b1565b5f604051808303818588803b158015612396575f5ffd5b505af11580156123a8573d5f5f3e3d5ffd5b50505050505050505050505050505050565b867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b826123f3613222565b6040518363ffffffff1660e01b8152600401612410929190615724565b602060405180830381865afa15801561242b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061244f9190615746565b61246c5760405163ea8e4eb560e01b815260040160405180910390fd5b5f5f61247b8a8a8a8a8a6137c1565b915091505f61233a6040518060600160405280856001600160801b03168152602001846001600160801b031681526020016124bc8a6001600160801b031690565b6001600160801b03169052613bce565b857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82612505613222565b6040518363ffffffff1660e01b8152600401612522929190615724565b602060405180830381865afa15801561253d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125619190615746565b61257e5760405163ea8e4eb560e01b815260040160405180910390fd5b6125898787876110ac565b63ffffffff168463ffffffff1614846125a38989896110ac565b90916125c457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526006602090815260408083206001600160801b03198a16845282528083206001600160801b038981168552925290912054811690841681101561262a5760405163776a3aa960e11b815260040160405180910390fd5b5f846001600160801b0316116126535760405163035a9e4760e11b815260040160405180910390fd5b6001600160401b0388165f8181526005602090815260408083206001600160801b03198c81168086529184528285206001600160801b038d811680885291865284872063ffffffff8e16885286528487208c8216600160801b8b8416021781556001810180549094168c831617909355968652600685528386209286529184528285209185529252822080549193889391926126f1918591166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550848261272191906157e0565b6001600160401b038a165f8181526003602090815260408083206001600160801b03198e168085529083528184206001600160801b038e16808652935292819020805463ffffffff8d16600160401b0263ffffffff60401b1990911617905551939550929091907f679cd78fb2cbc9b1fa61043bb803ac3d5a5a8e0dd7aaa5a94e8bc5721dd2b8aa906127db908b908b90899063ffffffff9390931683526001600160801b03918216602084015216604082015260600190565b60405180910390a4505050505050505050565b335f9081526020819052604090205460011461281d5760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b0361284a57600280546001600160a01b0319166001600160a01b038316179055612863565b604051633db0d5b960e01b815260040160405180910390fd5b604080518381526001600160a01b03831660208201527f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba910160405180910390a15050565b5f5c6001600160a01b0316612a3857335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612946575f5f5f5f6128f38e8e8d8f613bf3565b93509350935093508388612907919061591d565b9750612913838861591d565b96506001600160801b03821615612928578195505b806129365750505050612946565b5050600190920191506128cf9050565b505f826001600160801b0316118061296657505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612984613531565b8b8b8b6129cb60405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b81526004016129f097969594939291906156b1565b5f604051808303818588803b158015612a07575f5ffd5b505af1158015612a19573d5f5f3e3d5ffd5b50505050505b505f9150506001600160a01b0319815c16815d50610e6f565b336001600160a01b035f5c1614612a6257604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612ade575f5f5f5f612a8b8e8e8d8f613bf3565b93509350935093508388612a9f919061591d565b9750612aab838861591d565b96506001600160801b03821615612ac0578195505b80612ace5750505050612ade565b505060019092019150612a679050565b505f826001600160801b03161180612afe57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612b1c613531565b8b8b8b612b6360405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b505050505050505050565b5f5c6001600160a01b0316612cb657335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612c31575f5f5f5f612bde8e8e8d8f614113565b93509350935093508388612bf2919061591d565b9750612bfe838861591d565b96506001600160801b03821615612c13578195505b80612c215750505050612c31565b505060019092019150612bba9050565b505f826001600160801b03161180612c5157505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612c6f613531565b8b8b8b6129cb60405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b336001600160a01b035f5c1614612ce057604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612d5c575f5f5f5f612d098e8e8d8f614113565b93509350935093508388612d1d919061591d565b9750612d29838861591d565b96506001600160801b03821615612d3e578195505b80612d4c5750505050612d5c565b505060019092019150612ce59050565b505f826001600160801b03161180612d7c57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612d9a613531565b8b8b8b612b6360405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633625342b82612e1a613222565b6040518363ffffffff1660e01b8152600401612e37929190615724565b602060405180830381865afa158015612e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190615746565b612e935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600c602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16612ef957604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526009602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690612f52888884848a8a82613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131a1565b6001600160401b0384165f8181526009602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160201b9004165b81515f906001600160801b0316158061305557508163ffffffff16836020015163ffffffff16115b1561306157505f610a8d565b6020830151613070908361593c565b611105906001615779565b5f61308682826145ab565b60ff166004811115610a8d57610a8d61566f565b604080518082019091525f808252602082015260015b6130b98361307b565b60048111156130ca576130ca61566f565b146130e857604051638d54989d60e01b815260040160405180910390fd5b60408051808201909152806130fe8460016145e1565b815260200161310e846021614617565b6001600160801b0316905292915050565b604080518082019091525f808252602082015260026130b0565b60408051602081019091525f815260035b6131538361307b565b60048111156131645761316461566f565b1461318257604051638d54989d60e01b815260040160405180910390fd5b6040805160208101909152806131998460016145e1565b905292915050565b60606004825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b6040516020818303038152906040529050919050565b60408051602081019091525f8152600461314a565b60606005825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b5f60015c6001600160a01b03161580159061324757506001546001600160a01b031633145b61325057503390565b5060015c6001600160a01b031690565b5f80808360018111156132755761327561566f565b146132c4576001600160401b0389165f9081526008602090815260408083206001600160801b03198c16845282528083206001600160801b03881684528252808320888452909152902061330a565b6001600160401b0389165f9081526009602090815260408083206001600160801b03198c16845282528083206001600160801b0388168452825280832088845290915290205b90505f808460018111156133205761332061566f565b1461336f576001600160401b038a165f908152600a602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290206133b5565b6001600160401b038a165f908152600b602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290205b90506133c88a8a8a8a8a8a88888c61464d565b156133d7575f92505050613526565b866133e257876133e4565b5f5b9250866134065781546134019089906001600160801b03166157e0565b61341c565b815461341c9089906001600160801b031661591d565b82546001600160801b0319166001600160801b03919091161782555f84600181111561344a5761344a61566f565b1461345f5761345a8a8a876110ac565b61346a565b61346a8a8a87611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f84600181111561349d5761349d61566f565b036134e55760408051808201909152815460ff81161515825261010090046001600160801b031660208201526134e0908b908b908b908b908b908b908990614995565b613523565b60408051808201909152815460ff81161515825261010090046001600160801b03166020820152613523908b908b908b908b908b908b908990614aaa565b50505b979650505050505050565b5f60015c6001600160a01b031661354757503490565b505f90565b5f5c6001600160a01b031661364057335f805c6001600160a01b0319168217905d50805f5b81811015613629575f803086868581811061358e5761358e6159bd565b90506020028101906135a091906159d1565b6040516135ae929190615a1a565b5f60405180830381855af49150503d805f81146135e6576040519150601f19603f3d011682016040523d82523d5f602084013e6135eb565b606091505b50915091508161361f5780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b8082602001fd5b5050600101613571565b505f90506001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461366a57604051630101292160e31b815260040160405180910390fd5b805f5b8181101561371e575f803086868581811061368a5761368a6159bd565b905060200281019061369c91906159d1565b6040516136aa929190615a1a565b5f60405180830381855af49150503d805f81146136e2576040519150601f19603f3d011682016040523d82523d5f602084013e6136e7565b606091505b5091509150816137145780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b505060010161366d565b50505050565b5f610b2e858585855f614b99565b80516020808301516040516060936131cc93600193919201615a29565b6001600160801b0316151590565b5f613526878787878787614c06565b5f6001600160401b038211156137955760405163397df9e960e21b815260040160405180910390fd5b5090565b5f6111058383614c7b565b80516020808301516040516060936131cc93600293919201615a29565b6001600160401b0385165f9081526003602090815260408083206001600160801b03198816845282528083206001600160801b0387168452909152812054819063ffffffff600160401b90910481169085161115613832576040516386d1007760e01b815260040160405180910390fd5b61383d878787611437565b63ffffffff168463ffffffff161484613857898989611437565b909161387857604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526005602090815260408083206001600160801b03198a16845282528083206001600160801b03898116855290835281842063ffffffff808a1686529352908320600181018054888416600160801b81029185169190911790915581549194936138f9939192909116908490614ca416565b6001830154909150613913906001600160801b031661374f565b61391d575f613a64565b8154604051600162fe590960e01b03198152613a64916001600160801b0316906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ff01a6f79061397c908e906004016157cc565b602060405180830381865afa158015613997573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bb91906157ac565b604051630274be6d60e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309d2f9b490613a07908d906004016152c9565b602060405180830381865afa158015613a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a4691906157ac565b60018601546001600160801b03600160801b8204811691165f61375d565b82546002840180546001600160801b0319166001600160801b0384811691909117909155919550169250613a974261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b039384160217905589165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038d81168087529190945291909320805463ffffffff60601b1916600160601b63ffffffff8d160217905560018601549093917f14f07afe7ac79d02cc585b7f76d4d9687e82b16083b19e225a2fde74b32bf36e918b918b91613b4e911661374f565b613b58575f613b79565b6001880154613b79906001600160801b03600160801b820481169116613799565b88546040805163ffffffff9590951685526001600160801b03938416602086015291831684830152821660608401528a8216608084015290871660a0830152519081900360c00190a450509550959350505050565b60606003825f0151836020015184604001516040516020016131cc9493929190615a5a565b6001600160401b0384165f9081526009602090815260408083206001600160801b03198716845282528083206001600160801b03858116855290835281842086855290925282208054839283928392909116613c625760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160201b90910463ffffffff908116600160801b909204161115613cda57604051638691a7e760e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526004865284872093875292855283862091865290845282852063ffffffff600160801b97889004811680885291909552929094208054600160201b9092049093169091109550909290041615613dae5780546001808301548454613da993613da4936001600160801b0392831693600160801b90920483169290911690614cca565b614d19565b613db0565b5f5b94506001600160801b03851615613faf578054600182015483545f92613df192613da4926001600160801b0390811692600160801b90048116911685614cca565b90506001600160801b03811615613f6d576002820154613e19906001600160801b031661374f565b613e23575f613f6a565b613f6a816001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b8152600401613e7c91906152c9565b602060405180830381865afa158015613e97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ebb91906157ac565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78f6040518263ffffffff1660e01b8152600401613f0791906157cc565b602060405180830381865afa158015613f22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4691906157ac565b600186015460028701546001600160801b03600160801b909204821691165f61375d565b96505b8254869084905f90613f899084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167f49c87cda7a22a30abb60733a70e9787c6607d32928c46528890206fdc06fabce8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b031660405161404396959493929190615a93565b60405180910390a481546001600160801b03165f0361408f576140678a8a89611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f92506140d0565b815460019083906010906140b1908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6140db8a8a89611e75565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a865f614d42565b93505b5050945094509450949050565b6001600160401b0384165f9081526008602090815260408083206001600160801b03198716845282528083206001600160801b038581168552908352818420868552909252822080548392839283929091166141825760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160601b90910463ffffffff908116600160801b9092041611156141fa57604051639aac3e0b60e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526005865284872093875292855283862091865290845282852063ffffffff600160801b90970487168087529452919093208054600160601b909404909416909110945016156142bc57805482546142b791613da4916001600160801b039081169181811691600160801b909104166001614cca565b6142be565b5f5b94506001600160801b0385161561445657805482545f916142fb91613da4916001600160801b039182169180821691600160801b90041685614cca565b90506001600160801b03811615614414576001820154614323906001600160801b031661374f565b61432d575f614411565b614411816001600160801b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161438691906157cc565b602060405180830381865afa1580156143a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143c591906157ac565b604051630274be6d60e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906309d2f9b490613a07908e906004016152c9565b96505b8254869084905f906144309084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167fbaedde181510aaa5fcaded7a64ddd81c51a9b07b5ed0209b6e3a92801c93959e8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b03166040516144ea96959493929190615a93565b60405180910390a481546001600160801b03165f036145365761450e8a8a896110ac565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f9250614577565b81546001908390601090614558908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6145828a8a896110ac565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a866001614d42565b5f6145b7826001615ad2565b835110156145d857604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6145ed826020615ad2565b8351101561460e57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f614623826010615ad2565b8351101561464457604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f80808360018111156146625761466261566f565b14614677576146728b8b886110ac565b614682565b6146828b8b88611e75565b6040805180820190915286546001600160801b0381168252600160801b900463ffffffff1660208201529091506146b99082614f3e565b156146c7575f915050614988565b835460ff1680156146e057505f896001600160801b0316115b156146fe57604051637643c0f960e01b815260040160405180910390fd5b8761471357835460ff1916600117845561475a565b83548990859060019061473590849061010090046001600160801b031661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f83600181111561476d5761476d61566f565b0361487c575f60075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c595f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161486e96959493929190615ae5565b60405180910390a450614982565b5f60065f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c795f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161497896959493929190615ae5565b60405180910390a4505b60019150505b9998505050505050505050565b6001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614a0857806001600160801b0316876001600160801b031611614a02576149fd87826157e0565b614a12565b5f614a12565b614a12878261591d565b6001600160401b038a165f8181526007602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c595f395f51905f52614a848d8d8a611e75565b8754602088015188516040516127db94938e936001600160801b03909116928b92615ae5565b6001600160401b0388165f9081526006602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614b1d57806001600160801b0316876001600160801b031611614b1757614b1287826157e0565b614b27565b5f614b27565b614b27878261591d565b6001600160401b038a165f8181526006602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c795f395f51905f52614a848d8d8a6110ac565b5f8360ff168560ff1603614bc557614bbe613da46001600160801b0385168885614f79565b9050610b2e565b6111ca613da46001600160801b038516614be087600a615c06565b614bea908a615c14565b614bf560128a615c2b565b614c0090600a615c06565b86614cca565b5f614c19836001600160801b031661374f565b614c36576040516323d359a360e01b815260040160405180910390fd5b613526613da46001600160801b03861689614c5289600a615c06565b614c5c9190615c14565b6001600160801b038716614c718b600a615c06565b614c009190615c14565b5f611105613da4846001600160801b0316670de0b6b3a7640000856001600160801b0316614f97565b5f611102613da4856001600160801b0316856001600160801b0316670de0b6b3a7640000865b5f5f614cd7868686614f97565b90506001836002811115614ced57614ced61566f565b148015614d0957505f8480614d0457614d04615c44565b868809115b15610b2e576111ca600182615ad2565b5f6001600160801b038211156137955760405163e999826d60e01b815260040160405180910390fd5b5f8080836001811115614d5757614d5761566f565b14614da6576001600160401b0388165f908152600a602090815260408083206001600160801b03198b16845282528083206001600160801b038916845282528083208984529091529020614dec565b6001600160401b0388165f908152600b602090815260408083206001600160801b03198b16845282528083206001600160801b0389168452825280832089845290915290205b80549091505f9060ff16614e0f57815461010090046001600160801b0316614e1b565b84546001600160801b03165b825490915060ff1615614e5c5781548554614e47916001600160801b036101009091048116911661591d565b85546001600160801b03191686559250614ea6565b815485546001600160801b0361010090920482169187915f91614e819185911661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f846001811115614eb957614eb961566f565b03614ef4578154604080518082019091525f8082526020820152614eef918b918b91859160ff90911615908c908c908c90614995565b614f25565b8154604080518082019091525f8082526020820152614f25918b918b91859160ff90911615908c908c908c90614aaa565b5080546001600160881b03191690559695505050505050565b5f60018263ffffffff16111580614f5d575082516001600160801b0316155b8061110557505060209091015163ffffffff9182169116101590565b5f611102846001600160801b031684670de0b6b3a764000085614cca565b5f80805f19858709858702925082811083820303915050805f03614fce57838281614fc457614fc4615c44565b0492505050611105565b808411614fee57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f60208284031215615065575f5ffd5b81356001600160e01b031981168114611105575f5ffd5b80356001600160401b0381168114615092575f5ffd5b919050565b80356001600160801b031981168114615092575f5ffd5b6001600160801b03811681146150c2575f5ffd5b50565b5f5f5f5f608085870312156150d8575f5ffd5b6150e18561507c565b93506150ef60208601615097565b9250604085013591506060850135615106816150ae565b939692955090935050565b803563ffffffff81168114615092575f5ffd5b5f5f5f5f60808587031215615137575f5ffd5b6151408561507c565b935061514e60208601615097565b9250604085013561515e816150ae565b915061516c60608601615111565b905092959194509250565b5f5f5f5f5f6080868803121561518b575f5ffd5b6151948661507c565b94506151a260208701615097565b935060408601356151b2816150ae565b925060608601356001600160401b038111156151cc575f5ffd5b8601601f810188136151dc575f5ffd5b80356001600160401b038111156151f1575f5ffd5b886020828401011115615202575f5ffd5b959894975092955050506020019190565b80356001600160a01b0381168114615092575f5ffd5b5f5f5f5f5f60a0868803121561523d575f5ffd5b6152468661507c565b945061525460208701615097565b935060408601359250606086013561526b816150ae565b915061527960808701615213565b90509295509295909350565b5f5f5f60608486031215615297575f5ffd5b6152a08461507c565b92506152ae60208501615097565b915060408401356152be816150ae565b809150509250925092565b6001600160801b0391909116815260200190565b5f602082840312156152ed575f5ffd5b61110582615213565b5f5f5f5f60808587031215615309575f5ffd5b6153128561507c565b935061532060208601615097565b92506040850135615330816150ae565b9396929550929360600135925050565b5f5f5f5f84860360e0811215615354575f5ffd5b61535d8661507c565b945061536b60208701615097565b9350604086013561537b816150ae565b92506080605f198201121561538e575f5ffd5b50604051608081016001600160401b03811182821017156153bd57634e487b7160e01b5f52604160045260245ffd5b6040526153cc60608701615111565b81526153da60808701615111565b60208201526153eb60a08701615111565b60408201526153fc60c08701615111565b6060820152939692955090935050565b5f5f5f5f5f60a08688031215615420575f5ffd5b6154298661507c565b945061543760208701615097565b93506040860135615447816150ae565b925060608601359150608086013561545e816150ae565b809150509295509295909350565b5f5f6020838503121561547d575f5ffd5b82356001600160401b03811115615492575f5ffd5b8301601f810185136154a2575f5ffd5b80356001600160401b038111156154b7575f5ffd5b8560208260051b84010111156154cb575f5ffd5b6020919091019590945092505050565b5f5f5f5f5f5f5f60e0888a0312156154f1575f5ffd5b6154fa8861507c565b965061550860208901615097565b95506040880135615518816150ae565b945061552660608901615111565b93506080880135615536816150ae565b925060a0880135615546816150ae565b915061555460c08901615213565b905092959891949750929550565b5f5f5f5f5f5f60c08789031215615577575f5ffd5b6155808761507c565b955061558e60208801615097565b9450604087013561559e816150ae565b93506155ac60608801615111565b925060808701356155bc816150ae565b915060a08701356155cc816150ae565b809150509295509295509295565b5f5f604083850312156155eb575f5ffd5b823591506155fb60208401615213565b90509250929050565b5f5f5f5f5f5f60c08789031215615619575f5ffd5b6156228761507c565b955061563060208801615097565b94506040870135615640816150ae565b93506060870135925061565560808801615111565b915061566360a08801615213565b90509295509295509295565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03881681526001600160801b0319871660208201526001600160801b038616604082015260e0606082018190525f906156f390830187615683565b6001600160801b039590951660808301525091151560a08301526001600160a01b031660c090910152949350505050565b6001600160401b039290921682526001600160a01b0316602082015260400190565b5f60208284031215615756575f5ffd5b81518015158114611105575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b63ffffffff8181168382160190811115610a8d57610a8d615765565b63ffffffff92831681529116602082015260400190565b5f602082840312156157bc575f5ffd5b815160ff81168114611105575f5ffd5b6001600160401b0391909116815260200190565b6001600160801b038281168282160390811115610a8d57610a8d615765565b63ffffffff9490941684526001600160801b039283166020850152908216604084015216606082015260800190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602080825281018290525f6040600584901b830181019083018583601e1936839003015b878210156158e757868503603f190184528235818112615898575f5ffd5b89016020810190356001600160401b038111156158b3575f5ffd5b8036038213156158c1575f5ffd5b6158cc87828461582e565b9650505060208301925060208401935060018201915061587a565b5092979650505050505050565b604081525f6159066040830185615683565b905060018060a01b03831660208301529392505050565b6001600160801b038181168382160190811115610a8d57610a8d615765565b63ffffffff8281168282160390811115610a8d57610a8d615765565b6006811061597457634e487b7160e01b5f52602160045260245ffd5b60f81b9052565b6159858187615958565b60018101949094526001600160801b0319608093841b8116602186015291831b8216603185015290911b166041820152605101919050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e198436030181126159e6575f5ffd5b8301803591506001600160401b038211156159ff575f5ffd5b602001915036819003821315615a13575f5ffd5b9250929050565b818382375f9101908152919050565b615a338185615958565b6001600160801b0319608093841b811660018301529190921b166011820152602101919050565b615a648186615958565b6001600160801b0319608094851b8116600183015292841b83166011820152921b166021820152603101919050565b9586526001600160801b0394851660208701529284166040860152908316606085015290911660808301526001600160401b031660a082015260c00190565b80820180821115610a8d57610a8d615765565b63ffffffff96909616865260208601949094526001600160801b0392831660408601529082166060850152166080830152151560a082015260c00190565b6001815b6001841115615b5e57808504811115615b4257615b42615765565b6001841615615b5057908102905b60019390931c928002615b27565b935093915050565b5f82615b7457506001610a8d565b81615b8057505f610a8d565b8160018114615b965760028114615ba057615bbc565b6001915050610a8d565b60ff841115615bb157615bb1615765565b50506001821b610a8d565b5060208310610133831016604e8410600b8410161715615bdf575081810a610a8d565b615beb5f198484615b23565b805f1904821115615bfe57615bfe615765565b029392505050565b5f61110560ff841683615b66565b8082028115828204841417610a8d57610a8d615765565b60ff8181168382160190811115610a8d57610a8d615765565b634e487b7160e01b5f52601260045260245ffdfe1f5a5e518a04d4ae04df91bdcdfc726fd04628d7968eb87c8a177f55336765ff688670c8bdbd011a5a7703624480229795dd54b1ead47cb9a66061fa8b2e0b7a00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9300000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5
Deployed Bytecode
0x6080604052600436106101d5575f3560e01c806301ffc9a7146101d95780630a6670631461020d578063116191b61461024157806328537d06146102785780632f6c33bf14610344578063365a86fc146103655780633f92bf831461038457806342e413391461039757806346bfcc8f146103b65780635eb4d168146103e257806365fae35e1461046357806366e960e31461048257806371c4482614610503578063730316d114610522578063790b56ce146105415780637fe50ab2146105605780638a93ba581461057f5780638baa4083146105925780639b884cd5146105b15780639c52a7f1146105d05780639d26e184146105ef5780639e5d3a7a14610637578063ac9650d81461064a578063ae7275201461065d578063b5eaa51d1461067c578063bcf16c93146106c4578063be3bad4a14610721578063bf353dbb14610734578063c076a59f1461076d578063c3f4d5ed146107fe578063c592045514610811578063c88854a314610856578063d0d4133114610889578063d4e8be831461089c578063da8336ba146108bb578063e0aeab1e146108ce578063e3b304d4146108e1578063e47091c914610926578063ee1cb43d1461099d578063fc689b78146109b0578063fdfa8fe0146109cf575b5f5ffd5b3480156101e4575f5ffd5b506101f86101f3366004615055565b610a27565b60405190151581526020015b60405180910390f35b348015610218575f5ffd5b5061022c6102273660046150c5565b610a93565b60405163ffffffff9091168152602001610204565b34801561024c575f5ffd5b50600154610260906001600160a01b031681565b6040516001600160a01b039091168152602001610204565b348015610283575f5ffd5b506102f9610292366004615124565b600460209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b604080516001600160801b039788168152958716602087015293861693850193909352908416606084015290921660808201526001600160401b0390911660a082015260c001610204565b34801561034f575f5ffd5b5061036361035e366004615177565b610b37565b005b348015610370575f5ffd5b50600254610260906001600160a01b031681565b610363610392366004615229565b610e77565b3480156103a2575f5ffd5b5061022c6103b1366004615285565b6110ac565b3480156103c1575f5ffd5b506103d56103d03660046150c5565b61110c565b60405161020491906152c9565b3480156103ed575f5ffd5b506102f96103fc366004615124565b600560209081525f94855260408086208252938552838520815291845282842090915282529020805460018201546002909201546001600160801b0380831693600160801b938490048216938282169391819004831692821691046001600160401b031686565b34801561046e575f5ffd5b5061036361047d3660046152dd565b6111d4565b34801561048d575f5ffd5b506104df61049c3660046152f6565b600860209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b604080516001600160801b03909316835263ffffffff909116602083015201610204565b34801561050e575f5ffd5b5061022c61051d366004615285565b611247565b34801561052d575f5ffd5b5061036361053c366004615340565b61129d565b34801561054c575f5ffd5b5061036361055b36600461540c565b6113f8565b34801561056b575f5ffd5b5061022c61057a366004615285565b611437565b61036361058d36600461546c565b61148d565b34801561059d575f5ffd5b506103636105ac36600461540c565b6115c9565b3480156105bc575f5ffd5b506103d56105cb3660046150c5565b611609565b3480156105db575f5ffd5b506103636105ea3660046152dd565b6116c9565b3480156105fa575f5ffd5b506101f86106093660046152f6565b600c60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b6103636106453660046154db565b61173b565b61036361065836600461546c565b611d78565b348015610668575f5ffd5b5061022c610677366004615285565b611e75565b348015610687575f5ffd5b506101f86106963660046152f6565b600d60209081525f948552604080862082529385528385208152918452828420909152825290205460ff1681565b3480156106cf575f5ffd5b506104df6106de3660046152f6565b600960209081525f94855260408086208252938552838520815291845282842090915282529020546001600160801b03811690600160801b900463ffffffff1682565b61036361072f3660046154db565b611ec4565b34801561073f575f5ffd5b5061075f61074e3660046152dd565b5f6020819052908152604090205481565b604051908152602001610204565b348015610778575f5ffd5b506107ce610787366004615285565b600360209081525f938452604080852082529284528284209052825290205463ffffffff80821691600160201b8104821691600160401b8204811691600160601b90041684565b6040805163ffffffff95861681529385166020850152918416918301919091529091166060820152608001610204565b61036361080c3660046154db565b6123ba565b34801561081c575f5ffd5b506103d561082b366004615285565b600760209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610861575f5ffd5b506102607f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9381565b610363610897366004615562565b6124cc565b3480156108a7575f5ffd5b506103636108b63660046155da565b6127ee565b6103636108c9366004615604565b6128a8565b6103636108dc366004615604565b612b93565b3480156108ec575f5ffd5b506103d56108fb366004615285565b600660209081525f93845260408085208252928452828420905282529020546001600160801b031681565b348015610931575f5ffd5b5061097e6109403660046152f6565b600a60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b6040805192151583526001600160801b03909116602083015201610204565b6103636109ab366004615229565b612de1565b3480156109bb575f5ffd5b5061022c6109ca3660046150c5565b612f96565b3480156109da575f5ffd5b5061097e6109e93660046152f6565b600b60209081525f948552604080862082529385528385208152918452828420909152825290205460ff81169061010090046001600160801b031682565b5f6001600160e01b0319821663af00afbd60e01b1480610a5757506001600160e01b03198216632f6c33bf60e01b145b80610a7257506001600160e01b03198216630e8b676960e21b145b80610a8d57506001600160e01b031982166301ffc9a760e01b145b92915050565b6001600160401b0384165f8181526008602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160601b90041661302d565b95945050505050565b335f90815260208190526040902054600114610b665760405163ea8e4eb560e01b815260040160405180910390fd5b5f610ba583838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061307b92505050565b6004811115610bb657610bb661566f565b90505f1960ff821601610c1e575f610c0284848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061309a92505050565b9050610c1887878360200151845f0151896113f8565b50610e6f565b60011960ff821601610c7f575f610c6984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061311f92505050565b9050610c1887878360200151845f0151896115c9565b60021960ff821601610d98575f610cca84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061313992505050565b90505f610cdc8888845f01518961110c565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131a1565b5f60015f6040518863ffffffff1660e01b8152600401610d6397969594939291906156b1565b5f604051808303815f87803b158015610d7a575f5ffd5b505af1158015610d8c573d5f5f3e3d5ffd5b505050505b5050610e6f565b60031960ff821601610e56575f610de384848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506131e292505050565b90505f610df58888845f015189611609565b90506001600160801b03811615610d915760025460408051608081018252845181525f60208201819052918101919091526001600160801b03831660608201526001600160a01b039091169063c3ab3924908a908a908a90610d3d906131f7565b604051638d54989d60e01b815260040160405180910390fd5b505050505050565b847f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82610eb0613222565b6040518363ffffffff1660e01b8152600401610ecd929190615724565b602060405180830381865afa158015610ee8573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0c9190615746565b610f295760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600d602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16610f8f57604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526008602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690610fe9888884848a8a6001613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131f7565b6002549091506001600160a01b031663c3ab3924611049613531565b8b8b8a865f5f8d6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b5f604051808303818588803b158015611089575f5ffd5b505af115801561109b573d5f5f3e3d5ffd5b5050505050505b5050505050505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160401b900463ffffffff166001615779565b90505b9392505050565b335f9081526020819052604081205460011461113b5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600c602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff19166001179055958552600984528285209185529083528184209084528252808320878452909152812054909116906111ca90879087908490888882613260565b9695505050505050565b335f908152602081905260409020546001146112035760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160201b900463ffffffff166001615779565b335f908152602081905260409020546001146112cc5760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0384165f8181526003602090815260408083206001600160801b031988168085529083528184206001600160801b0388168086529084529382902086518154948801518489015160608a015163ffffffff908116600160601b0263ffffffff60601b19928216600160401b0292909216600160401b600160801b0319938216600160201b026001600160401b031990991691909416179690961716179390931790925551919290917f0f7c52086fe372e36e65c8c21cbcc8254ac152ce8c02cd914c162f62ed80237b906113ea9086905f60808201905063ffffffff835116825263ffffffff602084015116602083015263ffffffff604084015116604083015263ffffffff606084015116606083015292915050565b60405180910390a450505050565b335f908152602081905260409020546001146114275760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186865f613260565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b038516845290915281205461110290600160601b900463ffffffff166001615779565b5f5c6001600160a01b031661152f57335f805c6001600160a01b0319168217905d5060015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156114fb575f5ffd5b505af115801561150d573d5f5f3e3d5ffd5b5050505061151b828261354c565b5f6001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461155957604051630101292160e31b815260040160405180910390fd5b60015f9054906101000a90046001600160a01b03166001600160a01b031663d988dd406040518163ffffffff1660e01b81526004015f604051808303815f87803b1580156115a5575f5ffd5b505af11580156115b7573d5f5f3e3d5ffd5b505050506115c5828261354c565b5050565b335f908152602081905260409020546001146115f85760405163ea8e4eb560e01b815260040160405180910390fd5b610e6f858585600186866001613260565b335f908152602081905260408120546001146116385760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0385165f818152600d602090815260408083206001600160801b031989168085529083528184206001600160801b038881168087529185528386208a87528552838620805460ff1916600190811790915596865260088552838620928652918452828520908552835281842088855290925282205416916111ca9188918891859189908990613260565b335f908152602081905260409020546001146116f85760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82611774613222565b6040518363ffffffff1660e01b8152600401611791929190615724565b602060405180830381865afa1580156117ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d09190615746565b6117ed5760405163ea8e4eb560e01b815260040160405180910390fd5b6117f8888888611e75565b63ffffffff168563ffffffff1614856118128a8a8a611e75565b909161183c57604051632c647e3760e21b8152600401611833929190615795565b60405180910390fd5b50506001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b038a8116855292529091205481169085168110156118a25760405163776a3aa960e11b815260040160405180910390fd5b5f856001600160801b0316116118cb5760405163035a9e4760e11b815260040160405180910390fd5b5f6119f5866001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b815260040161192591906152c9565b602060405180830381865afa158015611940573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196491906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b81526004016119b091906157cc565b602060405180830381865afa1580156119cb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ef91906157ac565b88613724565b90505f60045f8c6001600160401b03166001600160401b031681526020019081526020015f205f8b6001600160801b0319166001600160801b03191681526020019081526020015f205f8a6001600160801b03166001600160801b031681526020019081526020015f205f8963ffffffff1663ffffffff1681526020019081526020015f20905086815f0160106101000a8154816001600160801b0302191690836001600160801b0316021790555081815f015f6101000a8154816001600160801b0302191690836001600160801b0316021790555082816001015f6101000a8154816001600160801b0302191690836001600160801b03160217905550858160010160106101000a8154816001600160801b0302191690836001600160801b031602179055508660075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f8282829054906101000a90046001600160801b0316611ba491906157e0565b92506101000a8154816001600160801b0302191690836001600160801b031602179055508683611bd491906157e0565b92508760035f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f8b6001600160801b03166001600160801b031681526020019081526020015f205f015f6101000a81548163ffffffff021916908363ffffffff160217905550886001600160801b03168a6001600160801b0319168c6001600160401b03167f1785217365be01fea67dbce22680b382886fe6a3a22156830b3cda5823a42a8e8b868c89604051611cb194939291906157ff565b60405180910390a45f611cf760405180604001604052808a6001600160801b03168152602001611ce78a6001600160801b031690565b6001600160801b03169052613732565b6002549091506001600160a01b031663c3ab3924611d13613531565b8e8e8e865f5f8e6040518963ffffffff1660e01b8152600401611d3c97969594939291906156b1565b5f604051808303818588803b158015611d53575f5ffd5b505af1158015611d65573d5f5f3e3d5ffd5b5050505050505050505050505050505050565b60015c6001600160a01b031615611da257604051631ccdbfa560e21b815260040160405180910390fd5b336001805c6001600160a01b0319168217905d506001546040516001600160a01b03909116906329d43364903490631152774b60e31b90611de99087908790602401615856565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b9092168252611e309133906004016158f4565b5f604051808303818588803b158015611e47575f5ffd5b505af1158015611e59573d5f5f3e3d5ffd5b505f935050506001805c6001600160a01b03191691505d505050565b6001600160401b0383165f9081526003602090815260408083206001600160801b03198616845282528083206001600160801b03851684529091528120546111029063ffffffff166001615779565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82611efd613222565b6040518363ffffffff1660e01b8152600401611f1a929190615724565b602060405180830381865afa158015611f35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f599190615746565b611f765760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0388165f9081526003602090815260408083206001600160801b03198b16845282528083206001600160801b038a16845290915290205463ffffffff9081169086161115611fde576040516386d1007760e01b815260040160405180910390fd5b611fe9888888611247565b63ffffffff168563ffffffff1614856120038a8a8a611247565b909161202457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0388165f9081526004602090815260408083206001600160801b0319808c1685529083528184206001600160801b038b8116865290845282852063ffffffff8b16865290935290832060028101805493891693909216831790915591906120939061374f565b61209d575f6121e6565b8154604051630274be6d60e21b81526121e691600160801b90046001600160801b0316907f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316906309d2f9b490612100908d906004016152c9565b602060405180830381865afa15801561211b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213f91906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161218b91906157cc565b602060405180830381865afa1580156121a6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ca91906157ac565b6001860154600160801b90046001600160801b03168a5f61375d565b90506121f14261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b03938416810291909117909155908b165f8181526003602090815260408083206001600160801b03198f168085529083528184206001600160801b038f81168087529190945291909320805463ffffffff60201b1916600160201b63ffffffff8f1602179055600187015490949293927f75d54fc68ce51f85af6cc4bc67a5d7d3267296e63539b2d428743a1a8a8380de928d928d926122b29291041661374f565b6122bc575f6122e3565b600288015460018901546122e3916001600160801b0390811691600160801b900416613799565b876040516122f494939291906157ff565b60405180910390a45f61233a6040518060400160405280846001600160801b0316815260200161232a8a6001600160801b031690565b6001600160801b031690526137a4565b6002549091506001600160a01b031663c3ab3924612356613531565b8d8d8d868c5f8d6040518963ffffffff1660e01b815260040161237f97969594939291906156b1565b5f604051808303818588803b158015612396575f5ffd5b505af11580156123a8573d5f5f3e3d5ffd5b50505050505050505050505050505050565b867f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b826123f3613222565b6040518363ffffffff1660e01b8152600401612410929190615724565b602060405180830381865afa15801561242b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061244f9190615746565b61246c5760405163ea8e4eb560e01b815260040160405180910390fd5b5f5f61247b8a8a8a8a8a6137c1565b915091505f61233a6040518060600160405280856001600160801b03168152602001846001600160801b031681526020016124bc8a6001600160801b031690565b6001600160801b03169052613bce565b857f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82612505613222565b6040518363ffffffff1660e01b8152600401612522929190615724565b602060405180830381865afa15801561253d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125619190615746565b61257e5760405163ea8e4eb560e01b815260040160405180910390fd5b6125898787876110ac565b63ffffffff168463ffffffff1614846125a38989896110ac565b90916125c457604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526006602090815260408083206001600160801b03198a16845282528083206001600160801b038981168552925290912054811690841681101561262a5760405163776a3aa960e11b815260040160405180910390fd5b5f846001600160801b0316116126535760405163035a9e4760e11b815260040160405180910390fd5b6001600160401b0388165f8181526005602090815260408083206001600160801b03198c81168086529184528285206001600160801b038d811680885291865284872063ffffffff8e16885286528487208c8216600160801b8b8416021781556001810180549094168c831617909355968652600685528386209286529184528285209185529252822080549193889391926126f1918591166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550848261272191906157e0565b6001600160401b038a165f8181526003602090815260408083206001600160801b03198e168085529083528184206001600160801b038e16808652935292819020805463ffffffff8d16600160401b0263ffffffff60401b1990911617905551939550929091907f679cd78fb2cbc9b1fa61043bb803ac3d5a5a8e0dd7aaa5a94e8bc5721dd2b8aa906127db908b908b90899063ffffffff9390931683526001600160801b03918216602084015216604082015260600190565b60405180910390a4505050505050505050565b335f9081526020819052604090205460011461281d5760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b0361284a57600280546001600160a01b0319166001600160a01b038316179055612863565b604051633db0d5b960e01b815260040160405180910390fd5b604080518381526001600160a01b03831660208201527f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba910160405180910390a15050565b5f5c6001600160a01b0316612a3857335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612946575f5f5f5f6128f38e8e8d8f613bf3565b93509350935093508388612907919061591d565b9750612913838861591d565b96506001600160801b03821615612928578195505b806129365750505050612946565b5050600190920191506128cf9050565b505f826001600160801b0316118061296657505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612984613531565b8b8b8b6129cb60405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b81526004016129f097969594939291906156b1565b5f604051808303818588803b158015612a07575f5ffd5b505af1158015612a19573d5f5f3e3d5ffd5b50505050505b505f9150506001600160a01b0319815c16815d50610e6f565b336001600160a01b035f5c1614612a6257604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612ade575f5f5f5f612a8b8e8e8d8f613bf3565b93509350935093508388612a9f919061591d565b9750612aab838861591d565b96506001600160801b03821615612ac0578195505b80612ace5750505050612ade565b505060019092019150612a679050565b505f826001600160801b03161180612afe57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612b1c613531565b8b8b8b612b6360405180608001604052808e81526020018a6001600160801b031681526020018b6001600160801b03168152602001896001600160801b03168152506131a1565b5f5f8c6040518963ffffffff1660e01b815260040161107297969594939291906156b1565b505050505050505050565b5f5c6001600160a01b0316612cb657335f805c6001600160a01b0319168217905d505f8080805b8563ffffffff168163ffffffff161015612c31575f5f5f5f612bde8e8e8d8f614113565b93509350935093508388612bf2919061591d565b9750612bfe838861591d565b96506001600160801b03821615612c13578195505b80612c215750505050612c31565b505060019092019150612bba9050565b505f826001600160801b03161180612c5157505f816001600160801b0316115b15612a1f576002546001600160a01b031663c3ab3924612c6f613531565b8b8b8b6129cb60405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b336001600160a01b035f5c1614612ce057604051630101292160e31b815260040160405180910390fd5b5f8080805b8563ffffffff168163ffffffff161015612d5c575f5f5f5f612d098e8e8d8f614113565b93509350935093508388612d1d919061591d565b9750612d29838861591d565b96506001600160801b03821615612d3e578195505b80612d4c5750505050612d5c565b505060019092019150612ce59050565b505f826001600160801b03161180612d7c57505f816001600160801b0316115b15612b88576002546001600160a01b031663c3ab3924612d9a613531565b8b8b8b612b6360405180608001604052808e81526020018b6001600160801b031681526020018a6001600160801b03168152602001896001600160801b03168152506131f7565b847f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b0316633625342b82612e1a613222565b6040518363ffffffff1660e01b8152600401612e37929190615724565b602060405180830381865afa158015612e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e769190615746565b612e935760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160401b0386165f908152600c602090815260408083206001600160801b03198916845282528083206001600160801b0387168452825280832087845290915290205460ff16612ef957604051635fb581dd60e01b815260040160405180910390fd5b6001600160401b0386165f9081526009602090815260408083206001600160801b03198916845282528083206001600160801b0387811685529083528184208885529092528220541690612f52888884848a8a82613260565b90506001600160801b038116156110a257604080516080810182528781525f602082018190529181018290526001600160801b038316606082015261102d906131a1565b6001600160401b0384165f8181526009602090815260408083206001600160801b031988168085529083528184206001600160801b0387811680875291855283862089875285528386208451808601865290549182168152600160801b90910463ffffffff90811682870152968652600385528386209286529184528285209085529092528220549192610b2e92600160201b9004165b81515f906001600160801b0316158061305557508163ffffffff16836020015163ffffffff16115b1561306157505f610a8d565b6020830151613070908361593c565b611105906001615779565b5f61308682826145ab565b60ff166004811115610a8d57610a8d61566f565b604080518082019091525f808252602082015260015b6130b98361307b565b60048111156130ca576130ca61566f565b146130e857604051638d54989d60e01b815260040160405180910390fd5b60408051808201909152806130fe8460016145e1565b815260200161310e846021614617565b6001600160801b0316905292915050565b604080518082019091525f808252602082015260026130b0565b60408051602081019091525f815260035b6131538361307b565b60048111156131645761316461566f565b1461318257604051638d54989d60e01b815260040160405180910390fd5b6040805160208101909152806131998460016145e1565b905292915050565b60606004825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b6040516020818303038152906040529050919050565b60408051602081019091525f8152600461314a565b60606005825f01518360200151846040015185606001516040516020016131cc95949392919061597b565b5f60015c6001600160a01b03161580159061324757506001546001600160a01b031633145b61325057503390565b5060015c6001600160a01b031690565b5f80808360018111156132755761327561566f565b146132c4576001600160401b0389165f9081526008602090815260408083206001600160801b03198c16845282528083206001600160801b03881684528252808320888452909152902061330a565b6001600160401b0389165f9081526009602090815260408083206001600160801b03198c16845282528083206001600160801b0388168452825280832088845290915290205b90505f808460018111156133205761332061566f565b1461336f576001600160401b038a165f908152600a602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290206133b5565b6001600160401b038a165f908152600b602090815260408083206001600160801b03198d16845282528083206001600160801b0389168452825280832089845290915290205b90506133c88a8a8a8a8a8a88888c61464d565b156133d7575f92505050613526565b866133e257876133e4565b5f5b9250866134065781546134019089906001600160801b03166157e0565b61341c565b815461341c9089906001600160801b031661591d565b82546001600160801b0319166001600160801b03919091161782555f84600181111561344a5761344a61566f565b1461345f5761345a8a8a876110ac565b61346a565b61346a8a8a87611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f84600181111561349d5761349d61566f565b036134e55760408051808201909152815460ff81161515825261010090046001600160801b031660208201526134e0908b908b908b908b908b908b908990614995565b613523565b60408051808201909152815460ff81161515825261010090046001600160801b03166020820152613523908b908b908b908b908b908b908990614aaa565b50505b979650505050505050565b5f60015c6001600160a01b031661354757503490565b505f90565b5f5c6001600160a01b031661364057335f805c6001600160a01b0319168217905d50805f5b81811015613629575f803086868581811061358e5761358e6159bd565b90506020028101906135a091906159d1565b6040516135ae929190615a1a565b5f60405180830381855af49150503d805f81146135e6576040519150601f19603f3d011682016040523d82523d5f602084013e6135eb565b606091505b50915091508161361f5780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b8082602001fd5b5050600101613571565b505f90506001600160a01b0319815c16815d505050565b336001600160a01b035f5c161461366a57604051630101292160e31b815260040160405180910390fd5b805f5b8181101561371e575f803086868581811061368a5761368a6159bd565b905060200281019061369c91906159d1565b6040516136aa929190615a1a565b5f60405180830381855af49150503d805f81146136e2576040519150601f19603f3d011682016040523d82523d5f602084013e6136e7565b606091505b5091509150816137145780515f81900361361857604051632b9e168960e21b815260040160405180910390fd5b505060010161366d565b50505050565b5f610b2e858585855f614b99565b80516020808301516040516060936131cc93600193919201615a29565b6001600160801b0316151590565b5f613526878787878787614c06565b5f6001600160401b038211156137955760405163397df9e960e21b815260040160405180910390fd5b5090565b5f6111058383614c7b565b80516020808301516040516060936131cc93600293919201615a29565b6001600160401b0385165f9081526003602090815260408083206001600160801b03198816845282528083206001600160801b0387168452909152812054819063ffffffff600160401b90910481169085161115613832576040516386d1007760e01b815260040160405180910390fd5b61383d878787611437565b63ffffffff168463ffffffff161484613857898989611437565b909161387857604051632c647e3760e21b8152600401611833929190615795565b50506001600160401b0387165f9081526005602090815260408083206001600160801b03198a16845282528083206001600160801b03898116855290835281842063ffffffff808a1686529352908320600181018054888416600160801b81029185169190911790915581549194936138f9939192909116908490614ca416565b6001830154909150613913906001600160801b031661374f565b61391d575f613a64565b8154604051600162fe590960e01b03198152613a64916001600160801b0316906001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade93169063ff01a6f79061397c908e906004016157cc565b602060405180830381865afa158015613997573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bb91906157ac565b604051630274be6d60e21b81526001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9316906309d2f9b490613a07908d906004016152c9565b602060405180830381865afa158015613a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613a4691906157ac565b60018601546001600160801b03600160801b8204811691165f61375d565b82546002840180546001600160801b0319166001600160801b0384811691909117909155919550169250613a974261376c565b600283018054600160801b600160c01b031916600160801b6001600160401b039384160217905589165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038d81168087529190945291909320805463ffffffff60601b1916600160601b63ffffffff8d160217905560018601549093917f14f07afe7ac79d02cc585b7f76d4d9687e82b16083b19e225a2fde74b32bf36e918b918b91613b4e911661374f565b613b58575f613b79565b6001880154613b79906001600160801b03600160801b820481169116613799565b88546040805163ffffffff9590951685526001600160801b03938416602086015291831684830152821660608401528a8216608084015290871660a0830152519081900360c00190a450509550959350505050565b60606003825f0151836020015184604001516040516020016131cc9493929190615a5a565b6001600160401b0384165f9081526009602090815260408083206001600160801b03198716845282528083206001600160801b03858116855290835281842086855290925282208054839283928392909116613c625760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160201b90910463ffffffff908116600160801b909204161115613cda57604051638691a7e760e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526004865284872093875292855283862091865290845282852063ffffffff600160801b97889004811680885291909552929094208054600160201b9092049093169091109550909290041615613dae5780546001808301548454613da993613da4936001600160801b0392831693600160801b90920483169290911690614cca565b614d19565b613db0565b5f5b94506001600160801b03851615613faf578054600182015483545f92613df192613da4926001600160801b0390811692600160801b90048116911685614cca565b90506001600160801b03811615613f6d576002820154613e19906001600160801b031661374f565b613e23575f613f6a565b613f6a816001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b03166309d2f9b48b6040518263ffffffff1660e01b8152600401613e7c91906152c9565b602060405180830381865afa158015613e97573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ebb91906157ac565b7f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78f6040518263ffffffff1660e01b8152600401613f0791906157cc565b602060405180830381865afa158015613f22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4691906157ac565b600186015460028701546001600160801b03600160801b909204821691165f61375d565b96505b8254869084905f90613f899084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167f49c87cda7a22a30abb60733a70e9787c6607d32928c46528890206fdc06fabce8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b031660405161404396959493929190615a93565b60405180910390a481546001600160801b03165f0361408f576140678a8a89611e75565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f92506140d0565b815460019083906010906140b1908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6140db8a8a89611e75565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a865f614d42565b93505b5050945094509450949050565b6001600160401b0384165f9081526008602090815260408083206001600160801b03198716845282528083206001600160801b038581168552908352818420868552909252822080548392839283929091166141825760405163484a885b60e01b815260040160405180910390fd5b6001600160401b0389165f9081526003602090815260408083206001600160801b03198c16845282528083206001600160801b038a1684529091529020548154600160601b90910463ffffffff908116600160801b9092041611156141fa57604051639aac3e0b60e01b815260040160405180910390fd5b6001600160401b0389165f8181526003602090815260408083206001600160801b03198d168085529083528184206001600160801b038c81168087529185528386205488549787526005865284872093875292855283862091865290845282852063ffffffff600160801b90970487168087529452919093208054600160601b909404909416909110945016156142bc57805482546142b791613da4916001600160801b039081169181811691600160801b909104166001614cca565b6142be565b5f5b94506001600160801b0385161561445657805482545f916142fb91613da4916001600160801b039182169180821691600160801b90041685614cca565b90506001600160801b03811615614414576001820154614323906001600160801b031661374f565b61432d575f614411565b614411816001600160801b03167f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade936001600160a01b031663ff01a6f78e6040518263ffffffff1660e01b815260040161438691906157cc565b602060405180830381865afa1580156143a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143c591906157ac565b604051630274be6d60e21b81526001600160a01b037f00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9316906309d2f9b490613a07908e906004016152c9565b96505b8254869084905f906144309084906001600160801b03166157e0565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b815f0160109054906101000a900463ffffffff1663ffffffff16896001600160801b0319168b6001600160401b03167fbaedde181510aaa5fcaded7a64ddd81c51a9b07b5ed0209b6e3a92801c93959e8b8b8a885f015f9054906101000a90046001600160801b03168d8960020160109054906101000a90046001600160401b03166040516144ea96959493929190615a93565b60405180910390a481546001600160801b03165f036145365761450e8a8a896110ac565b825463ffffffff91909116600160801b0263ffffffff60801b199091161782555f9250614577565b81546001908390601090614558908490600160801b900463ffffffff16615779565b92506101000a81548163ffffffff021916908363ffffffff1602179055505b6145828a8a896110ac565b825463ffffffff918216600160801b90910490911603614106576141038a8a8a8a866001614d42565b5f6145b7826001615ad2565b835110156145d857604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f6145ed826020615ad2565b8351101561460e57604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f614623826010615ad2565b8351101561464457604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f80808360018111156146625761466261566f565b14614677576146728b8b886110ac565b614682565b6146828b8b88611e75565b6040805180820190915286546001600160801b0381168252600160801b900463ffffffff1660208201529091506146b99082614f3e565b156146c7575f915050614988565b835460ff1680156146e057505f896001600160801b0316115b156146fe57604051637643c0f960e01b815260040160405180910390fd5b8761471357835460ff1916600117845561475a565b83548990859060019061473590849061010090046001600160801b031661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f83600181111561476d5761476d61566f565b0361487c575f60075f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c595f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161486e96959493929190615ae5565b60405180910390a450614982565b5f60065f8d6001600160401b03166001600160401b031681526020019081526020015f205f8c6001600160801b0319166001600160801b03191681526020019081526020015f205f886001600160801b03166001600160801b031681526020019081526020015f205f9054906101000a90046001600160801b03169050866001600160801b03168b6001600160801b0319168d6001600160401b03165f516020615c795f395f51905f52858c8b5f015f9054906101000a90046001600160801b0316878c5f0160019054906101000a90046001600160801b03168d5f015f9054906101000a900460ff1660405161497896959493929190615ae5565b60405180910390a4505b60019150505b9998505050505050505050565b6001600160401b0388165f9081526007602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614a0857806001600160801b0316876001600160801b031611614a02576149fd87826157e0565b614a12565b5f614a12565b614a12878261591d565b6001600160401b038a165f8181526007602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c595f395f51905f52614a848d8d8a611e75565b8754602088015188516040516127db94938e936001600160801b03909116928b92615ae5565b6001600160401b0388165f9081526006602090815260408083206001600160801b03198b16845282528083206001600160801b0387811685529252909120541685614b1d57806001600160801b0316876001600160801b031611614b1757614b1287826157e0565b614b27565b5f614b27565b614b27878261591d565b6001600160401b038a165f8181526006602090815260408083206001600160801b03198e81168086529184528285206001600160801b038c8116808852919095529290942080549094169286169290921790925592935091905f516020615c795f395f51905f52614a848d8d8a6110ac565b5f8360ff168560ff1603614bc557614bbe613da46001600160801b0385168885614f79565b9050610b2e565b6111ca613da46001600160801b038516614be087600a615c06565b614bea908a615c14565b614bf560128a615c2b565b614c0090600a615c06565b86614cca565b5f614c19836001600160801b031661374f565b614c36576040516323d359a360e01b815260040160405180910390fd5b613526613da46001600160801b03861689614c5289600a615c06565b614c5c9190615c14565b6001600160801b038716614c718b600a615c06565b614c009190615c14565b5f611105613da4846001600160801b0316670de0b6b3a7640000856001600160801b0316614f97565b5f611102613da4856001600160801b0316856001600160801b0316670de0b6b3a7640000865b5f5f614cd7868686614f97565b90506001836002811115614ced57614ced61566f565b148015614d0957505f8480614d0457614d04615c44565b868809115b15610b2e576111ca600182615ad2565b5f6001600160801b038211156137955760405163e999826d60e01b815260040160405180910390fd5b5f8080836001811115614d5757614d5761566f565b14614da6576001600160401b0388165f908152600a602090815260408083206001600160801b03198b16845282528083206001600160801b038916845282528083208984529091529020614dec565b6001600160401b0388165f908152600b602090815260408083206001600160801b03198b16845282528083206001600160801b0389168452825280832089845290915290205b80549091505f9060ff16614e0f57815461010090046001600160801b0316614e1b565b84546001600160801b03165b825490915060ff1615614e5c5781548554614e47916001600160801b036101009091048116911661591d565b85546001600160801b03191686559250614ea6565b815485546001600160801b0361010090920482169187915f91614e819185911661591d565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5f846001811115614eb957614eb961566f565b03614ef4578154604080518082019091525f8082526020820152614eef918b918b91859160ff90911615908c908c908c90614995565b614f25565b8154604080518082019091525f8082526020820152614f25918b918b91859160ff90911615908c908c908c90614aaa565b5080546001600160881b03191690559695505050505050565b5f60018263ffffffff16111580614f5d575082516001600160801b0316155b8061110557505060209091015163ffffffff9182169116101590565b5f611102846001600160801b031684670de0b6b3a764000085614cca565b5f80805f19858709858702925082811083820303915050805f03614fce57838281614fc457614fc4615c44565b0492505050611105565b808411614fee57604051637ee8242b60e01b815260040160405180910390fd5b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f60208284031215615065575f5ffd5b81356001600160e01b031981168114611105575f5ffd5b80356001600160401b0381168114615092575f5ffd5b919050565b80356001600160801b031981168114615092575f5ffd5b6001600160801b03811681146150c2575f5ffd5b50565b5f5f5f5f608085870312156150d8575f5ffd5b6150e18561507c565b93506150ef60208601615097565b9250604085013591506060850135615106816150ae565b939692955090935050565b803563ffffffff81168114615092575f5ffd5b5f5f5f5f60808587031215615137575f5ffd5b6151408561507c565b935061514e60208601615097565b9250604085013561515e816150ae565b915061516c60608601615111565b905092959194509250565b5f5f5f5f5f6080868803121561518b575f5ffd5b6151948661507c565b94506151a260208701615097565b935060408601356151b2816150ae565b925060608601356001600160401b038111156151cc575f5ffd5b8601601f810188136151dc575f5ffd5b80356001600160401b038111156151f1575f5ffd5b886020828401011115615202575f5ffd5b959894975092955050506020019190565b80356001600160a01b0381168114615092575f5ffd5b5f5f5f5f5f60a0868803121561523d575f5ffd5b6152468661507c565b945061525460208701615097565b935060408601359250606086013561526b816150ae565b915061527960808701615213565b90509295509295909350565b5f5f5f60608486031215615297575f5ffd5b6152a08461507c565b92506152ae60208501615097565b915060408401356152be816150ae565b809150509250925092565b6001600160801b0391909116815260200190565b5f602082840312156152ed575f5ffd5b61110582615213565b5f5f5f5f60808587031215615309575f5ffd5b6153128561507c565b935061532060208601615097565b92506040850135615330816150ae565b9396929550929360600135925050565b5f5f5f5f84860360e0811215615354575f5ffd5b61535d8661507c565b945061536b60208701615097565b9350604086013561537b816150ae565b92506080605f198201121561538e575f5ffd5b50604051608081016001600160401b03811182821017156153bd57634e487b7160e01b5f52604160045260245ffd5b6040526153cc60608701615111565b81526153da60808701615111565b60208201526153eb60a08701615111565b60408201526153fc60c08701615111565b6060820152939692955090935050565b5f5f5f5f5f60a08688031215615420575f5ffd5b6154298661507c565b945061543760208701615097565b93506040860135615447816150ae565b925060608601359150608086013561545e816150ae565b809150509295509295909350565b5f5f6020838503121561547d575f5ffd5b82356001600160401b03811115615492575f5ffd5b8301601f810185136154a2575f5ffd5b80356001600160401b038111156154b7575f5ffd5b8560208260051b84010111156154cb575f5ffd5b6020919091019590945092505050565b5f5f5f5f5f5f5f60e0888a0312156154f1575f5ffd5b6154fa8861507c565b965061550860208901615097565b95506040880135615518816150ae565b945061552660608901615111565b93506080880135615536816150ae565b925060a0880135615546816150ae565b915061555460c08901615213565b905092959891949750929550565b5f5f5f5f5f5f60c08789031215615577575f5ffd5b6155808761507c565b955061558e60208801615097565b9450604087013561559e816150ae565b93506155ac60608801615111565b925060808701356155bc816150ae565b915060a08701356155cc816150ae565b809150509295509295509295565b5f5f604083850312156155eb575f5ffd5b823591506155fb60208401615213565b90509250929050565b5f5f5f5f5f5f60c08789031215615619575f5ffd5b6156228761507c565b955061563060208801615097565b94506040870135615640816150ae565b93506060870135925061565560808801615111565b915061566360a08801615213565b90509295509295509295565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03881681526001600160801b0319871660208201526001600160801b038616604082015260e0606082018190525f906156f390830187615683565b6001600160801b039590951660808301525091151560a08301526001600160a01b031660c090910152949350505050565b6001600160401b039290921682526001600160a01b0316602082015260400190565b5f60208284031215615756575f5ffd5b81518015158114611105575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b63ffffffff8181168382160190811115610a8d57610a8d615765565b63ffffffff92831681529116602082015260400190565b5f602082840312156157bc575f5ffd5b815160ff81168114611105575f5ffd5b6001600160401b0391909116815260200190565b6001600160801b038281168282160390811115610a8d57610a8d615765565b63ffffffff9490941684526001600160801b039283166020850152908216604084015216606082015260800190565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b602080825281018290525f6040600584901b830181019083018583601e1936839003015b878210156158e757868503603f190184528235818112615898575f5ffd5b89016020810190356001600160401b038111156158b3575f5ffd5b8036038213156158c1575f5ffd5b6158cc87828461582e565b9650505060208301925060208401935060018201915061587a565b5092979650505050505050565b604081525f6159066040830185615683565b905060018060a01b03831660208301529392505050565b6001600160801b038181168382160190811115610a8d57610a8d615765565b63ffffffff8281168282160390811115610a8d57610a8d615765565b6006811061597457634e487b7160e01b5f52602160045260245ffd5b60f81b9052565b6159858187615958565b60018101949094526001600160801b0319608093841b8116602186015291831b8216603185015290911b166041820152605101919050565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e198436030181126159e6575f5ffd5b8301803591506001600160401b038211156159ff575f5ffd5b602001915036819003821315615a13575f5ffd5b9250929050565b818382375f9101908152919050565b615a338185615958565b6001600160801b0319608093841b811660018301529190921b166011820152602101919050565b615a648186615958565b6001600160801b0319608094851b8116600183015292841b83166011820152921b166021820152603101919050565b9586526001600160801b0394851660208701529284166040860152908316606085015290911660808301526001600160401b031660a082015260c00190565b80820180821115610a8d57610a8d615765565b63ffffffff96909616865260208601949094526001600160801b0392831660408601529082166060850152166080830152151560a082015260c00190565b6001815b6001841115615b5e57808504811115615b4257615b42615765565b6001841615615b5057908102905b60019390931c928002615b27565b935093915050565b5f82615b7457506001610a8d565b81615b8057505f610a8d565b8160018114615b965760028114615ba057615bbc565b6001915050610a8d565b60ff841115615bb157615bb1615765565b50506001821b610a8d565b5060208310610133831016604e8410600b8410161715615bdf575081810a610a8d565b615beb5f198484615b23565b805f1904821115615bfe57615bfe615765565b029392505050565b5f61110560ff841683615b66565b8082028115828204841417610a8d57610a8d615765565b60ff8181168382160190811115610a8d57610a8d615765565b634e487b7160e01b5f52601260045260245ffdfe1f5a5e518a04d4ae04df91bdcdfc726fd04628d7968eb87c8a177f55336765ff688670c8bdbd011a5a7703624480229795dd54b1ead47cb9a66061fa8b2e0b7a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade9300000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5
-----Decoded View---------------
Arg [0] : hubRegistry_ (address): 0x19f46D8130e610C6C0f0116EA40Fb781dEFaDE93
Arg [1] : gateway_ (address): 0x19a524D03aA94ECEe41a80341537BCFCb47D3172
Arg [2] : deployer (address): 0xB3C086Db30c1BE6e40D8775607C3662ab160bda5
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000019f46d8130e610c6c0f0116ea40fb781defade93
Arg [1] : 00000000000000000000000019a524d03aa94ecee41a80341537bcfcb47d3172
Arg [2] : 000000000000000000000000b3c086db30c1be6e40d8775607c3662ab160bda5
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 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.