Overview
MNT Balance
MNT Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 7,836 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Approve | 90345531 | 6 days ago | IN | 0 MNT | 0.0032605 | ||||
| Approve | 90345362 | 6 days ago | IN | 0 MNT | 0.00323875 | ||||
| Approve | 90144897 | 11 days ago | IN | 0 MNT | 0.00384062 | ||||
| Approve | 89809828 | 19 days ago | IN | 0 MNT | 0.0034992 | ||||
| Approve | 89681535 | 22 days ago | IN | 0 MNT | 0.00283495 | ||||
| Approve | 89434860 | 27 days ago | IN | 0 MNT | 0.00273216 | ||||
| Approve | 89057295 | 36 days ago | IN | 0 MNT | 0.00139002 | ||||
| Approve | 88812390 | 42 days ago | IN | 0 MNT | 0.00302326 | ||||
| Approve | 88797533 | 42 days ago | IN | 0 MNT | 0.0024064 | ||||
| Approve | 88797065 | 42 days ago | IN | 0 MNT | 0.00268722 | ||||
| Approve | 88580380 | 47 days ago | IN | 0 MNT | 0.00394722 | ||||
| Transfer | 88538213 | 48 days ago | IN | 0 MNT | 0.00278728 | ||||
| Transfer | 88537990 | 48 days ago | IN | 0.98540225 MNT | 0.00127495 | ||||
| Approve | 88250407 | 55 days ago | IN | 0 MNT | 0.00271362 | ||||
| Approve | 88135464 | 58 days ago | IN | 0 MNT | 0.00390696 | ||||
| Approve | 88041960 | 60 days ago | IN | 0 MNT | 0.00284748 | ||||
| Approve | 88041937 | 60 days ago | IN | 0 MNT | 0.00282014 | ||||
| Approve | 87978457 | 61 days ago | IN | 0 MNT | 0.00328214 | ||||
| Approve | 87959084 | 62 days ago | IN | 0 MNT | 0.0033374 | ||||
| Approve | 87940295 | 62 days ago | IN | 0 MNT | 0.00326258 | ||||
| Approve | 87912723 | 63 days ago | IN | 0 MNT | 0.00258919 | ||||
| Approve | 87904832 | 63 days ago | IN | 0 MNT | 0.00258542 | ||||
| Approve | 87795266 | 65 days ago | IN | 0 MNT | 0.00296223 | ||||
| Approve | 87795250 | 65 days ago | IN | 0 MNT | 0.00295915 | ||||
| Approve | 87754580 | 66 days ago | IN | 0 MNT | 0.00162398 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 86702501 | 91 days ago | Contract Creation | 0 MNT |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrintrMainTelecoin } from "../interfaces/telecoin/IPrintrMainTelecoin.sol";
import { ERC20 } from "./ERC20.sol";
import { Printed } from "./Printed.sol";
import { Telecoin } from "./Telecoin.sol";
/**
* @title PrintrMainTelecoin
* @notice Implementation of a Main Telecoin with teleport interface and interchain functionality
* @dev Extends Telecoin and InterchainStandard to provide cross-chain functionality
* @dev Bridging is only possible with lock/unlock/transferFrom, there are no mint/burn mechanisms
*/
contract PrintrTelecoin is IPrintrMainTelecoin, Printed, Telecoin {
/**
* @notice Initializes the token with its basic parameters
* @param params The deployment parameters for the telecoin
* @param treasury Address to receive the initial token supply
* @param initialSupply The initial supply to mint
*/
constructor(
TelecoinDeployParams memory params,
address treasury,
uint256 initialSupply
) Printed(params.printr, treasury, initialSupply, false) Telecoin(params) { }
/**
* @notice Internal function to handle token transfers with additional restrictions
* @dev Override of ERC20._update that includes Printed contract restrictions.
* First checks if the transfer violates bonding curve completion rules,
* then performs the actual balance update. This ensures tokens cannot be
* added to liquidity pools before the bonding curve is completed.
* @param from The address tokens are being transferred from (address(0) for minting)
* @param to The address tokens are being transferred to (address(0) for burning)
* @param amount The amount of tokens being transferred
* @custom:throws CurveIsNotComplete if attempting to add tokens to restricted pool before completion
*/
function _update(
address from,
address to,
uint256 amount
) internal override(Printed, ERC20) {
// Check Liquidity position opening restrictions
Printed._update(from, to, amount);
// Update balances
ERC20._update(from, to, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrinted } from "./IPrinted.sol";
import { ITelecoin } from "./ITelecoin.sol";
/**
* @title IPrintrTeleportingTelecoin
* @notice Interface for the PrintrTelecoin contract with teleport and curve completion functionality
* @dev Extends ITelecoin interface with additional token management functions
*/
interface IPrintrMainTelecoin is IPrinted, ITelecoin { }// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import { IERC20Permit } from "../interfaces/telecoin/IERC20Permit.sol";
import { IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
* @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
* @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
*/
contract ERC20 is IERC20Permit, IERC20Metadata, IERC20Errors {
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
EIP-2612 CONSTANTS
//////////////////////////////////////////////////////////////*/
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the ERC20 token with metadata and EIP-2612 permit functionality
* @dev Sets up the token name, symbol, decimals and initializes EIP-712 domain separator for permit signatures
* @param _name The human-readable name of the token (e.g. "My Token")
* @param _symbol The token symbol used on exchanges (e.g. "MTK")
* @param _decimals Number of decimal places for token amounts (typically 18 for most ERC20 tokens)
*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Approves another account to spend tokens on behalf of the caller
* @dev Implements the standard ERC20 approve function with unlimited allowance support
* @param spender The address that will be allowed to spend the tokens
* @param value The amount of tokens to approve for spending (in token's decimal units)
* @return Always returns true to indicate successful approval
*/
function approve(
address spender,
uint256 value
) public virtual returns (bool) {
allowance[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @notice Transfers tokens from the caller to another address
* @dev Uses internal _update function to handle balance changes and emit Transfer event
* @param to The recipient address to transfer tokens to
* @param value The amount of tokens to transfer (in token's decimal units)
* @return Always returns true to indicate successful transfer
*/
function transfer(
address to,
uint256 value
) public virtual returns (bool) {
_update(msg.sender, to, value);
return true;
}
/**
* @notice Transfers tokens from one address to another using allowance mechanism
* @dev Checks and updates allowance before transferring. Unlimited allowance (type(uint256).max) is not
* decremented
* @param from The address to transfer tokens from (must have sufficient balance)
* @param to The recipient address to transfer tokens to
* @param value The amount of tokens to transfer (in token's decimal units)
* @return Always returns true to indicate successful transfer
*/
function transferFrom(
address from,
address to,
uint256 value
) public virtual returns (bool) {
address spender = msg.sender;
uint256 allowed = allowance[from][spender];
if (allowed != type(uint256).max) {
if (allowed < value) {
revert ERC20InsufficientAllowance(spender, allowed, value);
}
allowance[from][spender] = allowed - value;
}
_update(from, to, value);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Permits an allowance to be set via signature, implementing EIP-2612
* @dev Validates the signature against EIP-712 typed data and sets allowance without requiring a transaction from
* owner
* @param owner The address that owns the tokens and is granting the allowance
* @param spender The address that will be allowed to spend the tokens
* @param value The amount of tokens to approve for spending (in token's decimal units)
* @param deadline The timestamp after which the permit signature is no longer valid
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (deadline < block.timestamp) {
revert ERC2612ExpiredSignature(deadline);
}
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
bytes32 structHash =
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));
bytes32 hash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash));
address recoveredAddress = ecrecover(hash, v, r, s);
if (recoveredAddress == address(0) || recoveredAddress != owner) {
revert ERC2612InvalidSigner(recoveredAddress, owner);
}
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
/**
* @notice Invalidates the current nonce for msg.sender
* @dev Increments the nonce, making all outstanding permit signatures invalid
* This provides users with an emergency mechanism to cancel pending permits in case of:
* - Key compromise or suspected phishing
* - Changed mind about a signed but not executed permit
* - Need to invalidate multiple permits at once
* Emits a NonceInvalidated event
*/
function invalidateNonce() external {
unchecked {
emit NonceInvalidated(msg.sender, ++nonces[msg.sender]);
}
}
/**
* @notice Returns the domain separator for EIP-712 signature validation
* @dev Returns cached separator if chain ID hasn't changed, otherwise recomputes it
* @return The EIP-712 domain separator hash for this contract and chain
*/
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
/**
* @notice Computes the EIP-712 domain separator for the current chain and contract
* @dev Used for EIP-712 signature validation in permit functions
* @return The computed domain separator hash including contract name, version, chain ID, and address
*/
function computeDomainSeparator() internal view virtual returns (bytes32) {
return keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL UPDATE LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Internal function to handle token transfers, mints, and burns
* @dev Handles balance updates and total supply changes. Emits Transfer event for all operations
* @param from The address to transfer from (address(0) for minting)
* @param to The address to transfer to (address(0) for burning)
* @param value The amount of tokens to transfer/mint/burn (in token's decimal units)
*/
function _update(
address from,
address to,
uint256 value
) internal virtual {
if (from == address(0)) {
// Increase total supply
totalSupply += value;
} else {
// Transfer - decrease from balance
uint256 fromBalance = balanceOf[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
balanceOf[from] = fromBalance - value;
}
}
if (to == address(0)) {
// Decrease total supply
unchecked {
totalSupply -= value;
}
} else {
// Transfer or mint - increase to balance
unchecked {
balanceOf[to] += value;
}
}
emit Transfer(from, to, value);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrinted } from "../interfaces/telecoin/IPrinted.sol";
import { ITelecoin } from "../interfaces/telecoin/ITelecoin.sol";
import { TeleportingTelecoin } from "./Teleporting.sol";
/**
* @title PrintrTelecoin
* @notice Implementation of a Telecoin with teleport capabilities and interchain functionality
* @dev Extends Telecoin and InterchainStandard to provide cross-chain functionality
*/
abstract contract Printed is IPrinted {
/// @notice Whether this is a main telecoin (uses lock/unlock) or teleporting telecoin
bool public immutable isTeleporting;
/// @notice Address of the Printr contract that created this token
address private immutable printr;
/**
* @notice Enum representing the different states of curve completion
* @dev Used to track the progression of the bonding curve
* @custom:value NotInitialized - Initial state before any completion actions
* @custom:value Restricted - State where transfers are restricted to a specific pool
* @custom:value Completed - Final state where curve is completed and unrestricted
*/
enum CompletionState {
NotInitialized, // Not yet initialized
Restricted, // Restricted to specific pool
Completed // Curve completed
}
/**
* @notice Struct to pack pool address and state in single storage slot
* @dev Packs address (160 bits) and state (8 bits) into 256 bits for gas optimization
* @param pool The address of the liquidity pool (160 bits)
* @param state The current completion state of the curve (8 bits)
*/
struct CompletionStatus {
address pool; // Pool address (160 bits)
CompletionState state; // Completion state (8 bits)
}
/// @notice Tracks the completion status and restricted pool address
CompletionStatus public completionStatus;
/**
* @notice Initializes the token with its basic parameters
* @param _printr Address of the Printr contract that created this token
* @param _treasury Address to receive the initial token supply
* @param _initialSupply The initial supply to mint to treasury
* @param _isTeleporting Whether this is a main telecoin (true) or wrapped telecoin (false)
*/
constructor(
address _printr,
address _treasury,
uint256 _initialSupply,
bool _isTeleporting
) {
printr = _printr;
isTeleporting = _isTeleporting;
// Mint the chain total supply directly to the treasury
_update(address(0), _treasury, _initialSupply);
}
/**
* @notice Sets the restricted pool address during curve initialization
* @dev Can only be called by Printr before completion. Updates the completion status
* to restrict transfers to the specified pool address until curve is marked complete.
* Uses atomic storage writes for gas efficiency.
* @param poolAddress The pool address to restrict transfers to during curve completion phase
* @custom:throws UnauthorizedAccount if caller is not Printr or curve is already complete
* @custom:throws ZeroAddress if pool address is zero
*/
function setRestrictedPool(
address poolAddress
) external {
if (poolAddress == address(0)) {
revert ITelecoin.ZeroAddress();
}
if (msg.sender != printr || completionStatus.state == CompletionState.Completed) {
revert ITelecoin.UnauthorizedAccount(msg.sender);
}
// Write the entire struct atomically in a single SSTORE
completionStatus = CompletionStatus({ pool: poolAddress, state: CompletionState.Restricted });
}
/**
* @notice Marks the bonding curve as completed, removing transfer restrictions
* @dev Can only be called by Printr when curve is not already completed.
* Clears the restricted pool address and sets state to Completed, allowing
* unrestricted token transfers. Uses atomic storage writes for gas efficiency.
* @custom:throws UnauthorizedAccount if caller is not Printr or curve is already completed
*/
function markCurveComplete() external {
if (msg.sender != printr || completionStatus.state == CompletionState.Completed) {
revert ITelecoin.UnauthorizedAccount(msg.sender);
}
// Write the entire struct atomically in a single SSTORE
// Clear pool address when marking complete
completionStatus = CompletionStatus({ pool: address(0), state: CompletionState.Completed });
}
/**
* @notice Internal hook to handle token transfers
* @dev Prevents adding tokens to liquidity pool before curve completion
* param from Address tokens are transferred from
* @param to Address tokens are transferred to
* param value Amount of tokens being transferred
* @custom:dev Inheriting contract must call super._update()
* @custom:throws CurveIsNotComplete if attempting to add to pool before completion
*/
function _update(
address,
/*from*/
address to,
uint256 /*value*/
) internal virtual {
// Read entire struct from storage once
CompletionStatus memory status = completionStatus;
// Disable adding token to liquidity pool before completion
if (status.state == CompletionState.Restricted && to == status.pool) {
revert CurveIsNotComplete();
}
/// @DEV: Make sure inheriting contract calls ERC20._update()
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IInterchainTokenService } from "../interfaces/its/IInterchainTokenService.sol";
import { IPrintrTeleport } from "../interfaces/printr/IPrintrTeleport.sol";
import { ITelecoin } from "../interfaces/telecoin/ITelecoin.sol";
import { ERC20 } from "./ERC20.sol";
import { ERC20Witness } from "./ERC20Witness.sol";
import { InterchainStandard } from "./InterchainStandard.sol";
import { OftStandard } from "./OftStandard.sol";
/**
* @title Telecoin
* @notice Base ERC20 token with teleport capabilities and witness permit functionality
* @dev Extends ERC20Witness and InterchainStandard to provide cross-chain teleport functionality
*/
contract Telecoin is ITelecoin, ERC20Witness, InterchainStandard, OftStandard {
/// @notice Printr Telecoin ID
bytes32 public immutable telecoinId;
/// @notice Maximum total supply of the token
uint256 public immutable maxSupply;
/// @notice Address of the Printr contract that created this token
address public immutable printr;
/// @notice Address of the ITS token manager for minting and burning
address public immutable itsTokenManager;
/**
* @notice Constructor for Telecoin
* @param params Deployment parameters struct containing token configuration
*/
constructor(
TelecoinDeployParams memory params
)
ERC20Witness(params.name, params.symbol, 18)
InterchainStandard(params.interchainTokenService, params.interchainTokenId)
{
if (
params.printr == address(0) || params.interchainTokenService == address(0)
|| params.itsTokenManager == address(0)
) {
revert ZeroAddress();
}
telecoinId = params.telecoinId;
maxSupply = params.maxSupply;
printr = params.printr;
itsTokenManager = params.itsTokenManager;
}
/**
* @notice Quotes the total teleport fee for any protocol (external interface)
* @param params The teleport parameters struct (includes protocol)
* @return totalNativeFee The total fee in native currency (protocol fee + bridge fee)
* @return basePairFee The fee in base pair tokens (0 if base pair is native)
* @return basePair The base pair address (address(0) if native)
* @return bridgeFee The bridge-specific gas fee (ITS gas fee or LZ messaging fee)
*/
function quoteTeleportFee(
IPrintrTeleport.TeleportParams memory params
)
public
override(ITelecoin)
returns (uint256 totalNativeFee, uint256 basePairFee, address basePair, uint256 bridgeFee)
{
return _quoteTeleportFee(params);
}
/**
* @notice Teleports tokens from sender to a destination chain
* @dev Routes to ITS or LayerZero based on params.protocol
* @param params The teleport parameters struct (includes protocol)
*/
function teleport(
IPrintrTeleport.TeleportParams calldata params
) public payable virtual {
if (params.protocol == IPrintrTeleport.TeleportProtocol.UNSPECIFIED) {
revert InvalidProtocol();
}
if (params.protocol == IPrintrTeleport.TeleportProtocol.ITS) {
_itsTeleport(msg.sender, params);
return;
}
_lzTeleport(msg.sender, params);
}
/**
* @notice Teleports tokens from a specified address to a destination chain
* @dev Routes to ITS or LayerZero based on params.protocol
* @param from The sender of the tokens (must have approved msg.sender)
* @param params The teleport parameters struct (includes protocol)
*/
function teleportFrom(
address from,
IPrintrTeleport.TeleportParams calldata params
) public payable virtual {
if (params.protocol == IPrintrTeleport.TeleportProtocol.UNSPECIFIED) {
revert InvalidProtocol();
}
if (params.protocol == IPrintrTeleport.TeleportProtocol.ITS) {
_itsTeleport(from, params);
return;
}
_lzTeleport(from, params);
}
/**
* @notice Transfer tokens from one address to another with special ITS token manager handling
* @dev If called by the ITS token manager, triggers Printr interchain transfer processing
* @param from Address to transfer from
* @param to Address to transfer to
* @param value Amount to transfer
* @return bool True if transfer succeeded
*/
function transferFrom(
address from,
address to,
uint256 value
) public override(ERC20, IERC20) returns (bool) {
if (msg.sender == itsTokenManager) {
IPrintrTeleport(printr).processInterchainTransfer(telecoinId, to, value);
}
return super.transferFrom(from, to, value);
}
/**
* @notice Internal function to decrease allowance
* @dev Preserves infinite allowance when value is max uint256
* @param sender Address owning the tokens
* @param spender Address spending the tokens
* @param value Amount to decrease allowance by
*/
function _decreaseAllowance(
address sender,
address spender,
uint256 value
) internal override {
uint256 _allowance = allowance[sender][spender];
if (_allowance < value) {
revert ERC20InsufficientAllowance(spender, _allowance, value);
}
if (_allowance != type(uint256).max) {
allowance[sender][spender] = _allowance - value;
}
}
/**
* @notice Internal function to broadcast interchain transfer event
* @dev Calls the printr contract (which is PrintrTeleport) to emit the transfer event
* @param sourceAddress Address initiating the transfer
* @param destChain Target chain for the transfer
* @param destAddress Address on the destination chain
* @param value Amount being transferred
*/
function _beforeInterchainTransfer(
address sourceAddress,
string calldata destChain,
bytes calldata destAddress,
uint256 value,
bytes calldata /*metadata*/
) internal override {
IPrintrTeleport(printr)
.broadcastInterchainTransfer(
telecoinId, // telecoinId first to protect from permitWitnessCall attacks
sourceAddress,
destChain,
destAddress,
value
);
}
/**
* @notice Internal fee quote implementation for OftStandard
* @dev Overrides OftStandard's virtual function, delegates to PrintrTeleport
* @param params The teleport parameters struct (includes protocol)
* @return totalNativeFee The total fee in native currency (protocol fee + bridge fee)
* @return basePairFee The fee in base pair tokens (0 if base pair is native)
* @return basePair The base pair address (address(0) if native)
* @return bridgeFee The bridge-specific gas fee (ITS gas fee or LZ messaging fee)
*/
function _quoteTeleportFee(
IPrintrTeleport.TeleportParams memory params
) internal override returns (uint256 totalNativeFee, uint256 basePairFee, address basePair, uint256 bridgeFee) {
return IPrintrTeleport(printr).quoteTeleportFee(address(this), params);
}
/**
* @notice Internal ITS teleport execution logic
* @dev Handles ITS protocol fee payment and calls appropriate interchain transfer function
* @param from The address sending the tokens
* @param params The teleport parameters struct (includes protocol)
*/
function _itsTeleport(
address from,
IPrintrTeleport.TeleportParams calldata params
) internal {
// Get the teleport fee using the unified function
(uint256 totalNativeFee,,, uint256 bridgeFee) = IPrintrTeleport(printr).quoteTeleportFee(address(this), params);
// Transfer only the protocol fee to printr (excluding bridge gas fee)
uint256 protocolFee = totalNativeFee - bridgeFee;
if (protocolFee > 0) {
payable(printr).transfer(protocolFee);
}
// Keep the bridge fee in the contract for ITS to use
// Use interchainTransfer if from == msg.sender, otherwise use interchainTransferFrom
if (from == msg.sender) {
interchainTransfer(params.destChain, params.destAddress, params.amount, params.metadata);
} else {
interchainTransferFrom(from, params.destChain, params.destAddress, params.amount, params.metadata);
}
}
/**
* @notice Internal LayerZero teleport execution logic
* @dev Handles protocol routing for teleport(), teleportFrom(), and OftStandard's send()
* @param from The address sending the tokens
* @param params The teleport parameters (memory to support both calldata and memory callers)
*/
function _lzTeleport(
address from,
IPrintrTeleport.TeleportParams memory params
) internal override {
// For LZ protocols
if (
params.protocol == IPrintrTeleport.TeleportProtocol.LZ_FAST
|| params.protocol == IPrintrTeleport.TeleportProtocol.LZ_SECURE
|| params.protocol == IPrintrTeleport.TeleportProtocol.LZ_SLOW
) {
// Use LayerZero for teleportation via PrintrTeleport
IPrintrTeleport(printr).transmitLzSend{ value: msg.value }(telecoinId, from, params);
return;
}
revert InvalidProtocol();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
/**
* @title IPrintrTeleportingTelecoin
* @notice Interface for the PrintrTelecoin contract with teleport and curve completion functionality
* @dev Extends ITelecoin interface with additional token management functions
*/
interface IPrinted {
/**
* @notice Error thrown when attempting to interact with an incomplete curve
* @dev This error is typically thrown when trying to add liquidity before curve completion
*/
error CurveIsNotComplete();
/**
* @notice Returns whether this is a main telecoin (uses lock/unlock) or teleporting telecoin
* @return True if this is a main telecoin, false if it's a teleporting telecoin
*/
function isTeleporting() external view returns (bool);
/**
* @notice Sets the restricted pool address during curve initialization
* @dev Can only be called by Printr before completion
* @param poolAddress The pool address to restrict transfers to
* @custom:throws UnauthorizedAccount if caller is not Printr or curve is already complete
* @custom:throws ZeroAddress if pool address is zero
*/
function setRestrictedPool(
address poolAddress
) external;
/**
* @notice Marks the curve as completed, removing transfer restrictions
* @dev Can only be called by Printr when curve is not already completed
* @custom:throws UnauthorizedAccount if caller is not Printr or curve is already completed
*/
function markCurveComplete() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IOFT } from "../layerzero/IOFT.sol";
import { IPrintrTeleport } from "../printr/IPrintrTeleport.sol";
import { IERC20Witness } from "./IERC20Witness.sol";
import { IInterchainStandard } from "./IInterchainStandard.sol";
/**
* @title ITelecoin
* @notice Interface for the Telecoin base contract
* @dev Extends IERC20 for base teleport functionality
*/
interface ITelecoin is IERC20Witness, IInterchainStandard, IOFT {
/**
* @notice Struct containing deployment parameters for telecoin contracts
* @param name Token name
* @param symbol Token symbol
* @param maxSupply Maximum supply of the token
* @param treasury Treasury address to receive initial supply
* @param interchainTokenService Interchain Token Service address
* @param itsTokenManager Token manager address
* @param telecoinId Universal telecoin ID
* @param interchainTokenId Interchain token ID for ITS compatibility
*/
struct TelecoinDeployParams {
bytes32 telecoinId;
string name;
string symbol;
uint256 maxSupply;
address printr;
address interchainTokenService;
address itsTokenManager;
bytes32 interchainTokenId;
}
/**
* @notice Error thrown when a zero address is provided where not allowed
*/
error ZeroAddress();
/**
* @notice Error thrown when an unauthorized account attempts a restricted operation
* @param account The address that attempted the unauthorized operation
*/
error UnauthorizedAccount(address account);
/**
* @notice Error thrown when an invalid protocol is specified
*/
error InvalidProtocol();
/**
* @notice Emitted when tokens are teleported in from another chain
* @param telecoinId The universal token ID
* @param to The address receiving the tokens
* @param value The amount of tokens teleported in
*/
event TeleportIn(bytes32 indexed telecoinId, address indexed to, uint256 value);
/**
* @notice Emitted when tokens are teleported out to another chain
* @param telecoinId The universal token ID
* @param from The address from which tokens are teleported
* @param value The amount of tokens teleported out
*/
event TeleportOut(bytes32 indexed telecoinId, address indexed from, uint256 value);
/**
* @notice Returns the universal token ID (deploySalt)
* @dev This value is immutable and set during contract construction
* @return The universal token ID based on deployment salt
*/
function telecoinId() external view returns (bytes32);
/**
* @notice Returns the address of the Printr contract that created this token
* @dev This value is immutable and set during contract construction
* @return The address of the Printr contract
*/
function printr() external view returns (address);
/**
* @notice Returns the address of the ITS token manager for minting and burning
* @dev This value is immutable and set during contract construction
* @return The address of the ITS token manager
*/
function itsTokenManager() external view returns (address);
/**
* @notice Quotes the total teleport fee for any protocol
* @dev Delegates to PrintrTeleport's quoteTeleportFee for fee calculation
* @param params The teleport parameters struct (includes protocol)
* @return totalNativeFee The total fee in native currency (protocol fee + bridge fee)
* @return basePairFee The fee in base pair tokens (0 if base pair is native)
* @return basePair The base pair address (address(0) if native)
* @return bridgeFee The bridge-specific gas fee (ITS gas fee or LZ messaging fee)
*/
function quoteTeleportFee(
IPrintrTeleport.TeleportParams memory params
) external returns (uint256 totalNativeFee, uint256 basePairFee, address basePair, uint256 bridgeFee);
/**
* @notice Teleports tokens from sender to a destination chain
* @param params The teleport parameters struct (includes protocol)
*/
function teleport(
IPrintrTeleport.TeleportParams calldata params
) external payable;
/**
* @notice Teleports tokens from a specified sender to a destination chain
* @param sender The sender of the tokens (must have approved msg.sender)
* @param params The teleport parameters struct (includes protocol)
*/
function teleportFrom(
address sender,
IPrintrTeleport.TeleportParams calldata params
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title IERC20Permit Interface with Errors
/// @notice Interface for ERC20 Permit extension with proper error definitions
/// @dev Extends the standard EIP-2612 permit functionality with error definitions
interface IERC20Permit {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Thrown when a permit signature has expired
* @param deadline The timestamp at which the signature expired
*/
error ERC2612ExpiredSignature(uint256 deadline);
/**
* @notice Thrown when the recovered signer does not match the expected owner
* @param signer The address recovered from the signature
* @param owner The expected owner address
*/
error ERC2612InvalidSigner(address signer, address owner);
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when an owner manually invalidates their nonce
* @param owner The address that invalidated their nonce
* @param newNonce The new nonce value after invalidation
*/
event NonceInvalidated(address indexed owner, uint256 newNonce);
/*//////////////////////////////////////////////////////////////
PERMIT LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the current nonce for the given owner
* @dev This value must be included whenever a signature is generated for permit
* @param owner The address to get the nonce for
* @return The current nonce value for the owner
*/
function nonces(
address owner
) external view returns (uint256);
/**
* @notice Returns the domain separator used in the encoding of signatures
* @dev Used to prevent signature replay attacks across different domains
* @return The EIP-712 domain separator hash
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the permit typehash used in EIP-712 signature encoding
* @dev Constant value defining the structure of permit messages
* @return The keccak256 hash of the permit type string
*/
function PERMIT_TYPEHASH() external view returns (bytes32);
/**
* @notice Sets allowance using EIP-2612 signature-based authorization
* @dev Allows setting allowance without requiring a separate transaction from the token owner
* @param owner The owner of the tokens
* @param spender The address authorized to spend the tokens
* @param value The amount of tokens to authorize for spending
* @param deadline The timestamp at which the permit expires
* @param v The recovery parameter of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Invalidates the current nonce for msg.sender
* @dev Increments the nonce, making all outstanding permit signatures invalid
* This provides users with an emergency mechanism to cancel pending permits in case of:
* - Key compromise or suspected phishing
* - Changed mind about a signed but not executed permit
* - Need to invalidate multiple permits at once
* Emits a NonceInvalidated event
*/
function invalidateNonce() external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrintrTeleport } from "../interfaces/printr/IPrintrTeleport.sol";
import { ITeleportingTelecoin } from "../interfaces/telecoin/ITeleporting.sol";
import { ERC20 } from "./ERC20.sol";
import { InterchainStandard } from "./InterchainStandard.sol";
import { Telecoin } from "./Telecoin.sol";
/**
* @title Teleporting
* @notice Base ERC20 token with teleport capabilities
* @dev Extends ERC20 and InterchainStandard to provide cross-chain teleport functionality
*/
contract TeleportingTelecoin is ITeleportingTelecoin, Telecoin {
/**
* @notice Constructor for TeleportingTelecoin
* @param params Deployment parameters struct containing token configuration
*/
constructor(
TelecoinDeployParams memory params
) Telecoin(params) { }
/**
* @notice Teleports tokens into existence for cross-chain transfers
* @dev Can only be called by the ITS token manager or Printr
* @param to Address to receive the teleported tokens
* @param value Amount of tokens to teleport in
*/
function teleportIn(
address to,
uint256 value
) public {
if (msg.sender != itsTokenManager && msg.sender != printr) {
revert UnauthorizedAccount(msg.sender);
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
emit TeleportIn(telecoinId, to, value);
_update(address(this), to, value);
}
/**
* @notice Teleports tokens out of existence for cross-chain transfers
* @dev Can be called by ITS, ITS Token Manager, or Printr
* @param from Address to teleport tokens from
* @param value Amount of tokens to teleport out
*/
function teleportOut(
address from,
uint256 value
) public {
if (msg.sender != address(interchainTokenService) && msg.sender != itsTokenManager && msg.sender != printr) {
revert UnauthorizedAccount(msg.sender);
}
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (msg.sender == address(interchainTokenService) || msg.sender == itsTokenManager) {
IPrintrTeleport(printr).processInterchainTransfer(telecoinId, from, value);
}
emit TeleportOut(telecoinId, from, value);
_decreaseAllowance(from, msg.sender, value);
_update(from, address(this), value);
}
/**
* @notice Internal function to update balances and total supply
* @dev Overrides ERC20 _update to handle teleporting via teleportIn/teleportOut
* @param from Address tokens are transferred from (address(this) for teleporting in)
* @param to Address tokens are transferred to (address(this) for teleporting out)
* @param value Amount of tokens to transfer
* @custom:throws ERC20InsufficientBalance if 'from' has insufficient balance
*/
function _update(
address from,
address to,
uint256 value
) internal virtual override {
if (from == address(this) || from == address(0)) {
// Teleporting in - increase total supply
totalSupply += value;
} else {
// Transfer or teleport out - decrease from balance
uint256 fromBalance = balanceOf[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
balanceOf[from] = fromBalance - value;
}
}
if (to == address(this) || to == address(0)) {
// Teleporting out - decrease total supply
unchecked {
totalSupply -= value;
}
} else {
// Transfer or teleport in - increase to balance
unchecked {
balanceOf[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @notice Fallback function that handles teleport operations for backwards compatibility
* @dev Decodes calldata and routes to teleportIn/teleportOut functions
*/
fallback() external {
if (msg.data.length < 4) {
revert InvalidFunctionSelector();
}
bytes4 selector = bytes4(msg.data[:4]);
(address account, uint256 amount) = abi.decode(msg.data[4:], (address, uint256));
// teleportIn selector: 0x40c10f19 (mint))
if (selector == 0x40c10f19) {
teleportIn(account, amount);
return;
}
// teleportOut selector: 0x9dc29fac (burn) or 0x79cc6790 (burnFrom)
if (selector == 0x9dc29fac || selector == 0x79cc6790) {
teleportOut(account, amount);
return;
}
revert InvalidFunctionSelector();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// https://github.com/axelarnetwork/interchain-token-service/blob/main/contracts/interfaces/IInterchainTokenService.sol
pragma solidity ^0.8.0;
type ITokenManager is address;
/**
* @title IInterchainGasEstimation Interface
* @notice This is an interface for the InterchainGasEstimation contract
* which allows for estimating gas fees for cross-chain communication on the Axelar network.
*/
interface IInterchainGasEstimation {
/**
* @notice Estimates the gas fee for a cross-chain contract call.
* @param destinationChain Axelar registered name of the destination chain
* @param destinationAddress Destination contract address being called
* @param executionGasLimit The gas limit to be used for the destination contract execution,
* e.g. pass in 200k if your app consumes needs upto 200k for this contract call
* @param params Additional parameters for the gas estimation
* @return gasEstimate The cross-chain gas estimate, in terms of source chain's native gas token that should be
* forwarded to the gas service.
*/
function estimateGasFee(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
uint256 executionGasLimit,
bytes calldata params
) external view returns (uint256 gasEstimate);
}
/**
* @title IInterchainTokenService Interface
* @notice Interface for the Interchain Token Service
*/
interface IInterchainTokenService {
enum TokenManagerType {
NATIVE_INTERCHAIN_TOKEN, // This type is reserved for interchain tokens deployed by ITS, and can't be used by
// custom token managers.
MINT_BURN_FROM, // The token will be minted/burned on transfers. The token needs to give mint permission to the
// token manager, but burning happens via an approval.
LOCK_UNLOCK, // The token will be locked/unlocked at the token manager.
LOCK_UNLOCK_FEE, // The token will be locked/unlocked at the token manager, which will account for any
// fee-on-transfer behaviour.
MINT_BURN // The token will be minted/burned on transfers. The token needs to give mint and burn permission to
// the token manager.
}
event InterchainTransfer(
bytes32 indexed tokenId,
address indexed sourceAddress,
string destinationChain,
bytes destinationAddress,
uint256 amount,
bytes32 indexed dataHash
);
event InterchainTransferReceived(
bytes32 indexed commandId,
bytes32 indexed tokenId,
string sourceChain,
bytes sourceAddress,
address indexed destinationAddress,
uint256 amount,
bytes32 dataHash
);
event TokenMetadataRegistered(address indexed tokenAddress, uint8 decimals);
event LinkTokenStarted(
bytes32 indexed tokenId,
string destinationChain,
bytes sourceTokenAddress,
bytes destinationTokenAddress,
TokenManagerType indexed tokenManagerType,
bytes params
);
event InterchainTokenDeploymentStarted(
bytes32 indexed tokenId,
string tokenName,
string tokenSymbol,
uint8 tokenDecimals,
bytes minter,
string destinationChain
);
event TokenManagerDeployed(
bytes32 indexed tokenId, address tokenManager, TokenManagerType indexed tokenManagerType, bytes params
);
event InterchainTokenDeployed(
bytes32 indexed tokenId,
address tokenAddress,
address indexed minter,
string name,
string symbol,
uint8 decimals
);
event InterchainTokenIdClaimed(bytes32 indexed tokenId, address indexed deployer, bytes32 indexed salt);
/**
* @notice Returns the address of the interchain gas service contract.
* @return gasService The instance of the IInterchainGasEstimation contract.
*/
function gasService() external view returns (IInterchainGasEstimation);
/**
* @notice Returns the address of the ITS Hub contract.
* @return hubAddress The address of the ITS Hub contract.
*/
function itsHubAddress() external view returns (string memory hubAddress);
/**
* @notice Returns the address of the token manager deployer contract.
* @return tokenManagerDeployerAddress The address of the token manager deployer contract.
*/
function tokenManagerDeployer() external view returns (address tokenManagerDeployerAddress);
/**
* @notice Returns the address of the interchain token deployer contract.
* @return interchainTokenDeployerAddress The address of the interchain token deployer contract.
*/
function interchainTokenDeployer() external view returns (address interchainTokenDeployerAddress);
/**
* @notice Returns the address of TokenManager implementation.
* @return tokenManagerAddress_ The address of the token manager contract.
*/
function tokenManager() external view returns (address tokenManagerAddress_);
/**
* @notice Returns the address of TokenHandler implementation.
* @return tokenHandlerAddress The address of the token handler contract.
*/
function tokenHandler() external view returns (address tokenHandlerAddress);
/**
* @notice Returns the address of the interchain token factory.
* @return address The address of the interchain token factory.
*/
function interchainTokenFactory() external view returns (address);
/**
* @notice Returns the hash of the chain name.
* @return bytes32 The hash of the chain name.
*/
function chainNameHash() external view returns (bytes32);
/**
* @notice Returns the address of the token manager associated with the given tokenId.
* @param tokenId The tokenId of the token manager.
* @return tokenManagerAddress_ The address of the token manager.
*/
function tokenManagerAddress(
bytes32 tokenId
) external view returns (address tokenManagerAddress_);
/**
* @notice Returns the instance of ITokenManager from a specific tokenId.
* @param tokenId The tokenId of the deployed token manager.
* @return tokenManager_ The instance of ITokenManager associated with the specified tokenId.
*/
function deployedTokenManager(
bytes32 tokenId
) external view returns (ITokenManager tokenManager_);
/**
* @notice Returns the address of the token that an existing tokenManager points to.
* @param tokenId The tokenId of the registered token.
* @return tokenAddress The address of the token.
*/
function registeredTokenAddress(
bytes32 tokenId
) external view returns (address tokenAddress);
/**
* @notice Returns the address of the interchain token associated with the given tokenId.
* @param tokenId The tokenId of the interchain token.
* @return tokenAddress The address of the interchain token.
*/
function interchainTokenAddress(
bytes32 tokenId
) external view returns (address tokenAddress);
/**
* @notice Returns the custom tokenId associated with the given operator and salt.
* @param operator_ The operator address.
* @param salt The salt used for token id calculation.
* @return tokenId The custom tokenId associated with the operator and salt.
*/
function interchainTokenId(
address operator_,
bytes32 salt
) external view returns (bytes32 tokenId);
/**
* @notice Registers metadata for a token on the ITS Hub. This metadata is used for scaling linked tokens.
* The token metadata must be registered before linkToken can be called for the corresponding token.
* @param tokenAddress The address of the token.
* @param gasValue The cross-chain gas value for sending the registration message to ITS Hub.
*/
function registerTokenMetadata(
address tokenAddress,
uint256 gasValue
) external payable;
/**
* @notice Only to be used by the InterchainTokenFactory to register custom tokens to this chain. Then link token
* can be used to register those tokens to other chains.
* @param salt A unique salt to derive tokenId from.
* @param tokenManagerType The type of the token manager to use for the token registration.
* @param linkParams The operator for the token.
*/
function registerCustomToken(
bytes32 salt,
address tokenAddress,
TokenManagerType tokenManagerType,
bytes calldata linkParams
) external payable returns (bytes32 tokenId);
/**
* @notice If `destinationChain` is an empty string, this function will register the token address on the current
* chain.
* Otherwise, it will link the token address on the destination chain with the token corresponding to the tokenId on
* the current chain.
* A token manager is deployed on EVM chains that's responsible for managing the linked token.
* @dev This function replaces the prior `deployTokenManager` function.
* @param salt A unique identifier to allow for multiple tokens registered per deployer.
* @param destinationChain The chain to link the token to. Pass an empty string for this chain.
* @param destinationTokenAddress The token address to link, as bytes.
* @param tokenManagerType The type of the token manager to use to send and receive tokens.
* @param linkParams Additional parameteres to use to link the token. Fow not it is just the address of the
* operator.
* @param gasValue Pass a non-zero value only for remote linking, which should be the gas to use to pay for the
* contract call.
* @return tokenId The tokenId associated with the token manager.
*/
function linkToken(
bytes32 salt,
string calldata destinationChain,
bytes memory destinationTokenAddress,
TokenManagerType tokenManagerType,
bytes memory linkParams,
uint256 gasValue
) external payable returns (bytes32 tokenId);
/**
* @notice Deploys and registers an interchain token on a remote chain.
* @param salt The salt used for token deployment.
* @param destinationChain The name of the destination chain. Use '' for this chain.
* @param name The name of the interchain tokens.
* @param symbol The symbol of the interchain tokens.
* @param decimals The number of decimals for the interchain tokens.
* @param minter The minter data for mint/burn operations.
* @param gasValue The gas value for deployment.
* @return tokenId The tokenId corresponding to the deployed InterchainToken.
*/
function deployInterchainToken(
bytes32 salt,
string calldata destinationChain,
string memory name,
string memory symbol,
uint8 decimals,
bytes memory minter,
uint256 gasValue
) external payable returns (bytes32 tokenId);
/**
* @notice Initiates an interchain transfer of a specified token to a destination chain.
* @param tokenId The unique identifier of the token to be transferred.
* @param destinationChain The destination chain to send the tokens to.
* @param destinationAddress The address on the destination chain to send the tokens to.
* @param amount The amount of tokens to be transferred.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function interchainTransfer(
bytes32 tokenId,
string calldata destinationChain,
bytes calldata destinationAddress,
uint256 amount,
bytes calldata metadata,
uint256 gasValue
) external payable;
/**
* @notice Sets the flow limits for multiple tokens.
* @param tokenIds An array of tokenIds.
* @param flowLimits An array of flow limits corresponding to the tokenIds.
*/
function setFlowLimits(
bytes32[] calldata tokenIds,
uint256[] calldata flowLimits
) external;
/**
* @notice Allows the owner to pause/unpause the token service.
* @param paused whether to pause or unpause.
*/
function setPauseStatus(
bool paused
) external;
/**
* @notice Allows the owner to migrate legacy tokens that cannot be migrated automatically.
* @param tokenId the tokenId of the registered token.
*/
function migrateInterchainToken(
bytes32 tokenId
) external;
/**
* @notice Transmit an interchain transfer for the given tokenId.
* @dev Only callable by a token registered under a tokenId.
* @param tokenId The tokenId of the token (which must be the msg.sender).
* @param sourceAddress The address where the token is coming from.
* @param destinationChain The name of the chain to send tokens to.
* @param destinationAddress The destinationAddress for the interchainTransfer.
* @param amount The amount of token to give.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function transmitInterchainTransfer(
bytes32 tokenId,
address sourceAddress,
string calldata destinationChain,
bytes memory destinationAddress,
uint256 amount,
bytes calldata metadata
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrintrStorage } from "../printr/IPrintrStorage.sol";
/**
* @title IPrintrTeleport
* @notice Interface for PrintrTeleport contract that handles cross-chain messaging with Solana
* @dev This interface defines the functionality for sending and receiving messages between EVM and Solana
* using the Teleport message protocol for token transfers
*/
interface IPrintrTeleport is IPrintrStorage {
/**
* @notice Error thrown when payload has invalid length
*/
error InvalidPayloadLength();
/**
* @notice Error thrown when message kind is unexpected
*/
error UnexpectedMessageKind();
/**
* @notice Error thrown when endpoint address is invalid
*/
error InvalidEndpoint();
/**
* @notice Error thrown when solana program address is invalid
*/
error InvalidSolanaProgram();
/**
* @notice Error thrown when sender is not authorized
*/
error UnauthorizedSender();
/**
* @notice Error thrown when contract has insufficient fee balance
*/
error InsufficientFee();
/**
* @notice Error thrown when fee transfer fails
*/
error FeeTransferFailed();
/**
* @notice Error thrown when an invalid protocol is specified
*/
error InvalidProtocol();
/**
* @notice Error thrown when the chain ID length is invalid
*/
error InvalidChainIdLength();
/**
* @notice Error thrown when a non-numeric character is found in chain ID
*/
error InvalidNumericCharacter();
/**
* @notice Error thrown when the endpoint ID is invalid
*/
error InvalidEndpointId();
/**
* @notice Error thrown when calldata is invalid
*/
error InvalidCalldata();
/**
* @notice Error thrown when security level is invalid
*/
error InvalidSecurityLevel();
/**
* @notice Error thrown when protocol is not in global whitelist
*/
error ProtocolNotWhitelisted();
/**
* @notice Error thrown when protocol is in token blacklist
*/
error ProtocolBlacklisted();
/**
* @notice Error thrown when invalid protocol bit position used
*/
error InvalidProtocolBitPosition();
/**
* @notice Error thrown when teleport amount exceeds maximum supported value
* @dev Maximum supported amount is type(uint64).max * 1e9 (in 18 decimals)
* @param requestedAmount The amount that was requested to teleport
* @param maxAmount The maximum amount that can be teleported
*/
error TeleportAmountOverflow(uint256 requestedAmount, uint256 maxAmount);
/**
* @notice Protocol enum for teleportation methods
* @dev Must match the Protocol enum in ITelecoin for compatibility
*/
enum TeleportProtocol {
UNSPECIFIED, // 0 - Used to catch malformed transactions
ITS, // 1 - Interchain Token Service
LZ_FAST, // 2 - Fast LayerZero channel with minimal confirmations
LZ_SECURE, // 3 - Secure LayerZero channel with balanced confirmations
LZ_SLOW // 4 - Slow LayerZero channel with maximum confirmations
}
/**
* @notice Struct containing constructor parameters for LayerZero deployment
* @param itsFlatFee Flat fee for ITS transfers
* @param itsBipsFee Basis points fee for ITS transfers
* @param lzFlatFee Flat fee for LayerZero transfers
* @param lzBipsFee Basis points fee for LayerZero transfers
* @param lzEndpoint LayerZero endpoint address for this chain
* @param fastSolanaLzPeer Solana LayerZero peer address for fast/low security channel
* @param secureSolanaLzPeer Solana LayerZero peer address for secure/medium security channel
* @param slowSolanaLzPeer Solana LayerZero peer address for slow/high security channel
* @param lzReceiveGasLimit Gas limit for LayerZero receive operations
* @param lzReceiveNativeDrop Native drop amount for LayerZero receive operations
*/
struct TeleportDeployParams {
uint256 itsFlatFee;
uint16 itsBipsFee;
uint256 lzFlatFee;
uint16 lzBipsFee;
address lzEndpoint;
bytes32 fastSolanaLzPeer;
bytes32 secureSolanaLzPeer;
bytes32 slowSolanaLzPeer;
uint128 lzReceiveGasLimit;
uint128 lzReceiveNativeDrop;
}
/**
* @notice Struct containing teleport parameters
* @param destChain The destination chain identifier
* @param destAddress The bytes representation of the address of the recipient
* @param amount The amount of tokens to be transferred
* @param metadata Additional data for the cross-chain transfer
* @param protocol The teleportation protocol to use (ITS, LZ_FAST, LZ_SECURE, LZ_SLOW)
*/
struct TeleportParams {
string destChain;
bytes destAddress;
uint256 amount;
bytes metadata;
TeleportProtocol protocol;
}
/**
* @notice Event emitted when a new LayerZero delegate is set for a channel
* @param protocol The teleport protocol (LZ_FAST, LZ_SECURE, LZ_SLOW)
* @param delegate Address of the new LayerZero delegate
*/
event LzDelegateUpdated(TeleportProtocol indexed protocol, address indexed delegate);
/**
* @notice Event emitted when global protocol whitelist is updated
* @param newWhitelist The new whitelist bitmap
*/
event TeleportProtocolWhitelistUpdated(bytes32 indexed newWhitelist);
/**
* @notice Event emitted when a token's protocol blacklist is updated
* @param telecoinId The telecoin ID
* @param newBlacklist The new blacklist bitmap
*/
event TelecoinProtocolBlacklistUpdated(bytes32 indexed telecoinId, bytes32 indexed newBlacklist);
/**
* @notice Event emitted when tokens are teleported to another chain
* @param telecoinId The ID of the token being transferred
* @param tokenAddress The address of the token contract
* @param sourceAddress The address initiating the transfer
* @param destChain The target chain for the transfer
* @param destAddress The address on the destination chain
* @param amount The amount of tokens being transferred
*/
event Teleporting(
bytes32 indexed telecoinId,
address indexed tokenAddress,
address indexed sourceAddress,
string destChain,
bytes destAddress,
uint256 amount
);
// ============================================
// EXTERNAL FUNCTIONS
// ============================================
/**
* @notice Calculates the universal token ID based on token parameters
* @dev Returns the telecoinId as a universal token ID that's vendor-agnostic
* @param tokenParams Parameters for the token deployment
* @return telecoinId The universal token ID
*/
function getTelecoinId(
TelecoinParams calldata tokenParams
) external pure returns (bytes32 telecoinId);
/**
* @notice Sets the LayerZero delegate address for a specific channel
* @dev Only callable by the contract owner or authorized account
* @param protocol The teleport protocol to configure (LZ_FAST, LZ_SECURE, LZ_SLOW)
* @param delegate Address of the new LayerZero delegate
*/
function setLzDelegate(
TeleportProtocol protocol,
address delegate
) external;
/**
* @notice Gets the LZChannel address for a specific protocol
* @param protocol The teleport protocol (LZ_FAST, LZ_SECURE, LZ_SLOW)
* @return channel Address of the LZChannel contract for this protocol
*/
function getLzChannel(
TeleportProtocol protocol
) external view returns (address channel);
/**
* @notice Updates the global protocol whitelist by enabling and/or disabling protocols
* @dev Only callable by the contract owner. Processes disable array first, then enable array.
* @param enable Array of protocols to enable globally
* @param disable Array of protocols to disable globally
*/
function updateGlobalProtocols(
TeleportProtocol[] calldata enable,
TeleportProtocol[] calldata disable
) external;
/**
* @notice Gets the global protocol whitelist bitmap
* @return whitelist Bitmap of enabled protocols
*/
function getTeleportProtocolWhitelist() external view returns (bytes32 whitelist);
/**
* @notice Updates the protocol blacklist for a specific telecoin
* @dev Only callable by the contract owner. Processes enable array first (removes from blacklist), then disable
* array (adds to blacklist).
* @param telecoinId The ID of the telecoin
* @param enable Array of protocols to enable for this telecoin (remove from blacklist)
* @param disable Array of protocols to disable for this telecoin (add to blacklist)
*/
function updateTelecoinProtocols(
bytes32 telecoinId,
TeleportProtocol[] calldata enable,
TeleportProtocol[] calldata disable
) external;
/**
* @notice Gets a token's protocol blacklist bitmap
* @param telecoinId The telecoin ID
* @return blacklist Bitmap of disabled protocols for this token
*/
function getTelecoinProtocolBlacklist(
bytes32 telecoinId
) external view returns (bytes32 blacklist);
/**
* @notice Checks if a protocol is allowed for a specific token
* @dev Returns true if protocol is in global whitelist AND NOT in token blacklist
* @param telecoinId The telecoin ID
* @param protocol The protocol to check
* @return allowed True if protocol is allowed for this token
*/
function isProtocolAllowed(
bytes32 telecoinId,
TeleportProtocol protocol
) external view returns (bool allowed);
/**
* @notice Quotes the total teleport fee for any protocol
* @dev Consolidates fee calculation for ITS, LayerZero, and future protocols
* @param token Token address to transfer
* @param params The teleport parameters struct (includes protocol)
* @return totalNativeFee The total fee in native currency (protocol fee + bridge fee)
* @return basePairFee The fee in base pair tokens (0 if base pair is native)
* @return basePair The base pair address (address(0) if native)
* @return bridgeFee The bridge-specific gas fee (ITS gas fee or LZ messaging fee)
*/
function quoteTeleportFee(
address token,
TeleportParams calldata params
) external returns (uint256 totalNativeFee, uint256 basePairFee, address basePair, uint256 bridgeFee);
/**
* @notice Universal teleport function that routes to ITS or LayerZero
* @dev Routes tokens to the appropriate cross-chain protocol based on params.protocol
* @param token The token address to teleport
* @param params The teleport parameters struct (includes protocol)
*/
function teleport(
address token,
TeleportParams calldata params
) external payable;
/**
* @notice Universal teleport function with witness signature support
* @dev Called via permitWitnessCall to enable signature-based teleportation
* @dev Signer must be the first param to protect from permitWitnessCall attacks
* @param signer Address initiating the teleport, must be first parameter
* @param telecoinId The telecoin ID instead of token address
* @param params The teleport parameters struct (includes protocol)
*/
function witnessTeleport(
address signer,
bytes32 telecoinId,
TeleportParams calldata params
) external payable;
/**
* @notice Transmits a LayerZero cross-chain token transfer
* @dev Called by token contracts to initiate LayerZero transfers
* @dev telecoinId first param, to protect from permitWitnessCall calls
* @param telecoinId Universal token ID (32 bytes)
* @param sender Address initiating the transfer
* @param params The teleport parameters struct
*/
function transmitLzSend(
bytes32 telecoinId,
address sender,
TeleportParams calldata params
) external payable;
/**
* @notice Broadcasts an interchain transfer event
* @dev Emits an InterchainTransfer event with the provided parameters
* @dev telecoinId first param, to protect from permitWitnessCall calls
* @param telecoinId The ID of the token being transferred
* @param sourceAddress The address initiating the transfer
* @param destChain The target chain for the transfer
* @param destAddress The address on the destination chain
* @param amount The amount of tokens being transferred
*/
function broadcastInterchainTransfer(
bytes32 telecoinId,
address sourceAddress,
string calldata destChain,
bytes calldata destAddress,
uint256 amount
) external;
/**
* @notice Processes an incoming interchain transfer from Solana
* @dev Processes tokens for the specified sender based on the received message
* @param telecoinId The ID of the token being transferred
* @param sender The address receiving the tokens
* @param amount The amount of tokens to process
*/
function processInterchainTransfer(
bytes32 telecoinId,
address sender,
uint256 amount
) external;
// ============================================
// EXTERNAL VIEW FUNCTIONS
// ============================================
/**
* @notice Gets the LayerZero endpoint address
* @return The LayerZero endpoint address
*/
function lzEndpoint() external view returns (address);
/**
* @notice Gets the current gas limit for LayerZero receive operations
* @return gasLimit Current gas limit
*/
function lzReceiveGasLimit() external view returns (uint128 gasLimit);
/**
* @notice Gets the current native drop amount for LayerZero receive operations
* @return nativeDrop Current native drop amount
*/
function lzReceiveNativeDrop() external view returns (uint128 nativeDrop);
/**
* @notice Receives teleport messages from authorized channels
* @dev Called by LZChannel contracts to forward processed messages
* @param protocol The teleport protocol of the calling channel (LZ_FAST, LZ_SECURE, LZ_SLOW)
* @param originSender The LayerZero origin sender address (Solana peer or self)
* @param message The processed teleport payload
*/
function receiveFromChannel(
TeleportProtocol protocol,
bytes32 originSender,
bytes calldata message
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "../interfaces/telecoin/IERC20Witness.sol";
import "./ERC20.sol";
/**
* @notice ERC20 extension with witness-based permit functionality for enhanced security
* @dev Extends ERC20 with permitWitness functions that include additional validation data
*/
contract ERC20Witness is IERC20Witness, ERC20 {
/*//////////////////////////////////////////////////////////////
EIP-2612 CONSTANTS
//////////////////////////////////////////////////////////////*/
bytes32 public constant PERMIT_WITNESS_TYPEHASH = keccak256(
"PermitWitness(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline,bytes32 witness)"
);
string public constant PERMIT_WITNESS_TYPESTRING_STAB =
"PermitWitness(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline,";
string public constant WITNESS_CALL_TYPESTRING =
"ContractCall call)ContractCall(address target,string method,uint256 nativeValue,bytes params)";
bytes32 public constant WITNESS_CALL_TYPEHASH =
keccak256("ContractCall(address target,string method,uint256 nativeValue,bytes params)");
// Witness type prefixes to prevent signature collision between different witness functions
bytes32 public constant TRANSFER_WITNESS = bytes32(0);
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the ERC20Witness token with metadata and witness-based permit functionality
* @dev Calls parent ERC20 constructor to set up basic token functionality with added witness capabilities
* @param _name The human-readable name of the token (e.g. "My Token")
* @param _symbol The token symbol used on exchanges (e.g. "MTK")
* @param _decimals Number of decimal places for token amounts (typically 18 for most ERC20 tokens)
*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) ERC20(_name, _symbol, _decimals) { }
/*//////////////////////////////////////////////////////////////
PERMIT WITNESS LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Sets allowance via signature with additional witness data for enhanced security
* @dev Extends EIP-2612 permit with witness parameter to prevent signature replay across different contexts
* @param owner The address that owns the tokens and is granting the allowance
* @param spender The address that will be allowed to spend the tokens
* @param value The amount of tokens to approve for spending (in token's decimal units)
* @param deadline The timestamp after which the permit signature is no longer valid
* @param witness Additional context data hash to prevent cross-context signature replay
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (witness == TRANSFER_WITNESS) {
revert ERC20InvalidWitness();
}
_validatePermitWitness(owner, spender, value, deadline, witness, v, r, s);
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @notice Sets allowance via signature with additional witness data for enhanced security
* @dev Extends EIP-2612 permit with witness parameter to prevent signature replay across different contexts
* @param owner The address that owns the tokens and is granting the allowance
* @param spender The address that will be allowed to spend the tokens
* @param value The amount of tokens to approve for spending (in token's decimal units)
* @param deadline The timestamp after which the permit signature is no longer valid
* @param witness Additional context data hash to prevent cross-context signature replay
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
string memory witnessTypeString,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
if (witness == TRANSFER_WITNESS) {
revert ERC20InvalidWitness();
}
_validatePermitWitness(owner, spender, value, deadline, witness, witnessTypeString, v, r, s);
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @notice Executes a direct transfer via signature without setting persistent allowance
* @dev Uses witness-based permit with TRANSFER_WITNESS to authorize a one-time transfer
* @param owner The address that owns the tokens and is authorizing the transfer
* @param spender The address that will receive the tokens (typically msg.sender)
* @param value The amount of tokens to transfer (in token's decimal units)
* @param deadline The timestamp after which the permit signature is no longer valid
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
* @return Always returns true to indicate successful transfer
*/
function permitTransferFrom(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual returns (bool) {
// Use permitWitness to set the allowance
_validatePermitWitness(owner, spender, value, deadline, TRANSFER_WITNESS, v, r, s);
// Execute the transfer
_update(owner, spender, value);
return true;
}
/**
* @notice Executes an external contract call with permit-based authorization
* @dev Sets allowance via witness permit then executes arbitrary call. Witness is derived from call data to
* prevent replay
* @param owner The address that owns the tokens and is authorizing the call
* @param spender The address that will be allowed to spend the tokens (typically the target contract)
* @param value The amount of tokens to approve for spending (in token's decimal units)
* @param deadline The timestamp after which the permit signature is no longer valid
* @param call ContractCall struct containing target, method, and encoded params with owner as first param
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
* @return The return data from the external contract call
*/
function permitWitnessCall(
address owner,
address spender,
uint256 value,
uint256 deadline,
ContractCall calldata call,
uint8 v,
bytes32 r,
bytes32 s
) public payable returns (bytes memory) {
// Validate inputs before expensive signature operations
if (call.target == address(0) || call.target == address(this)) {
revert ERC20InvalidCallTarget();
}
// Validate method is non-empty
if (bytes(call.method).length == 0) {
revert ERC20InvalidCallData();
}
// CRITICAL: Validate owner is first parameter (32 bytes) in call.params
if (call.params.length < 32 || bytes32(call.params[0:32]) != bytes32(uint256(uint160(owner)))) {
revert ERC20InvalidCallData();
}
// Validate msg.value is sufficient for the native value transfer
if (msg.value < call.nativeValue) {
revert ERC20InvalidCallData();
}
bytes32 witness = keccak256(
abi.encode(
WITNESS_CALL_TYPEHASH,
call.target,
keccak256(bytes(call.method)),
call.nativeValue,
keccak256(call.params)
)
);
// Use permitWitness to set the allowance
permitWitness(owner, spender, value, deadline, witness, WITNESS_CALL_TYPESTRING, v, r, s);
// Building the call data
bytes memory callData = abi.encodePacked(bytes4(keccak256(bytes(call.method))), call.params);
// Execute the external call
(bool success, bytes memory returnData) = call.target.call{ value: msg.value }(callData);
if (!success) {
// Forward the revert reason if available
if (returnData.length > 0) {
assembly {
let returnDataSize := mload(returnData)
revert(add(32, returnData), returnDataSize)
}
} else {
revert ERC20CallFailed();
}
}
return returnData;
}
/*//////////////////////////////////////////////////////////////
PERMIT WITNESS INTERNAL VALIDATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Internal function to validate witness-based permit signatures using default typeHash
* @dev Validates EIP-712 signature for witness permit with PERMIT_WITNESS_TYPEHASH
* @param owner The expected owner address that should have signed the permit
* @param spender The spender address included in the signed message
* @param value The token amount included in the signed message (in token's decimal units)
* @param deadline The deadline timestamp included in the signed message
* @param witness The witness data hash included in the signed message
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function _validatePermitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
uint8 v,
bytes32 r,
bytes32 s
) internal {
_validatePermitWitnessSignature(owner, spender, value, deadline, witness, PERMIT_WITNESS_TYPEHASH, v, r, s);
}
/**
* @notice Internal function to validate witness-based permit signatures with custom witness type
* @dev Validates EIP-712 signature for witness permit with custom witnessTypeString
* @param owner The expected owner address that should have signed the permit
* @param spender The spender address included in the signed message
* @param value The token amount included in the signed message (in token's decimal units)
* @param deadline The deadline timestamp included in the signed message
* @param witness The witness data hash included in the signed message
* @param witnessTypeString Custom witness type string for EIP-712 type construction
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function _validatePermitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
string memory witnessTypeString,
uint8 v,
bytes32 r,
bytes32 s
) internal {
// Validate witnessTypeString is not empty and reasonable length
if (bytes(witnessTypeString).length == 0 || bytes(witnessTypeString).length > 1024) {
revert ERC20InvalidWitness();
}
bytes32 typeHash = keccak256(abi.encodePacked(PERMIT_WITNESS_TYPESTRING_STAB, witnessTypeString));
_validatePermitWitnessSignature(owner, spender, value, deadline, witness, typeHash, v, r, s);
}
/**
* @notice Core internal function to validate witness-based permit signatures with a given typeHash
* @dev Validates EIP-712 signature, checking deadline, incrementing nonce, and recovering signer
* @param owner The expected owner address that should have signed the permit
* @param spender The spender address included in the signed message
* @param value The token amount included in the signed message (in token's decimal units)
* @param deadline The deadline timestamp included in the signed message
* @param witness The witness data hash included in the signed message
* @param typeHash The EIP-712 typeHash for the permit structure
* @param v The recovery identifier of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function _validatePermitWitnessSignature(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
bytes32 typeHash,
uint8 v,
bytes32 r,
bytes32 s
) internal {
if (deadline < block.timestamp) {
revert ERC2612ExpiredSignature(deadline);
}
bytes32 hash;
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
uint256 nonce = nonces[owner]++;
bytes32 structHash = keccak256(abi.encode(typeHash, owner, spender, value, nonce, deadline, witness));
hash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash));
}
address recoveredAddress = ecrecover(hash, v, r, s);
if (recoveredAddress == address(0) || recoveredAddress != owner) {
revert ERC2612InvalidSigner(recoveredAddress, owner);
}
}
}// SPDX-License-Identifier: MIT
// https://github.com/axelarnetwork/interchain-token-service/blob/main/contracts/interchain-token/InterchainTokenStandard.sol
pragma solidity ^0.8.0;
import { IInterchainTokenService } from "../interfaces/its/IInterchainTokenService.sol";
import { IInterchainStandard } from "../interfaces/telecoin/IInterchainStandard.sol";
/**
* @title An example implementation of the IInterchainTokenStandard.
* @notice The is an abstract contract that needs to be extended with an ERC20 implementation. See `InterchainToken` for
* an example implementation.
*/
abstract contract InterchainStandard is IInterchainStandard {
IInterchainTokenService public immutable interchainTokenService;
bytes32 public immutable interchainTokenId;
/**
* @notice Constructor for InterchainStandard
* @dev Initializes the ITS integration by setting the token service and token ID
* @param _interchainTokenService Address of the Interchain Token Service contract
* @param _interchainTokenId Unique identifier for this token in the ITS system
*/
constructor(
address _interchainTokenService,
bytes32 _interchainTokenId
) {
interchainTokenService = IInterchainTokenService(_interchainTokenService);
interchainTokenId = _interchainTokenId;
}
/**
* @notice Implementation of the interchainTransfer method
* @dev We chose to either pass `metadata` as raw data on a remote contract call, or if no data is passed, just do a
* transfer.
* A different implementation could use metadata to specify a function to invoke, or for other purposes as well.
* @param destinationChain The destination chain identifier.
* @param recipient The bytes representation of the address of the recipient.
* @param amount The amount of token to be transferred.
* @param metadata Either empty, just to facilitate an interchain transfer, or the data to be passed for an
* interchain contract call with transfer
* as per semantics defined by the token service.
*/
function interchainTransfer(
string calldata destinationChain,
bytes calldata recipient,
uint256 amount,
bytes calldata metadata
) public payable {
address sender = msg.sender;
_beforeInterchainTransfer(msg.sender, destinationChain, recipient, amount, metadata);
IInterchainTokenService(interchainTokenService)
.transmitInterchainTransfer{
value: address(this).balance
}(interchainTokenId, sender, destinationChain, recipient, amount, metadata);
}
/**
* @notice Transfers tokens from a sender to a recipient on a destination chain using allowance
* @dev Requires prior approval from sender. Decreases allowance before executing cross-chain transfer
* @param sender The address owning the tokens (must have approved msg.sender)
* @param destinationChain The destination chain identifier (e.g., "ethereum", "arbitrum")
* @param recipient The bytes representation of the recipient address on destination chain
* @param amount The amount of tokens to transfer
* @param metadata Additional data for the transfer, can be empty or contain call data
*/
function interchainTransferFrom(
address sender,
string calldata destinationChain,
bytes calldata recipient,
uint256 amount,
bytes calldata metadata
) public payable {
_decreaseAllowance(sender, msg.sender, amount);
_beforeInterchainTransfer(sender, destinationChain, recipient, amount, metadata);
IInterchainTokenService(interchainTokenService)
.transmitInterchainTransfer{
value: address(this).balance
}(interchainTokenId, sender, destinationChain, recipient, amount, metadata);
}
/**
* @notice A method to be overwritten that will be called before an interchain transfer. One can approve the
* tokenManager here if needed,
* to allow users for a 1-call transfer in case of a lock-unlock token manager.
* @param from The sender of the tokens. They need to have approved `msg.sender` before this is called.
* @param destinationChain The string representation of the destination chain.
* @param destinationAddress The bytes representation of the address of the recipient.
* @param amount The amount of token to be transferred.
* @param metadata Either empty, just to facilitate an interchain transfer, or the data to be passed to an
* interchain contract call and transfer.
*/
function _beforeInterchainTransfer(
address from,
string calldata destinationChain,
bytes calldata destinationAddress,
uint256 amount,
bytes calldata metadata
) internal virtual { }
/**
* @notice Decreases the allowance of a spender for a sender's tokens
* @dev Virtual function that must be implemented by inheriting contracts. Should preserve infinite allowance when
* applicable
* @param sender Address owning the tokens
* @param spender Address spending the tokens
* @param amount Amount to decrease the allowance by
*/
function _decreaseAllowance(
address sender,
address spender,
uint256 amount
) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { ILayerZeroEndpointV2 } from "../interfaces/layerzero/ILayerZeroEndpointV2.sol";
import { IOFT, OFTFeeDetail, OFTLimit, OFTReceipt, SendParam } from "../interfaces/layerzero/IOFT.sol";
import { IPrintrTeleport } from "../interfaces/printr/IPrintrTeleport.sol";
/**
* @title OftStandard
* @notice Abstract contract implementing LayerZero OFT standard for Telecoins
* @dev Delegates to existing teleport infrastructure under the hood
* @dev Expects inheriting contracts to provide _lzTeleport and quoteTeleportFee implementations from Telecoin
*/
abstract contract OftStandard is IOFT {
/**
* @notice Retrieves interfaceID and version of the OFT
* @return interfaceId The interface ID (0x02e49c2c)
* @return version The version (1)
*/
function oftVersion() external pure returns (bytes4 interfaceId, uint64 version) {
return (0x02e49c2c, 1);
}
/**
* @notice Retrieves the address of the token associated with the OFT
* @return token The address of the ERC20 token implementation (this contract)
*/
function token() external view returns (address) {
return address(this);
}
/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send
* @return requiresApproval False, as the token itself implements the OFT interface
*/
function approvalRequired() external pure returns (bool) {
return false;
}
/**
* @notice Retrieves the shared decimals of the OFT
* @return sharedDecimals The shared decimals (9)
*/
function sharedDecimals() external pure returns (uint8) {
return 9;
}
/**
* @notice Provides a quote for OFT-related operations
* @param _sendParam The parameters for the send operation
* @return limit The OFT limit information
* @return oftFeeDetails The details of OFT fees
* @return receipt The OFT receipt information
*/
function quoteOFT(
SendParam calldata _sendParam
) external returns (OFTLimit memory limit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory receipt) {
// Convert SendParam to TeleportParams
IPrintrTeleport.TeleportParams memory params = _sendParamToTeleportParams(_sendParam);
// Get fee from PrintrTeleport
(uint256 totalNativeFee,,, uint256 bridgeFee) = _quoteTeleportFee(params);
// Calculate protocol fee
uint256 protocolFee = totalNativeFee - bridgeFee;
// Return limits (no hard limits on telecoin transfers)
limit = OFTLimit({ minAmountLD: 0, maxAmountLD: type(uint256).max });
// Return fee details array with protocol fee and bridge fee
oftFeeDetails = new OFTFeeDetail[](2);
oftFeeDetails[0] = OFTFeeDetail({ feeAmountLD: int256(protocolFee), description: "Protocol Fee" });
oftFeeDetails[1] = OFTFeeDetail({ feeAmountLD: int256(bridgeFee), description: "Bridge Fee" });
// Return receipt (1:1 transfer, no conversion)
receipt = OFTReceipt({ amountSentLD: _sendParam.amountLD, amountReceivedLD: _sendParam.amountLD });
}
/**
* @notice Provides a quote for the send() operation
* @param _sendParam The parameters for the send() operation
* @return fee The calculated LayerZero messaging fee
*/
function quoteSend(
SendParam calldata _sendParam,
bool /* _payInLzToken */
) external returns (ILayerZeroEndpointV2.MessagingFee memory fee) {
// Convert SendParam to TeleportParams
IPrintrTeleport.TeleportParams memory params = _sendParamToTeleportParams(_sendParam);
// Get fee from PrintrTeleport
(uint256 totalNativeFee,,,) = _quoteTeleportFee(params);
// Return MessagingFee (we don't support LZ token payments)
fee = ILayerZeroEndpointV2.MessagingFee({ nativeFee: totalNativeFee, lzTokenFee: 0 });
}
/**
* @notice Executes the send() operation
* @param _sendParam The parameters for the send operation
* @param _fee The fee information supplied by the caller
* @return receipt The LayerZero messaging receipt
* @return oftReceipt The OFT receipt information
*/
function send(
SendParam calldata _sendParam,
ILayerZeroEndpointV2.MessagingFee calldata _fee,
address /* _refundAddress */
) external payable returns (ILayerZeroEndpointV2.MessagingReceipt memory receipt, OFTReceipt memory oftReceipt) {
// Check slippage
if (_sendParam.amountLD < _sendParam.minAmountLD) {
revert SlippageExceeded(_sendParam.amountLD, _sendParam.minAmountLD);
}
// Convert SendParam to TeleportParams
IPrintrTeleport.TeleportParams memory params = _sendParamToTeleportParams(_sendParam);
// Call the LayerZero teleport function
_lzTeleport(msg.sender, params);
// Create a pseudo-GUID from sender and params
bytes32 guid = keccak256(abi.encodePacked(msg.sender, _sendParam.dstEid, _sendParam.amountLD));
// Emit OFTSent event
emit OFTSent(guid, _sendParam.dstEid, msg.sender, _sendParam.amountLD, _sendParam.amountLD);
// Return receipt (we don't have access to LayerZero's actual GUID and nonce, so we create synthetic values)
receipt = ILayerZeroEndpointV2.MessagingReceipt({
guid: guid, nonce: uint64(block.timestamp), fee: ILayerZeroEndpointV2.MessagingFee(_fee.nativeFee, 0)
});
// Return OFT receipt
oftReceipt = OFTReceipt({ amountSentLD: _sendParam.amountLD, amountReceivedLD: _sendParam.amountLD });
}
function _quoteTeleportFee(
IPrintrTeleport.TeleportParams memory params
) internal virtual returns (uint256 totalNativeFee, uint256 basePairFee, address basePair, uint256 bridgeFee);
/**
* @notice Internal abstract function for teleporting tokens
* @dev Must be implemented by Telecoin to call its teleport() function
* @param params The teleport parameters
*/
function _lzTeleport(
address from,
IPrintrTeleport.TeleportParams memory params
) internal virtual;
/**
* @notice Converts SendParam to TeleportParams
* @param _sendParam The OFT SendParam struct
* @return params The equivalent TeleportParams struct
*/
function _sendParamToTeleportParams(
SendParam calldata _sendParam
) internal pure returns (IPrintrTeleport.TeleportParams memory params) {
// Map endpoint ID to chain name
string memory destChain = _eidToString(_sendParam.dstEid);
// Determine protocol based on extraOptions (default to LZ_FAST)
IPrintrTeleport.TeleportProtocol protocol = _parseProtocolFromOptions(_sendParam.extraOptions);
// Convert recipient from bytes32 to bytes
bytes memory destAddress = abi.encodePacked(_sendParam.to);
// Combine composeMsg and oftCmd into metadata if present
bytes memory metadata;
if (_sendParam.composeMsg.length > 0 || _sendParam.oftCmd.length > 0) {
metadata = abi.encode(_sendParam.composeMsg, _sendParam.oftCmd);
}
params = IPrintrTeleport.TeleportParams({
destChain: destChain,
destAddress: destAddress,
amount: _sendParam.amountLD,
metadata: metadata,
protocol: protocol
});
}
/**
* @notice Converts LayerZero endpoint ID to string representation
* @param eid Endpoint ID
* @return eidString The endpoint ID as a string (e.g., "30101")
*/
function _eidToString(
uint32 eid
) internal pure returns (string memory eidString) {
// Convert uint32 to string
if (eid == 0) {
return "0";
}
uint32 temp = eid;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (eid != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint32(eid % 10)));
eid /= 10;
}
return string(buffer);
}
/**
* @notice Parses LayerZero extraOptions to determine protocol
* @param extraOptions The extra options bytes (can encode security level)
* @return protocol The teleport protocol to use
*/
function _parseProtocolFromOptions(
bytes calldata extraOptions
) internal pure returns (IPrintrTeleport.TeleportProtocol protocol) {
// Default to LZ_FAST if no options provided
if (extraOptions.length == 0) {
return IPrintrTeleport.TeleportProtocol.LZ_FAST;
}
// Parse first byte as security level indicator if present
// 1 = LZ_FAST, 2 = LZ_SECURE, 3 = LZ_SLOW
uint8 securityLevel = uint8(extraOptions[0]);
if (securityLevel == 1) {
return IPrintrTeleport.TeleportProtocol.LZ_FAST;
} else if (securityLevel == 2) {
return IPrintrTeleport.TeleportProtocol.LZ_SECURE;
} else if (securityLevel == 3) {
return IPrintrTeleport.TeleportProtocol.LZ_SLOW;
}
// Default to LZ_FAST for any other value
return IPrintrTeleport.TeleportProtocol.LZ_FAST;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { ILayerZeroEndpointV2 } from "./ILayerZeroEndpointV2.sol";
/**
* @dev Struct representing token parameters for the OFT send() operation.
*/
struct SendParam {
uint32 dstEid; // Destination endpoint ID
bytes32 to; // Recipient address
uint256 amountLD; // Amount to send in local decimals
uint256 minAmountLD; // Minimum amount to send in local decimals
bytes extraOptions; // Additional options for LayerZero message
bytes composeMsg; // Composed message for send() operation
bytes oftCmd; // OFT command (unused in default implementations)
}
/**
* @dev Struct representing OFT limit information.
*/
struct OFTLimit {
uint256 minAmountLD; // Minimum amount in local decimals
uint256 maxAmountLD; // Maximum amount in local decimals
}
/**
* @dev Struct representing OFT receipt information.
*/
struct OFTReceipt {
uint256 amountSentLD; // Amount debited from sender
uint256 amountReceivedLD; // Amount to be received on remote side
}
/**
* @dev Struct representing OFT fee details.
*/
struct OFTFeeDetail {
int256 feeAmountLD; // Amount of fee in local decimals
string description; // Description of the fee
}
/**
* @title IOFT
* @dev Interface for the Omnichain Fungible Token (OFT) standard.
* @dev Interface ID: 0x02e49c2c
*/
interface IOFT {
// Custom errors
error InvalidLocalDecimals();
error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);
// Events
event OFTSent(
bytes32 indexed guid, uint32 dstEid, address indexed fromAddress, uint256 amountSentLD, uint256 amountReceivedLD
);
event OFTReceived(bytes32 indexed guid, uint32 srcEid, address indexed toAddress, uint256 amountReceivedLD);
/**
* @notice Retrieves interfaceID and version of the OFT.
* @return interfaceId The interface ID (0x02e49c2c).
* @return version The version.
*/
function oftVersion() external view returns (bytes4 interfaceId, uint64 version);
/**
* @notice Retrieves the address of the token associated with the OFT.
* @return token The address of the ERC20 token implementation.
*/
function token() external view returns (address);
/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
* @return requiresApproval Whether approval is required.
*/
function approvalRequired() external view returns (bool);
/**
* @notice Retrieves the shared decimals of the OFT.
* @return sharedDecimals The shared decimals (typically 6).
*/
function sharedDecimals() external view returns (uint8);
/**
* @notice Provides a quote for OFT-related operations.
* @param _sendParam The parameters for the send operation.
* @return limit The OFT limit information.
* @return oftFeeDetails The details of OFT fees.
* @return receipt The OFT receipt information.
*/
function quoteOFT(
SendParam calldata _sendParam
) external returns (OFTLimit memory limit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory receipt);
/**
* @notice Provides a quote for the send() operation.
* @param _sendParam The parameters for the send() operation.
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
* @return fee The calculated LayerZero messaging fee.
*/
function quoteSend(
SendParam calldata _sendParam,
bool _payInLzToken
) external returns (ILayerZeroEndpointV2.MessagingFee memory fee);
/**
* @notice Executes the send() operation.
* @param _sendParam The parameters for the send operation.
* @param _fee The fee information supplied by the caller.
* @param _refundAddress The address to receive any excess funds.
* @return receipt The LayerZero messaging receipt.
* @return oftReceipt The OFT receipt information.
*/
function send(
SendParam calldata _sendParam,
ILayerZeroEndpointV2.MessagingFee calldata _fee,
address _refundAddress
) external payable returns (ILayerZeroEndpointV2.MessagingReceipt memory receipt, OFTReceipt memory oftReceipt);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import { IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC20Permit } from "./IERC20Permit.sol";
/// @title IERC20Witness Interface
/// @notice Interface for ERC20 tokens with witness-based permit functionality
/// @dev Extends standard ERC20 with permitWitness functions that include additional validation data
interface IERC20Witness is IERC20Permit, IERC20Metadata, IERC20Errors {
/*//////////////////////////////////////////////////////////////
WITNESS-SPECIFIC ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Thrown when an invalid witness value is provided
* @dev The witness data failed validation checks
*/
error ERC20InvalidWitness();
/**
* @notice Thrown when attempting to call the contract itself
* @dev Self-calls are not permitted for security reasons
*/
error ERC20InvalidCallTarget();
/**
* @notice Thrown when invalid call data is provided
* @dev The call data format or content is malformed
*/
error ERC20InvalidCallData();
/**
* @notice Thrown when an external call fails during witness operations
* @dev The target contract call returned failure or reverted
*/
error ERC20CallFailed();
struct ContractCall {
address target;
string method;
uint256 nativeValue;
bytes params;
}
/*//////////////////////////////////////////////////////////////
PERMIT WITNESS LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the permit witness typehash for EIP-712 signature encoding
* @dev Used for permitWitness function signature validation
* @return The keccak256 hash of the permit witness type string
*/
function PERMIT_WITNESS_TYPEHASH() external view returns (bytes32);
/**
* @notice Returns the base permit witness type string for EIP-712 structured data
* @dev Used as a prefix to construct full type strings with witness data
* @return The base permit witness type string stub
*/
function PERMIT_WITNESS_TYPESTRING_STAB() external view returns (string memory);
/**
* @notice Returns the contract call witness type string completion
* @dev Appended to PERMIT_WITNESS_TYPESTRING_STAB to form complete EIP-712 type string
* @return The contract call type string completion
*/
function WITNESS_CALL_TYPESTRING() external view returns (string memory);
/**
* @notice Returns the contract call typehash for EIP-712 signature encoding
* @dev Used for ContractCall struct hashing in witness validation
* @return The keccak256 hash of the ContractCall type string
*/
function WITNESS_CALL_TYPEHASH() external view returns (bytes32);
/**
* @notice Returns the witness type identifier for transfer operations
* @dev Used to validate witness data in transfer contexts
* @return The bytes32 identifier for transfer witness operations
*/
function TRANSFER_WITNESS() external view returns (bytes32);
/**
* @notice Sets allowance using signature with additional witness validation
* @dev Extends standard permit functionality with witness data for enhanced security
* @param owner The owner of the tokens
* @param spender The address authorized to spend the tokens
* @param value The amount of tokens to authorize for spending
* @param deadline The timestamp at which the permit expires
* @param witness Additional validation data to prevent certain attack vectors
* @param v The recovery parameter of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Sets allowance using signature with custom witness type string for free-form witness data
* @dev Extends permitWitness with witnessTypeString parameter to support various witness structures
* @param owner The owner of the tokens
* @param spender The address authorized to spend the tokens
* @param value The amount of tokens to authorize for spending
* @param deadline The timestamp at which the permit expires
* @param witness Additional validation data hash to prevent certain attack vectors
* @param witnessTypeString The EIP-712 type string for the witness data structure
* @param v The recovery parameter of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
*/
function permitWitness(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes32 witness,
string calldata witnessTypeString,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Permits and executes a direct transfer using signature authorization
* @dev Combines permit and transferFrom into a single operation with witness validation
* @param owner The owner of the tokens to transfer
* @param spender The recipient address for the transfer
* @param value The amount of tokens to transfer
* @param deadline The timestamp at which the permit expires
* @param v The recovery parameter of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
* @return success Whether the transfer operation was successful
*/
function permitTransferFrom(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (bool success);
/**
* @notice Permits token allowance and executes an external call in one transaction
* @dev Combines permit functionality with external contract interaction using witness validation
* @param owner The owner of the tokens
* @param spender The address authorized to spend the tokens
* @param value The amount of tokens to authorize for spending
* @param deadline The timestamp at which the permit expires
* @param call ContractCall struct containing target address, method signature, and parameters
* @param v The recovery parameter of the signature (27 or 28)
* @param r The first 32 bytes of the signature
* @param s The second 32 bytes of the signature
* @return returnData The return data from the executed external call
*/
function permitWitnessCall(
address owner,
address spender,
uint256 value,
uint256 deadline,
ContractCall calldata call,
uint8 v,
bytes32 r,
bytes32 s
) external payable returns (bytes memory returnData);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IInterchainTokenService } from "../its/IInterchainTokenService.sol";
/**
* @title IInterchainStandard Interface
* @notice This interface defines functions for cross-chain token transfers.
*/
interface IInterchainStandard {
/**
* @notice Returns the Interchain Token Service instance.
* @return The IInterchainTokenService contract instance.
*/
function interchainTokenService() external view returns (IInterchainTokenService);
/**
* @notice Returns the interchain token identifier.
* @return The bytes32 identifier of the interchain token.
*/
function interchainTokenId() external view returns (bytes32);
/**
* @notice Implementation of the interchainTransfer method.
* @dev We chose to either pass `metadata` as raw data on a remote contract call, or if no data is passed, just do a
* transfer.
* A different implementation could use metadata to specify a function to invoke, or for other purposes as well.
* @param destinationChain The destination chain identifier.
* @param recipient The bytes representation of the address of the recipient.
* @param amount The amount of token to be transferred.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract).
*/
function interchainTransfer(
string calldata destinationChain,
bytes calldata recipient,
uint256 amount,
bytes calldata metadata
) external payable;
/**
* @notice Implementation of the interchainTransferFrom method
* @dev We chose to either pass `metadata` as raw data on a remote contract call, or, if no data is passed, just do
* a transfer.
* A different implementation could use metadata to specify a function to invoke, or for other purposes as well.
* @param sender The sender of the tokens. They need to have approved `msg.sender` before this is called.
* @param destinationChain The string representation of the destination chain.
* @param recipient The bytes representation of the address of the recipient.
* @param amount The amount of token to be transferred.
* @param metadata Optional metadata for the call for additional effects (such as calling a destination contract.)
*/
function interchainTransferFrom(
address sender,
string calldata destinationChain,
bytes calldata recipient,
uint256 amount,
bytes calldata metadata
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { ITelecoin } from "./ITelecoin.sol";
/**
* @title ITeleportingTelecoin
* @notice Interface for the TeleportingTelecoin contract with teleporting capabilities
* @dev Extends ITelecoin for teleport functionality with ITS integration
*/
interface ITeleportingTelecoin is ITelecoin {
/**
* @notice Error thrown when invalid function selector is provided
*/
error InvalidFunctionSelector();
/**
* @notice Teleports tokens into existence for cross-chain transfers
* @param to Address to receive the tokens
* @param value Amount of tokens to teleport in
*/
function teleportIn(
address to,
uint256 value
) external;
/**
* @notice Teleports tokens out of existence for cross-chain transfers
* @param from Address whose tokens are being teleported out
* @param value Amount of tokens to teleport out
*/
function teleportOut(
address from,
uint256 value
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { ITreasury } from "../ITreasury.sol";
/**
* @title Printr Storage Interface
* @notice Interface for the Printr contract, which manages tokens with linear bonding curves
* @dev All price calculations use PRECISION_SCALAR (1e18) for accurate floating point math
* Implements cross-chain token deployment through ITelecoinFactory integration
* This interface defines the core storage and view functions for the Printr system
*/
interface IPrintrStorage {
/// @notice Custom errors for the Printr contract
error FeeIsTooHigh(uint256 fee);
error WrongChainName();
error InsufficientPayment();
error InsufficientInitialBuy();
error InvalidBasePairDecimals();
error InvalidBasePrices();
error InvalidBasePairs();
error InvalidCreatorAddress();
error InvalidInitialPrice();
error InvalidLength();
error TooHighThreshold();
error ZeroAmount();
error PoolCreationFailed();
error TokenNotFound();
error SwapFailed();
error LiquidityAlreadyDeployed();
error LiquidityDeploymentFailed();
error InvalidQuoteResult();
error PriceExceedsLimit();
error RefundFailed();
error RenounceOwnershipDisabled();
error InvalidImplementation();
error FeePercentagesMustSum();
error UnauthorizedCaller();
error Create3AddressMismatch();
/**
* @notice Parameters structure for telecoin deployment
* @dev Uses bytes32 for efficient storage and cross-chain compatibility
* @param salt Unique identifier for deployment
* @param creatorAddresses Creator addresses for different chains encoded as bytes
* @param name Telecoin name encoded as bytes32, 31 characters max
* @param symbol Telecoin symbol encoded as bytes32, 31 characters max
* @param packedParams Packed parameters bit layout:
* [0-7] uint8 maxTokenSupplyE (power of 10)
* [8-23] uint16 completionThreshold (basis points, max 10000)
* [24-135] uint112 initialPrice, assuming 18 decimal places for both tokens
* [136-255] uint120 initialBuySpending, assuming 18 decimal places
* @param chains Chain names encoded as bytes32, first chain is the home chain
* @param basePairs Base currency token addresses encoded as bytes32
* @param basePrices Initial prices in base currency per chain as uint128 packed in bytes, 18 decimals for both
*/
struct TelecoinParams {
bytes32 salt;
bytes creatorAddresses;
bytes32 name;
bytes32 symbol;
bytes32 packedParams;
bytes32[] chains;
bytes32[] basePairs;
bytes basePrices;
}
/**
* @notice Unpacked version of the packedParams for easier handling
* @dev Packed bytes32 converted into individual parameters
* @param maxTokenSupplyE Maximum token supply as power of 10
* @param completionThreshold Completion threshold in basis points (max 10000) of max supply
* @param initialPrice Initial token price, assuming 18 decimal places for both tokens
* @param initialBuySpending Initial buy amount, assuming 18 decimal places
*/
struct UnpackedParams {
uint8 maxTokenSupplyE;
uint256 completionThreshold;
uint256 initialPrice;
uint256 initialBuySpending;
}
/**
* @notice Comprehensive information about a token's configuration and state
* @dev Whole struct is packed into 2 storage slots for efficiency
* @param basePair Address of the base currency token (160 bits)
* @param totalCurves Number of curves across all chains (16 bits)
* @param maxTokenSupplyE Maximum token supply as pow of 10 (8 bits)
* @param virtualReserveE Precision scalar for virtualReserve (8 bits)
* @param virtualReserve Compressed virtual reserve balance for bonding curve (64 bits)
* @param reserve Current reserve balance of the base currency token (192 bits)
* @param completionThreshold Threshold for curve completion as percentage of total supply (64 bits)
*/
struct Curve {
/// @dev Slot 1: immutable (160 + 16 + 8 + 8 + 64 = 256 bits, fits in 1 slot)
address basePair;
uint16 totalCurves;
uint8 maxTokenSupplyE;
uint8 virtualReserveE;
uint64 virtualReserve;
/// @dev Slot 2: mutable (192 + 64 = 256 bits)
uint192 reserve;
uint64 completionThreshold;
}
/**
* @notice Readable format of curve information
* @param basePair Base currency token address
* @param totalCurves Total number of curves across chains
* @param maxTokenSupply Maximum token supply
* @param virtualReserve Virtual reserve for curve calculations (already scaled with virtualReserveE)
* @param reserve Current base currency reserve
* @param completionThreshold Completion threshold value
*/
struct CurveInfo {
address basePair;
uint16 totalCurves;
uint256 maxTokenSupply;
uint256 virtualReserve;
uint256 reserve;
uint256 completionThreshold;
}
/**
* @notice Parameters for deploying Printr contracts
* @dev Used to avoid stack too deep errors in constructor
* @param chainName Name of the blockchain network
* @param treasury Address of the treasury contract
* @param legacyTreasury Address of the legacy treasury contract (for migration)
* @param mainTelecoinFactory Address of the main token factory contract
* @param teleportingTelecoinFactory Address of the teleporting token factory contract
* @param its Address of the Interchain Token Service
* @param itsFactory Address of the ITS factory
* @param wrappedNativeToken Address of wrapped native token (e.g., WETH)
* @param locker Address of the locker contract
* @param liquidityModule Address of the liquidity module
* @param create3Deployer Address of the CREATE3 deployer for deterministic LZChannel deployments
* @param growthFundFund Address of the growth fund
* @param buybackFund Address of the buyback
* @param teamTreasuryFund Address of the team treasury
* @param stakingFund Address of the staking
* @param printrDev Address of the dev NFT contract
* @param legacyPrintrDev Address of the legacy dev NFT contract (for migration)
* @param feePercentGrowth Fee percentage for growth fund in basis points
* @param feePercentBuyback Fee percentage for buyback in basis points
* @param feePercentTeam Fee percentage for team treasury in basis points
* @param feePercentCreator Fee percentage for creator in basis points
* @param tradingFee Trading fee percentage in basis points
*/
struct DeploymentParams {
string chainName;
address treasury;
address legacyTreasury;
address mainTelecoinFactory;
address teleportingTelecoinFactory;
address its;
address itsFactory;
address wrappedNativeToken;
address locker;
address liquidityModule;
address create3Deployer;
address growthFund;
address buybackFund;
address teamTreasuryFund;
address stakingFund;
address printrDev;
address legacyPrintrDev;
uint256 feePercentGrowth;
uint256 feePercentBuyback;
uint256 feePercentTeam;
uint256 feePercentCreator;
uint16 tradingFee;
}
/// @notice Returns the current chain's hash identifier
function currentChainHash() external view returns (bytes32);
/// @notice Returns the treasury contract address
function treasury() external view returns (ITreasury);
/// @notice Returns the main token factory contract address
function mainTelecoinFactory() external view returns (address);
/// @notice Returns the teleporting token factory contract address
function teleportingTelecoinFactory() external view returns (address);
/// @notice Returns the ITS contract address
function interchainTokenService() external view returns (address);
/// @notice Returns the ITS factory contract address
function itsFactory() external view returns (address);
/// @notice Returns the wrapped native token address
function wrappedNativeToken() external view returns (address);
/// @notice Returns the liquidity module contract address
function liquidityModule() external view returns (address);
/// @notice Returns the locker contract address
function locker() external view returns (address);
/// @notice Returns the CREATE3 deployer address
function create3Deployer() external view returns (address);
/// @notice Returns the growth fund address
function growthFund() external view returns (address);
/// @notice Returns the buyback address
function buybackFund() external view returns (address);
/// @notice Returns the team treasury address
function teamTreasuryFund() external view returns (address);
/// @notice Returns the staking address
function stakingFund() external view returns (address);
/// @notice Returns the creator NFT contract address
function printrDev() external view returns (address);
/// @notice Returns the fee percentage for growth fund
function feePercentGrowth() external view returns (uint256);
/// @notice Returns the fee percentage for buyback
function feePercentBuyback() external view returns (uint256);
/// @notice Returns the fee percentage for team treasury
function feePercentTeam() external view returns (uint256);
/// @notice Returns the fee percentage for creator
function feePercentCreator() external view returns (uint256);
/// @notice Returns the trading fee percentage in basis points
function tradingFee() external view returns (uint16);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
/**
* @title ILayerZeroEndpointV2
* @notice Interface for LayerZero V2 endpoint contract
* @dev Defines the core messaging functions for cross-chain communication
*/
interface ILayerZeroEndpointV2 {
/**
* @notice Struct containing messaging fee information
* @param nativeFee Native fee amount to send
* @param lzTokenFee LayerZero token fee amount
*/
struct MessagingFee {
uint256 nativeFee;
uint256 lzTokenFee;
}
/**
* @notice Struct containing messaging parameters
* @param dstEid Destination endpoint ID
* @param receiver Receiver address on destination chain (as bytes32)
* @param message Message payload to send
* @param options Execution options for the message
* @param payInLzToken Whether to pay fees in LZ token
*/
struct MessagingParams {
uint32 dstEid;
bytes32 receiver;
bytes message;
bytes options;
bool payInLzToken;
}
/**
* @notice Struct containing messaging receipt information
* @param guid Globally unique identifier for the message
* @param nonce Message nonce
* @param fee Messaging fee paid
*/
struct MessagingReceipt {
bytes32 guid;
uint64 nonce;
MessagingFee fee;
}
/**
* @notice Send a message to another chain
* @param params Messaging parameters
* @param refundAddress Address to refund excess fees
* @return receipt Message receipt containing guid and fee info
*/
function send(
MessagingParams calldata params,
address refundAddress
) external payable returns (MessagingReceipt memory receipt);
/**
* @notice Quote the fee for sending a message
* @param params Messaging parameters
* @param sender The sender address
* @return fee The messaging fee quote
*/
function quote(
MessagingParams calldata params,
address sender
) external view returns (MessagingFee memory fee);
/**
* @notice Struct for setting configuration parameters
* @param eid Endpoint ID
* @param configType Configuration type (1=Executor, 2=ULN)
* @param config Encoded configuration data
*/
struct SetConfigParam {
uint32 eid;
uint32 configType;
bytes config;
}
/**
* @notice Set configuration for an OApp
* @param oapp The OApp address to configure
* @param lib The library address (SendLib or ReceiveLib)
* @param params Array of configuration parameters
*/
function setConfig(
address oapp,
address lib,
SetConfigParam[] calldata params
) external;
/**
* @notice Set send library for an OApp
* @param _oapp The OApp address
* @param _eid Destination endpoint ID
* @param _newLib Send library address
*/
function setSendLibrary(
address _oapp,
uint32 _eid,
address _newLib
) external;
/**
* @notice Set receive library for an OApp
* @param _oapp The OApp address
* @param _eid Source endpoint ID
* @param _newLib Receive library address
* @param _gracePeriod Grace period for library switch
*/
function setReceiveLibrary(
address _oapp,
uint32 _eid,
address _newLib,
uint256 _gracePeriod
) external;
/**
* @notice Set delegate for message handling
* @param delegate Address of the delegate
*/
function setDelegate(
address delegate
) external;
/**
* @notice Get the send library for an OApp and destination
* @param _sender The sender address
* @param _eid Destination endpoint ID
* @return lib The send library address
*/
function getSendLibrary(
address _sender,
uint32 _eid
) external view returns (address lib);
/**
* @notice Get the receive library for an OApp and source
* @param _receiver The receiver address
* @param _eid Source endpoint ID
* @return lib The receive library address
*/
function getReceiveLibrary(
address _receiver,
uint32 _eid
) external view returns (address lib, bool);
/**
* @notice Get the default send library for an endpoint
* @param _eid Destination endpoint ID
* @return The default send library address
*/
function defaultSendLibrary(
uint32 _eid
) external view returns (address);
/**
* @notice Get the default receive library for an endpoint
* @param _eid Source endpoint ID
* @return The default receive library address
*/
function defaultReceiveLibrary(
uint32 _eid
) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
/**
* @title ITreasury
* @notice Interface for managing protocol fee collection and token withdrawals
* @dev Handles LP fee collection and controlled withdrawals of tokens/native currency
*/
interface ITreasury {
/**
* @notice Thrown when an unauthorized address attempts to access treasury functions
*/
error WrongAccess();
/**
* @notice Thrown when a withdrawal of native currency fails
*/
error FailedWithdrawal();
/**
* @notice Thrown when a zero address is provided where a valid address is required
*/
error ZeroAddress();
/**
* @notice Emitted when fees are collected from a liquidity position
* @param token0 Address of the first token in the pair
* @param token1 Address of the second token in the pair
* @param recipient Address receiving the collected fees
* @param amount0 Amount of token0 collected
* @param amount1 Amount of token1 collected
* @param lockId ID of the locked liquidity position
*/
event CollectedLiquidityFees(
address indexed token0,
address indexed token1,
address indexed recipient,
uint256 amount0,
uint256 amount1,
uint256 lockId
);
/**
* @notice Collects accumulated fees from a locked liquidity position by delegating to the liquidity module
* @dev Only callable by authorized addresses. Delegates to the appropriate liquidity module
* which handles locker-specific logic (GoPlus, generic, etc.) and token ordering.
* @param liquidityModule Address of the liquidity module that manages this position's DEX
* @param lockId ID of the locked liquidity position
* @param token Address of the first token in the pair
* @param basePair Address of the second token in the pair (base currency)
* @param recipient Address to receive the collected fees
* @custom:throws WrongAccess if caller is not authorized
*/
function collectLiquidityFees(
address liquidityModule,
uint256 lockId,
address token,
address basePair,
address recipient
) external;
/**
* @notice Withdraws tokens or native currency from the treasury
* @dev Only callable by authorized addresses
* @param token Address of token to withdraw (address(0) for native currency)
* @param recipient Address to receive the withdrawal
* @param amount Amount to withdraw
* @custom:throws WrongAccess if caller is not authorized
* @custom:throws FailedWithdrawal if native currency transfer fails
*/
function withdraw(
address token,
address recipient,
uint256 amount
) external;
/**
* @notice Handles receipt of ERC721 tokens (LP position NFTs)
* @dev Required for compatibility with ERC721 token transfers
* @return bytes4 Function selector to indicate successful receipt
*/
function onERC721Received(
address, /* operator */
address, /* from */
uint256, /* tokenId */
bytes calldata /* data */
) external pure returns (bytes4);
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 2000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"bytes32","name":"telecoinId","type":"bytes32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"address","name":"printr","type":"address"},{"internalType":"address","name":"interchainTokenService","type":"address"},{"internalType":"address","name":"itsTokenManager","type":"address"},{"internalType":"bytes32","name":"interchainTokenId","type":"bytes32"}],"internalType":"struct ITelecoin.TelecoinDeployParams","name":"params","type":"tuple"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CurveIsNotComplete","type":"error"},{"inputs":[],"name":"ERC20CallFailed","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[],"name":"ERC20InvalidCallData","type":"error"},{"inputs":[],"name":"ERC20InvalidCallTarget","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"ERC20InvalidWitness","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidLocalDecimals","type":"error"},{"inputs":[],"name":"InvalidProtocol","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"UnauthorizedAccount","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"newNonce","type":"uint256"}],"name":"NonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"telecoinId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TeleportIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"telecoinId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TeleportOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_WITNESS_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_WITNESS_TYPESTRING_STAB","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITNESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITNESS_CALL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITNESS_CALL_TYPESTRING","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approvalRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"completionStatus","outputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"enum Printed.CompletionState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interchainTokenService","outputs":[{"internalType":"contract IInterchainTokenService","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"interchainTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"interchainTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"invalidateNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isTeleporting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"itsTokenManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"markCurveComplete","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oftVersion","outputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"},{"internalType":"uint64","name":"version","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"witness","type":"bytes32"},{"internalType":"string","name":"witnessTypeString","type":"string"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitWitness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"witness","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitWitness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"string","name":"method","type":"string"},{"internalType":"uint256","name":"nativeValue","type":"uint256"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct IERC20Witness.ContractCall","name":"call","type":"tuple"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitWitnessCall","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"printr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"}],"name":"quoteOFT","outputs":[{"components":[{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"uint256","name":"maxAmountLD","type":"uint256"}],"internalType":"struct OFTLimit","name":"limit","type":"tuple"},{"components":[{"internalType":"int256","name":"feeAmountLD","type":"int256"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct OFTFeeDetail[]","name":"oftFeeDetails","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"receipt","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bool","name":"","type":"bool"}],"name":"quoteSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct ILayerZeroEndpointV2.MessagingFee","name":"fee","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"destChain","type":"string"},{"internalType":"bytes","name":"destAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"enum IPrintrTeleport.TeleportProtocol","name":"protocol","type":"uint8"}],"internalType":"struct IPrintrTeleport.TeleportParams","name":"params","type":"tuple"}],"name":"quoteTeleportFee","outputs":[{"internalType":"uint256","name":"totalNativeFee","type":"uint256"},{"internalType":"uint256","name":"basePairFee","type":"uint256"},{"internalType":"address","name":"basePair","type":"address"},{"internalType":"uint256","name":"bridgeFee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct ILayerZeroEndpointV2.MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"","type":"address"}],"name":"send","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct ILayerZeroEndpointV2.MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct ILayerZeroEndpointV2.MessagingReceipt","name":"receipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"setRestrictedPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharedDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"telecoinId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"destChain","type":"string"},{"internalType":"bytes","name":"destAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"enum IPrintrTeleport.TeleportProtocol","name":"protocol","type":"uint8"}],"internalType":"struct IPrintrTeleport.TeleportParams","name":"params","type":"tuple"}],"name":"teleport","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"components":[{"internalType":"string","name":"destChain","type":"string"},{"internalType":"bytes","name":"destAddress","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"enum IPrintrTeleport.TeleportProtocol","name":"protocol","type":"uint8"}],"internalType":"struct IPrintrTeleport.TeleportParams","name":"params","type":"tuple"}],"name":"teleportFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101e0604052348015610010575f5ffd5b5060405161431d38038061431d83398101604081905261002f916104b8565b60a08084015160e0850151602086015160408701516080808901516001600160a01b0381169096525f908190528895601291849184918491908c908c90610077818484610150565b50505050826001908161008a919061063f565b506002610097838261063f565b5060ff811660c0524660e0526100ab61016b565b610100525050506001600160a01b03948516610120525050506101405260808201511615806100e5575060a08101516001600160a01b0316155b806100fb575060c08101516001600160a01b0316155b156101195760405163d92e233d60e01b815260040160405180910390fd5b80516101605260608101516101805260808101516001600160a01b039081166101a05260c090910151166101c052506107a3915050565b61015b838383610204565b6101668383836102ad565b505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600160405161019c91906106f9565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b604080518082019091525f80546001600160a01b038116835290919082906020830190600160a01b900460ff1660028111156102425761024261076a565b60028111156102535761025361076a565b90525090506001816020015160028111156102705761027061076a565b148015610289575080516001600160a01b038481169116145b156102a757604051632c47a42360e01b815260040160405180910390fd5b50505050565b6001600160a01b0383166102d7578060035f8282546102cc919061077e565b9091555061034b9050565b6001600160a01b0383165f908152600460205260409020548181101561032d5760405163391434e360e21b81526001600160a01b0385166004820152602481018290526044810183905260640160405180910390fd5b6001600160a01b0384165f9081526004602052604090209082900390555b6001600160a01b03821661036757600380548290039055610385565b6001600160a01b0382165f9081526004602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516103ca91815260200190565b60405180910390a3505050565b634e487b7160e01b5f52604160045260245ffd5b60405161010081016001600160401b038111828210171561040e5761040e6103d7565b60405290565b5f82601f830112610423575f5ffd5b81516001600160401b0381111561043c5761043c6103d7565b604051601f8201601f19908116603f011681016001600160401b038111828210171561046a5761046a6103d7565b604052818152838201602001851015610481575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b80516001600160a01b03811681146104b3575f5ffd5b919050565b5f5f5f606084860312156104ca575f5ffd5b83516001600160401b038111156104df575f5ffd5b840161010081870312156104f1575f5ffd5b6104f96103eb565b8151815260208201516001600160401b03811115610515575f5ffd5b61052188828501610414565b60208301525060408201516001600160401b0381111561053f575f5ffd5b61054b88828501610414565b604083015250606082810151908201526105676080830161049d565b608082015261057860a0830161049d565b60a082015261058960c0830161049d565b60c082015260e0918201519181019190915292506105a96020850161049d565b6040949094015192959394509192915050565b600181811c908216806105d057607f821691505b6020821081036105ee57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561016657805f5260205f20601f840160051c810160208510156106195750805b601f840160051c820191505b81811015610638575f8155600101610625565b5050505050565b81516001600160401b03811115610658576106586103d7565b61066c8161066684546105bc565b846105f4565b6020601f82116001811461069e575f83156106875750848201515b5f19600385901b1c1916600184901b178455610638565b5f84815260208120601f198516915b828110156106cd57878501518255602094850194600190920191016106ad565b50848210156106ea57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f5f8354610706816105bc565b60018216801561071d57600181146107325761075f565b60ff198316865281151582028601935061075f565b865f5260205f205f5b838110156107575781548882015260019091019060200161073b565b505081860193505b509195945050505050565b634e487b7160e01b5f52602160045260245ffd5b8082018082111561079d57634e487b7160e01b5f52601160045260245ffd5b92915050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c051613a986108855f395f81816105ca0152610e0401525f818161093e01528181610e8f01528181611bea01528181611c9e01528181611de901528181611fab015261236001525f61084b01525f81816106d901528181610e5201528181611e18015261238d01525f81816103fd01528181611464015261155901525f818161036501528181611435015261152a01525f610f5001525f610f1b01525f61052301525f81816117700152611af201525f6107b10152613a985ff3fe6080604052600436106102e2575f3560e01c80637ecebe0011610186578063bc0ba3c5116100dc578063dd62ed3e11610087578063f7cca09211610062578063f7cca0921461092d578063fc0c546a14610960578063ffe1aca514610972575f5ffd5b8063dd62ed3e146108a0578063eddd5458146108d6578063f1e3d5c41461090e575f5ffd5b8063d505accf116100b7578063d505accf1461081b578063d5abeb011461083a578063daf551d61461086d575f5ffd5b8063bc0ba3c5146107d3578063c7c7f5b3146107e6578063cf8af0a214610807575f5ffd5b806395d89b411161013c578063a60fee3711610117578063a60fee371461076e578063a9059cbb14610781578063b29300eb146107a0575f5ffd5b806395d89b41146107355780639f68b96414610749578063a5d454381461075b575f5ffd5b8063857749b01161016c578063857749b0146106fb57806386e118231461070e5780638b9868ec14610721575f5ffd5b80637ecebe001461069d57806381cce245146106c8575f5ffd5b806323b872dd1161023b57806336ee2bf7116101f15780635a57b46f116101cc5780635a57b46f1461064b57806370a082311461065f5780637787cbab1461068a575f5ffd5b806336ee2bf7146105b95780633b6f743b146105ec5780633b87f25214610618575f5ffd5b8063313ce56711610221578063313ce5671461051257806334c52e8b146105575780633644e515146105a5575f5ffd5b806323b872dd146104c057806330adf81f146104df575f5ffd5b80631248828a1161029b578063156a0d0f11610276578063156a0d0f1461044c57806318160ddd1461048c578063211be91f146104a1575f5ffd5b80631248828a146103cd578063129d8188146103ec57806313e06dce1461042d575f5ffd5b8063095ea7b3116102cb578063095ea7b31461032557806309c6bed9146103545780630d35b4151461039f575f5ffd5b806306fdde03146102e657806308951d8a14610310575b5f5ffd5b3480156102f1575f5ffd5b506102fa610986565b6040516103079190612a46565b60405180910390f35b61032361031e366004612a82565b610a12565b005b348015610330575f5ffd5b5061034461033f366004612acf565b610a9a565b6040519015158152602001610307565b34801561035f575f5ffd5b506103877f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610307565b3480156103aa575f5ffd5b506103be6103b9366004612b09565b610b06565b60405161030793929190612b3b565b3480156103d8575f5ffd5b506103236103e7366004612cd7565b610ca7565b3480156103f7575f5ffd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610307565b348015610438575f5ffd5b50610323610447366004612d77565b610d3c565b348015610457575f5ffd5b50604080517f02e49c2c0000000000000000000000000000000000000000000000000000000081526001602082015201610307565b348015610497575f5ffd5b5061041f60035481565b3480156104ac575f5ffd5b506103446104bb366004612dea565b610dcf565b3480156104cb575f5ffd5b506103446104da366004612e54565b610df9565b3480156104ea575f5ffd5b5061041f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b34801561051d575f5ffd5b506105457f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610307565b348015610562575f5ffd5b50610576610571366004612f56565b610efc565b604051610307949392919093845260208401929092526001600160a01b03166040830152606082015260800190565b3480156105b0575f5ffd5b5061041f610f18565b3480156105c4575f5ffd5b506103877f000000000000000000000000000000000000000000000000000000000000000081565b3480156105f7575f5ffd5b5061060b610606366004612f88565b610f72565b6040516103079190612fdb565b348015610623575f5ffd5b5061041f7fd74ba6270a1b25309f90735a3fcf045013fa182f846cd6210eab933f64fd346b81565b348015610656575f5ffd5b50610323610fba565b34801561066a575f5ffd5b5061041f610679366004612ff2565b60046020525f908152604090205481565b61032361069836600461300d565b611007565b3480156106a8575f5ffd5b5061041f6106b7366004612ff2565b60066020525f908152604090205481565b3480156106d3575f5ffd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610706575f5ffd5b506009610545565b6102fa61071c36600461303f565b611089565b34801561072c575f5ffd5b506102fa6113c1565b348015610740575f5ffd5b506102fa6113dd565b348015610754575f5ffd5b505f610344565b348015610766575f5ffd5b5061041f5f81565b61032361077c3660046130ff565b6113ea565b34801561078c575f5ffd5b5061034461079b366004612acf565b6114d4565b3480156107ab575f5ffd5b506103447f000000000000000000000000000000000000000000000000000000000000000081565b6103236107e13660046131b9565b6114e9565b6107f96107f4366004613261565b611591565b6040516103079291906132ca565b348015610812575f5ffd5b50610323611765565b348015610826575f5ffd5b50610323610835366004612dea565b61184a565b348015610845575f5ffd5b5061041f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610878575f5ffd5b5061041f7fbbbdcca327a1e5a9a22b7fea84fdadce610270aa8286c2f83d4b2e6713c7fc4381565b3480156108ab575f5ffd5b5061041f6108ba36600461331c565b600560209081525f928352604080842090915290825290205481565b3480156108e1575f5ffd5b505f54610900906001600160a01b03811690600160a01b900460ff1682565b60405161030792919061335c565b348015610919575f5ffd5b50610323610928366004612ff2565b611aa7565b348015610938575f5ffd5b506103877f000000000000000000000000000000000000000000000000000000000000000081565b34801561096b575f5ffd5b5030610387565b34801561097d575f5ffd5b506102fa611bca565b6001805461099390613389565b80601f01602080910402602001604051908101604052809291908181526020018280546109bf90613389565b8015610a0a5780601f106109e157610100808354040283529160200191610a0a565b820191905f5260205f20905b8154815290600101906020018083116109ed57829003601f168201915b505050505081565b5f610a2360a08301608084016133bb565b6004811115610a3457610a34613348565b03610a52576040516301fc71f560e21b815260040160405180910390fd5b6001610a6460a08301608084016133bb565b6004811115610a7557610a75613348565b03610a8857610a848282611be6565b5050565b610a8482610a95836133d4565b611d5b565b335f8181526005602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610af49086815260200190565b60405180910390a35060015b92915050565b604080518082019091525f80825260208201526060610b3660405180604001604052805f81526020015f81525090565b5f610b4085611e8f565b90505f5f610b4d83611fa5565b9350505091505f8183610b6091906133f3565b6040805180820182525f81525f1960208201528151600280825260608201909352909950919250816020015b604080518082019091525f815260606020820152815260200190600190039081610b8c57905050955060405180604001604052808281526020016040518060400160405280600c81526020017f50726f746f636f6c204665650000000000000000000000000000000000000000815250815250865f81518110610c1157610c11613406565b602002602001018190525060405180604001604052808381526020016040518060400160405280600a81526020017f427269646765204665650000000000000000000000000000000000000000000081525081525086600181518110610c7957610c79613406565b602090810291909101810191909152604080518082018252990135808a529089015250949693959450505050565b84610cc55760405163034e229160e61b815260040160405180910390fd5b610cd6898989898989898989612037565b6001600160a01b038981165f818152600560209081526040808320948d16808452948252918290208b905590518a81527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050505050505050565b83610d5a5760405163034e229160e61b815260040160405180910390fd5b610d6a88888888888888886120c6565b6001600160a01b038881165f818152600560209081526040808320948c16808452948252918290208a905590518981527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35050505050505050565b5f610de088888888858989896120c6565b610deb888888612101565b506001979650505050505050565b5f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163303610ee7576040517f16176e640000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201526001600160a01b038481166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906316176e64906064015f604051808303815f87803b158015610ed0575f5ffd5b505af1158015610ee2573d5f5f3e3d5ffd5b505050505b610ef284848461211c565b90505b9392505050565b5f5f5f5f610f0985611fa5565b93509350935093509193509193565b5f7f00000000000000000000000000000000000000000000000000000000000000004614610f4d57610f486121e1565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b604080518082019091525f80825260208201525f610f8f84611e8f565b90505f610f9b82611fa5565b505060408051808201909152918252505f602082015295945050505050565b335f8181526006602090815260409182902080546001019081905591519182527f1800cd2301fbc20790ed94f3d55a28ef2306a9c31cd3c72b5b71b6e4cf5c6241910160405180910390a2565b5f61101860a08301608084016133bb565b600481111561102957611029613348565b03611047576040516301fc71f560e21b815260040160405180910390fd5b600161105960a08301608084016133bb565b600481111561106a5761106a613348565b0361107c576110793382611be6565b50565b61107933610a95836133d4565b60605f6110996020870187612ff2565b6001600160a01b031614806110c25750306110b76020870187612ff2565b6001600160a01b0316145b156110f9576040517fffad318100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611106602086018661341a565b90505f03611127576040516338f9038160e21b815260040160405180910390fd5b6020611136606087018761341a565b9050108061117057506001600160a01b038916611156606087018761341a565b611164916020915f9161345d565b61116d91613484565b14155b1561118e576040516338f9038160e21b815260040160405180910390fd5b84604001353410156111b3576040516338f9038160e21b815260040160405180910390fd5b5f7fbbbdcca327a1e5a9a22b7fea84fdadce610270aa8286c2f83d4b2e6713c7fc436111e26020880188612ff2565b6111ef602089018961341a565b6040516111fd9291906134a1565b6040518091039020886040013589806060019061121a919061341a565b6040516112289291906134a1565b60405190819003812061126895949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b6040516020818303038152906040528051906020012090506112a98a8a8a8a856040518060800160405280605d8152602001613a06605d91398b8b8b610ca7565b5f6112b7602088018861341a565b6040516112c59291906134a1565b6040519081900390206112db606089018961341a565b6040516020016112ed939291906134b0565b60408051601f1981840301815291905290505f8061130e60208a018a612ff2565b6001600160a01b031634846040516113269190613502565b5f6040518083038185875af1925050503d805f8114611360576040519150601f19603f3d011682016040523d82523d5f602084013e611365565b606091505b5091509150816113b15780511561137f5780518082602001fd5b6040517fa4ecb78800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9c9b505050505050505050505050565b6040518060800160405280605981526020016139ad6059913981565b6002805461099390613389565b6113f588338561227a565b6114058888888888888888612330565b6040517f70756cde0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370756cde90479061149c907f0000000000000000000000000000000000000000000000000000000000000000908d908d908d908d908d908d908d908d90600401613536565b5f604051808303818588803b1580156114b3575f5ffd5b505af11580156114c5573d5f5f3e3d5ffd5b50505050505050505050505050565b5f6114e0338484612101565b50600192915050565b336114fa8189898989898989612330565b6040517f70756cde0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370756cde90479061149c907f00000000000000000000000000000000000000000000000000000000000000009086908e908e908e908e908e908e908e90600401613536565b61159961299f565b604080518082019091525f808252602082015284606001358560400135101561160357604080517f71c4efed000000000000000000000000000000000000000000000000000000008152908601356004820152606086013560248201526044015b60405180910390fd5b5f61160d86611e8f565b90506116193382611d5b565b5f33611628602089018961358c565b886040013560405160200161169c9392919060609390931b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016835260e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000166014830152601882015260380190565b60408051601f1981840301815291905280516020918201209150339082907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a906116e8908b018b61358c565b6040805163ffffffff90921682528b810135602083018190529082015260600160405180910390a36040805160608101825291825267ffffffffffffffff421660208084019190915281518083018352973588525f8882015282820197909752805180820182529701358088529587019590955250929492505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415806117b9575060025f54600160a01b900460ff1660028111156117b7576117b7613348565b145b156117f2576040517f32b2baa30000000000000000000000000000000000000000000000000000000081523360048201526024016115fa565b604080518082019091525f808252600260209092019190915280547fffffffffffffffffffffff0000000000000000000000000000000000000000001674020000000000000000000000000000000000000000179055565b42841015611887576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018590526024016115fa565b6001600160a01b038781165f81815260066020908152604080832080546001810190915581517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a084019490945260c08084018990528451808503909101815260e0909301909352815191909201209061191a610f18565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810183905260620160408051601f1981840301815282825280516020918201205f80855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa1580156119bd573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811615806119f25750896001600160a01b0316816001600160a01b031614155b15611a3c576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b1660248201526044016115fa565b6001600160a01b039081165f9081526005602090815260408083208c8516808552908352928190208b9055518a8152919450918b1692507f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6001600160a01b038116611ae7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141580611b3b575060025f54600160a01b900460ff166002811115611b3957611b39613348565b145b15611b74576040517f32b2baa30000000000000000000000000000000000000000000000000000000081523360048201526024016115fa565b604080518082019091526001600160a01b039190911680825260016020909201919091525f80547fffffffffffffffffffffff00000000000000000000000000000000000000000016909117600160a01b179055565b6040518060800160405280605d8152602001613a06605d913981565b5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630ecb55e530856040518363ffffffff1660e01b8152600401611c36929190613605565b6080604051808303815f875af1158015611c52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7691906136b8565b9350505091505f8183611c8991906133f3565b90508015611ce6576040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169082156108fc029083905f818181858888f19350505050158015611ce4573d5f5f3e3d5ffd5b505b336001600160a01b03861603611d2757611d22611d03858061341a565b611d10602088018861341a565b60408901356107e160608b018b61341a565b611d54565b611d5485611d35868061341a565b611d42602089018961341a565b60408a013561077c60608c018c61341a565b5050505050565b600281608001516004811115611d7357611d73613348565b1480611d945750600381608001516004811115611d9257611d92613348565b145b80611db45750600481608001516004811115611db257611db2613348565b145b15611e76576040517f7d96cc840000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637d96cc84903490611e44907f00000000000000000000000000000000000000000000000000000000000000009087908790600401613763565b5f604051808303818588803b158015611e5b575f5ffd5b505af1158015611e6d573d5f5f3e3d5ffd5b50505050505050565b6040516301fc71f560e21b815260040160405180910390fd5b611e976129e0565b5f611ead611ea8602085018561358c565b6123f8565b90505f611ec5611ec0608086018661341a565b612543565b90505f8460200135604051602001611edf91815260200190565b60408051601f19818403018152919052905060605f611f0160a088018861341a565b90501180611f1c57505f611f1860c088018861341a565b9050115b15611f6057611f2e60a087018761341a565b611f3b60c089018961341a565b604051602001611f4e9493929190613793565b60405160208183030381529060405290505b6040518060a0016040528085815260200183815260200187604001358152602001828152602001846004811115611f9957611f99613348565b90529695505050505050565b5f5f5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630ecb55e530876040518363ffffffff1660e01b8152600401611ff79291906137c4565b6080604051808303815f875af1158015612013573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0991906136b8565b8351158061204757506104008451115b156120655760405163034e229160e61b815260040160405180910390fd5b5f6040518060800160405280605981526020016139ad60599139856040516020016120919291906137e5565b6040516020818303038152906040528051906020012090506120ba8a8a8a8a8a868a8a8a6125b8565b50505050505050505050565b6120f788888888887fd74ba6270a1b25309f90735a3fcf045013fa182f846cd6210eab933f64fd346b8989896125b8565b5050505050505050565b61210c8383836127a4565b612117838383612860565b505050565b6001600160a01b0383165f9081526005602090815260408083203380855292528220545f1981146121ca578381101561219a576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604481018590526064016115fa565b6121a484826133f3565b6001600160a01b038088165f908152600560209081526040808320938716835292905220555b6121d5868686612101565b50600195945050505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600160405161221291906137f9565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b038084165f90815260056020908152604080832093861683529290522054818110156122f2576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016115fa565b5f19811461232a5761230482826133f3565b6001600160a01b038086165f908152600560209081526040808320938816835292905220555b50505050565b6040517f5b9a77e40000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635b9a77e4906123c1907f0000000000000000000000000000000000000000000000000000000000000000908c908c908c908c908c908c906004016138b3565b5f604051808303815f87803b1580156123d8575f5ffd5b505af11580156123ea573d5f5f3e3d5ffd5b505050505050505050505050565b60608163ffffffff165f0361244057505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b815f5b63ffffffff82161561246f578061245981613903565b91506124689050600a8361392f565b9150612443565b5f8167ffffffffffffffff81111561248957612489612bf4565b6040519080825280601f01601f1916602001820160405280156124b3576020820181803683370190505b5090505b63ffffffff85161561253b576124ce6001836133f3565b91506124db600a86613956565b6124e690603061397d565b60f81b8183815181106124fb576124fb613406565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350612534600a8661392f565b94506124b7565b949350505050565b5f81810361255357506002610b00565b5f83835f81811061256657612566613406565b919091013560f81c9150506001819003612584576002915050610b00565b8060ff16600203612599576003915050610b00565b8060ff166003036125ae576004915050610b00565b5060029392505050565b428610156125f5576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018790526024016115fa565b6001600160a01b03808a165f81815260066020908152604080832080546001810190915581519283018a905290820193909352928b166060840152608083018a905260a0830182905260c0830189905260e0830188905291829061010001604051602081830303815290604052805190602001209050612673610f18565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810182905260620160408051601f1981840301815282825280516020918201205f80855291840180845281905260ff8a1692840192909252606083018890526080830187905290945092506001915060a0016020604051602081039080840390855afa158015612718573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116158061274d57508a6001600160a01b0316816001600160a01b031614155b15612797576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528c1660248201526044016115fa565b5050505050505050505050565b604080518082019091525f80546001600160a01b038116835290919082906020830190600160a01b900460ff1660028111156127e2576127e2613348565b60028111156127f3576127f3613348565b905250905060018160200151600281111561281057612810613348565b148015612829575080516001600160a01b038481169116145b1561232a576040517f2c47a42300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831661288a578060035f82825461287f9190613999565b909155506129139050565b6001600160a01b0383165f90815260046020526040902054818110156128f5576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604481018390526064016115fa565b6001600160a01b0384165f9081526004602052604090209082900390555b6001600160a01b03821661292f5760038054829003905561294d565b6001600160a01b0382165f9081526004602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161299291815260200190565b60405180910390a3505050565b60405180606001604052805f81526020015f67ffffffffffffffff1681526020016129db60405180604001604052805f81526020015f81525090565b905290565b6040518060a0016040528060608152602001606081526020015f8152602001606081526020015f60048111156129db576129db613348565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ef56020830184612a18565b6001600160a01b0381168114611079575f5ffd5b5f60a08284031215612a7c575f5ffd5b50919050565b5f5f60408385031215612a93575f5ffd5b8235612a9e81612a58565b9150602083013567ffffffffffffffff811115612ab9575f5ffd5b612ac585828601612a6c565b9150509250929050565b5f5f60408385031215612ae0575f5ffd5b8235612aeb81612a58565b946020939093013593505050565b5f60e08284031215612a7c575f5ffd5b5f60208284031215612b19575f5ffd5b813567ffffffffffffffff811115612b2f575f5ffd5b61253b84828501612af9565b83518152602080850151908201525f60a0820160a0604084015280855180835260c08501915060c08160051b8601019250602087015f5b82811015612bd8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408786030184528151805186526020810151905060406020870152612bc26040870182612a18565b9550506020938401939190910190600101612b72565b505085516060860152505060208401516080840152905061253b565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715612c2b57612c2b612bf4565b60405290565b5f82601f830112612c40575f5ffd5b8135602083015f5f67ffffffffffffffff841115612c6057612c60612bf4565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff82111715612c8f57612c8f612bf4565b604052838152905080828401871015612ca6575f5ffd5b838360208301375f602085830101528094505050505092915050565b803560ff81168114612cd2575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f6101208a8c031215612cf0575f5ffd5b8935612cfb81612a58565b985060208a0135612d0b81612a58565b975060408a0135965060608a0135955060808a0135945060a08a013567ffffffffffffffff811115612d3b575f5ffd5b612d478c828d01612c31565b945050612d5660c08b01612cc2565b989b979a50959894979396929550929360e081013593506101000135919050565b5f5f5f5f5f5f5f5f610100898b031215612d8f575f5ffd5b8835612d9a81612a58565b97506020890135612daa81612a58565b9650604089013595506060890135945060808901359350612dcd60a08a01612cc2565b979a969950949793969295929450505060c08201359160e0013590565b5f5f5f5f5f5f5f60e0888a031215612e00575f5ffd5b8735612e0b81612a58565b96506020880135612e1b81612a58565b95506040880135945060608801359350612e3760808901612cc2565b9699959850939692959460a0840135945060c09093013592915050565b5f5f5f60608486031215612e66575f5ffd5b8335612e7181612a58565b92506020840135612e8181612a58565b929592945050506040919091013590565b803560058110612cd2575f5ffd5b5f60a08284031215612eb0575f5ffd5b612eb8612c08565b9050813567ffffffffffffffff811115612ed0575f5ffd5b612edc84828501612c31565b825250602082013567ffffffffffffffff811115612ef8575f5ffd5b612f0484828501612c31565b60208301525060408281013590820152606082013567ffffffffffffffff811115612f2d575f5ffd5b612f3984828501612c31565b606083015250612f4b60808301612e92565b608082015292915050565b5f60208284031215612f66575f5ffd5b813567ffffffffffffffff811115612f7c575f5ffd5b61253b84828501612ea0565b5f5f60408385031215612f99575f5ffd5b823567ffffffffffffffff811115612faf575f5ffd5b612fbb85828601612af9565b92505060208301358015158114612fd0575f5ffd5b809150509250929050565b815181526020808301519082015260408101610b00565b5f60208284031215613002575f5ffd5b8135610ef581612a58565b5f6020828403121561301d575f5ffd5b813567ffffffffffffffff811115613033575f5ffd5b61253b84828501612a6c565b5f5f5f5f5f5f5f5f610100898b031215613057575f5ffd5b883561306281612a58565b9750602089013561307281612a58565b96506040890135955060608901359450608089013567ffffffffffffffff81111561309b575f5ffd5b89016080818c0312156130ac575f5ffd5b9350612dcd60a08a01612cc2565b5f5f83601f8401126130ca575f5ffd5b50813567ffffffffffffffff8111156130e1575f5ffd5b6020830191508360208285010111156130f8575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f60a0898b031215613116575f5ffd5b883561312181612a58565b9750602089013567ffffffffffffffff81111561313c575f5ffd5b6131488b828c016130ba565b909850965050604089013567ffffffffffffffff811115613167575f5ffd5b6131738b828c016130ba565b90965094505060608901359250608089013567ffffffffffffffff811115613199575f5ffd5b6131a58b828c016130ba565b999c989b5096995094979396929594505050565b5f5f5f5f5f5f5f6080888a0312156131cf575f5ffd5b873567ffffffffffffffff8111156131e5575f5ffd5b6131f18a828b016130ba565b909850965050602088013567ffffffffffffffff811115613210575f5ffd5b61321c8a828b016130ba565b90965094505060408801359250606088013567ffffffffffffffff811115613242575f5ffd5b61324e8a828b016130ba565b989b979a50959850939692959293505050565b5f5f5f8385036080811215613274575f5ffd5b843567ffffffffffffffff81111561328a575f5ffd5b61329687828801612af9565b9450506040601f19820112156132aa575f5ffd5b5060208401915060608401356132bf81612a58565b809150509250925092565b5f60c0820190508351825267ffffffffffffffff60208501511660208301526040840151613305604084018280518252602090810151910152565b5082516080830152602083015160a0830152610ef5565b5f5f6040838503121561332d575f5ffd5b823561333881612a58565b91506020830135612fd081612a58565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b0383168152604081016003831061337c5761337c613348565b8260208301529392505050565b600181811c9082168061339d57607f821691505b602082108103612a7c57634e487b7160e01b5f52602260045260245ffd5b5f602082840312156133cb575f5ffd5b610ef582612e92565b5f610b003683612ea0565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610b0057610b006133df565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e1984360301811261342f575f5ffd5b83018035915067ffffffffffffffff821115613449575f5ffd5b6020019150368190038213156130f8575f5ffd5b5f5f8585111561346b575f5ffd5b83861115613477575f5ffd5b5050820193919092039150565b80356020831015610b00575f19602084900360031b1b1692915050565b818382375f9101908152919050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301375f910160040190815292915050565b5f81518060208401855e5f93019283525090919050565b5f610ef582846134eb565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b8981526001600160a01b038916602082015260c060408201525f61355e60c08301898b61350d565b828103606084015261357181888a61350d565b905085608084015282810360a08401526113b181858761350d565b5f6020828403121561359c575f5ffd5b813563ffffffff81168114610ef5575f5ffd5b5f5f8335601e198436030181126135c4575f5ffd5b830160208101925035905067ffffffffffffffff8111156135e3575f5ffd5b8036038213156130f8575f5ffd5b6005811061360157613601613348565b9052565b6001600160a01b0383168152604060208201525f61362383846135af565b60a0604085015261363860e08501828461350d565b91505061364860208501856135af565b603f1985840301606086015261365f83828461350d565b60408701356080870152925061367b91505060608501856135af565b603f198584030160a086015261369283828461350d565b925050506136a260808501612e92565b6136af60c08501826135f1565b50949350505050565b5f5f5f5f608085870312156136cb575f5ffd5b84516020860151604087015191955093506136e581612a58565b6060959095015193969295505050565b5f815160a0845261370960a0850182612a18565b9050602083015184820360208601526137228282612a18565b91505060408301516040850152606083015184820360608601526137468282612a18565b915050608083015161375b60808601826135f1565b509392505050565b8381526001600160a01b0383166020820152606060408201525f61378a60608301846136f5565b95945050505050565b604081525f6137a660408301868861350d565b82810360208401526137b981858761350d565b979650505050505050565b6001600160a01b0383168152604060208201525f610ef260408301846136f5565b5f610ef26137f383866134eb565b846134eb565b5f5f83545f8160011c9050600182168061381457607f821691505b60208210810361383257634e487b7160e01b5f52602260045260245ffd5b8080156138465760018114613879576138a7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506138a7565b5f888152602090205f5b8481101561389f57815489820152600190910190602001613883565b505082870194505b50929695505050505050565b8781526001600160a01b038716602082015260a060408201525f6138db60a08301878961350d565b82810360608401526138ee81868861350d565b91505082608083015298975050505050505050565b5f60018201613914576139146133df565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff8316806139445761394461391b565b8063ffffffff84160491505092915050565b5f63ffffffff83168061396b5761396b61391b565b8063ffffffff84160691505092915050565b63ffffffff8181168382160190811115610b0057610b006133df565b80820180821115610b0057610b006133df56fe5065726d69745769746e6573732861646472657373206f776e65722c61646472657373207370656e6465722c75696e743235362076616c75652c75696e74323536206e6f6e63652c75696e7432353620646561646c696e652c436f6e747261637443616c6c2063616c6c29436f6e747261637443616c6c2861646472657373207461726765742c737472696e67206d6574686f642c75696e74323536206e617469766556616c75652c627974657320706172616d7329a26469706673582212200a879d7cd53f6866cf7e8eb4367e38dd98d8c6a3e8ebc07fad84cb0ccd422df364736f6c634300081b003300000000000000000000000000000000000000000000000000000000000000600000000000000000000000008c843012b347664caf84b907053754208a933fee0000000000000000000000000000000000000000033b2e3c9fd0803ce80000007e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000033b2e3c9fd0803ce8000000000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c000000000000000000000000f86d58e91b99e83bd21e36e6c09bb86f598c2a9ad2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e10570000000000000000000000000000000000000000000000000000000000000009e98791e9a692e5a4b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e98791e9a692e5a4b40000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102e2575f3560e01c80637ecebe0011610186578063bc0ba3c5116100dc578063dd62ed3e11610087578063f7cca09211610062578063f7cca0921461092d578063fc0c546a14610960578063ffe1aca514610972575f5ffd5b8063dd62ed3e146108a0578063eddd5458146108d6578063f1e3d5c41461090e575f5ffd5b8063d505accf116100b7578063d505accf1461081b578063d5abeb011461083a578063daf551d61461086d575f5ffd5b8063bc0ba3c5146107d3578063c7c7f5b3146107e6578063cf8af0a214610807575f5ffd5b806395d89b411161013c578063a60fee3711610117578063a60fee371461076e578063a9059cbb14610781578063b29300eb146107a0575f5ffd5b806395d89b41146107355780639f68b96414610749578063a5d454381461075b575f5ffd5b8063857749b01161016c578063857749b0146106fb57806386e118231461070e5780638b9868ec14610721575f5ffd5b80637ecebe001461069d57806381cce245146106c8575f5ffd5b806323b872dd1161023b57806336ee2bf7116101f15780635a57b46f116101cc5780635a57b46f1461064b57806370a082311461065f5780637787cbab1461068a575f5ffd5b806336ee2bf7146105b95780633b6f743b146105ec5780633b87f25214610618575f5ffd5b8063313ce56711610221578063313ce5671461051257806334c52e8b146105575780633644e515146105a5575f5ffd5b806323b872dd146104c057806330adf81f146104df575f5ffd5b80631248828a1161029b578063156a0d0f11610276578063156a0d0f1461044c57806318160ddd1461048c578063211be91f146104a1575f5ffd5b80631248828a146103cd578063129d8188146103ec57806313e06dce1461042d575f5ffd5b8063095ea7b3116102cb578063095ea7b31461032557806309c6bed9146103545780630d35b4151461039f575f5ffd5b806306fdde03146102e657806308951d8a14610310575b5f5ffd5b3480156102f1575f5ffd5b506102fa610986565b6040516103079190612a46565b60405180910390f35b61032361031e366004612a82565b610a12565b005b348015610330575f5ffd5b5061034461033f366004612acf565b610a9a565b6040519015158152602001610307565b34801561035f575f5ffd5b506103877f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c81565b6040516001600160a01b039091168152602001610307565b3480156103aa575f5ffd5b506103be6103b9366004612b09565b610b06565b60405161030793929190612b3b565b3480156103d8575f5ffd5b506103236103e7366004612cd7565b610ca7565b3480156103f7575f5ffd5b5061041f7fd2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e105781565b604051908152602001610307565b348015610438575f5ffd5b50610323610447366004612d77565b610d3c565b348015610457575f5ffd5b50604080517f02e49c2c0000000000000000000000000000000000000000000000000000000081526001602082015201610307565b348015610497575f5ffd5b5061041f60035481565b3480156104ac575f5ffd5b506103446104bb366004612dea565b610dcf565b3480156104cb575f5ffd5b506103446104da366004612e54565b610df9565b3480156104ea575f5ffd5b5061041f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b34801561051d575f5ffd5b506105457f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610307565b348015610562575f5ffd5b50610576610571366004612f56565b610efc565b604051610307949392919093845260208401929092526001600160a01b03166040830152606082015260800190565b3480156105b0575f5ffd5b5061041f610f18565b3480156105c4575f5ffd5b506103877f000000000000000000000000f86d58e91b99e83bd21e36e6c09bb86f598c2a9a81565b3480156105f7575f5ffd5b5061060b610606366004612f88565b610f72565b6040516103079190612fdb565b348015610623575f5ffd5b5061041f7fd74ba6270a1b25309f90735a3fcf045013fa182f846cd6210eab933f64fd346b81565b348015610656575f5ffd5b50610323610fba565b34801561066a575f5ffd5b5061041f610679366004612ff2565b60046020525f908152604090205481565b61032361069836600461300d565b611007565b3480156106a8575f5ffd5b5061041f6106b7366004612ff2565b60066020525f908152604090205481565b3480156106d3575f5ffd5b5061041f7f7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e81565b348015610706575f5ffd5b506009610545565b6102fa61071c36600461303f565b611089565b34801561072c575f5ffd5b506102fa6113c1565b348015610740575f5ffd5b506102fa6113dd565b348015610754575f5ffd5b505f610344565b348015610766575f5ffd5b5061041f5f81565b61032361077c3660046130ff565b6113ea565b34801561078c575f5ffd5b5061034461079b366004612acf565b6114d4565b3480156107ab575f5ffd5b506103447f000000000000000000000000000000000000000000000000000000000000000081565b6103236107e13660046131b9565b6114e9565b6107f96107f4366004613261565b611591565b6040516103079291906132ca565b348015610812575f5ffd5b50610323611765565b348015610826575f5ffd5b50610323610835366004612dea565b61184a565b348015610845575f5ffd5b5061041f7f0000000000000000000000000000000000000000033b2e3c9fd0803ce800000081565b348015610878575f5ffd5b5061041f7fbbbdcca327a1e5a9a22b7fea84fdadce610270aa8286c2f83d4b2e6713c7fc4381565b3480156108ab575f5ffd5b5061041f6108ba36600461331c565b600560209081525f928352604080842090915290825290205481565b3480156108e1575f5ffd5b505f54610900906001600160a01b03811690600160a01b900460ff1682565b60405161030792919061335c565b348015610919575f5ffd5b50610323610928366004612ff2565b611aa7565b348015610938575f5ffd5b506103877f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff24317281565b34801561096b575f5ffd5b5030610387565b34801561097d575f5ffd5b506102fa611bca565b6001805461099390613389565b80601f01602080910402602001604051908101604052809291908181526020018280546109bf90613389565b8015610a0a5780601f106109e157610100808354040283529160200191610a0a565b820191905f5260205f20905b8154815290600101906020018083116109ed57829003601f168201915b505050505081565b5f610a2360a08301608084016133bb565b6004811115610a3457610a34613348565b03610a52576040516301fc71f560e21b815260040160405180910390fd5b6001610a6460a08301608084016133bb565b6004811115610a7557610a75613348565b03610a8857610a848282611be6565b5050565b610a8482610a95836133d4565b611d5b565b335f8181526005602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610af49086815260200190565b60405180910390a35060015b92915050565b604080518082019091525f80825260208201526060610b3660405180604001604052805f81526020015f81525090565b5f610b4085611e8f565b90505f5f610b4d83611fa5565b9350505091505f8183610b6091906133f3565b6040805180820182525f81525f1960208201528151600280825260608201909352909950919250816020015b604080518082019091525f815260606020820152815260200190600190039081610b8c57905050955060405180604001604052808281526020016040518060400160405280600c81526020017f50726f746f636f6c204665650000000000000000000000000000000000000000815250815250865f81518110610c1157610c11613406565b602002602001018190525060405180604001604052808381526020016040518060400160405280600a81526020017f427269646765204665650000000000000000000000000000000000000000000081525081525086600181518110610c7957610c79613406565b602090810291909101810191909152604080518082018252990135808a529089015250949693959450505050565b84610cc55760405163034e229160e61b815260040160405180910390fd5b610cd6898989898989898989612037565b6001600160a01b038981165f818152600560209081526040808320948d16808452948252918290208b905590518a81527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050505050505050565b83610d5a5760405163034e229160e61b815260040160405180910390fd5b610d6a88888888888888886120c6565b6001600160a01b038881165f818152600560209081526040808320948c16808452948252918290208a905590518981527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35050505050505050565b5f610de088888888858989896120c6565b610deb888888612101565b506001979650505050505050565b5f6001600160a01b037f000000000000000000000000f86d58e91b99e83bd21e36e6c09bb86f598c2a9a163303610ee7576040517f16176e640000000000000000000000000000000000000000000000000000000081527f7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e60048201526001600160a01b038481166024830152604482018490527f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff24317216906316176e64906064015f604051808303815f87803b158015610ed0575f5ffd5b505af1158015610ee2573d5f5f3e3d5ffd5b505050505b610ef284848461211c565b90505b9392505050565b5f5f5f5f610f0985611fa5565b93509350935093509193509193565b5f7f00000000000000000000000000000000000000000000000000000000000013884614610f4d57610f486121e1565b905090565b507fdcb34e2c2e1ba19c9d8270f7d4bf372253af98c483843871c92cbc195fbe996890565b604080518082019091525f80825260208201525f610f8f84611e8f565b90505f610f9b82611fa5565b505060408051808201909152918252505f602082015295945050505050565b335f8181526006602090815260409182902080546001019081905591519182527f1800cd2301fbc20790ed94f3d55a28ef2306a9c31cd3c72b5b71b6e4cf5c6241910160405180910390a2565b5f61101860a08301608084016133bb565b600481111561102957611029613348565b03611047576040516301fc71f560e21b815260040160405180910390fd5b600161105960a08301608084016133bb565b600481111561106a5761106a613348565b0361107c576110793382611be6565b50565b61107933610a95836133d4565b60605f6110996020870187612ff2565b6001600160a01b031614806110c25750306110b76020870187612ff2565b6001600160a01b0316145b156110f9576040517fffad318100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611106602086018661341a565b90505f03611127576040516338f9038160e21b815260040160405180910390fd5b6020611136606087018761341a565b9050108061117057506001600160a01b038916611156606087018761341a565b611164916020915f9161345d565b61116d91613484565b14155b1561118e576040516338f9038160e21b815260040160405180910390fd5b84604001353410156111b3576040516338f9038160e21b815260040160405180910390fd5b5f7fbbbdcca327a1e5a9a22b7fea84fdadce610270aa8286c2f83d4b2e6713c7fc436111e26020880188612ff2565b6111ef602089018961341a565b6040516111fd9291906134a1565b6040518091039020886040013589806060019061121a919061341a565b6040516112289291906134a1565b60405190819003812061126895949392916020019485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b6040516020818303038152906040528051906020012090506112a98a8a8a8a856040518060800160405280605d8152602001613a06605d91398b8b8b610ca7565b5f6112b7602088018861341a565b6040516112c59291906134a1565b6040519081900390206112db606089018961341a565b6040516020016112ed939291906134b0565b60408051601f1981840301815291905290505f8061130e60208a018a612ff2565b6001600160a01b031634846040516113269190613502565b5f6040518083038185875af1925050503d805f8114611360576040519150601f19603f3d011682016040523d82523d5f602084013e611365565b606091505b5091509150816113b15780511561137f5780518082602001fd5b6040517fa4ecb78800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9c9b505050505050505050505050565b6040518060800160405280605981526020016139ad6059913981565b6002805461099390613389565b6113f588338561227a565b6114058888888888888888612330565b6040517f70756cde0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c16906370756cde90479061149c907fd2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e1057908d908d908d908d908d908d908d908d90600401613536565b5f604051808303818588803b1580156114b3575f5ffd5b505af11580156114c5573d5f5f3e3d5ffd5b50505050505050505050505050565b5f6114e0338484612101565b50600192915050565b336114fa8189898989898989612330565b6040517f70756cde0000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c16906370756cde90479061149c907fd2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e10579086908e908e908e908e908e908e908e90600401613536565b61159961299f565b604080518082019091525f808252602082015284606001358560400135101561160357604080517f71c4efed000000000000000000000000000000000000000000000000000000008152908601356004820152606086013560248201526044015b60405180910390fd5b5f61160d86611e8f565b90506116193382611d5b565b5f33611628602089018961358c565b886040013560405160200161169c9392919060609390931b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016835260e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000166014830152601882015260380190565b60408051601f1981840301815291905280516020918201209150339082907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a906116e8908b018b61358c565b6040805163ffffffff90921682528b810135602083018190529082015260600160405180910390a36040805160608101825291825267ffffffffffffffff421660208084019190915281518083018352973588525f8882015282820197909752805180820182529701358088529587019590955250929492505050565b336001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172161415806117b9575060025f54600160a01b900460ff1660028111156117b7576117b7613348565b145b156117f2576040517f32b2baa30000000000000000000000000000000000000000000000000000000081523360048201526024016115fa565b604080518082019091525f808252600260209092019190915280547fffffffffffffffffffffff0000000000000000000000000000000000000000001674020000000000000000000000000000000000000000179055565b42841015611887576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018590526024016115fa565b6001600160a01b038781165f81815260066020908152604080832080546001810190915581517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a084019490945260c08084018990528451808503909101815260e0909301909352815191909201209061191a610f18565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810183905260620160408051601f1981840301815282825280516020918201205f80855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa1580156119bd573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811615806119f25750896001600160a01b0316816001600160a01b031614155b15611a3c576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528b1660248201526044016115fa565b6001600160a01b039081165f9081526005602090815260408083208c8516808552908352928190208b9055518a8152919450918b1692507f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6001600160a01b038116611ae7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff24317216141580611b3b575060025f54600160a01b900460ff166002811115611b3957611b39613348565b145b15611b74576040517f32b2baa30000000000000000000000000000000000000000000000000000000081523360048201526024016115fa565b604080518082019091526001600160a01b039190911680825260016020909201919091525f80547fffffffffffffffffffffff00000000000000000000000000000000000000000016909117600160a01b179055565b6040518060800160405280605d8152602001613a06605d913981565b5f5f7f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff2431726001600160a01b0316630ecb55e530856040518363ffffffff1660e01b8152600401611c36929190613605565b6080604051808303815f875af1158015611c52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c7691906136b8565b9350505091505f8183611c8991906133f3565b90508015611ce6576040516001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172169082156108fc029083905f818181858888f19350505050158015611ce4573d5f5f3e3d5ffd5b505b336001600160a01b03861603611d2757611d22611d03858061341a565b611d10602088018861341a565b60408901356107e160608b018b61341a565b611d54565b611d5485611d35868061341a565b611d42602089018961341a565b60408a013561077c60608c018c61341a565b5050505050565b600281608001516004811115611d7357611d73613348565b1480611d945750600381608001516004811115611d9257611d92613348565b145b80611db45750600481608001516004811115611db257611db2613348565b145b15611e76576040517f7d96cc840000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff2431721690637d96cc84903490611e44907f7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e9087908790600401613763565b5f604051808303818588803b158015611e5b575f5ffd5b505af1158015611e6d573d5f5f3e3d5ffd5b50505050505050565b6040516301fc71f560e21b815260040160405180910390fd5b611e976129e0565b5f611ead611ea8602085018561358c565b6123f8565b90505f611ec5611ec0608086018661341a565b612543565b90505f8460200135604051602001611edf91815260200190565b60408051601f19818403018152919052905060605f611f0160a088018861341a565b90501180611f1c57505f611f1860c088018861341a565b9050115b15611f6057611f2e60a087018761341a565b611f3b60c089018961341a565b604051602001611f4e9493929190613793565b60405160208183030381529060405290505b6040518060a0016040528085815260200183815260200187604001358152602001828152602001846004811115611f9957611f99613348565b90529695505050505050565b5f5f5f5f7f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff2431726001600160a01b0316630ecb55e530876040518363ffffffff1660e01b8152600401611ff79291906137c4565b6080604051808303815f875af1158015612013573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0991906136b8565b8351158061204757506104008451115b156120655760405163034e229160e61b815260040160405180910390fd5b5f6040518060800160405280605981526020016139ad60599139856040516020016120919291906137e5565b6040516020818303038152906040528051906020012090506120ba8a8a8a8a8a868a8a8a6125b8565b50505050505050505050565b6120f788888888887fd74ba6270a1b25309f90735a3fcf045013fa182f846cd6210eab933f64fd346b8989896125b8565b5050505050505050565b61210c8383836127a4565b612117838383612860565b505050565b6001600160a01b0383165f9081526005602090815260408083203380855292528220545f1981146121ca578381101561219a576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604481018590526064016115fa565b6121a484826133f3565b6001600160a01b038088165f908152600560209081526040808320938716835292905220555b6121d5868686612101565b50600195945050505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600160405161221291906137f9565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b038084165f90815260056020908152604080832093861683529290522054818110156122f2576040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101829052604481018390526064016115fa565b5f19811461232a5761230482826133f3565b6001600160a01b038086165f908152600560209081526040808320938816835292905220555b50505050565b6040517f5b9a77e40000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff2431721690635b9a77e4906123c1907f7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e908c908c908c908c908c908c906004016138b3565b5f604051808303815f87803b1580156123d8575f5ffd5b505af11580156123ea573d5f5f3e3d5ffd5b505050505050505050505050565b60608163ffffffff165f0361244057505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b815f5b63ffffffff82161561246f578061245981613903565b91506124689050600a8361392f565b9150612443565b5f8167ffffffffffffffff81111561248957612489612bf4565b6040519080825280601f01601f1916602001820160405280156124b3576020820181803683370190505b5090505b63ffffffff85161561253b576124ce6001836133f3565b91506124db600a86613956565b6124e690603061397d565b60f81b8183815181106124fb576124fb613406565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350612534600a8661392f565b94506124b7565b949350505050565b5f81810361255357506002610b00565b5f83835f81811061256657612566613406565b919091013560f81c9150506001819003612584576002915050610b00565b8060ff16600203612599576003915050610b00565b8060ff166003036125ae576004915050610b00565b5060029392505050565b428610156125f5576040517f62791302000000000000000000000000000000000000000000000000000000008152600481018790526024016115fa565b6001600160a01b03808a165f81815260066020908152604080832080546001810190915581519283018a905290820193909352928b166060840152608083018a905260a0830182905260c0830189905260e0830188905291829061010001604051602081830303815290604052805190602001209050612673610f18565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810182905260620160408051601f1981840301815282825280516020918201205f80855291840180845281905260ff8a1692840192909252606083018890526080830187905290945092506001915060a0016020604051602081039080840390855afa158015612718573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116158061274d57508a6001600160a01b0316816001600160a01b031614155b15612797576040517f4b800e460000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528c1660248201526044016115fa565b5050505050505050505050565b604080518082019091525f80546001600160a01b038116835290919082906020830190600160a01b900460ff1660028111156127e2576127e2613348565b60028111156127f3576127f3613348565b905250905060018160200151600281111561281057612810613348565b148015612829575080516001600160a01b038481169116145b1561232a576040517f2c47a42300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03831661288a578060035f82825461287f9190613999565b909155506129139050565b6001600160a01b0383165f90815260046020526040902054818110156128f5576040517fe450d38c0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604481018390526064016115fa565b6001600160a01b0384165f9081526004602052604090209082900390555b6001600160a01b03821661292f5760038054829003905561294d565b6001600160a01b0382165f9081526004602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161299291815260200190565b60405180910390a3505050565b60405180606001604052805f81526020015f67ffffffffffffffff1681526020016129db60405180604001604052805f81526020015f81525090565b905290565b6040518060a0016040528060608152602001606081526020015f8152602001606081526020015f60048111156129db576129db613348565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ef56020830184612a18565b6001600160a01b0381168114611079575f5ffd5b5f60a08284031215612a7c575f5ffd5b50919050565b5f5f60408385031215612a93575f5ffd5b8235612a9e81612a58565b9150602083013567ffffffffffffffff811115612ab9575f5ffd5b612ac585828601612a6c565b9150509250929050565b5f5f60408385031215612ae0575f5ffd5b8235612aeb81612a58565b946020939093013593505050565b5f60e08284031215612a7c575f5ffd5b5f60208284031215612b19575f5ffd5b813567ffffffffffffffff811115612b2f575f5ffd5b61253b84828501612af9565b83518152602080850151908201525f60a0820160a0604084015280855180835260c08501915060c08160051b8601019250602087015f5b82811015612bd8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408786030184528151805186526020810151905060406020870152612bc26040870182612a18565b9550506020938401939190910190600101612b72565b505085516060860152505060208401516080840152905061253b565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715612c2b57612c2b612bf4565b60405290565b5f82601f830112612c40575f5ffd5b8135602083015f5f67ffffffffffffffff841115612c6057612c60612bf4565b50604051601f19601f85018116603f0116810181811067ffffffffffffffff82111715612c8f57612c8f612bf4565b604052838152905080828401871015612ca6575f5ffd5b838360208301375f602085830101528094505050505092915050565b803560ff81168114612cd2575f5ffd5b919050565b5f5f5f5f5f5f5f5f5f6101208a8c031215612cf0575f5ffd5b8935612cfb81612a58565b985060208a0135612d0b81612a58565b975060408a0135965060608a0135955060808a0135945060a08a013567ffffffffffffffff811115612d3b575f5ffd5b612d478c828d01612c31565b945050612d5660c08b01612cc2565b989b979a50959894979396929550929360e081013593506101000135919050565b5f5f5f5f5f5f5f5f610100898b031215612d8f575f5ffd5b8835612d9a81612a58565b97506020890135612daa81612a58565b9650604089013595506060890135945060808901359350612dcd60a08a01612cc2565b979a969950949793969295929450505060c08201359160e0013590565b5f5f5f5f5f5f5f60e0888a031215612e00575f5ffd5b8735612e0b81612a58565b96506020880135612e1b81612a58565b95506040880135945060608801359350612e3760808901612cc2565b9699959850939692959460a0840135945060c09093013592915050565b5f5f5f60608486031215612e66575f5ffd5b8335612e7181612a58565b92506020840135612e8181612a58565b929592945050506040919091013590565b803560058110612cd2575f5ffd5b5f60a08284031215612eb0575f5ffd5b612eb8612c08565b9050813567ffffffffffffffff811115612ed0575f5ffd5b612edc84828501612c31565b825250602082013567ffffffffffffffff811115612ef8575f5ffd5b612f0484828501612c31565b60208301525060408281013590820152606082013567ffffffffffffffff811115612f2d575f5ffd5b612f3984828501612c31565b606083015250612f4b60808301612e92565b608082015292915050565b5f60208284031215612f66575f5ffd5b813567ffffffffffffffff811115612f7c575f5ffd5b61253b84828501612ea0565b5f5f60408385031215612f99575f5ffd5b823567ffffffffffffffff811115612faf575f5ffd5b612fbb85828601612af9565b92505060208301358015158114612fd0575f5ffd5b809150509250929050565b815181526020808301519082015260408101610b00565b5f60208284031215613002575f5ffd5b8135610ef581612a58565b5f6020828403121561301d575f5ffd5b813567ffffffffffffffff811115613033575f5ffd5b61253b84828501612a6c565b5f5f5f5f5f5f5f5f610100898b031215613057575f5ffd5b883561306281612a58565b9750602089013561307281612a58565b96506040890135955060608901359450608089013567ffffffffffffffff81111561309b575f5ffd5b89016080818c0312156130ac575f5ffd5b9350612dcd60a08a01612cc2565b5f5f83601f8401126130ca575f5ffd5b50813567ffffffffffffffff8111156130e1575f5ffd5b6020830191508360208285010111156130f8575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f60a0898b031215613116575f5ffd5b883561312181612a58565b9750602089013567ffffffffffffffff81111561313c575f5ffd5b6131488b828c016130ba565b909850965050604089013567ffffffffffffffff811115613167575f5ffd5b6131738b828c016130ba565b90965094505060608901359250608089013567ffffffffffffffff811115613199575f5ffd5b6131a58b828c016130ba565b999c989b5096995094979396929594505050565b5f5f5f5f5f5f5f6080888a0312156131cf575f5ffd5b873567ffffffffffffffff8111156131e5575f5ffd5b6131f18a828b016130ba565b909850965050602088013567ffffffffffffffff811115613210575f5ffd5b61321c8a828b016130ba565b90965094505060408801359250606088013567ffffffffffffffff811115613242575f5ffd5b61324e8a828b016130ba565b989b979a50959850939692959293505050565b5f5f5f8385036080811215613274575f5ffd5b843567ffffffffffffffff81111561328a575f5ffd5b61329687828801612af9565b9450506040601f19820112156132aa575f5ffd5b5060208401915060608401356132bf81612a58565b809150509250925092565b5f60c0820190508351825267ffffffffffffffff60208501511660208301526040840151613305604084018280518252602090810151910152565b5082516080830152602083015160a0830152610ef5565b5f5f6040838503121561332d575f5ffd5b823561333881612a58565b91506020830135612fd081612a58565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b0383168152604081016003831061337c5761337c613348565b8260208301529392505050565b600181811c9082168061339d57607f821691505b602082108103612a7c57634e487b7160e01b5f52602260045260245ffd5b5f602082840312156133cb575f5ffd5b610ef582612e92565b5f610b003683612ea0565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610b0057610b006133df565b634e487b7160e01b5f52603260045260245ffd5b5f5f8335601e1984360301811261342f575f5ffd5b83018035915067ffffffffffffffff821115613449575f5ffd5b6020019150368190038213156130f8575f5ffd5b5f5f8585111561346b575f5ffd5b83861115613477575f5ffd5b5050820193919092039150565b80356020831015610b00575f19602084900360031b1b1692915050565b818382375f9101908152919050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301375f910160040190815292915050565b5f81518060208401855e5f93019283525090919050565b5f610ef582846134eb565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b8981526001600160a01b038916602082015260c060408201525f61355e60c08301898b61350d565b828103606084015261357181888a61350d565b905085608084015282810360a08401526113b181858761350d565b5f6020828403121561359c575f5ffd5b813563ffffffff81168114610ef5575f5ffd5b5f5f8335601e198436030181126135c4575f5ffd5b830160208101925035905067ffffffffffffffff8111156135e3575f5ffd5b8036038213156130f8575f5ffd5b6005811061360157613601613348565b9052565b6001600160a01b0383168152604060208201525f61362383846135af565b60a0604085015261363860e08501828461350d565b91505061364860208501856135af565b603f1985840301606086015261365f83828461350d565b60408701356080870152925061367b91505060608501856135af565b603f198584030160a086015261369283828461350d565b925050506136a260808501612e92565b6136af60c08501826135f1565b50949350505050565b5f5f5f5f608085870312156136cb575f5ffd5b84516020860151604087015191955093506136e581612a58565b6060959095015193969295505050565b5f815160a0845261370960a0850182612a18565b9050602083015184820360208601526137228282612a18565b91505060408301516040850152606083015184820360608601526137468282612a18565b915050608083015161375b60808601826135f1565b509392505050565b8381526001600160a01b0383166020820152606060408201525f61378a60608301846136f5565b95945050505050565b604081525f6137a660408301868861350d565b82810360208401526137b981858761350d565b979650505050505050565b6001600160a01b0383168152604060208201525f610ef260408301846136f5565b5f610ef26137f383866134eb565b846134eb565b5f5f83545f8160011c9050600182168061381457607f821691505b60208210810361383257634e487b7160e01b5f52602260045260245ffd5b8080156138465760018114613879576138a7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506138a7565b5f888152602090205f5b8481101561389f57815489820152600190910190602001613883565b505082870194505b50929695505050505050565b8781526001600160a01b038716602082015260a060408201525f6138db60a08301878961350d565b82810360608401526138ee81868861350d565b91505082608083015298975050505050505050565b5f60018201613914576139146133df565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f63ffffffff8316806139445761394461391b565b8063ffffffff84160491505092915050565b5f63ffffffff83168061396b5761396b61391b565b8063ffffffff84160691505092915050565b63ffffffff8181168382160190811115610b0057610b006133df565b80820180821115610b0057610b006133df56fe5065726d69745769746e6573732861646472657373206f776e65722c61646472657373207370656e6465722c75696e743235362076616c75652c75696e74323536206e6f6e63652c75696e7432353620646561646c696e652c436f6e747261637443616c6c2063616c6c29436f6e747261637443616c6c2861646472657373207461726765742c737472696e67206d6574686f642c75696e74323536206e617469766556616c75652c627974657320706172616d7329a26469706673582212200a879d7cd53f6866cf7e8eb4367e38dd98d8c6a3e8ebc07fad84cb0ccd422df364736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000600000000000000000000000008c843012b347664caf84b907053754208a933fee0000000000000000000000000000000000000000033b2e3c9fd0803ce80000007e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000033b2e3c9fd0803ce8000000000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c000000000000000000000000f86d58e91b99e83bd21e36e6c09bb86f598c2a9ad2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e10570000000000000000000000000000000000000000000000000000000000000009e98791e9a692e5a4b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e98791e9a692e5a4b40000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : params (tuple):
Arg [1] : telecoinId (bytes32): 0x7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e
Arg [2] : name (string): 金馒头
Arg [3] : symbol (string): 金馒头
Arg [4] : maxSupply (uint256): 1000000000000000000000000000
Arg [5] : printr (address): 0xb77726291b125515D0A7AfFeeA2b04f2FF243172
Arg [6] : interchainTokenService (address): 0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C
Arg [7] : itsTokenManager (address): 0xf86D58E91B99E83bD21E36E6c09bb86F598c2A9a
Arg [8] : interchainTokenId (bytes32): 0xd2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e1057
Arg [1] : treasury (address): 0x8c843012B347664caf84B907053754208a933FeE
Arg [2] : initialSupply (uint256): 1000000000000000000000000000
-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 0000000000000000000000008c843012b347664caf84b907053754208a933fee
Arg [2] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [3] : 7e3025f2c9216a9af6a5584f40b5201fac5b1d32cead574bd6418aadd6cfa27e
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [6] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [7] : 000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172
Arg [8] : 000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c
Arg [9] : 000000000000000000000000f86d58e91b99e83bd21e36e6c09bb86f598c2a9a
Arg [10] : d2e4b549db5c1a88654068f57856777094150dc0d8776333ea88f0bea84e1057
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [12] : e98791e9a692e5a4b40000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [14] : e98791e9a692e5a4b40000000000000000000000000000000000000000000000
Net Worth in USD
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.