Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 32901269 | 194 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MessageProcessor
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 {Auth} from "src/misc/Auth.sol";
import {D18} from "src/misc/types/D18.sol";
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {IRoot} from "src/common/interfaces/IRoot.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {IMessageHandler} from "src/common/interfaces/IMessageHandler.sol";
import {ITokenRecoverer} from "src/common/interfaces/ITokenRecoverer.sol";
import {IMessageProcessor} from "src/common/interfaces/IMessageProcessor.sol";
import {IMessageProperties} from "src/common/interfaces/IMessageProperties.sol";
import {MessageType, MessageLib, VaultUpdateKind} from "src/common/libraries/MessageLib.sol";
import {
ISpokeGatewayHandler,
IBalanceSheetGatewayHandler,
IHubGatewayHandler,
IUpdateContractGatewayHandler
} from "src/common/interfaces/IGatewayHandlers.sol";
contract MessageProcessor is Auth, IMessageProcessor {
using CastLib for *;
using MessageLib for *;
using BytesLib for bytes;
IRoot public immutable root;
ITokenRecoverer public immutable tokenRecoverer;
IHubGatewayHandler public hub;
ISpokeGatewayHandler public spoke;
IBalanceSheetGatewayHandler public balanceSheet;
IUpdateContractGatewayHandler public contractUpdater;
constructor(IRoot root_, ITokenRecoverer tokenRecoverer_, address deployer) Auth(deployer) {
root = root_;
tokenRecoverer = tokenRecoverer_;
}
//----------------------------------------------------------------------------------------------
// Administration
//----------------------------------------------------------------------------------------------
/// @inheritdoc IMessageProcessor
function file(bytes32 what, address data) external auth {
if (what == "hub") hub = IHubGatewayHandler(data);
else if (what == "spoke") spoke = ISpokeGatewayHandler(data);
else if (what == "balanceSheet") balanceSheet = IBalanceSheetGatewayHandler(data);
else if (what == "contractUpdater") contractUpdater = IUpdateContractGatewayHandler(data);
else revert FileUnrecognizedParam();
emit File(what, data);
}
//----------------------------------------------------------------------------------------------
// Handlers
//----------------------------------------------------------------------------------------------
/// @inheritdoc IMessageHandler
function handle(uint16 centrifugeId, bytes calldata message) external auth {
MessageType kind = message.messageType();
uint16 sourceCentrifugeId = message.messageSourceCentrifugeId();
require(sourceCentrifugeId == 0 || sourceCentrifugeId == centrifugeId, InvalidSourceChain());
if (kind == MessageType.ScheduleUpgrade) {
MessageLib.ScheduleUpgrade memory m = message.deserializeScheduleUpgrade();
root.scheduleRely(m.target.toAddress());
} else if (kind == MessageType.CancelUpgrade) {
MessageLib.CancelUpgrade memory m = message.deserializeCancelUpgrade();
root.cancelRely(m.target.toAddress());
} else if (kind == MessageType.RecoverTokens) {
MessageLib.RecoverTokens memory m = message.deserializeRecoverTokens();
tokenRecoverer.recoverTokens(
IRecoverable(m.target.toAddress()), m.token.toAddress(), m.tokenId, m.to.toAddress(), m.amount
);
} else if (kind == MessageType.RegisterAsset) {
MessageLib.RegisterAsset memory m = message.deserializeRegisterAsset();
hub.registerAsset(AssetId.wrap(m.assetId), m.decimals);
} else if (kind == MessageType.Request) {
MessageLib.Request memory m = MessageLib.deserializeRequest(message);
hub.request(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.payload);
} else if (kind == MessageType.NotifyPool) {
spoke.addPool(PoolId.wrap(MessageLib.deserializeNotifyPool(message).poolId));
} else if (kind == MessageType.NotifyShareClass) {
MessageLib.NotifyShareClass memory m = MessageLib.deserializeNotifyShareClass(message);
spoke.addShareClass(
PoolId.wrap(m.poolId),
ShareClassId.wrap(m.scId),
m.name,
m.symbol.toString(),
m.decimals,
m.salt,
m.hook.toAddress()
);
} else if (kind == MessageType.NotifyPricePoolPerShare) {
MessageLib.NotifyPricePoolPerShare memory m = MessageLib.deserializeNotifyPricePoolPerShare(message);
spoke.updatePricePoolPerShare(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.price, m.timestamp);
} else if (kind == MessageType.NotifyPricePoolPerAsset) {
MessageLib.NotifyPricePoolPerAsset memory m = MessageLib.deserializeNotifyPricePoolPerAsset(message);
spoke.updatePricePoolPerAsset(
PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.price, m.timestamp
);
} else if (kind == MessageType.NotifyShareMetadata) {
MessageLib.NotifyShareMetadata memory m = MessageLib.deserializeNotifyShareMetadata(message);
spoke.updateShareMetadata(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.name, m.symbol.toString());
} else if (kind == MessageType.UpdateShareHook) {
MessageLib.UpdateShareHook memory m = MessageLib.deserializeUpdateShareHook(message);
spoke.updateShareHook(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.hook.toAddress());
} else if (kind == MessageType.InitiateTransferShares) {
MessageLib.InitiateTransferShares memory m = MessageLib.deserializeInitiateTransferShares(message);
hub.initiateTransferShares(
m.centrifugeId, PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver, m.amount, m.extraGasLimit
);
} else if (kind == MessageType.ExecuteTransferShares) {
MessageLib.ExecuteTransferShares memory m = MessageLib.deserializeExecuteTransferShares(message);
spoke.executeTransferShares(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.receiver, m.amount);
} else if (kind == MessageType.UpdateRestriction) {
MessageLib.UpdateRestriction memory m = MessageLib.deserializeUpdateRestriction(message);
spoke.updateRestriction(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.payload);
} else if (kind == MessageType.UpdateContract) {
MessageLib.UpdateContract memory m = MessageLib.deserializeUpdateContract(message);
contractUpdater.execute(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.target.toAddress(), m.payload);
} else if (kind == MessageType.RequestCallback) {
MessageLib.RequestCallback memory m = MessageLib.deserializeRequestCallback(message);
spoke.requestCallback(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.payload);
} else if (kind == MessageType.UpdateVault) {
MessageLib.UpdateVault memory m = MessageLib.deserializeUpdateVault(message);
spoke.updateVault(
PoolId.wrap(m.poolId),
ShareClassId.wrap(m.scId),
AssetId.wrap(m.assetId),
m.vaultOrFactory.toAddress(),
VaultUpdateKind(m.kind)
);
} else if (kind == MessageType.SetRequestManager) {
MessageLib.SetRequestManager memory m = MessageLib.deserializeSetRequestManager(message);
spoke.setRequestManager(
PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.manager.toAddress()
);
} else if (kind == MessageType.UpdateBalanceSheetManager) {
MessageLib.UpdateBalanceSheetManager memory m = MessageLib.deserializeUpdateBalanceSheetManager(message);
balanceSheet.updateManager(PoolId.wrap(m.poolId), m.who.toAddress(), m.canManage);
} else if (kind == MessageType.UpdateHoldingAmount) {
MessageLib.UpdateHoldingAmount memory m = message.deserializeUpdateHoldingAmount();
hub.updateHoldingAmount(
centrifugeId,
PoolId.wrap(m.poolId),
ShareClassId.wrap(m.scId),
AssetId.wrap(m.assetId),
m.amount,
D18.wrap(m.pricePerUnit),
m.isIncrease,
m.isSnapshot,
m.nonce
);
} else if (kind == MessageType.UpdateShares) {
MessageLib.UpdateShares memory m = message.deserializeUpdateShares();
hub.updateShares(
centrifugeId,
PoolId.wrap(m.poolId),
ShareClassId.wrap(m.scId),
m.shares,
m.isIssuance,
m.isSnapshot,
m.nonce
);
} else if (kind == MessageType.MaxAssetPriceAge) {
MessageLib.MaxAssetPriceAge memory m = message.deserializeMaxAssetPriceAge();
spoke.setMaxAssetPriceAge(
PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), AssetId.wrap(m.assetId), m.maxPriceAge
);
} else if (kind == MessageType.MaxSharePriceAge) {
MessageLib.MaxSharePriceAge memory m = message.deserializeMaxSharePriceAge();
spoke.setMaxSharePriceAge(PoolId.wrap(m.poolId), ShareClassId.wrap(m.scId), m.maxPriceAge);
} else {
revert InvalidMessage(uint8(kind));
}
}
/// @inheritdoc IMessageProperties
function messageLength(bytes calldata message) external pure returns (uint16) {
return message.messageLength();
}
/// @inheritdoc IMessageProperties
function messagePoolId(bytes calldata message) external pure returns (PoolId) {
return message.messagePoolId();
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;
import {IAuth} from "src/misc/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 "src/misc/libraries/MathLib.sol";
type D18 is uint128;
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 substract 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/division-by-zero");
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.8.28;
/// @title CastLib
library CastLib {
function toAddressLeftPadded(bytes32 addr) internal pure returns (address) {
require(bytes12(addr) == 0, "First 12 bytes should be zero");
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, "Input should be 20 bytes");
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, "Input should be 128 bytes");
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;
/// @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: 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: BUSL-1.1
pragma solidity 0.8.28;
import {MathLib} from "src/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} for AssetId global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
interface IRoot {
// --- Events ---
event File(bytes32 indexed what, uint256 data);
event Pause();
event Unpause();
event ScheduleRely(address indexed target, uint256 indexed scheduledTime);
event CancelRely(address indexed target);
event RelyContract(address indexed target, address indexed user);
event DenyContract(address indexed target, address indexed user);
event Endorse(address indexed user);
event Veto(address indexed user);
error DelayTooLong();
error FileUnrecognizedParam();
error TargetNotScheduled();
error TargetNotReady();
/// @notice Returns whether the root is paused
function paused() external view returns (bool);
/// @notice Returns the current timelock for adding new wards
function delay() external view returns (uint256);
/// @notice Trusted contracts within the system
function endorsements(address target) external view returns (uint256);
/// @notice Returns when `relyTarget` has passed the timelock
function schedule(address relyTarget) external view returns (uint256 timestamp);
// --- Administration ---
/// @notice Updates a contract parameter
/// @param what Accepts a bytes32 representation of 'delay'
function file(bytes32 what, uint256 data) external;
/// --- Endorsements ---
/// @notice Endorses the `user`
/// @dev Endorsed users are trusted contracts in the system. They are allowed to bypass
/// token restrictions (e.g. the Escrow can automatically receive share class tokens by being endorsed), and
/// can automatically set operators in ERC-7540 vaults (e.g. the VaultRouter) is always an operator.
function endorse(address user) external;
/// @notice Removes the endorsed user
function veto(address user) external;
/// @notice Returns whether the user is endorsed
function endorsed(address user) external view returns (bool);
// --- Pause management ---
/// @notice Pause any contracts that depend on `Root.paused()`
function pause() external;
/// @notice Unpause any contracts that depend on `Root.paused()`
function unpause() external;
/// --- Timelocked ward management ---
/// @notice Schedule relying a new ward after the delay has passed
function scheduleRely(address target) external;
/// @notice Cancel a pending scheduled rely
function cancelRely(address target) external;
/// @notice Execute a scheduled rely
/// @dev Can be triggered by anyone since the scheduling is protected
function executeScheduledRely(address target) external;
/// --- External contract ward management ---
/// @notice Make an address a ward on any contract that Root is a ward on
function relyContract(address target, address user) external;
/// @notice Removes an address as a ward on any contract that Root is a ward on
function denyContract(address target, address user) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {PoolId} from "src/common/types/PoolId.sol";
type ShareClassId is bytes16;
function isNull(ShareClassId scId) pure returns (bool) {
return ShareClassId.unwrap(scId) == 0;
}
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, raw, equals as ==} for ShareClassId global;// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @notice Generic interface for entities that handle incoming messages
interface IMessageHandler {
/// @notice Dispatched when an invalid message is trying to handle
error InvalidMessage(uint8 code);
/// @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;
import {IRecoverable} from "src/misc/interfaces/IRecoverable.sol";
interface ITokenRecoverer {
event RecoverTokens(
IRecoverable indexed target, address indexed token, uint256 tokenId, address indexed to, uint256 amount
);
function recoverTokens(IRecoverable target, address token, uint256 tokenId, address to, uint256 amount) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IMessageHandler} from "src/common/interfaces/IMessageHandler.sol";
import {IMessageProperties} from "src/common/interfaces/IMessageProperties.sol";
interface IMessageProcessor is IMessageHandler, IMessageProperties {
error InvalidSourceChain();
/// @notice Emitted when a call to `file()` was performed.
event File(bytes32 indexed what, address addr);
/// @notice Dispatched when the `what` parameter of `file()` is not supported by the implementation.
error FileUnrecognizedParam();
/// @notice Updates a contract parameter.
/// @param what Name of the parameter to update.
/// Accepts a `bytes32` representation of 'hubRegistry' string value.
/// @param data New value given to the `what` parameter
function file(bytes32 what, address data) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {PoolId} from "src/common/types/PoolId.sol";
/// @notice Defines methods to get properties from raw messages
interface IMessageProperties {
/// @notice Inspect the message to return the length
function messageLength(bytes calldata message) external pure returns (uint16);
/// @notice Inspect the message to return the associated PoolId if any
function messagePoolId(bytes calldata message) external pure returns (PoolId);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {CastLib} from "src/misc/libraries/CastLib.sol";
import {BytesLib} from "src/misc/libraries/BytesLib.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
// NOTE: Should never exceed 254 messages because id == 255 corresponds to message proofs
enum MessageType {
/// @dev Placeholder for null message type
_Invalid,
// -- Pool independent messages
ScheduleUpgrade,
CancelUpgrade,
RecoverTokens,
RegisterAsset,
_Placeholder5,
_Placeholder6,
_Placeholder7,
_Placeholder8,
_Placeholder9,
_Placeholder10,
_Placeholder11,
_Placeholder12,
_Placeholder13,
_Placeholder14,
_Placeholder15,
// -- Pool dependent messages
NotifyPool,
NotifyShareClass,
NotifyPricePoolPerShare,
NotifyPricePoolPerAsset,
NotifyShareMetadata,
UpdateShareHook,
InitiateTransferShares,
ExecuteTransferShares,
UpdateRestriction,
UpdateContract,
UpdateVault,
UpdateBalanceSheetManager,
UpdateHoldingAmount,
UpdateShares,
MaxAssetPriceAge,
MaxSharePriceAge,
Request,
RequestCallback,
SetRequestManager
}
/// @dev Used internally in the UpdateVault message (not represent a submessage)
enum VaultUpdateKind {
DeployAndLink,
Link,
Unlink
}
library MessageLib {
using MessageLib for bytes;
using BytesLib for bytes;
using CastLib for *;
error UnknownMessageType();
/// @dev Encode all message lengths in this constant to avoid a large list of if/elseif checks
/// and reduce generated bytecode.
/// If the message has some dynamic part, will be added later in `messageLength()`.
// forgefmt: disable-next-item
uint256 constant MESSAGE_LENGTHS_1 =
(33 << uint8(MessageType.ScheduleUpgrade) * 8) +
(33 << uint8(MessageType.CancelUpgrade) * 8) +
(161 << uint8(MessageType.RecoverTokens) * 8) +
(18 << uint8(MessageType.RegisterAsset) * 8) +
(0 << uint8(MessageType._Placeholder5) * 8) +
(0 << uint8(MessageType._Placeholder6) * 8) +
(0 << uint8(MessageType._Placeholder7) * 8) +
(0 << uint8(MessageType._Placeholder8) * 8) +
(0 << uint8(MessageType._Placeholder9) * 8) +
(0 << uint8(MessageType._Placeholder10) * 8) +
(0 << uint8(MessageType._Placeholder11) * 8) +
(0 << uint8(MessageType._Placeholder12) * 8) +
(0 << uint8(MessageType._Placeholder13) * 8) +
(0 << uint8(MessageType._Placeholder14) * 8) +
(0 << uint8(MessageType._Placeholder15) * 8) +
(9 << uint8(MessageType.NotifyPool) * 8) +
(250 << uint8(MessageType.NotifyShareClass) * 8) +
(49 << uint8(MessageType.NotifyPricePoolPerShare) * 8) +
(65 << uint8(MessageType.NotifyPricePoolPerAsset) * 8) +
(185 << uint8(MessageType.NotifyShareMetadata) * 8) +
(57 << uint8(MessageType.UpdateShareHook) * 8) +
(91 << uint8(MessageType.InitiateTransferShares) * 8) +
(73 << uint8(MessageType.ExecuteTransferShares) * 8) +
(25 << uint8(MessageType.UpdateRestriction) * 8) +
(57 << uint8(MessageType.UpdateContract) * 8) +
(74 << uint8(MessageType.UpdateVault) * 8) +
(42 << uint8(MessageType.UpdateBalanceSheetManager) * 8) +
(91 << uint8(MessageType.UpdateHoldingAmount) * 8) +
(59 << uint8(MessageType.UpdateShares) * 8) +
(49 << uint8(MessageType.MaxAssetPriceAge) * 8) +
(33 << uint8(MessageType.MaxSharePriceAge) * 8);
// forgefmt: disable-next-item
uint256 constant MESSAGE_LENGTHS_2 =
(41 << (uint8(MessageType.Request) - 32) * 8) +
(41 << (uint8(MessageType.RequestCallback) - 32) * 8) +
(73 << (uint8(MessageType.SetRequestManager) - 32) * 8);
function messageType(bytes memory message) internal pure returns (MessageType) {
return MessageType(message.toUint8(0));
}
function messageCode(bytes memory message) internal pure returns (uint8) {
return message.toUint8(0);
}
function messageLength(bytes memory message) internal pure returns (uint16 length) {
uint8 kind = message.toUint8(0);
require(kind <= uint8(type(MessageType).max), UnknownMessageType());
length = (kind <= 31)
? uint16(uint8(bytes32(MESSAGE_LENGTHS_1)[31 - kind]))
: uint16(uint8(bytes32(MESSAGE_LENGTHS_2)[63 - kind]));
// Special treatment for messages with dynamic size:
if (kind == uint8(MessageType.UpdateRestriction)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.UpdateContract)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.Request)) {
length += 2 + message.toUint16(length); //payloadLength
} else if (kind == uint8(MessageType.RequestCallback)) {
length += 2 + message.toUint16(length); //payloadLength
}
}
function messagePoolId(bytes memory message) internal pure returns (PoolId poolId) {
uint8 kind = message.toUint8(0);
// All messages from NotifyPool to the end contains a PoolId in position 1.
if (kind >= uint8(MessageType.NotifyPool)) {
return PoolId.wrap(message.toUint64(1));
} else {
return PoolId.wrap(0);
}
}
function messageSourceCentrifugeId(bytes memory message) internal pure returns (uint16) {
uint8 kind = message.toUint8(0);
if (kind <= uint8(MessageType.RecoverTokens)) {
return 0; // Non centrifugeId associated
} else if (kind == uint8(MessageType.UpdateShares) || kind == uint8(MessageType.InitiateTransferShares)) {
return 0; // Non centrifugeId associated
} else if (kind == uint8(MessageType.RegisterAsset)) {
return AssetId.wrap(message.toUint128(1)).centrifugeId();
} else if (kind == uint8(MessageType.UpdateHoldingAmount)) {
return AssetId.wrap(message.toUint128(25)).centrifugeId();
} else if (kind == uint8(MessageType.Request)) {
return AssetId.wrap(message.toUint128(25)).centrifugeId();
} else {
return message.messagePoolId().centrifugeId();
}
}
//---------------------------------------
// ScheduleUpgrade
//---------------------------------------
struct ScheduleUpgrade {
bytes32 target;
}
function deserializeScheduleUpgrade(bytes memory data) internal pure returns (ScheduleUpgrade memory) {
require(messageType(data) == MessageType.ScheduleUpgrade, UnknownMessageType());
return ScheduleUpgrade({target: data.toBytes32(1)});
}
function serialize(ScheduleUpgrade memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.ScheduleUpgrade, t.target);
}
//---------------------------------------
// CancelUpgrade
//---------------------------------------
struct CancelUpgrade {
bytes32 target;
}
function deserializeCancelUpgrade(bytes memory data) internal pure returns (CancelUpgrade memory) {
require(messageType(data) == MessageType.CancelUpgrade, UnknownMessageType());
return CancelUpgrade({target: data.toBytes32(1)});
}
function serialize(CancelUpgrade memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.CancelUpgrade, t.target);
}
//---------------------------------------
// RecoverTokens
//---------------------------------------
struct RecoverTokens {
bytes32 target;
bytes32 token;
uint256 tokenId;
bytes32 to;
uint256 amount;
}
function deserializeRecoverTokens(bytes memory data) internal pure returns (RecoverTokens memory) {
require(messageType(data) == MessageType.RecoverTokens, UnknownMessageType());
return RecoverTokens({
target: data.toBytes32(1),
token: data.toBytes32(33),
tokenId: data.toUint256(65),
to: data.toBytes32(97),
amount: data.toUint256(129)
});
}
function serialize(RecoverTokens memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.RecoverTokens, t.target, t.token, t.tokenId, t.to, t.amount);
}
//---------------------------------------
// RegisterAsset
//---------------------------------------
struct RegisterAsset {
uint128 assetId;
uint8 decimals;
}
function deserializeRegisterAsset(bytes memory data) internal pure returns (RegisterAsset memory) {
require(messageType(data) == MessageType.RegisterAsset, UnknownMessageType());
return RegisterAsset({assetId: data.toUint128(1), decimals: data.toUint8(17)});
}
function serialize(RegisterAsset memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.RegisterAsset, t.assetId, t.decimals);
}
//---------------------------------------
// NotifyPool
//---------------------------------------
struct NotifyPool {
uint64 poolId;
}
function deserializeNotifyPool(bytes memory data) internal pure returns (NotifyPool memory) {
require(messageType(data) == MessageType.NotifyPool, UnknownMessageType());
return NotifyPool({poolId: data.toUint64(1)});
}
function serialize(NotifyPool memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPool, t.poolId);
}
//---------------------------------------
// NotifyShareClass
//---------------------------------------
struct NotifyShareClass {
uint64 poolId;
bytes16 scId;
string name; // Fixed to 128 bytes
bytes32 symbol; // utf8
uint8 decimals;
bytes32 salt;
bytes32 hook;
}
function deserializeNotifyShareClass(bytes memory data) internal pure returns (NotifyShareClass memory) {
require(messageType(data) == MessageType.NotifyShareClass, UnknownMessageType());
return NotifyShareClass({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
name: data.slice(25, 128).bytes128ToString(),
symbol: data.toBytes32(153),
decimals: data.toUint8(185),
salt: data.toBytes32(186),
hook: data.toBytes32(218)
});
}
function serialize(NotifyShareClass memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.NotifyShareClass,
t.poolId,
t.scId,
bytes(t.name).sliceZeroPadded(0, 128),
t.symbol,
t.decimals,
t.salt,
t.hook
);
}
//---------------------------------------
// NotifyPricePoolPerShare
//---------------------------------------
struct NotifyPricePoolPerShare {
uint64 poolId;
bytes16 scId;
uint128 price;
uint64 timestamp;
}
function deserializeNotifyPricePoolPerShare(bytes memory data)
internal
pure
returns (NotifyPricePoolPerShare memory)
{
require(messageType(data) == MessageType.NotifyPricePoolPerShare, UnknownMessageType());
return NotifyPricePoolPerShare({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
price: data.toUint128(25),
timestamp: data.toUint64(41)
});
}
function serialize(NotifyPricePoolPerShare memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPricePoolPerShare, t.poolId, t.scId, t.price, t.timestamp);
}
//---------------------------------------
// NotifyPricePoolPerAsset
//---------------------------------------
struct NotifyPricePoolPerAsset {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint128 price;
uint64 timestamp;
}
function deserializeNotifyPricePoolPerAsset(bytes memory data)
internal
pure
returns (NotifyPricePoolPerAsset memory)
{
require(messageType(data) == MessageType.NotifyPricePoolPerAsset, UnknownMessageType());
return NotifyPricePoolPerAsset({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
price: data.toUint128(41),
timestamp: data.toUint64(57)
});
}
function serialize(NotifyPricePoolPerAsset memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.NotifyPricePoolPerAsset, t.poolId, t.scId, t.assetId, t.price, t.timestamp);
}
//---------------------------------------
// NotifyShareMetadata
//---------------------------------------
struct NotifyShareMetadata {
uint64 poolId;
bytes16 scId;
string name; // Fixed to 128 bytes
bytes32 symbol; // utf8
}
function deserializeNotifyShareMetadata(bytes memory data) internal pure returns (NotifyShareMetadata memory) {
require(messageType(data) == MessageType.NotifyShareMetadata, UnknownMessageType());
return NotifyShareMetadata({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
name: data.slice(25, 128).bytes128ToString(),
symbol: data.toBytes32(153)
});
}
function serialize(NotifyShareMetadata memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.NotifyShareMetadata, t.poolId, t.scId, bytes(t.name).sliceZeroPadded(0, 128), t.symbol
);
}
//---------------------------------------
// UpdateShareHook
//---------------------------------------
struct UpdateShareHook {
uint64 poolId;
bytes16 scId;
bytes32 hook;
}
function deserializeUpdateShareHook(bytes memory data) internal pure returns (UpdateShareHook memory) {
require(messageType(data) == MessageType.UpdateShareHook, UnknownMessageType());
return UpdateShareHook({poolId: data.toUint64(1), scId: data.toBytes16(9), hook: data.toBytes32(25)});
}
function serialize(UpdateShareHook memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateShareHook, t.poolId, t.scId, t.hook);
}
//---------------------------------------
// InitiateTransferShares
//---------------------------------------
struct InitiateTransferShares {
uint64 poolId;
bytes16 scId;
uint16 centrifugeId;
bytes32 receiver;
uint128 amount;
uint128 extraGasLimit;
}
function deserializeInitiateTransferShares(bytes memory data)
internal
pure
returns (InitiateTransferShares memory)
{
require(messageType(data) == MessageType.InitiateTransferShares, UnknownMessageType());
return InitiateTransferShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
centrifugeId: data.toUint16(25),
receiver: data.toBytes32(27),
amount: data.toUint128(59),
extraGasLimit: data.toUint128(75)
});
}
function serialize(InitiateTransferShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.InitiateTransferShares, t.poolId, t.scId, t.centrifugeId, t.receiver, t.amount, t.extraGasLimit
);
}
//---------------------------------------
// ExecuteTransferShares
//---------------------------------------
struct ExecuteTransferShares {
uint64 poolId;
bytes16 scId;
bytes32 receiver;
uint128 amount;
}
function deserializeExecuteTransferShares(bytes memory data) internal pure returns (ExecuteTransferShares memory) {
require(messageType(data) == MessageType.ExecuteTransferShares, UnknownMessageType());
return ExecuteTransferShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
receiver: data.toBytes32(25),
amount: data.toUint128(57)
});
}
function serialize(ExecuteTransferShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.ExecuteTransferShares, t.poolId, t.scId, t.receiver, t.amount);
}
//---------------------------------------
// UpdateRestriction
//---------------------------------------
struct UpdateRestriction {
uint64 poolId;
bytes16 scId;
bytes payload; // As sequence of bytes
}
function deserializeUpdateRestriction(bytes memory data) internal pure returns (UpdateRestriction memory) {
require(messageType(data) == MessageType.UpdateRestriction, UnknownMessageType());
uint16 payloadLength = data.toUint16(25);
return UpdateRestriction({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
payload: data.slice(27, payloadLength)
});
}
function serialize(UpdateRestriction memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateRestriction, t.poolId, t.scId, uint16(t.payload.length), t.payload);
}
//---------------------------------------
// UpdateContract
//---------------------------------------
struct UpdateContract {
uint64 poolId;
bytes16 scId;
bytes32 target;
bytes payload; // As sequence of bytes
}
function deserializeUpdateContract(bytes memory data) internal pure returns (UpdateContract memory) {
require(messageType(data) == MessageType.UpdateContract, UnknownMessageType());
uint16 payloadLength = data.toUint16(57);
return UpdateContract({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
target: data.toBytes32(25),
payload: data.slice(59, payloadLength)
});
}
function serialize(UpdateContract memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateContract, t.poolId, t.scId, t.target, uint16(t.payload.length), t.payload
);
}
//---------------------------------------
// Request
//---------------------------------------
struct Request {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes payload; // As sequence of bytes
}
function deserializeRequest(bytes memory data) internal pure returns (Request memory) {
require(messageType(data) == MessageType.Request, UnknownMessageType());
uint16 payloadLength = data.toUint16(41);
return Request({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
payload: data.slice(43, payloadLength)
});
}
function serialize(Request memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.Request, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload);
}
//---------------------------------------
// RequestCallback
//---------------------------------------
struct RequestCallback {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes payload; // As sequence of bytes
}
function deserializeRequestCallback(bytes memory data) internal pure returns (RequestCallback memory) {
require(messageType(data) == MessageType.RequestCallback, UnknownMessageType());
uint16 payloadLength = data.toUint16(41);
return RequestCallback({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
payload: data.slice(43, payloadLength)
});
}
function serialize(RequestCallback memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.RequestCallback, t.poolId, t.scId, t.assetId, uint16(t.payload.length), t.payload
);
}
//---------------------------------------
// VaultUpdate
//---------------------------------------
struct UpdateVault {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes32 vaultOrFactory;
uint8 kind;
}
function deserializeUpdateVault(bytes memory data) internal pure returns (UpdateVault memory) {
require(messageType(data) == MessageType.UpdateVault, UnknownMessageType());
return UpdateVault({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
vaultOrFactory: data.toBytes32(41),
kind: data.toUint8(73)
});
}
function serialize(UpdateVault memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateVault, t.poolId, t.scId, t.assetId, t.vaultOrFactory, t.kind);
}
//---------------------------------------
// SetRequestManager
//---------------------------------------
struct SetRequestManager {
uint64 poolId;
bytes16 scId;
uint128 assetId;
bytes32 manager;
}
function deserializeSetRequestManager(bytes memory data) internal pure returns (SetRequestManager memory) {
require(messageType(data) == MessageType.SetRequestManager, UnknownMessageType());
return SetRequestManager({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
manager: data.toBytes32(41)
});
}
function serialize(SetRequestManager memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.SetRequestManager, t.poolId, t.scId, t.assetId, t.manager);
}
//---------------------------------------
// UpdateBalanceSheetManager
//---------------------------------------
struct UpdateBalanceSheetManager {
uint64 poolId;
bytes32 who;
bool canManage;
}
function deserializeUpdateBalanceSheetManager(bytes memory data)
internal
pure
returns (UpdateBalanceSheetManager memory)
{
require(messageType(data) == MessageType.UpdateBalanceSheetManager, UnknownMessageType());
return UpdateBalanceSheetManager({poolId: data.toUint64(1), who: data.toBytes32(9), canManage: data.toBool(41)});
}
function serialize(UpdateBalanceSheetManager memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.UpdateBalanceSheetManager, t.poolId, t.who, t.canManage);
}
//---------------------------------------
// UpdateHoldingAmount
//---------------------------------------
struct UpdateHoldingAmount {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint128 amount;
uint128 pricePerUnit;
uint64 timestamp;
bool isIncrease;
bool isSnapshot;
uint64 nonce;
}
function deserializeUpdateHoldingAmount(bytes memory data) internal pure returns (UpdateHoldingAmount memory h) {
require(messageType(data) == MessageType.UpdateHoldingAmount, "UnknownMessageType");
return UpdateHoldingAmount({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
amount: data.toUint128(41),
pricePerUnit: data.toUint128(57),
timestamp: data.toUint64(73),
isIncrease: data.toBool(81),
isSnapshot: data.toBool(82),
nonce: data.toUint64(83)
});
}
function serialize(UpdateHoldingAmount memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateHoldingAmount,
t.poolId,
t.scId,
t.assetId,
t.amount,
t.pricePerUnit,
t.timestamp,
t.isIncrease,
t.isSnapshot,
t.nonce
);
}
//---------------------------------------
// UpdateShares
//---------------------------------------
struct UpdateShares {
uint64 poolId;
bytes16 scId;
uint128 shares;
uint64 timestamp;
bool isIssuance;
bool isSnapshot;
uint64 nonce;
}
function deserializeUpdateShares(bytes memory data) internal pure returns (UpdateShares memory) {
require(messageType(data) == MessageType.UpdateShares, UnknownMessageType());
return UpdateShares({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
shares: data.toUint128(25),
timestamp: data.toUint64(41),
isIssuance: data.toBool(49),
isSnapshot: data.toBool(50),
nonce: data.toUint64(51)
});
}
function serialize(UpdateShares memory t) internal pure returns (bytes memory) {
return abi.encodePacked(
MessageType.UpdateShares, t.poolId, t.scId, t.shares, t.timestamp, t.isIssuance, t.isSnapshot, t.nonce
);
}
//---------------------------------------
// MaxAssetPriceAge
//---------------------------------------
struct MaxAssetPriceAge {
uint64 poolId;
bytes16 scId;
uint128 assetId;
uint64 maxPriceAge;
}
function deserializeMaxAssetPriceAge(bytes memory data) internal pure returns (MaxAssetPriceAge memory) {
require(messageType(data) == MessageType.MaxAssetPriceAge, UnknownMessageType());
return MaxAssetPriceAge({
poolId: data.toUint64(1),
scId: data.toBytes16(9),
assetId: data.toUint128(25),
maxPriceAge: data.toUint64(41)
});
}
function serialize(MaxAssetPriceAge memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.MaxAssetPriceAge, t.poolId, t.scId, t.assetId, t.maxPriceAge);
}
//---------------------------------------
// MaxSharePriceAge
//---------------------------------------
struct MaxSharePriceAge {
uint64 poolId;
bytes16 scId;
uint64 maxPriceAge;
}
function deserializeMaxSharePriceAge(bytes memory data) internal pure returns (MaxSharePriceAge memory) {
require(messageType(data) == MessageType.MaxSharePriceAge, UnknownMessageType());
return MaxSharePriceAge({poolId: data.toUint64(1), scId: data.toBytes16(9), maxPriceAge: data.toUint64(25)});
}
function serialize(MaxSharePriceAge memory t) internal pure returns (bytes memory) {
return abi.encodePacked(MessageType.MaxSharePriceAge, t.poolId, t.scId, t.maxPriceAge);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {D18} from "src/misc/types/D18.sol";
import {PoolId} from "src/common/types/PoolId.sol";
import {AssetId} from "src/common/types/AssetId.sol";
import {ShareClassId} from "src/common/types/ShareClassId.sol";
import {VaultUpdateKind} from "src/common/libraries/MessageLib.sol";
/// -----------------------------------------------------
/// Hub Handlers
/// -----------------------------------------------------
/// @notice Interface for Hub methods called by messages
interface IHubGatewayHandler {
/// @notice Tells that an asset was already registered in Vaults, in order to perform the corresponding register.
function registerAsset(AssetId assetId, uint8 decimals) external;
/// @notice Handles a request originating from the Spoke side.
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param payload The request payload to be processed
function request(PoolId poolId, ShareClassId scId, AssetId assetId, bytes calldata payload) external payable;
/// @notice Update a holding by request from Vaults.
function updateHoldingAmount(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
AssetId assetId,
uint128 amount,
D18 pricePoolPerAsset,
bool isIncrease,
bool isSnapshot,
uint64 nonce
) external;
/// @notice Forward an initiated share transfer to the destination chain.
function initiateTransferShares(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
bytes32 receiver,
uint128 amount,
uint128 extraGasLimit
) external;
/// @notice Updates the total issuance of shares by request from vaults.
function updateShares(
uint16 centrifugeId,
PoolId poolId,
ShareClassId scId,
uint128 amount,
bool isIssuance,
bool isSnapshot,
uint64 nonce
) external;
}
/// -----------------------------------------------------
/// Vaults Handlers
/// -----------------------------------------------------
/// @notice Interface for spoke related methods called by messages
interface ISpokeGatewayHandler {
/// @notice New pool details from an existing Centrifuge pool are added.
/// @param poolId The pool id
function addPool(PoolId poolId) external;
/// @notice New share class details from an existing Centrifuge pool are added.
function addShareClass(
PoolId poolId,
ShareClassId scId,
string memory tokenName,
string memory tokenSymbol,
uint8 decimals,
bytes32 salt,
address hook
) external;
/// @notice Updates the request manager for a specific asset
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param manager The new request manager address
function setRequestManager(PoolId poolId, ShareClassId scId, AssetId assetId, address manager) external;
/// @notice Updates the tokenName and tokenSymbol of a share class token
function updateShareMetadata(PoolId poolId, ShareClassId scId, string memory tokenName, string memory tokenSymbol)
external;
/// @notice Updates the price of a share class token, i.e. the factor of pool currency amount per share class token
/// @param poolId The pool id
/// @param scId The share class id
/// @param price The price of pool currency per share class token as factor.
/// @param computedAt The timestamp when the price was computed
function updatePricePoolPerShare(PoolId poolId, ShareClassId scId, uint128 price, uint64 computedAt) external;
/// @notice Updates the price of an asset, i.e. the factor of pool currency amount per asset unit
/// @param poolId The pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param poolPerAsset The price of pool currency per asset unit as factor.
/// @param computedAt The timestamp when the price was computed
function updatePricePoolPerAsset(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
uint128 poolPerAsset,
uint64 computedAt
) external;
/// @notice Updates the hook of a share class token
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param hook The new hook addres
function updateShareHook(PoolId poolId, ShareClassId scId, address hook) external;
/// @notice Updates the restrictions on a share class token for a specific user
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param update The restriction update in the form of a bytes array indicating
/// the restriction to be updated, the user to be updated, and a validUntil timestamp.
function updateRestriction(PoolId poolId, ShareClassId scId, bytes memory update) external;
/// @notice Mints share class tokens to a recipient
function executeTransferShares(PoolId poolId, ShareClassId scId, bytes32 receiver, uint128 amount) external;
/// @notice Updates a vault based on VaultUpdateKind
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param vaultOrFactory The address of the vault or the factory, depending on the kind value
/// @param kind The kind of action applied
function updateVault(
PoolId poolId,
ShareClassId scId,
AssetId assetId,
address vaultOrFactory,
VaultUpdateKind kind
) external;
/// @notice Updates the max price age of an asset
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param assetId The asset id
/// @param maxPriceAge new max price age value
function setMaxAssetPriceAge(PoolId poolId, ShareClassId scId, AssetId assetId, uint64 maxPriceAge) external;
/// @notice Updates the max price age of a share
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param maxPriceAge new max price age value
function setMaxSharePriceAge(PoolId poolId, ShareClassId scId, uint64 maxPriceAge) external;
/// @notice Handles a request callback originating from the Hub side.
/// @dev Results from a Spoke-to-Hub-request as second order callback from the Hub.
/// @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
function requestCallback(PoolId poolId, ShareClassId scId, AssetId assetId, bytes memory payload) external;
}
/// @notice Interface for the update contract method, called by message
interface IUpdateContractGatewayHandler {
/// @notice Updates the target address. Generic update function from Hub to Vaults
/// @param poolId The centrifuge pool id
/// @param scId The share class id
/// @param target The target address to be called
/// @param update The payload to be processed by the target address
function execute(PoolId poolId, ShareClassId scId, address target, bytes memory update) external;
}
/// @notice Interface for methods implemented by a balance sheet
interface IBalanceSheetGatewayHandler {
function updateManager(PoolId poolId, address who, bool canManage) external;
}// 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)
function wards(address target) external view returns (uint256);
/// @notice Make user a ward (give them admin access)
function rely(address user) external;
/// @notice Remove user as a ward (remove admin access)
function deny(address user) external;
}// 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 Uint32_Overflow();
error Uint64_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);
}
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);
}
/// @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;
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@chimera/=lib/chimera/src/",
"createx-forge/=lib/createx-forge/",
"chimera/=lib/chimera/src/",
"ds-test/=lib/chimera/lib/forge-std/lib/ds-test/src/",
"setup-helpers/=lib/setup-helpers/src/"
],
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IRoot","name":"root_","type":"address"},{"internalType":"contract ITokenRecoverer","name":"tokenRecoverer_","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FileUnrecognizedParam","type":"error"},{"inputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"name":"InvalidMessage","type":"error"},{"inputs":[],"name":"InvalidSourceChain","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"SliceOverflow","type":"error"},{"inputs":[],"name":"UnknownMessageType","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"what","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"File","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Rely","type":"event"},{"inputs":[],"name":"balanceSheet","outputs":[{"internalType":"contract IBalanceSheetGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractUpdater","outputs":[{"internalType":"contract IUpdateContractGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"what","type":"bytes32"},{"internalType":"address","name":"data","type":"address"}],"name":"file","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"centrifugeId","type":"uint16"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"handle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract IHubGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"}],"name":"messageLength","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"}],"name":"messagePoolId","outputs":[{"internalType":"PoolId","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"contract IRoot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"spoke","outputs":[{"internalType":"contract ISpokeGatewayHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenRecoverer","outputs":[{"internalType":"contract ITokenRecoverer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c060405234801561000f575f5ffd5b506040516138be3803806138be83398101604081905261002e916100a1565b6001600160a01b0381165f8181526020819052604080822060019055518392917fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6091a250506001600160a01b039182166080521660a0526100eb565b6001600160a01b038116811461009e575f5ffd5b50565b5f5f5f606084860312156100b3575f5ffd5b83516100be8161008a565b60208501519093506100cf8161008a565b60408501519092506100e08161008a565b809150509250925092565b60805160a05161379e6101205f395f818160df015261052501525f81816101ed015281816103ac0152610490015261379e5ff3fe608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806322285cf6146100b1578063268808c6146100da578063365a86fc146101015780633b514cf11461011457806347bfbcc6146101345780634f35b71c1461014757806365fae35e1461015c5780636c3be0ce1461016f5780639c52a7f114610195578063bf353dbb146101a8578063d4e8be83146101d5578063ebf0c717146101e8578063ed15d9601461020f575b5f5ffd5b6003546100c4906001600160a01b031681565b6040516100d191906132d2565b60405180910390f35b6100c47f000000000000000000000000000000000000000000000000000000000000000081565b6001546100c4906001600160a01b031681565b61012761012236600461332a565b610222565b6040516100d19190613368565b6002546100c4906001600160a01b031681565b61015a61015536600461337c565b61026a565b005b61015a61016a3660046133ed565b611535565b61018261017d36600461332a565b6115a8565b60405161ffff90911681526020016100d1565b61015a6101a33660046133ed565b6115e7565b6101c76101b63660046133ed565b5f6020819052908152604090205481565b6040519081526020016100d1565b61015a6101e3366004613406565b611659565b6100c47f000000000000000000000000000000000000000000000000000000000000000081565b6004546100c4906001600160a01b031681565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117a892505050565b90505b92915050565b335f908152602081905260409020546001146102995760405163ea8e4eb560e01b815260040160405180910390fd5b5f6102d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e192505050565b90505f61031984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061180092505050565b905061ffff8116158061033357508461ffff168161ffff16145b61035057604051639284b19760e01b815260040160405180910390fd5b600182602281111561036457610364613430565b03610434575f6103a885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506118b192505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633b6874616103e5835f0151611919565b6040518263ffffffff1660e01b815260040161040191906132d2565b5f604051808303815f87803b158015610418575f5ffd5b505af115801561042a573d5f5f3e3d5ffd5b505050505061152e565b600282602281111561044857610448613430565b036104c9575f61048c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061197392505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166311fd3baa6103e5835f0151611919565b60038260228111156104dd576104dd613430565b036105ce575f61052185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061198892505050565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663109037c061055e835f0151611919565b61056b8460200151611919565b846040015161057d8660600151611919565b608087015160405160e087901b6001600160e01b03191681526001600160a01b039586166004820152938516602485015260448401929092529092166064820152608481019190915260a401610401565b60048260228111156105e2576105e2613430565b03610670575f61062685858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611a4692505050565b60015481516020830151604051633207adab60e01b81526001600160801b03909216600483015260ff1660248201529192506001600160a01b031690633207adab90604401610401565b602082602281111561068457610684613430565b0361070e575f6106c885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611acd92505050565b6001548151602083015160408085015160608601519151632f6c33bf60e01b81529596506001600160a01b0390941694632f6c33bf946104019493929091600401613472565b601082602281111561072257610722613430565b036107cd57600254604080516020601f87018190048102820181019092528581526001600160a01b0390921691632b89610191610779919088908890819084018382808284375f92019190915250611bae92505050565b516040516001600160e01b031960e084901b16815261079b9190600401613368565b5f604051808303815f87803b1580156107b2575f5ffd5b505af11580156107c4573d5f5f3e3d5ffd5b5050505061152e565b60118260228111156107e1576107e1613430565b03610891575f61082585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1e92505050565b60025481516020830151604084015160608501519495506001600160a01b0390931693636ea6e0a1939061085890611d3f565b86608001518760a0015161086f8960c00151611919565b6040518863ffffffff1660e01b815260040161040197969594939291906134be565b60128260228111156108a5576108a5613430565b0361092f575f6108e985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b6002548151602083015160408085015160608601519151634869ac6960e01b81529596506001600160a01b0390941694634869ac6994610401949392909160040161352f565b601382602281111561094357610943613430565b03610a08575f61098785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611f2b92505050565b60025481516020830151604080850151606086015160808701519251633a4ba8bf60e01b81526001600160401b0395861660048201526001600160801b031990941660248501526001600160801b0391821660448501521660648301529190911660848201529192506001600160a01b031690633a4ba8bf9060a401610401565b6014826022811115610a1c57610a1c613430565b03610ab2575f610a6085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061200b92505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363931efb549390610a9390611d3f565b6040518563ffffffff1660e01b8152600401610401949392919061356d565b6015826022811115610ac657610ac6613430565b03610b83575f610b0a85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506120c892505050565b6002548151602083015160408401519394506001600160a01b039092169263fb59077a9290610b3890611919565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160a01b03166044820152606401610401565b6016826022811115610b9757610b97613430565b03610c6a575f610bdb85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061216892505050565b600154604082810151835160208501516060860151608087015160a0880151955163ecca8cf760e01b815261ffff90951660048601526001600160401b0390931660248501526001600160801b0319909116604484015260648301526001600160801b03908116608483015290911660a48201529192506001600160a01b03169063ecca8cf79060c401610401565b6017826022811115610c7e57610c7e613430565b03610d35575f610cc285858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061226b92505050565b600254815160208301516040808501516060860151915163bccbfa8960e01b81526001600160401b0390941660048501526001600160801b0319909216602484015260448301919091526001600160801b031660648201529192506001600160a01b03169063bccbfa8990608401610401565b6018826022811115610d4957610d49613430565b03610dcc575f610d8d85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232292505050565b600254815160208301516040808501519051630f8dad5d60e11b81529495506001600160a01b0390931693631f1b5aba936104019392916004016135bd565b6019826022811115610de057610de0613430565b03610e76575f610e2485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123dc92505050565b6004548151602083015160408401519394506001600160a01b0390921692630b1271059290610e5290611919565b85606001516040518563ffffffff1660e01b815260040161040194939291906135f9565b6021826022811115610e8a57610e8a613430565b03610f14575f610ece85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124ad92505050565b60025481516020830151604080850151606086015191516336c6cf3760e21b81529596506001600160a01b039094169463db1b3cdc946104019493929091600401613472565b601a826022811115610f2857610f28613430565b03610fd8575f610f6c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124d692505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363b3cfb8179390610f9f90611919565b866080015160ff166002811115610fb857610fb8613430565b6040518663ffffffff1660e01b815260040161040195949392919061363b565b6022826022811115610fec57610fec613430565b036110bc575f61103085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506125ad92505050565b60025481516020830151604084015160608501519495506001600160a01b03909316936325dc4956939061106390611919565b6040516001600160e01b031960e087901b1681526001600160401b0390941660048501526001600160801b031990921660248401526001600160801b031660448301526001600160a01b03166064820152608401610401565b601b8260228111156110d0576110d0613430565b03611185575f61111485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266d92505050565b600354815160208301519293506001600160a01b039091169163a6fd509b919061113d90611919565b60408086015190516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160a01b03909116602483015215156044820152606401610401565b601c82602281111561119957611199613430565b036112b1575f6111dd85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061270d92505050565b905060015f9054906101000a90046001600160a01b03166001600160a01b0316630646affc87835f015184602001518560400151866060015187608001518860c001518960e001518a61010001516040518a63ffffffff1660e01b81526004016104019998979695949392919061ffff9990991689526001600160401b0397881660208a01526001600160801b03199690961660408901526001600160801b0394851660608901529284166080880152921660a086015290151560c0850152151560e0840152166101008201526101200190565b601d8260228111156112c5576112c5613430565b036113a1575f61130985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061288692505050565b60015481516020830151604080850151608086015160a087015160c08801519351631de0563360e21b815261ffff8f1660048201526001600160401b0396871660248201526001600160801b031990951660448601526001600160801b03909216606485015215156084840152151560a48301529190911660c48201529192506001600160a01b03169063778158cc9060e401610401565b601e8260228111156113b5576113b5613430565b0361143f575f6113f985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061299892505050565b6002548151602083015160408085015160608601519151636a4873e160e11b81529596506001600160a01b039094169463d490e7c294610401949392909160040161352f565b601f82602281111561145357611453613430565b036114f8575f61149785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129c292505050565b60025481516020830151604080850151905163eece6c4360e01b81526001600160401b0393841660048201526001600160801b031990921660248301529190911660448201529192506001600160a01b03169063eece6c4390606401610401565b81602281111561150a5761150a613430565b604051630391465960e11b815260ff90911660048201526024015b60405180910390fd5b5050505050565b335f908152602081905260409020546001146115645760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612a6292505050565b335f908152602081905260409020546001146116165760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f908152602081905260409020546001146116885760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b036116b557600180546001600160a01b0319166001600160a01b03831617905561176c565b816473706f6b6560d81b036116e457600280546001600160a01b0319166001600160a01b03831617905561176c565b816b18985b185b98d954da19595d60a21b0361171a57600380546001600160a01b0319166001600160a01b03831617905561176c565b816e31b7b73a3930b1ba2ab83230ba32b960891b0361175357600480546001600160a01b0319166001600160a01b03831617905561176c565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba8260405161179c91906132d2565b60405180910390a25050565b5f806117b48382612f58565b9050601060ff8216106117d3576117cc836001612f8e565b9392505050565b505f92915050565b50919050565b5f6117ec8282612f58565b60ff16602281111561026457610264613430565b5f8061180c8382612f58565b9050600360ff82161161182157505f92915050565b60ff8116601d1480611836575060ff81166016145b1561184357505f92915050565b60031960ff821601611867576117cc61185d846001612fc4565b60701c61ffff1690565b601b1960ff821601611881576117cc61185d846019612fc4565b601f1960ff82160161189b576117cc61185d846019612fc4565b6117cc6118a7846117a8565b60301c61ffff1690565b60408051602081019091525f815260015b6118cb836117e1565b60228111156118dc576118dc613430565b146118fa576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611911846001612ffa565b905292915050565b5f6001600160601b0382161561196c5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b6044820152606401611525565b5060601c90565b60408051602081019091525f815260026118c2565b6119b56040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60036119c0836117e1565b60228111156119d1576119d1613430565b146119ef576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611a06846001612ffa565b8152602001611a16846021612ffa565b8152602001611a26846041612ffa565b8152602001611a36846061612ffa565b8152602001611911846081612ffa565b604080518082019091525f80825260208201526004611a64836117e1565b6022811115611a7557611a75613430565b14611a93576040516304c735eb60e11b815260040160405180910390fd5b6040805180820190915280611aa9846001612fc4565b6001600160801b03168152602001611ac2846011612f58565b60ff16905292915050565b604080516080810182525f808252602080830182905292820152606080820152905b611af8836117e1565b6022811115611b0957611b09613430565b14611b27576040516304c735eb60e11b815260040160405180910390fd5b5f611b33836029613030565b90506040518060800160405280611b54600186612f8e90919063ffffffff16565b6001600160401b03168152602001611b6d856009613066565b6001600160801b0319168152602001611b87856019612fc4565b6001600160801b03168152602001611ba585602b61ffff8616613072565b90529392505050565b60408051602081019091525f81526010611bc7836117e1565b6022811115611bd857611bd8613430565b14611bf6576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611c0d846001612f8e565b6001600160401b0316905292915050565b611c6e6040518060e001604052805f6001600160401b031681526020015f6001600160801b0319168152602001606081526020015f81526020015f60ff1681526020015f81526020015f81525090565b6011611c79836117e1565b6022811115611c8a57611c8a613430565b14611ca8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e0810190915280611cbf846001612f8e565b6001600160401b03168152602001611cd8846009613066565b6001600160801b0319168152602001611cfc611cf78560196080613072565b613134565b8152602001611d0c846099612ffa565b8152602001611d1c8460b9612f58565b60ff168152602001611d2f8460ba612ffa565b81526020016119118460da612ffa565b60605f5b60208160ff16108015611d775750828160ff1660208110611d6657611d666136a5565b1a60f81b6001600160f81b03191615155b15611d8e5780611d86816136cd565b915050611d43565b5f8160ff166001600160401b03811115611daa57611daa6136eb565b6040519080825280601f01601f191660200182016040528015611dd4576020820181803683370190505b5090505f91505b60208260ff16108015611e0f5750838260ff1660208110611dfe57611dfe6136a5565b1a60f81b6001600160f81b03191615155b156117cc57838260ff1660208110611e2957611e296136a5565b1a60f81b818360ff1681518110611e4257611e426136a5565b60200101906001600160f81b03191690815f1a90535081611e62816136cd565b925050611ddb565b604080516080810182525f80825260208201819052918101829052606081019190915260125b611e99836117e1565b6022811115611eaa57611eaa613430565b14611ec8576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280611edf846001612f8e565b6001600160401b03168152602001611ef8846009613066565b6001600160801b0319168152602001611f12846019612fc4565b6001600160801b03168152602001611c0d846029612f8e565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526013611f60836117e1565b6022811115611f7157611f71613430565b14611f8f576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611fa6846001612f8e565b6001600160401b03168152602001611fbf846009613066565b6001600160801b0319168152602001611fd9846019612fc4565b6001600160801b03168152602001611ff2846029612fc4565b6001600160801b03168152602001611c0d846039612f8e565b604080516080810182525f80825260208201819052606092820183905291810191909152601461203a836117e1565b602281111561204b5761204b613430565b14612069576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612080846001612f8e565b6001600160401b03168152602001612099846009613066565b6001600160801b03191681526020016120b8611cf78560196080613072565b8152602001611911846099612ffa565b604080516060810182525f808252602082018190529181019190915260156120ef836117e1565b602281111561210057612100613430565b1461211e576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612135846001612f8e565b6001600160401b0316815260200161214e846009613066565b6001600160801b0319168152602001611911846019612ffa565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915260166121a4836117e1565b60228111156121b5576121b5613430565b146121d3576040516304c735eb60e11b815260040160405180910390fd5b6040805160c08101909152806121ea846001612f8e565b6001600160401b03168152602001612203846009613066565b6001600160801b031916815260200161221d846019613030565b61ffff16815260200161223184601b612ffa565b815260200161224184603b612fc4565b6001600160801b0316815260200161225a84604b612fc4565b6001600160801b0316905292915050565b604080516080810182525f8082526020820181905291810182905260608101919091526017612299836117e1565b60228111156122aa576122aa613430565b146122c8576040516304c735eb60e11b815260040160405180910390fd5b6040805160808101909152806122df846001612f8e565b6001600160401b031681526020016122f8846009613066565b6001600160801b0319168152602001612312846019612ffa565b815260200161225a846039612fc4565b60408051606080820183525f8083526020830152918101919091526018612348836117e1565b602281111561235957612359613430565b14612377576040516304c735eb60e11b815260040160405180910390fd5b5f612383836019613030565b905060405180606001604052806123a4600186612f8e90919063ffffffff16565b6001600160401b031681526020016123bd856009613066565b6001600160801b0319168152602001611ba585601b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526019612409836117e1565b602281111561241a5761241a613430565b14612438576040516304c735eb60e11b815260040160405180910390fd5b5f612444836039613030565b90506040518060800160405280612465600186612f8e90919063ffffffff16565b6001600160401b0316815260200161247e856009613066565b6001600160801b0319168152602001612498856019612ffa565b8152602001611ba585603b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526021611aef565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152601a61250b836117e1565b602281111561251c5761251c613430565b1461253a576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280612551846001612f8e565b6001600160401b0316815260200161256a846009613066565b6001600160801b0319168152602001612584846019612fc4565b6001600160801b0316815260200161259d846029612ffa565b8152602001611ac2846049612f58565b604080516080810182525f80825260208201819052918101829052606081019190915260226125db836117e1565b60228111156125ec576125ec613430565b1461260a576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612621846001612f8e565b6001600160401b0316815260200161263a846009613066565b6001600160801b0319168152602001612654846019612fc4565b6001600160801b03168152602001611911846029612ffa565b604080516060810182525f8082526020820181905291810191909152601b612694836117e1565b60228111156126a5576126a5613430565b146126c3576040516304c735eb60e11b815260040160405180910390fd5b6040805160608101909152806126da846001612f8e565b6001600160401b031681526020016126f3846009612ffa565b8152602001612703846029613285565b1515905292915050565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152601c612760836117e1565b602281111561277157612771613430565b146127b35760405162461bcd60e51b8152602060048201526012602482015271556e6b6e6f776e4d6573736167655479706560701b6044820152606401611525565b604080516101208101909152806127cb846001612f8e565b6001600160401b031681526020016127e4846009613066565b6001600160801b03191681526020016127fe846019612fc4565b6001600160801b03168152602001612817846029612fc4565b6001600160801b03168152602001612830846039612fc4565b6001600160801b03168152602001612849846049612f8e565b6001600160401b03168152602001612862846051613285565b15158152602001612874846052613285565b15158152602001611c0d846053612f8e565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152601d6128c9836117e1565b60228111156128da576128da613430565b146128f8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e081019091528061290f846001612f8e565b6001600160401b03168152602001612928846009613066565b6001600160801b0319168152602001612942846019612fc4565b6001600160801b0316815260200161295b846029612f8e565b6001600160401b03168152602001612974846031613285565b15158152602001612986846032613285565b15158152602001611c0d846033612f8e565b604080516080810182525f808252602082018190529181018290526060810191909152601e611e90565b604080516060810182525f8082526020820181905291810191909152601f6129e9836117e1565b60228111156129fa576129fa613430565b14612a18576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612a2f846001612f8e565b6001600160401b03168152602001612a48846009613066565b6001600160801b0319168152602001611c0d846019612f8e565b5f80612a6e8382612f58565b9050602260ff82161115612a95576040516304c735eb60e11b815260040160405180910390fd5b601f8160ff161115612b3657612aad602060226136ff565b612ab8906008613718565b604960ff919091161b612acd602060216136ff565b612ad8906008613718565b602960ff919091161b612aec6020806136ff565b612af7906008613718565b60ff166029901b612b08919061373b565b612b12919061373b565b612b1d82603f6136ff565b60ff1660208110612b3057612b306136a5565b1a612ebd565b612b42601f6008613718565b602160ff919091161b612b57601e6008613718565b603160ff919091161b612b6c601d6008613718565b603b60ff919091161b612b81601c6008613718565b605b60ff919091161b612b96601b6008613718565b602a60ff919091161b612bab601a6008613718565b604a60ff919091161b612bc060196008613718565b603960ff919091161b612bd560186008613718565b601960ff919091161b612bea60176008613718565b604960ff919091161b612bff60166008613718565b605b60ff919091161b612c1460156008613718565b603960ff919091161b612c2960146008613718565b60b960ff919091161b612c3e60136008613718565b604160ff919091161b612c5360126008613718565b603160ff919091161b612c6860116008613718565b60fa60ff919091161b612c7d60106008613718565b600960ff919091161b612c92600f6008613718565b505f612ca0600e6008613718565b505f612cae600d6008613718565b505f612cbc600c6008613718565b505f612cca600b6008613718565b505f612cd8600a6008613718565b505f612ce660096008613718565b505f612cf3600880613718565b505f612d0160076008613718565b505f612d0f60066008613718565b505f612d1d60056008613718565b505f612d2b60046008613718565b601260ff919091161b612d4060036008613718565b60a160ff919091161b612d5560026008613718565b602160ff919091161b612d6a60016008613718565b60ff166021901b612d7b919061373b565b612d85919061373b565b612d8f919061373b565b612d99919061373b565b612da3919061373b565b612dad919061373b565b612db7919061373b565b612dc1919061373b565b612dcb919061373b565b612dd5919061373b565b612ddf919061373b565b612de9919061373b565b612df3919061373b565b612dfd919061373b565b612e07919061373b565b612e11919061373b565b612e1b919061373b565b612e25919061373b565b612e2f919061373b565b612e39919061373b565b612e43919061373b565b612e4d919061373b565b612e57919061373b565b612e61919061373b565b612e6b919061373b565b612e75919061373b565b612e7f919061373b565b612e89919061373b565b612e93919061373b565b612e9d919061373b565b612ea882601f6136ff565b60ff1660208110612ebb57612ebb6136a5565b1a5b915060171960ff821601612ef557612ed98361ffff8416613030565b612ee490600261374e565b612eee908361374e565b91506117db565b60181960ff821601612f0f57612ed98361ffff8416613030565b601f1960ff821601612f2957612ed98361ffff8416613030565b60201960ff8216016117db57612f438361ffff8416613030565b612f4e90600261374e565b6117cc908361374e565b5f612f6482600161373b565b83511015612f8557604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f612f9a82600861373b565b83511015612fbb57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f612fd082601061373b565b83511015612ff157604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f61300682602061373b565b8351101561302757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61303c82600261373b565b8351101561305d57604051633b99b53d60e01b815260040160405180910390fd5b50016002015190565b5f61300682601061373b565b60608182601f011015613098576040516323d5783d60e11b815260040160405180910390fd5b6130a2828461373b565b845110156130c357604051633b99b53d60e01b815260040160405180910390fd5b6060821580156130e15760405191505f82526020820160405261312b565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561311a578051835260209283019201613102565b5050858452601f01601f1916604052505b50949350505050565b606081516080146131835760405162461bcd60e51b8152602060048201526019602482015278496e7075742073686f756c642062652031323820627974657360381b6044820152606401611525565b5f5b60808160ff161080156131ba5750828160ff16815181106131a8576131a86136a5565b01602001516001600160f81b03191615155b156131d157806131c9816136cd565b915050613185565b5f8160ff166001600160401b038111156131ed576131ed6136eb565b6040519080825280601f01601f191660200182016040528015613217576020820181803683370190505b5090505f5b8260ff168160ff16101561327d57848160ff168151811061323f5761323f6136a5565b602001015160f81c60f81b828260ff168151811061325f5761325f6136a5565b60200101906001600160f81b03191690815f1a90535060010161321c565b509392505050565b5f818351116132a757604051633b99b53d60e01b815260040160405180910390fd5b8282815181106132b9576132b96136a5565b01602001516001600160f81b0319161515905092915050565b6001600160a01b0391909116815260200190565b5f5f83601f8401126132f6575f5ffd5b5081356001600160401b0381111561330c575f5ffd5b602083019150836020828501011115613323575f5ffd5b9250929050565b5f5f6020838503121561333b575f5ffd5b82356001600160401b03811115613350575f5ffd5b61335c858286016132e6565b90969095509350505050565b6001600160401b0391909116815260200190565b5f5f5f6040848603121561338e575f5ffd5b833561ffff8116811461339f575f5ffd5b925060208401356001600160401b038111156133b9575f5ffd5b6133c5868287016132e6565b9497909650939450505050565b80356001600160a01b03811681146133e8575f5ffd5b919050565b5f602082840312156133fd575f5ffd5b610261826133d2565b5f5f60408385031215613417575f5ffd5b82359150613427602084016133d2565b90509250929050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03851681526001600160801b0319841660208201526001600160801b03831660408201526080606082018190525f906134b490830184613444565b9695505050505050565b6001600160401b03881681526001600160801b03198716602082015260e0604082018190525f906134f190830188613444565b82810360608401526135038188613444565b60ff969096166080840152505060a08101929092526001600160a01b031660c090910152949350505050565b6001600160401b0394851681526001600160801b03199390931660208401526001600160801b03919091166040830152909116606082015260800190565b6001600160401b03851681526001600160801b0319841660208201526080604082018190525f906135a090830185613444565b82810360608401526135b28185613444565b979650505050505050565b6001600160401b03841681526001600160801b0319831660208201526060604082018190525f906135f090830184613444565b95945050505050565b6001600160401b03851681526001600160801b0319841660208201526001600160a01b03831660408201526080606082018190525f906134b490830184613444565b6001600160401b03861681526001600160801b0319851660208201526001600160801b03841660408201526001600160a01b038316606082015260a081016003831061369557634e487b7160e01b5f52602160045260245ffd5b8260808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036136e2576136e26136b9565b60010192915050565b634e487b7160e01b5f52604160045260245ffd5b60ff8281168282160390811115610264576102646136b9565b60ff8181168382160290811690818114613734576137346136b9565b5092915050565b80820180821115610264576102646136b9565b61ffff8181168382160190811115610264576102646136b956fea26469706673582212204ddc3189e664c8eacd053fd177c15840896bdc59375965b656c8c1e82211de9f64736f6c634300081c00330000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f00000000000000000000000094269dbaba605b63321221679df1356be0c00e630000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100ad575f3560e01c806322285cf6146100b1578063268808c6146100da578063365a86fc146101015780633b514cf11461011457806347bfbcc6146101345780634f35b71c1461014757806365fae35e1461015c5780636c3be0ce1461016f5780639c52a7f114610195578063bf353dbb146101a8578063d4e8be83146101d5578063ebf0c717146101e8578063ed15d9601461020f575b5f5ffd5b6003546100c4906001600160a01b031681565b6040516100d191906132d2565b60405180910390f35b6100c47f00000000000000000000000094269dbaba605b63321221679df1356be0c00e6381565b6001546100c4906001600160a01b031681565b61012761012236600461332a565b610222565b6040516100d19190613368565b6002546100c4906001600160a01b031681565b61015a61015536600461337c565b61026a565b005b61015a61016a3660046133ed565b611535565b61018261017d36600461332a565b6115a8565b60405161ffff90911681526020016100d1565b61015a6101a33660046133ed565b6115e7565b6101c76101b63660046133ed565b5f6020819052908152604090205481565b6040519081526020016100d1565b61015a6101e3366004613406565b611659565b6100c47f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f81565b6004546100c4906001600160a01b031681565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117a892505050565b90505b92915050565b335f908152602081905260409020546001146102995760405163ea8e4eb560e01b815260040160405180910390fd5b5f6102d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506117e192505050565b90505f61031984848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061180092505050565b905061ffff8116158061033357508461ffff168161ffff16145b61035057604051639284b19760e01b815260040160405180910390fd5b600182602281111561036457610364613430565b03610434575f6103a885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506118b192505050565b90507f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f6001600160a01b0316633b6874616103e5835f0151611919565b6040518263ffffffff1660e01b815260040161040191906132d2565b5f604051808303815f87803b158015610418575f5ffd5b505af115801561042a573d5f5f3e3d5ffd5b505050505061152e565b600282602281111561044857610448613430565b036104c9575f61048c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061197392505050565b90507f0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f6001600160a01b03166311fd3baa6103e5835f0151611919565b60038260228111156104dd576104dd613430565b036105ce575f61052185858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061198892505050565b90507f00000000000000000000000094269dbaba605b63321221679df1356be0c00e636001600160a01b031663109037c061055e835f0151611919565b61056b8460200151611919565b846040015161057d8660600151611919565b608087015160405160e087901b6001600160e01b03191681526001600160a01b039586166004820152938516602485015260448401929092529092166064820152608481019190915260a401610401565b60048260228111156105e2576105e2613430565b03610670575f61062685858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611a4692505050565b60015481516020830151604051633207adab60e01b81526001600160801b03909216600483015260ff1660248201529192506001600160a01b031690633207adab90604401610401565b602082602281111561068457610684613430565b0361070e575f6106c885858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611acd92505050565b6001548151602083015160408085015160608601519151632f6c33bf60e01b81529596506001600160a01b0390941694632f6c33bf946104019493929091600401613472565b601082602281111561072257610722613430565b036107cd57600254604080516020601f87018190048102820181019092528581526001600160a01b0390921691632b89610191610779919088908890819084018382808284375f92019190915250611bae92505050565b516040516001600160e01b031960e084901b16815261079b9190600401613368565b5f604051808303815f87803b1580156107b2575f5ffd5b505af11580156107c4573d5f5f3e3d5ffd5b5050505061152e565b60118260228111156107e1576107e1613430565b03610891575f61082585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1e92505050565b60025481516020830151604084015160608501519495506001600160a01b0390931693636ea6e0a1939061085890611d3f565b86608001518760a0015161086f8960c00151611919565b6040518863ffffffff1660e01b815260040161040197969594939291906134be565b60128260228111156108a5576108a5613430565b0361092f575f6108e985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b6002548151602083015160408085015160608601519151634869ac6960e01b81529596506001600160a01b0390941694634869ac6994610401949392909160040161352f565b601382602281111561094357610943613430565b03610a08575f61098785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611f2b92505050565b60025481516020830151604080850151606086015160808701519251633a4ba8bf60e01b81526001600160401b0395861660048201526001600160801b031990941660248501526001600160801b0391821660448501521660648301529190911660848201529192506001600160a01b031690633a4ba8bf9060a401610401565b6014826022811115610a1c57610a1c613430565b03610ab2575f610a6085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061200b92505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363931efb549390610a9390611d3f565b6040518563ffffffff1660e01b8152600401610401949392919061356d565b6015826022811115610ac657610ac6613430565b03610b83575f610b0a85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506120c892505050565b6002548151602083015160408401519394506001600160a01b039092169263fb59077a9290610b3890611919565b6040516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160801b031990911660248301526001600160a01b03166044820152606401610401565b6016826022811115610b9757610b97613430565b03610c6a575f610bdb85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061216892505050565b600154604082810151835160208501516060860151608087015160a0880151955163ecca8cf760e01b815261ffff90951660048601526001600160401b0390931660248501526001600160801b0319909116604484015260648301526001600160801b03908116608483015290911660a48201529192506001600160a01b03169063ecca8cf79060c401610401565b6017826022811115610c7e57610c7e613430565b03610d35575f610cc285858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061226b92505050565b600254815160208301516040808501516060860151915163bccbfa8960e01b81526001600160401b0390941660048501526001600160801b0319909216602484015260448301919091526001600160801b031660648201529192506001600160a01b03169063bccbfa8990608401610401565b6018826022811115610d4957610d49613430565b03610dcc575f610d8d85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061232292505050565b600254815160208301516040808501519051630f8dad5d60e11b81529495506001600160a01b0390931693631f1b5aba936104019392916004016135bd565b6019826022811115610de057610de0613430565b03610e76575f610e2485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506123dc92505050565b6004548151602083015160408401519394506001600160a01b0390921692630b1271059290610e5290611919565b85606001516040518563ffffffff1660e01b815260040161040194939291906135f9565b6021826022811115610e8a57610e8a613430565b03610f14575f610ece85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124ad92505050565b60025481516020830151604080850151606086015191516336c6cf3760e21b81529596506001600160a01b039094169463db1b3cdc946104019493929091600401613472565b601a826022811115610f2857610f28613430565b03610fd8575f610f6c85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506124d692505050565b60025481516020830151604084015160608501519495506001600160a01b039093169363b3cfb8179390610f9f90611919565b866080015160ff166002811115610fb857610fb8613430565b6040518663ffffffff1660e01b815260040161040195949392919061363b565b6022826022811115610fec57610fec613430565b036110bc575f61103085858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506125ad92505050565b60025481516020830151604084015160608501519495506001600160a01b03909316936325dc4956939061106390611919565b6040516001600160e01b031960e087901b1681526001600160401b0390941660048501526001600160801b031990921660248401526001600160801b031660448301526001600160a01b03166064820152608401610401565b601b8260228111156110d0576110d0613430565b03611185575f61111485858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061266d92505050565b600354815160208301519293506001600160a01b039091169163a6fd509b919061113d90611919565b60408086015190516001600160e01b031960e086901b1681526001600160401b0390931660048401526001600160a01b03909116602483015215156044820152606401610401565b601c82602281111561119957611199613430565b036112b1575f6111dd85858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061270d92505050565b905060015f9054906101000a90046001600160a01b03166001600160a01b0316630646affc87835f015184602001518560400151866060015187608001518860c001518960e001518a61010001516040518a63ffffffff1660e01b81526004016104019998979695949392919061ffff9990991689526001600160401b0397881660208a01526001600160801b03199690961660408901526001600160801b0394851660608901529284166080880152921660a086015290151560c0850152151560e0840152166101008201526101200190565b601d8260228111156112c5576112c5613430565b036113a1575f61130985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061288692505050565b60015481516020830151604080850151608086015160a087015160c08801519351631de0563360e21b815261ffff8f1660048201526001600160401b0396871660248201526001600160801b031990951660448601526001600160801b03909216606485015215156084840152151560a48301529190911660c48201529192506001600160a01b03169063778158cc9060e401610401565b601e8260228111156113b5576113b5613430565b0361143f575f6113f985858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061299892505050565b6002548151602083015160408085015160608601519151636a4873e160e11b81529596506001600160a01b039094169463d490e7c294610401949392909160040161352f565b601f82602281111561145357611453613430565b036114f8575f61149785858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506129c292505050565b60025481516020830151604080850151905163eece6c4360e01b81526001600160401b0393841660048201526001600160801b031990921660248301529190911660448201529192506001600160a01b03169063eece6c4390606401610401565b81602281111561150a5761150a613430565b604051630391465960e11b815260ff90911660048201526024015b60405180910390fd5b5050505050565b335f908152602081905260409020546001146115645760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f8181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b5f61026183838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612a6292505050565b335f908152602081905260409020546001146116165760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0381165f81815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b335f908152602081905260409020546001146116885760405163ea8e4eb560e01b815260040160405180910390fd5b8162343ab160e91b036116b557600180546001600160a01b0319166001600160a01b03831617905561176c565b816473706f6b6560d81b036116e457600280546001600160a01b0319166001600160a01b03831617905561176c565b816b18985b185b98d954da19595d60a21b0361171a57600380546001600160a01b0319166001600160a01b03831617905561176c565b816e31b7b73a3930b1ba2ab83230ba32b960891b0361175357600480546001600160a01b0319166001600160a01b03831617905561176c565b604051633db0d5b960e01b815260040160405180910390fd5b817f8fef588b5fc1afbf5b2f06c1a435d513f208da2e6704c3d8f0e0ec91167066ba8260405161179c91906132d2565b60405180910390a25050565b5f806117b48382612f58565b9050601060ff8216106117d3576117cc836001612f8e565b9392505050565b505f92915050565b50919050565b5f6117ec8282612f58565b60ff16602281111561026457610264613430565b5f8061180c8382612f58565b9050600360ff82161161182157505f92915050565b60ff8116601d1480611836575060ff81166016145b1561184357505f92915050565b60031960ff821601611867576117cc61185d846001612fc4565b60701c61ffff1690565b601b1960ff821601611881576117cc61185d846019612fc4565b601f1960ff82160161189b576117cc61185d846019612fc4565b6117cc6118a7846117a8565b60301c61ffff1690565b60408051602081019091525f815260015b6118cb836117e1565b60228111156118dc576118dc613430565b146118fa576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611911846001612ffa565b905292915050565b5f6001600160601b0382161561196c5760405162461bcd60e51b8152602060048201526018602482015277496e7075742073686f756c6420626520323020627974657360401b6044820152606401611525565b5060601c90565b60408051602081019091525f815260026118c2565b6119b56040518060a001604052805f81526020015f81526020015f81526020015f81526020015f81525090565b60036119c0836117e1565b60228111156119d1576119d1613430565b146119ef576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611a06846001612ffa565b8152602001611a16846021612ffa565b8152602001611a26846041612ffa565b8152602001611a36846061612ffa565b8152602001611911846081612ffa565b604080518082019091525f80825260208201526004611a64836117e1565b6022811115611a7557611a75613430565b14611a93576040516304c735eb60e11b815260040160405180910390fd5b6040805180820190915280611aa9846001612fc4565b6001600160801b03168152602001611ac2846011612f58565b60ff16905292915050565b604080516080810182525f808252602080830182905292820152606080820152905b611af8836117e1565b6022811115611b0957611b09613430565b14611b27576040516304c735eb60e11b815260040160405180910390fd5b5f611b33836029613030565b90506040518060800160405280611b54600186612f8e90919063ffffffff16565b6001600160401b03168152602001611b6d856009613066565b6001600160801b0319168152602001611b87856019612fc4565b6001600160801b03168152602001611ba585602b61ffff8616613072565b90529392505050565b60408051602081019091525f81526010611bc7836117e1565b6022811115611bd857611bd8613430565b14611bf6576040516304c735eb60e11b815260040160405180910390fd5b604080516020810190915280611c0d846001612f8e565b6001600160401b0316905292915050565b611c6e6040518060e001604052805f6001600160401b031681526020015f6001600160801b0319168152602001606081526020015f81526020015f60ff1681526020015f81526020015f81525090565b6011611c79836117e1565b6022811115611c8a57611c8a613430565b14611ca8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e0810190915280611cbf846001612f8e565b6001600160401b03168152602001611cd8846009613066565b6001600160801b0319168152602001611cfc611cf78560196080613072565b613134565b8152602001611d0c846099612ffa565b8152602001611d1c8460b9612f58565b60ff168152602001611d2f8460ba612ffa565b81526020016119118460da612ffa565b60605f5b60208160ff16108015611d775750828160ff1660208110611d6657611d666136a5565b1a60f81b6001600160f81b03191615155b15611d8e5780611d86816136cd565b915050611d43565b5f8160ff166001600160401b03811115611daa57611daa6136eb565b6040519080825280601f01601f191660200182016040528015611dd4576020820181803683370190505b5090505f91505b60208260ff16108015611e0f5750838260ff1660208110611dfe57611dfe6136a5565b1a60f81b6001600160f81b03191615155b156117cc57838260ff1660208110611e2957611e296136a5565b1a60f81b818360ff1681518110611e4257611e426136a5565b60200101906001600160f81b03191690815f1a90535081611e62816136cd565b925050611ddb565b604080516080810182525f80825260208201819052918101829052606081019190915260125b611e99836117e1565b6022811115611eaa57611eaa613430565b14611ec8576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280611edf846001612f8e565b6001600160401b03168152602001611ef8846009613066565b6001600160801b0319168152602001611f12846019612fc4565b6001600160801b03168152602001611c0d846029612f8e565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526013611f60836117e1565b6022811115611f7157611f71613430565b14611f8f576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280611fa6846001612f8e565b6001600160401b03168152602001611fbf846009613066565b6001600160801b0319168152602001611fd9846019612fc4565b6001600160801b03168152602001611ff2846029612fc4565b6001600160801b03168152602001611c0d846039612f8e565b604080516080810182525f80825260208201819052606092820183905291810191909152601461203a836117e1565b602281111561204b5761204b613430565b14612069576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612080846001612f8e565b6001600160401b03168152602001612099846009613066565b6001600160801b03191681526020016120b8611cf78560196080613072565b8152602001611911846099612ffa565b604080516060810182525f808252602082018190529181019190915260156120ef836117e1565b602281111561210057612100613430565b1461211e576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612135846001612f8e565b6001600160401b0316815260200161214e846009613066565b6001600160801b0319168152602001611911846019612ffa565b6040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915260166121a4836117e1565b60228111156121b5576121b5613430565b146121d3576040516304c735eb60e11b815260040160405180910390fd5b6040805160c08101909152806121ea846001612f8e565b6001600160401b03168152602001612203846009613066565b6001600160801b031916815260200161221d846019613030565b61ffff16815260200161223184601b612ffa565b815260200161224184603b612fc4565b6001600160801b0316815260200161225a84604b612fc4565b6001600160801b0316905292915050565b604080516080810182525f8082526020820181905291810182905260608101919091526017612299836117e1565b60228111156122aa576122aa613430565b146122c8576040516304c735eb60e11b815260040160405180910390fd5b6040805160808101909152806122df846001612f8e565b6001600160401b031681526020016122f8846009613066565b6001600160801b0319168152602001612312846019612ffa565b815260200161225a846039612fc4565b60408051606080820183525f8083526020830152918101919091526018612348836117e1565b602281111561235957612359613430565b14612377576040516304c735eb60e11b815260040160405180910390fd5b5f612383836019613030565b905060405180606001604052806123a4600186612f8e90919063ffffffff16565b6001600160401b031681526020016123bd856009613066565b6001600160801b0319168152602001611ba585601b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526019612409836117e1565b602281111561241a5761241a613430565b14612438576040516304c735eb60e11b815260040160405180910390fd5b5f612444836039613030565b90506040518060800160405280612465600186612f8e90919063ffffffff16565b6001600160401b0316815260200161247e856009613066565b6001600160801b0319168152602001612498856019612ffa565b8152602001611ba585603b61ffff8616613072565b604080516080810182525f80825260208201819052918101919091526060808201526021611aef565b6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152601a61250b836117e1565b602281111561251c5761251c613430565b1461253a576040516304c735eb60e11b815260040160405180910390fd5b6040805160a0810190915280612551846001612f8e565b6001600160401b0316815260200161256a846009613066565b6001600160801b0319168152602001612584846019612fc4565b6001600160801b0316815260200161259d846029612ffa565b8152602001611ac2846049612f58565b604080516080810182525f80825260208201819052918101829052606081019190915260226125db836117e1565b60228111156125ec576125ec613430565b1461260a576040516304c735eb60e11b815260040160405180910390fd5b604080516080810190915280612621846001612f8e565b6001600160401b0316815260200161263a846009613066565b6001600160801b0319168152602001612654846019612fc4565b6001600160801b03168152602001611911846029612ffa565b604080516060810182525f8082526020820181905291810191909152601b612694836117e1565b60228111156126a5576126a5613430565b146126c3576040516304c735eb60e11b815260040160405180910390fd5b6040805160608101909152806126da846001612f8e565b6001600160401b031681526020016126f3846009612ffa565b8152602001612703846029613285565b1515905292915050565b60408051610120810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152601c612760836117e1565b602281111561277157612771613430565b146127b35760405162461bcd60e51b8152602060048201526012602482015271556e6b6e6f776e4d6573736167655479706560701b6044820152606401611525565b604080516101208101909152806127cb846001612f8e565b6001600160401b031681526020016127e4846009613066565b6001600160801b03191681526020016127fe846019612fc4565b6001600160801b03168152602001612817846029612fc4565b6001600160801b03168152602001612830846039612fc4565b6001600160801b03168152602001612849846049612f8e565b6001600160401b03168152602001612862846051613285565b15158152602001612874846052613285565b15158152602001611c0d846053612f8e565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152601d6128c9836117e1565b60228111156128da576128da613430565b146128f8576040516304c735eb60e11b815260040160405180910390fd5b6040805160e081019091528061290f846001612f8e565b6001600160401b03168152602001612928846009613066565b6001600160801b0319168152602001612942846019612fc4565b6001600160801b0316815260200161295b846029612f8e565b6001600160401b03168152602001612974846031613285565b15158152602001612986846032613285565b15158152602001611c0d846033612f8e565b604080516080810182525f808252602082018190529181018290526060810191909152601e611e90565b604080516060810182525f8082526020820181905291810191909152601f6129e9836117e1565b60228111156129fa576129fa613430565b14612a18576040516304c735eb60e11b815260040160405180910390fd5b604080516060810190915280612a2f846001612f8e565b6001600160401b03168152602001612a48846009613066565b6001600160801b0319168152602001611c0d846019612f8e565b5f80612a6e8382612f58565b9050602260ff82161115612a95576040516304c735eb60e11b815260040160405180910390fd5b601f8160ff161115612b3657612aad602060226136ff565b612ab8906008613718565b604960ff919091161b612acd602060216136ff565b612ad8906008613718565b602960ff919091161b612aec6020806136ff565b612af7906008613718565b60ff166029901b612b08919061373b565b612b12919061373b565b612b1d82603f6136ff565b60ff1660208110612b3057612b306136a5565b1a612ebd565b612b42601f6008613718565b602160ff919091161b612b57601e6008613718565b603160ff919091161b612b6c601d6008613718565b603b60ff919091161b612b81601c6008613718565b605b60ff919091161b612b96601b6008613718565b602a60ff919091161b612bab601a6008613718565b604a60ff919091161b612bc060196008613718565b603960ff919091161b612bd560186008613718565b601960ff919091161b612bea60176008613718565b604960ff919091161b612bff60166008613718565b605b60ff919091161b612c1460156008613718565b603960ff919091161b612c2960146008613718565b60b960ff919091161b612c3e60136008613718565b604160ff919091161b612c5360126008613718565b603160ff919091161b612c6860116008613718565b60fa60ff919091161b612c7d60106008613718565b600960ff919091161b612c92600f6008613718565b505f612ca0600e6008613718565b505f612cae600d6008613718565b505f612cbc600c6008613718565b505f612cca600b6008613718565b505f612cd8600a6008613718565b505f612ce660096008613718565b505f612cf3600880613718565b505f612d0160076008613718565b505f612d0f60066008613718565b505f612d1d60056008613718565b505f612d2b60046008613718565b601260ff919091161b612d4060036008613718565b60a160ff919091161b612d5560026008613718565b602160ff919091161b612d6a60016008613718565b60ff166021901b612d7b919061373b565b612d85919061373b565b612d8f919061373b565b612d99919061373b565b612da3919061373b565b612dad919061373b565b612db7919061373b565b612dc1919061373b565b612dcb919061373b565b612dd5919061373b565b612ddf919061373b565b612de9919061373b565b612df3919061373b565b612dfd919061373b565b612e07919061373b565b612e11919061373b565b612e1b919061373b565b612e25919061373b565b612e2f919061373b565b612e39919061373b565b612e43919061373b565b612e4d919061373b565b612e57919061373b565b612e61919061373b565b612e6b919061373b565b612e75919061373b565b612e7f919061373b565b612e89919061373b565b612e93919061373b565b612e9d919061373b565b612ea882601f6136ff565b60ff1660208110612ebb57612ebb6136a5565b1a5b915060171960ff821601612ef557612ed98361ffff8416613030565b612ee490600261374e565b612eee908361374e565b91506117db565b60181960ff821601612f0f57612ed98361ffff8416613030565b601f1960ff821601612f2957612ed98361ffff8416613030565b60201960ff8216016117db57612f438361ffff8416613030565b612f4e90600261374e565b6117cc908361374e565b5f612f6482600161373b565b83511015612f8557604051633b99b53d60e01b815260040160405180910390fd5b50016001015190565b5f612f9a82600861373b565b83511015612fbb57604051633b99b53d60e01b815260040160405180910390fd5b50016008015190565b5f612fd082601061373b565b83511015612ff157604051633b99b53d60e01b815260040160405180910390fd5b50016010015190565b5f61300682602061373b565b8351101561302757604051633b99b53d60e01b815260040160405180910390fd5b50016020015190565b5f61303c82600261373b565b8351101561305d57604051633b99b53d60e01b815260040160405180910390fd5b50016002015190565b5f61300682601061373b565b60608182601f011015613098576040516323d5783d60e11b815260040160405180910390fd5b6130a2828461373b565b845110156130c357604051633b99b53d60e01b815260040160405180910390fd5b6060821580156130e15760405191505f82526020820160405261312b565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561311a578051835260209283019201613102565b5050858452601f01601f1916604052505b50949350505050565b606081516080146131835760405162461bcd60e51b8152602060048201526019602482015278496e7075742073686f756c642062652031323820627974657360381b6044820152606401611525565b5f5b60808160ff161080156131ba5750828160ff16815181106131a8576131a86136a5565b01602001516001600160f81b03191615155b156131d157806131c9816136cd565b915050613185565b5f8160ff166001600160401b038111156131ed576131ed6136eb565b6040519080825280601f01601f191660200182016040528015613217576020820181803683370190505b5090505f5b8260ff168160ff16101561327d57848160ff168151811061323f5761323f6136a5565b602001015160f81c60f81b828260ff168151811061325f5761325f6136a5565b60200101906001600160f81b03191690815f1a90535060010161321c565b509392505050565b5f818351116132a757604051633b99b53d60e01b815260040160405180910390fd5b8282815181106132b9576132b96136a5565b01602001516001600160f81b0319161515905092915050565b6001600160a01b0391909116815260200190565b5f5f83601f8401126132f6575f5ffd5b5081356001600160401b0381111561330c575f5ffd5b602083019150836020828501011115613323575f5ffd5b9250929050565b5f5f6020838503121561333b575f5ffd5b82356001600160401b03811115613350575f5ffd5b61335c858286016132e6565b90969095509350505050565b6001600160401b0391909116815260200190565b5f5f5f6040848603121561338e575f5ffd5b833561ffff8116811461339f575f5ffd5b925060208401356001600160401b038111156133b9575f5ffd5b6133c5868287016132e6565b9497909650939450505050565b80356001600160a01b03811681146133e8575f5ffd5b919050565b5f602082840312156133fd575f5ffd5b610261826133d2565b5f5f60408385031215613417575f5ffd5b82359150613427602084016133d2565b90509250929050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160401b03851681526001600160801b0319841660208201526001600160801b03831660408201526080606082018190525f906134b490830184613444565b9695505050505050565b6001600160401b03881681526001600160801b03198716602082015260e0604082018190525f906134f190830188613444565b82810360608401526135038188613444565b60ff969096166080840152505060a08101929092526001600160a01b031660c090910152949350505050565b6001600160401b0394851681526001600160801b03199390931660208401526001600160801b03919091166040830152909116606082015260800190565b6001600160401b03851681526001600160801b0319841660208201526080604082018190525f906135a090830185613444565b82810360608401526135b28185613444565b979650505050505050565b6001600160401b03841681526001600160801b0319831660208201526060604082018190525f906135f090830184613444565b95945050505050565b6001600160401b03851681526001600160801b0319841660208201526001600160a01b03831660408201526080606082018190525f906134b490830184613444565b6001600160401b03861681526001600160801b0319851660208201526001600160801b03841660408201526001600160a01b038316606082015260a081016003831061369557634e487b7160e01b5f52602160045260245ffd5b8260808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036136e2576136e26136b9565b60010192915050565b634e487b7160e01b5f52604160045260245ffd5b60ff8281168282160390811115610264576102646136b9565b60ff8181168382160290811690818114613734576137346136b9565b5092915050565b80820180821115610264576102646136b9565b61ffff8181168382160190811115610264576102646136b956fea26469706673582212204ddc3189e664c8eacd053fd177c15840896bdc59375965b656c8c1e82211de9f64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f00000000000000000000000094269dbaba605b63321221679df1356be0c00e630000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
-----Decoded View---------------
Arg [0] : root_ (address): 0x7Ed48C31f2fdC40d37407cBaBf0870B2b688368f
Arg [1] : tokenRecoverer_ (address): 0x94269dBaBA605b63321221679df1356be0c00E63
Arg [2] : deployer (address): 0x5f3f8ea3b54BFF7795dE7754866e0Eac52e0881d
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000007ed48c31f2fdc40d37407cbabf0870b2b688368f
Arg [1] : 00000000000000000000000094269dbaba605b63321221679df1356be0c00e63
Arg [2] : 0000000000000000000000005f3f8ea3b54bff7795de7754866e0eac52e0881d
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.