Source Code
Overview
MNT Balance
MNT Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 87415268 | 74 days ago | Contract Creation | 0 MNT |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PrintrDev
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 2000 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IPrintrGetters } from "../interfaces/printr/IPrintrGetters.sol";
import { IPrintrStorage } from "../interfaces/printr/IPrintrStorage.sol";
import { IPrintrTrading } from "../interfaces/printr/IPrintrTrading.sol";
import { IPrintrDev } from "../interfaces/telecoin/IPrintrDev.sol";
import { IPrintrTeleportingTelecoin } from "../interfaces/telecoin/IPrintrTeleportingTelecoin.sol";
/**
* @title PrintrDev
* @notice NFT contract that represents developer rights for PRINTR telecoins
* @dev One NFT is minted per PRINTR telecoin to track the developer
*/
contract PrintrDev is ERC721, IPrintrDev {
using Strings for bytes32;
using Strings for uint256;
using Strings for address;
/// @notice The Printr contract that can mint NFTs
address public immutable printr;
/**
* @notice Initialize the Dev NFT contract
* @dev Sets the Printr contract address
* @param _printr The address of the Printr contract
*/
constructor(
address _printr
) ERC721("Printr Dev Liquidity Position", "PRINTR DEV") {
printr = _printr;
}
/**
* @notice Mints a new Dev NFT representing developer rights for a PRINTR token
* @dev Only callable by the Printr contract. The NFT token ID is derived from the telecoin ID.
* Each PRINTR telecoin can only have one associated Dev NFT, ensuring unique ownership.
* @param telecoinId The unique identifier of the PRINTR telecoin (bytes32)
* @param creator The address that will receive the minted Dev NFT
* @return id The minted NFT token ID (uint256 representation of telecoinId)
* @custom:throws OnlyPrintrCanMint if caller is not the Printr contract
* @custom:throws PositionAlreadyCreated if a Dev NFT already exists for this telecoin ID
*/
function mint(
bytes32 telecoinId,
address creator
) external returns (uint256 id) {
if (msg.sender != printr) {
revert OnlyPrintrCanMint();
}
// Use token address as NFT ID directly
id = uint256(telecoinId);
if (_ownerOf(id) != address(0)) {
revert PositionAlreadyCreated();
}
_mint(creator, id);
}
/**
* @notice Generates the metadata URI for a Dev NFT
* @dev Creates a base64-encoded JSON metadata object containing the NFT's name, description,
* image URL, external URL, and comprehensive attributes array with 10 metadata fields.
* Function is split into helpers to avoid stack too deep with Paris EVM version.
* @param id The NFT token ID to generate metadata for
* @return The complete token URI as a data URL with base64-encoded JSON metadata
* @custom:throws ERC721NonexistentToken if the token ID does not exist
*/
function tokenURI(
uint256 id
) public view virtual override(ERC721, IERC721Metadata) returns (string memory) {
_requireOwned(id);
address token = idToToken(id);
bytes memory json = abi.encodePacked(
_buildBaseMetadata(id, token), _buildTokenAttributes(token), _buildCurveAttributes(token), "]}"
);
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(json)));
}
/**
* @notice Builds the base metadata JSON (name, description, image, external_url)
* @dev Helper function to reduce stack depth in tokenURI
* @param id The NFT token ID
* @param token The token address
* @return Base metadata JSON string as bytes
*/
function _buildBaseMetadata(
uint256 id,
address token
) internal pure returns (bytes memory) {
return abi.encodePacked(
'{"name":"PRINTR Dev Position #',
id.toString(),
'","description":"Developer rights for PRINTR telecoin"',
',"external_url":"https://printr.money/token/',
token.toHexString(),
'","image":"https://cdn.printr.money/nft/',
id.toHexString(32),
'.svg","attributes":['
);
}
/**
* @notice Builds token-specific attributes (address, name, symbol, decimals, creator)
* @dev Helper function to reduce stack depth in tokenURI
* @param token The token address
* @return Token attributes JSON as bytes
*/
function _buildTokenAttributes(
address token
) internal view returns (bytes memory) {
return abi.encodePacked(
'{"trait_type":"Token Address","value":"',
token.toHexString(),
'"},{"trait_type":"Token Name","value":"',
_getTokenName(token),
'"},{"trait_type":"Token Symbol","value":"',
_getTokenSymbol(token),
'"},{"trait_type":"Decimals","value":"18"}',
',{"trait_type":"Creator","value":"',
ownerOf(uint256(IPrintrTeleportingTelecoin(token).telecoinId())).toHexString(),
'"}'
);
}
/**
* @notice Builds curve-specific attributes (price, supply, status, base pair)
* @dev Helper function to reduce stack depth in tokenURI. Fetches curve data internally.
* @param token The token address
* @return Curve attributes JSON as bytes
*/
function _buildCurveAttributes(
address token
) internal view returns (bytes memory) {
IPrintrStorage.CurveInfo memory curve;
try IPrintrGetters(printr).getCurve(token) returns (IPrintrStorage.CurveInfo memory c) {
curve = c;
} catch {
// curve remains empty (basePair == address(0))
}
uint256 totalSupply = _getTotalSupply(token);
return abi.encodePacked(
',{"trait_type":"Current Price","value":"',
_getCurrentPrice(curve, totalSupply),
'","display_type":"number"}',
',{"trait_type":"Chain Supply","value":"',
totalSupply.toString(),
'","display_type":"number"},{"trait_type":"Global Supply","value":"',
curve.maxTokenSupply.toString(),
'","display_type":"number"},{"trait_type":"Status","value":"',
_getCurveStatus(curve.completionThreshold, totalSupply),
'"},{"trait_type":"Base Pair Symbol","value":"',
_getBasePairSymbol(curve.basePair),
'"},{"trait_type":"Base Pair Address","value":"',
curve.basePair.toHexString(),
'"}'
);
}
/**
* @notice Safely retrieves the token name
* @dev Returns "Unknown Token" if the name cannot be retrieved
* @param token The token address
* @return The token name or fallback value
*/
function _getTokenName(
address token
) internal view returns (string memory) {
try IERC20Metadata(token).name() returns (string memory name) {
return bytes(name).length > 0 ? name : "Unknown Token";
} catch {
return "Unknown Token";
}
}
/**
* @notice Safely retrieves the token symbol
* @dev Returns "???" if the symbol cannot be retrieved
* @param token The token address
* @return The token symbol or fallback value
*/
function _getTokenSymbol(
address token
) internal view returns (string memory) {
try IERC20Metadata(token).symbol() returns (string memory symbol) {
return bytes(symbol).length > 0 ? symbol : "???";
} catch {
return "???";
}
}
/**
* @notice Safely retrieves the base pair token symbol
* @dev Returns "None" if address is zero, "Unknown" if the symbol cannot be retrieved
* @param basePair The base pair token address
* @return The base pair symbol or fallback value
*/
function _getBasePairSymbol(
address basePair
) internal view returns (string memory) {
if (basePair == address(0)) {
return "None";
}
try IERC20Metadata(basePair).symbol() returns (string memory symbol) {
return bytes(symbol).length > 0 ? symbol : "Unknown";
} catch {
return "Unknown";
}
}
/**
* @notice Safely retrieves the token total supply
* @dev Returns 0 if the supply cannot be retrieved
* @param token The token address
* @return The token total supply or 0
*/
function _getTotalSupply(
address token
) internal view returns (uint256) {
try IERC20(token).totalSupply() returns (uint256 supply) {
return supply;
} catch {
return 0;
}
}
/**
* @notice Calculates the current price per token from curve data
* @dev Uses the bonding curve formula: price = (reserve + virtualReserve) / supply
* @param curve The curve information containing reserve data
* @param totalSupply The current total supply of tokens
* @return priceString Formatted price string or "0"
*/
function _getCurrentPrice(
IPrintrStorage.CurveInfo memory curve,
uint256 totalSupply
) internal pure returns (string memory) {
if (curve.basePair == address(0) || totalSupply == 0) {
return "0";
}
// Calculate price: (reserve + virtualReserve) * 1e18 / supply
// This gives approximate current price per token in base pair units
uint256 totalReserve = curve.reserve + curve.virtualReserve;
uint256 price = (totalReserve * 1e18) / totalSupply;
return price.toString();
}
/**
* @notice Determines if the token curve is active or graduated
* @dev Compares total supply against completion threshold
* @param completionThreshold The completion threshold from curve data
* @param totalSupply The current total supply of the token
* @return "Active" if curve is ongoing, "Graduated" if completed
*/
function _getCurveStatus(
uint256 completionThreshold,
uint256 totalSupply
) internal pure returns (string memory) {
if (completionThreshold == 0) {
return "Graduated";
}
return totalSupply >= completionThreshold ? "Graduated" : "Active";
}
/**
* @notice Converts a PRINTR telecoin address to its corresponding Dev NFT token ID
* @dev Retrieves the telecoin ID from the PRINTR telecoin contract and converts it to uint256.
* This creates a deterministic mapping between PRINTR telecoins and their Dev NFTs.
* @param token The address of the PRINTR telecoin contract
* @return id The corresponding Dev NFT token ID (uint256 representation of telecoin ID)
*/
function tokenToId(
address token
) external view returns (uint256 id) {
return uint256(IPrintrTeleportingTelecoin(token).telecoinId());
}
/**
* @notice Converts a Dev NFT token ID to its corresponding PRINTR telecoin address
* @dev Queries the Printr contract to get the telecoin address for the given telecoin ID.
* This provides the reverse mapping from Dev NFT to PRINTR telecoin.
* @param id The Dev NFT token ID to look up
* @return token The address of the corresponding PRINTR telecoin contract
*/
function idToToken(
uint256 id
) public view returns (address token) {
return IPrintrGetters(printr).getTokenAddress(bytes32(id));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
mapping(uint256 tokenId => address) private _owners;
mapping(address owner => uint256) private _balances;
mapping(uint256 tokenId => address) private _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
unchecked {
_balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
_balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
_balances[to] += 1;
}
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
_tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.2) (utils/Base64.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library Base64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
string memory result = new string(4 * ((data.length + 2) / 3));
/// @solidity memory-safe-assembly
assembly {
// Prepare the lookup table (skip the first "length" byte)
let tablePtr := add(table, 1)
// Prepare result pointer, jump over length
let resultPtr := add(result, 0x20)
let dataPtr := data
let endPtr := add(data, mload(data))
// In some cases, the last iteration will read bytes after the end of the data. We cache the value, and
// set it to zero to make sure no dirty bytes are read in that section.
let afterPtr := add(endPtr, 0x20)
let afterCache := mload(afterPtr)
mstore(afterPtr, 0x00)
// Run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 byte (24 bits) chunk
// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F to bitmask the least significant 6 bits.
// Use this as an index into the lookup table, mload an entire word
// so the desired character is in the least significant byte, and
// mstore8 this least significant byte into the result and continue.
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// Reset the value that was cached
mstore(afterPtr, afterCache)
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// 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
// 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 { IPrintrStorage } from "./IPrintrStorage.sol";
/**
* @title Printr Getters Interface
* @notice Interface for the PrintrGetters contract
* @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 IPrintrGetters is IPrintrStorage {
/**
* @notice Retrieves the address of a token based on its universal ID
* @param telecoinId The universal token ID (deploySalt)
* @return Address of the token associated with the given ID
*/
function getTokenAddress(
bytes32 telecoinId
) external view returns (address);
/**
* @notice Calculates the deterministic address for a token deployment
* @dev Uses creator address and deployment parameters to compute the deployment address
* @param tokenParams Parameters for the token deployment
* @return tokenAddress The calculated token deployment address
*/
function getTokenAddress(
TelecoinParams calldata tokenParams
) external view returns (address tokenAddress);
/**
* @notice Retrieves information about a specific token
* @param token Address of the token
* @return CurveInfo struct containing the token's configuration and state
*/
function getCurve(
address token
) external view returns (CurveInfo memory);
/**
* @notice Gets the lock status for a token
* @param token Address of the token to check
* @return Array containing lock information
*/
function getLiquidityLocks(
address token
) external view returns (uint256[2] memory);
}// 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 first legacy dev NFT contract (for migration from V1 - oldest original)
* @param legacyPrintrDev2 Address of the second legacy dev NFT contract (for migration from V2 - without base64
* fix)
* @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;
address legacyPrintrDev2;
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;
import { IPrintrStorage } from "./IPrintrStorage.sol";
/**
* @title Printr Trading Interface
* @notice Interface for trading operations on tokens with linear bonding curves
* @dev All price calculations use PRECISION_SCALAR (1e18) for accurate floating point math
* Handles buying, selling, and cross-chain trading operations
*/
interface IPrintrTrading is IPrintrStorage {
/**
* @notice Parameters for token trading operations
* @param account Account performing the trade
* @param token Address of the token being traded
* @param amount Amount of tokens in the trade
* @param priceLimit Maximum/minimum price limit for slippage protection
* @param tokenSupply Current token supply before the trade
* @param tradingFee Fee percentage applied to the trade
*/
struct TradeParams {
address account;
address recipient;
address token;
uint256 amount;
uint256 priceLimit;
uint16 tradingFee;
}
/**
* @notice Emitted when tokens are traded through the bonding curve
* @param token Address of the token contract
* @param trader Address that performed the trade
* @param isBuy True if tokens were bought, false if sold
* @param amount Number of tokens traded
* @param cost Amount of base currency involved in the trade
* @param priceAfter Price per token achieved in the trade
* @param issuedSupply New total supply after the trade
* @param reserve New reserve balance after the trade
*/
event TokenTrade(
address indexed token,
address indexed trader,
bool isBuy,
uint256 amount,
uint256 cost,
uint256 priceAfter,
uint256 issuedSupply,
uint256 reserve
);
/**
* @notice Emitted when a token graduates from bonding curve to liquidity pool
* @param token Address of the token that graduated
* @param totalSupply Total supply at graduation
*/
event TokenGraduated(address indexed token, uint256 totalSupply);
/**
* @notice Emitted when a token graduation process encounters a partial failure
* @dev Used for graceful degradation when liquidity deployment or post-graduation swap fails
* @param token Address of the token that experienced partial graduation failure
* @param stage Stage at which failure occurred (0=liquidity deployment, 1=post-graduation swap)
*/
event TokenGraduationPartialFailure(address indexed token, uint8 stage, uint256 gasLeft);
/**
* @notice Estimates the cost of issuing a specific amount of tokens
* @dev Uses linear bonding curve. All calculations are scaled by PRECISION_SCALAR
* @param token Address of the token
* @param tokenAmount Number of tokens to issue
* @return availableAmount Amount of tokens available for issuing
* @return cost Cost in base currency to issue the specified amount of tokens
* @return fee Trading fee amount in base currency
* @return priceAfter Effective price per token in base currency
* @return issuedSupply New total supply after the issue
*/
function estimateTokenCost(
address token,
uint256 tokenAmount
) external returns (uint256 availableAmount, uint256 cost, uint256 fee, uint256 priceAfter, uint256 issuedSupply);
/**
* @notice Quote the amount of tokens receivable for a specific amount of base currency
* @dev Calculates tokens received including trading fees
* @param token The token address
* @param baseAmount The amount of base currency to spend
* @return tokenAmount The amount of tokens receivable
* @return cost The actual amount in base currency required for the purchase
* @return fee The trading fee amount in base currency
* @return priceAfter The effective price per token
* @return issuedSupply The new total supply after the purchase
*/
function quoteTokenAmount(
address token,
uint256 baseAmount
) external returns (uint256 tokenAmount, uint256 cost, uint256 fee, uint256 priceAfter, uint256 issuedSupply);
/**
* @notice Estimates the refund amount for redeeming a specific amount of tokens
* @dev Uses the same linear bonding curve as issue, but in reverse
* @param token Address of the token
* @param tokenAmount Number of tokens to redeem
* @return tokenAmountIn Amount of tokens that can actually be sold (capped by supply)
* @return refund Refund amount in base currency for redeeming the specified tokens
* @return fee Trading fee amount in base currency
* @return priceAfter Effective price per token in base currency
* @return issuedSupply New total supply after the redemption
*/
function estimateTokenRefund(
address token,
uint256 tokenAmount
) external returns (uint256 tokenAmountIn, uint256 refund, uint256 fee, uint256 priceAfter, uint256 issuedSupply);
/**
* @notice Issues tokens according to the bonding curve
* @param token Address of the token to issue
* @param recipient Address to receive the issued tokens
* @param amount Amount of tokens to issue
* @param maxPrice Maximum acceptable price per token for slippage protection
*/
function buy(
address token,
address recipient,
uint256 amount,
uint256 maxPrice
) external payable returns (TradeParams memory params);
/**
* @notice Buys tokens with a specified amount of base currency
* @param token Address of the token to buy
* @param recipient Address to receive the tokens
* @param baseAmount Amount of base currency to spend. Pass type(uint256).max to use
* the maximum available amount (all approved tokens or all sent ETH)
* @param maxPrice Maximum acceptable price per token for slippage protection
*/
function spend(
address token,
address recipient,
uint256 baseAmount,
uint256 maxPrice
) external payable returns (TradeParams memory params);
/**
* @notice Redeems tokens and returns base currency according to the bonding curve
* @param token Address of the token to redeem
* @param recipient Address to receive the refunded base currency
* @param amount Amount of tokens to redeem. Pass type(uint256).max to sell all tokens
* @param minPrice Minimum acceptable refund per token for slippage protection
*/
function sell(
address token,
address recipient,
uint256 amount,
uint256 minPrice
) external returns (TradeParams memory params);
/**
* @notice Sells tokens and returns base currency according to the bonding curve
* @dev Called by the Telecoin contract via permitWitnessCall
* @param account Address of the account selling tokens
* @param token Address of the token to sell
* @param recipient Address to receive the refund
* @param amount Amount of tokens to sell. Pass type(uint256).max to sell all tokens
* @param minPrice Minimum acceptable price per token
*/
function witnessSell(
address account,
address token,
address recipient,
uint256 amount,
uint256 minPrice
) external returns (TradeParams memory params);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
/**
* @title IPrintrDev
* @notice Interface for the Dev NFT contract that tracks token creators
* @dev Each PRINTR token gets one Dev NFT minted to its creator
*/
interface IPrintrDev is IERC721, IERC721Metadata {
/// @notice Custom errors for the PrintrDev contract
error OnlyPrintrCanMint();
error PositionAlreadyCreated();
/**
* @notice Mint a new Dev NFT for a token
* @dev Only callable by the Printr contract
* @param telecoinId The PRINTR token ID (bytes32)
* @param creator The creator who will receive the NFT
* @return id The minted NFT token ID
*/
function mint(
bytes32 telecoinId,
address creator
) external returns (uint256 id);
/**
* @notice Get the NFT token ID for a specific PRINTR token
* @param token The PRINTR token address
* @return id The NFT token ID (which is the token address as uint256)
*/
function tokenToId(
address token
) external view returns (uint256 id);
/**
* @notice Get the PRINTR token address for a specific NFT token ID
* @param id The NFT token ID
* @return token The PRINTR token address
*/
function idToToken(
uint256 id
) external view returns (address token);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import { IPrinted } from "./IPrinted.sol";
import { ITeleportingTelecoin } from "./ITeleporting.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 IPrintrTeleportingTelecoin is IPrinted, ITeleportingTelecoin { }// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// 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) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// 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);
}// 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 Enum representing the teleport type of a Telecoin
* @dev Values 0-1 are legacy types for backward compatibility with deployed contracts
* Values 2-3 are new types that support teleporting by calling methods on a Telecoin
* - LegacyMain (0): Legacy Main Telecoin (bool false, uses lock/unlock)
* - LegacyTeleporting (1): Legacy Teleporting Telecoin (bool true, uses mint/burn)
* - Main (2): New Main Telecoin with Telecoin.teleport() support
* - Teleporting (3): New Teleporting Telecoin with Telecoin.teleport() support
*/
enum TeleportType {
LegacyMain, // 0 - backward compatible with bool false
LegacyTeleporting, // 1 - backward compatible with bool true
Main, // 2 - new Main Telecoin type
Teleporting // 3 - new Teleporting Telecoin type
}
/**
* @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 the teleport type of this Telecoin
* @dev Values 0-1 are legacy (backward compatible), values 2-3 support transmitLzSend
* @return teleportType The TeleportType enum value:
* - LegacyMain (0): Legacy Main Telecoin (lock/unlock)
* - LegacyTeleporting (1): Legacy Teleporting Telecoin (mint/burn)
* - Main (2): New Main Telecoin with transmitLzSend support
* - Teleporting (3): New Teleporting Telecoin with transmitLzSend support
*/
function isTeleporting() external view returns (TeleportType teleportType);
/**
* @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 { 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
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
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 Error thrown when a native token transfer fails
*/
error TransferFailed();
/**
* @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.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.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 returns (bytes memory receipt);
/**
* @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 { 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;
/**
* @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.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
// 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;
}{
"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":[{"internalType":"address","name":"_printr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[],"name":"OnlyPrintrCanMint","type":"error"},{"inputs":[],"name":"PositionAlreadyCreated","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"StringsInsufficientHexLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"idToToken","outputs":[{"internalType":"address","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"telecoinId","type":"bytes32"},{"internalType":"address","name":"creator","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"printr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"tokenToId","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b506040516128fa3803806128fa83398101604081905261002e916100b6565b6040518060400160405280601d81526020017f5072696e747220446576204c697175696469747920506f736974696f6e0000008152506040518060400160405280600a815260200169282924a72a29102222ab60b11b815250815f9081610095919061017b565b5060016100a2828261017b565b5050506001600160a01b0316608052610235565b5f602082840312156100c6575f5ffd5b81516001600160a01b03811681146100dc575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061010b57607f821691505b60208210810361012957634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561017657805f5260205f20601f840160051c810160208510156101545750805b601f840160051c820191505b81811015610173575f8155600101610160565b50505b505050565b81516001600160401b03811115610194576101946100e3565b6101a8816101a284546100f7565b8461012f565b6020601f8211600181146101da575f83156101c35750848201515b5f19600385901b1c1916600184901b178455610173565b5f84815260208120601f198516915b8281101561020957878501518255602094850194600190920191016101e9565b508482101561022657868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b6080516126986102625f395f81816102aa01528181610528015281816107ad0152610dd301526126985ff3fe608060405234801561000f575f5ffd5b5060043610610115575f3560e01c806370a08231116100ad578063c87b56dd1161007d578063e985e9c511610063578063e985e9c514610257578063f5c6b96b14610292578063f7cca092146102a5575f5ffd5b8063c87b56dd14610231578063ca82a01414610244575f5ffd5b806370a08231146101f057806395d89b4114610203578063a22cb4651461020b578063b88d4fde1461021e575f5ffd5b806323b872dd116100e857806323b872dd14610196578063293c6a3a146101a957806342842e0e146101ca5780636352211e146101dd575f5ffd5b806301ffc9a71461011957806306fdde0314610141578063081812fc14610156578063095ea7b314610181575b5f5ffd5b61012c610127366004611b00565b6102cc565b60405190151581526020015b60405180910390f35b6101496103b0565b6040516101389190611b49565b610169610164366004611b5b565b61043f565b6040516001600160a01b039091168152602001610138565b61019461018f366004611b86565b610466565b005b6101946101a4366004611bb0565b610475565b6101bc6101b7366004611bee565b61051c565b604051908152602001610138565b6101946101d8366004611bb0565b6105da565b6101696101eb366004611b5b565b6105f9565b6101bc6101fe366004611c1c565b610603565b610149610661565b610194610219366004611c37565b610670565b61019461022c366004611cfc565b61067b565b61014961023f366004611b5b565b610692565b6101bc610252366004611c1c565b61071b565b61012c610265366004611da4565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205460ff1690565b6101696102a0366004611b5b565b61077c565b6101697f000000000000000000000000000000000000000000000000000000000000000081565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061035e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806103aa57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60605f80546103be90611dd0565b80601f01602080910402602001604051908101604052809291908181526020018280546103ea90611dd0565b80156104355780601f1061040c57610100808354040283529160200191610435565b820191905f5260205f20905b81548152906001019060200180831161041857829003601f168201915b5050505050905090565b5f6104498261081e565b505f828152600460205260409020546001600160a01b03166103aa565b61047182823361086f565b5050565b6001600160a01b0382166104a357604051633250574960e11b81525f60048201526024015b60405180910390fd5b5f6104af83833361087c565b9050836001600160a01b0316816001600160a01b031614610516576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b038086166004830152602482018490528216604482015260640161049a565b50505050565b5f336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461057f576040517f878d41a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f8281526002602052604090205482906001600160a01b0316156105d0576040517f0f04799c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103aa8282610986565b6105f483838360405180602001604052805f81525061067b565b505050565b5f6103aa8261081e565b5f6001600160a01b038216610646576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f600482015260240161049a565b506001600160a01b03165f9081526003602052604090205490565b6060600180546103be90611dd0565b610471338383610a00565b610686848484610475565b61051684848484610ad5565b606061069d8261081e565b505f6106a88361077c565b90505f6106b58483610c45565b6106be83610c96565b6106c784610d59565b6040516020016106d993929190611e1f565b60405160208183030381529060405290506106f381610eac565b6040516020016107039190611e6b565b60405160208183030381529060405292505050919050565b5f816001600160a01b03166381cce2456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610758573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103aa9190611e9c565b6040517fb12e4410000000000000000000000000000000000000000000000000000000008152600481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b12e441090602401602060405180830381865afa1580156107fa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103aa9190611eb3565b5f818152600260205260408120546001600160a01b0316806103aa576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810184905260240161049a565b6105f48383836001611007565b5f828152600260205260408120546001600160a01b03908116908316156108a8576108a881848661115a565b6001600160a01b038116156108e2576108c35f855f5f611007565b6001600160a01b0381165f90815260036020526040902080545f190190555b6001600160a01b03851615610910576001600160a01b0385165f908152600360205260409020805460010190555b5f8481526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6001600160a01b0382166109af57604051633250574960e11b81525f600482015260240161049a565b5f6109bb83835f61087c565b90506001600160a01b038116156105f4576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f600482015260240161049a565b6001600160a01b038216610a4b576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161049a565b6001600160a01b038381165f8181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b15610516576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290610b30903390889087908790600401611ece565b6020604051808303815f875af1925050508015610b6a575060408051601f3d908101601f19168201909252610b6791810190611f0e565b60015b610bd1573d808015610b97576040519150601f19603f3d011682016040523d82523d5f602084013e610b9c565b606091505b5080515f03610bc957604051633250574960e11b81526001600160a01b038516600482015260240161049a565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014610c3e57604051633250574960e11b81526001600160a01b038516600482015260240161049a565b5050505050565b6060610c50836111f0565b610c62836001600160a01b031661128d565b610c6d85602061129f565b604051602001610c7f93929190611f29565b604051602081830303815290604052905092915050565b6060610caa826001600160a01b031661128d565b610cb3836114bf565b610cbc846115a1565b610d30610d22866001600160a01b03166381cce2456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101eb9190611e9c565b6001600160a01b031661128d565b604051602001610d439493929190612084565b6040516020818303038152906040529050919050565b6060610d9b6040518060c001604052805f6001600160a01b031681526020015f61ffff1681526020015f81526020015f81526020015f81526020015f81525090565b6040517f61f029fb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f000000000000000000000000000000000000000000000000000000000000000016906361f029fb9060240160c060405180830381865afa925050508015610e36575060408051601f3d908101601f19168201909252610e3391810190612232565b60015b15610e3e5790505b5f610e4884611680565b9050610e5482826116e6565b610e5d826111f0565b610e6a84604001516111f0565b610e788560a0015185611786565b8551610e8390611849565b8651610e97906001600160a01b031661128d565b604051602001610703969594939291906122a3565b606081515f03610ec957505060408051602081019091525f815290565b5f6040518060600160405280604081526020016126236040913990505f600384516002610ef6919061253b565b610f00919061254e565b610f0b90600461256d565b67ffffffffffffffff811115610f2357610f23611c67565b6040519080825280601f01601f191660200182016040528015610f4d576020820181803683370190505b509050600182016020820185865187016020810180515f82525b82841015610fc2576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f8116870151865350600185019450610f67565b9052505085516003900660018114610fe15760028114610ff457610ffc565b603d6001830353603d6002830353610ffc565b603d60018303535b509195945050505050565b808061101b57506001600160a01b03821615155b15611113575f61102a8461081e565b90506001600160a01b038316158015906110565750826001600160a01b0316816001600160a01b031614155b801561108757506001600160a01b038082165f9081526005602090815260408083209387168352929052205460ff16155b156110c9576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161049a565b81156111115783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b61116583838361196f565b6105f4576001600160a01b0383166111ac576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810182905260240161049a565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024810182905260440161049a565b60605f6111fc836119ef565b60010190505f8167ffffffffffffffff81111561121b5761121b611c67565b6040519080825280601f01601f191660200182016040528015611245576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461124f57509392505050565b60606103aa6001600160a01b03831660145b6060825f6112ae84600261256d565b6112b990600261253b565b67ffffffffffffffff8111156112d1576112d1611c67565b6040519080825280601f01601f1916602001820160405280156112fb576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f8151811061133157611331612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061139357611393612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f6113cd85600261256d565b6113d890600161253b565b90505b6001811115611474577f303132333435363738396162636465660000000000000000000000000000000083600f166010811061141957611419612584565b1a60f81b82828151811061142f5761142f612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049290921c9161146d81612598565b90506113db565b5081156114b7576040517fe22e27eb000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260440161049a565b949350505050565b6060816001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa92505050801561151e57506040513d5f823e601f3d908101601f1916820160405261151b91908101906125ad565b60015b61155b57505060408051808201909152600d81527f556e6b6e6f776e20546f6b656e00000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600d81526020017f556e6b6e6f776e20546f6b656e000000000000000000000000000000000000008152505b9392505050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa92505050801561160057506040513d5f823e601f3d908101601f191682016040526115fd91908101906125ad565b60015b61163d57505060408051808201909152600381527f3f3f3f0000000000000000000000000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600381526020017f3f3f3f000000000000000000000000000000000000000000000000000000000081525061159a565b5f816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116db575060408051601f3d908101601f191682019092526116d891810190611e9c565b60015b6103aa57505f919050565b81516060906001600160a01b031615806116fe575081155b1561173d575060408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201526103aa565b5f83606001518460800151611752919061253b565b90505f8361176883670de0b6b3a764000061256d565b611772919061254e565b905061177d816111f0565b95945050505050565b6060825f036117c9575060408051808201909152600981527f477261647561746564000000000000000000000000000000000000000000000060208201526103aa565b8282101561180c576040518060400160405280600681526020017f416374697665000000000000000000000000000000000000000000000000000081525061159a565b6040518060400160405280600981526020017f47726164756174656400000000000000000000000000000000000000000000008152509392505050565b60606001600160a01b03821661189257505060408051808201909152600481527f4e6f6e6500000000000000000000000000000000000000000000000000000000602082015290565b816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa9250505080156118ef57506040513d5f823e601f3d908101601f191682016040526118ec91908101906125ad565b60015b61192c57505060408051808201909152600781527f556e6b6e6f776e00000000000000000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600781526020017f556e6b6e6f776e0000000000000000000000000000000000000000000000000081525061159a565b5f6001600160a01b038316158015906114b75750826001600160a01b0316846001600160a01b031614806119c757506001600160a01b038085165f9081526005602090815260408083209387168352929052205460ff165b806114b75750505f908152600460205260409020546001600160a01b03908116911614919050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611a37577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310611a63576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611a8157662386f26fc10000830492506010015b6305f5e1008310611a99576305f5e100830492506008015b6127108310611aad57612710830492506004015b60648310611abf576064830492506002015b600a83106103aa5760010192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114611afd575f5ffd5b50565b5f60208284031215611b10575f5ffd5b813561159a81611ad0565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61159a6020830184611b1b565b5f60208284031215611b6b575f5ffd5b5035919050565b6001600160a01b0381168114611afd575f5ffd5b5f5f60408385031215611b97575f5ffd5b8235611ba281611b72565b946020939093013593505050565b5f5f5f60608486031215611bc2575f5ffd5b8335611bcd81611b72565b92506020840135611bdd81611b72565b929592945050506040919091013590565b5f5f60408385031215611bff575f5ffd5b823591506020830135611c1181611b72565b809150509250929050565b5f60208284031215611c2c575f5ffd5b813561159a81611b72565b5f5f60408385031215611c48575f5ffd5b8235611c5381611b72565b915060208301358015158114611c11575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715611c9e57611c9e611c67565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611ccd57611ccd611c67565b604052919050565b5f67ffffffffffffffff821115611cee57611cee611c67565b50601f01601f191660200190565b5f5f5f5f60808587031215611d0f575f5ffd5b8435611d1a81611b72565b93506020850135611d2a81611b72565b925060408501359150606085013567ffffffffffffffff811115611d4c575f5ffd5b8501601f81018713611d5c575f5ffd5b8035611d6f611d6a82611cd5565b611ca4565b818152886020838501011115611d83575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215611db5575f5ffd5b8235611dc081611b72565b91506020830135611c1181611b72565b600181811c90821680611de457607f821691505b602082108103611e0257634e487b7160e01b5f52602260045260245ffd5b50919050565b5f81518060208401855e5f93019283525090919050565b5f611e3c611e36611e308488611e08565b86611e08565b84611e08565b7f5d7d000000000000000000000000000000000000000000000000000000000000815260020195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525f61159a601d830184611e08565b5f60208284031215611eac575f5ffd5b5051919050565b5f60208284031215611ec3575f5ffd5b815161159a81611b72565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f611f046080830184611b1b565b9695505050505050565b5f60208284031215611f1e575f5ffd5b815161159a81611ad0565b7f7b226e616d65223a225052494e54522044657620506f736974696f6e2023000081525f611f5a601e830186611e08565b7f222c226465736372697074696f6e223a22446576656c6f70657220726967687481527f7320666f72205052494e54522074656c65636f696e220000000000000000000060208201527f2c2265787465726e616c5f75726c223a2268747470733a2f2f7072696e74722e60368201527f6d6f6e65792f746f6b656e2f00000000000000000000000000000000000000006056820152611ffc6062820186611e08565b90507f222c22696d616765223a2268747470733a2f2f63646e2e7072696e74722e6d6f81527f6e65792f6e66742f00000000000000000000000000000000000000000000000060208201526120546028820185611e08565b7f2e737667222c2261747472696275746573223a5b00000000000000000000000081526014019695505050505050565b7f7b2274726169745f74797065223a22546f6b656e2041646472657373222c227681526630b63ab2911d1160c91b60208201525f6120c56027830187611e08565b7f227d2c7b2274726169745f74797065223a22546f6b656e204e616d65222c227681526630b63ab2911d1160c91b60208201526121056027820187611e08565b90507f227d2c7b2274726169745f74797065223a22546f6b656e2053796d626f6c222c81527f2276616c7565223a220000000000000000000000000000000000000000000000602082015261215d6029820186611e08565b90507f227d2c7b2274726169745f74797065223a22446563696d616c73222c2276616c81527f7565223a223138227d000000000000000000000000000000000000000000000060208201527f2c7b2274726169745f74797065223a2243726561746f72222c2276616c75652260298201527f3a220000000000000000000000000000000000000000000000000000000000006049820152612201604b820185611e08565b7f227d0000000000000000000000000000000000000000000000000000000000008152600201979650505050505050565b5f60c0828403128015612243575f5ffd5b5061224c611c7b565b825161225781611b72565b8152602083015161ffff8116811461226d575f5ffd5b602082015260408381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b7f2c7b2274726169745f74797065223a2243757272656e74205072696365222c2281527f76616c7565223a2200000000000000000000000000000000000000000000000060208201525f6122fa6028830189611e08565b7f222c22646973706c61795f74797065223a226e756d626572227d00000000000081527f2c7b2274726169745f74797065223a22436861696e20537570706c79222c2276601a8201526630b63ab2911d1160c91b603a8201526123606041820189611e08565b90507f222c22646973706c61795f74797065223a226e756d626572227d2c7b2274726181527f69745f74797065223a22476c6f62616c20537570706c79222c2276616c75652260208201527f3a2200000000000000000000000000000000000000000000000000000000000060408201526123de6042820188611e08565b7f222c22646973706c61795f74797065223a226e756d626572227d2c7b2274726181527f69745f74797065223a22537461747573222c2276616c7565223a22000000000060208201529050603b81016125196124f06124ea61249b612495612446868d611e08565b7f227d2c7b2274726169745f74797065223a224261736520506169722053796d6281527f6f6c222c2276616c7565223a22000000000000000000000000000000000000006020820152602d0190565b8a611e08565b7f227d2c7b2274726169745f74797065223a22426173652050616972204164647281527f657373222c2276616c7565223a220000000000000000000000000000000000006020820152602e0190565b87611e08565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b9a9950505050505050505050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156103aa576103aa612527565b5f8261256857634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176103aa576103aa612527565b634e487b7160e01b5f52603260045260245ffd5b5f816125a6576125a6612527565b505f190190565b5f602082840312156125bd575f5ffd5b815167ffffffffffffffff8111156125d3575f5ffd5b8201601f810184136125e3575f5ffd5b80516125f1611d6a82611cd5565b818152856020838501011115612605575f5ffd5b8160208401602083015e5f9181016020019190915294935050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122004d128e854659d626dbea689e34ff98df0928a760c5392e4e75baef777ed989d64736f6c634300081b0033000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610115575f3560e01c806370a08231116100ad578063c87b56dd1161007d578063e985e9c511610063578063e985e9c514610257578063f5c6b96b14610292578063f7cca092146102a5575f5ffd5b8063c87b56dd14610231578063ca82a01414610244575f5ffd5b806370a08231146101f057806395d89b4114610203578063a22cb4651461020b578063b88d4fde1461021e575f5ffd5b806323b872dd116100e857806323b872dd14610196578063293c6a3a146101a957806342842e0e146101ca5780636352211e146101dd575f5ffd5b806301ffc9a71461011957806306fdde0314610141578063081812fc14610156578063095ea7b314610181575b5f5ffd5b61012c610127366004611b00565b6102cc565b60405190151581526020015b60405180910390f35b6101496103b0565b6040516101389190611b49565b610169610164366004611b5b565b61043f565b6040516001600160a01b039091168152602001610138565b61019461018f366004611b86565b610466565b005b6101946101a4366004611bb0565b610475565b6101bc6101b7366004611bee565b61051c565b604051908152602001610138565b6101946101d8366004611bb0565b6105da565b6101696101eb366004611b5b565b6105f9565b6101bc6101fe366004611c1c565b610603565b610149610661565b610194610219366004611c37565b610670565b61019461022c366004611cfc565b61067b565b61014961023f366004611b5b565b610692565b6101bc610252366004611c1c565b61071b565b61012c610265366004611da4565b6001600160a01b039182165f90815260056020908152604080832093909416825291909152205460ff1690565b6101696102a0366004611b5b565b61077c565b6101697f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff24317281565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061035e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806103aa57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60605f80546103be90611dd0565b80601f01602080910402602001604051908101604052809291908181526020018280546103ea90611dd0565b80156104355780601f1061040c57610100808354040283529160200191610435565b820191905f5260205f20905b81548152906001019060200180831161041857829003601f168201915b5050505050905090565b5f6104498261081e565b505f828152600460205260409020546001600160a01b03166103aa565b61047182823361086f565b5050565b6001600160a01b0382166104a357604051633250574960e11b81525f60048201526024015b60405180910390fd5b5f6104af83833361087c565b9050836001600160a01b0316816001600160a01b031614610516576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b038086166004830152602482018490528216604482015260640161049a565b50505050565b5f336001600160a01b037f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172161461057f576040517f878d41a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f8281526002602052604090205482906001600160a01b0316156105d0576040517f0f04799c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103aa8282610986565b6105f483838360405180602001604052805f81525061067b565b505050565b5f6103aa8261081e565b5f6001600160a01b038216610646576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f600482015260240161049a565b506001600160a01b03165f9081526003602052604090205490565b6060600180546103be90611dd0565b610471338383610a00565b610686848484610475565b61051684848484610ad5565b606061069d8261081e565b505f6106a88361077c565b90505f6106b58483610c45565b6106be83610c96565b6106c784610d59565b6040516020016106d993929190611e1f565b60405160208183030381529060405290506106f381610eac565b6040516020016107039190611e6b565b60405160208183030381529060405292505050919050565b5f816001600160a01b03166381cce2456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610758573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103aa9190611e9c565b6040517fb12e4410000000000000000000000000000000000000000000000000000000008152600481018290525f907f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff2431726001600160a01b03169063b12e441090602401602060405180830381865afa1580156107fa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103aa9190611eb3565b5f818152600260205260408120546001600160a01b0316806103aa576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810184905260240161049a565b6105f48383836001611007565b5f828152600260205260408120546001600160a01b03908116908316156108a8576108a881848661115a565b6001600160a01b038116156108e2576108c35f855f5f611007565b6001600160a01b0381165f90815260036020526040902080545f190190555b6001600160a01b03851615610910576001600160a01b0385165f908152600360205260409020805460010190555b5f8481526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6001600160a01b0382166109af57604051633250574960e11b81525f600482015260240161049a565b5f6109bb83835f61087c565b90506001600160a01b038116156105f4576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f600482015260240161049a565b6001600160a01b038216610a4b576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260240161049a565b6001600160a01b038381165f8181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b15610516576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290610b30903390889087908790600401611ece565b6020604051808303815f875af1925050508015610b6a575060408051601f3d908101601f19168201909252610b6791810190611f0e565b60015b610bd1573d808015610b97576040519150601f19603f3d011682016040523d82523d5f602084013e610b9c565b606091505b5080515f03610bc957604051633250574960e11b81526001600160a01b038516600482015260240161049a565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014610c3e57604051633250574960e11b81526001600160a01b038516600482015260240161049a565b5050505050565b6060610c50836111f0565b610c62836001600160a01b031661128d565b610c6d85602061129f565b604051602001610c7f93929190611f29565b604051602081830303815290604052905092915050565b6060610caa826001600160a01b031661128d565b610cb3836114bf565b610cbc846115a1565b610d30610d22866001600160a01b03166381cce2456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101eb9190611e9c565b6001600160a01b031661128d565b604051602001610d439493929190612084565b6040516020818303038152906040529050919050565b6060610d9b6040518060c001604052805f6001600160a01b031681526020015f61ffff1681526020015f81526020015f81526020015f81526020015f81525090565b6040517f61f029fb0000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f000000000000000000000000b77726291b125515d0a7affeea2b04f2ff24317216906361f029fb9060240160c060405180830381865afa925050508015610e36575060408051601f3d908101601f19168201909252610e3391810190612232565b60015b15610e3e5790505b5f610e4884611680565b9050610e5482826116e6565b610e5d826111f0565b610e6a84604001516111f0565b610e788560a0015185611786565b8551610e8390611849565b8651610e97906001600160a01b031661128d565b604051602001610703969594939291906122a3565b606081515f03610ec957505060408051602081019091525f815290565b5f6040518060600160405280604081526020016126236040913990505f600384516002610ef6919061253b565b610f00919061254e565b610f0b90600461256d565b67ffffffffffffffff811115610f2357610f23611c67565b6040519080825280601f01601f191660200182016040528015610f4d576020820181803683370190505b509050600182016020820185865187016020810180515f82525b82841015610fc2576003840193508351603f8160121c168701518653600186019550603f81600c1c168701518653600186019550603f8160061c168701518653600186019550603f8116870151865350600185019450610f67565b9052505085516003900660018114610fe15760028114610ff457610ffc565b603d6001830353603d6002830353610ffc565b603d60018303535b509195945050505050565b808061101b57506001600160a01b03821615155b15611113575f61102a8461081e565b90506001600160a01b038316158015906110565750826001600160a01b0316816001600160a01b031614155b801561108757506001600160a01b038082165f9081526005602090815260408083209387168352929052205460ff16155b156110c9576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161049a565b81156111115783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b61116583838361196f565b6105f4576001600160a01b0383166111ac576040517f7e2732890000000000000000000000000000000000000000000000000000000081526004810182905260240161049a565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024810182905260440161049a565b60605f6111fc836119ef565b60010190505f8167ffffffffffffffff81111561121b5761121b611c67565b6040519080825280601f01601f191660200182016040528015611245576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461124f57509392505050565b60606103aa6001600160a01b03831660145b6060825f6112ae84600261256d565b6112b990600261253b565b67ffffffffffffffff8111156112d1576112d1611c67565b6040519080825280601f01601f1916602001820160405280156112fb576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f8151811061133157611331612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061139357611393612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f6113cd85600261256d565b6113d890600161253b565b90505b6001811115611474577f303132333435363738396162636465660000000000000000000000000000000083600f166010811061141957611419612584565b1a60f81b82828151811061142f5761142f612584565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049290921c9161146d81612598565b90506113db565b5081156114b7576040517fe22e27eb000000000000000000000000000000000000000000000000000000008152600481018690526024810185905260440161049a565b949350505050565b6060816001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa92505050801561151e57506040513d5f823e601f3d908101601f1916820160405261151b91908101906125ad565b60015b61155b57505060408051808201909152600d81527f556e6b6e6f776e20546f6b656e00000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600d81526020017f556e6b6e6f776e20546f6b656e000000000000000000000000000000000000008152505b9392505050565b6060816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa92505050801561160057506040513d5f823e601f3d908101601f191682016040526115fd91908101906125ad565b60015b61163d57505060408051808201909152600381527f3f3f3f0000000000000000000000000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600381526020017f3f3f3f000000000000000000000000000000000000000000000000000000000081525061159a565b5f816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156116db575060408051601f3d908101601f191682019092526116d891810190611e9c565b60015b6103aa57505f919050565b81516060906001600160a01b031615806116fe575081155b1561173d575060408051808201909152600181527f300000000000000000000000000000000000000000000000000000000000000060208201526103aa565b5f83606001518460800151611752919061253b565b90505f8361176883670de0b6b3a764000061256d565b611772919061254e565b905061177d816111f0565b95945050505050565b6060825f036117c9575060408051808201909152600981527f477261647561746564000000000000000000000000000000000000000000000060208201526103aa565b8282101561180c576040518060400160405280600681526020017f416374697665000000000000000000000000000000000000000000000000000081525061159a565b6040518060400160405280600981526020017f47726164756174656400000000000000000000000000000000000000000000008152509392505050565b60606001600160a01b03821661189257505060408051808201909152600481527f4e6f6e6500000000000000000000000000000000000000000000000000000000602082015290565b816001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa9250505080156118ef57506040513d5f823e601f3d908101601f191682016040526118ec91908101906125ad565b60015b61192c57505060408051808201909152600781527f556e6b6e6f776e00000000000000000000000000000000000000000000000000602082015290565b5f8151116103aa576040518060400160405280600781526020017f556e6b6e6f776e0000000000000000000000000000000000000000000000000081525061159a565b5f6001600160a01b038316158015906114b75750826001600160a01b0316846001600160a01b031614806119c757506001600160a01b038085165f9081526005602090815260408083209387168352929052205460ff165b806114b75750505f908152600460205260409020546001600160a01b03908116911614919050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611a37577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310611a63576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611a8157662386f26fc10000830492506010015b6305f5e1008310611a99576305f5e100830492506008015b6127108310611aad57612710830492506004015b60648310611abf576064830492506002015b600a83106103aa5760010192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114611afd575f5ffd5b50565b5f60208284031215611b10575f5ffd5b813561159a81611ad0565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61159a6020830184611b1b565b5f60208284031215611b6b575f5ffd5b5035919050565b6001600160a01b0381168114611afd575f5ffd5b5f5f60408385031215611b97575f5ffd5b8235611ba281611b72565b946020939093013593505050565b5f5f5f60608486031215611bc2575f5ffd5b8335611bcd81611b72565b92506020840135611bdd81611b72565b929592945050506040919091013590565b5f5f60408385031215611bff575f5ffd5b823591506020830135611c1181611b72565b809150509250929050565b5f60208284031215611c2c575f5ffd5b813561159a81611b72565b5f5f60408385031215611c48575f5ffd5b8235611c5381611b72565b915060208301358015158114611c11575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b60405160c0810167ffffffffffffffff81118282101715611c9e57611c9e611c67565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611ccd57611ccd611c67565b604052919050565b5f67ffffffffffffffff821115611cee57611cee611c67565b50601f01601f191660200190565b5f5f5f5f60808587031215611d0f575f5ffd5b8435611d1a81611b72565b93506020850135611d2a81611b72565b925060408501359150606085013567ffffffffffffffff811115611d4c575f5ffd5b8501601f81018713611d5c575f5ffd5b8035611d6f611d6a82611cd5565b611ca4565b818152886020838501011115611d83575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215611db5575f5ffd5b8235611dc081611b72565b91506020830135611c1181611b72565b600181811c90821680611de457607f821691505b602082108103611e0257634e487b7160e01b5f52602260045260245ffd5b50919050565b5f81518060208401855e5f93019283525090919050565b5f611e3c611e36611e308488611e08565b86611e08565b84611e08565b7f5d7d000000000000000000000000000000000000000000000000000000000000815260020195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525f61159a601d830184611e08565b5f60208284031215611eac575f5ffd5b5051919050565b5f60208284031215611ec3575f5ffd5b815161159a81611b72565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f611f046080830184611b1b565b9695505050505050565b5f60208284031215611f1e575f5ffd5b815161159a81611ad0565b7f7b226e616d65223a225052494e54522044657620506f736974696f6e2023000081525f611f5a601e830186611e08565b7f222c226465736372697074696f6e223a22446576656c6f70657220726967687481527f7320666f72205052494e54522074656c65636f696e220000000000000000000060208201527f2c2265787465726e616c5f75726c223a2268747470733a2f2f7072696e74722e60368201527f6d6f6e65792f746f6b656e2f00000000000000000000000000000000000000006056820152611ffc6062820186611e08565b90507f222c22696d616765223a2268747470733a2f2f63646e2e7072696e74722e6d6f81527f6e65792f6e66742f00000000000000000000000000000000000000000000000060208201526120546028820185611e08565b7f2e737667222c2261747472696275746573223a5b00000000000000000000000081526014019695505050505050565b7f7b2274726169745f74797065223a22546f6b656e2041646472657373222c227681526630b63ab2911d1160c91b60208201525f6120c56027830187611e08565b7f227d2c7b2274726169745f74797065223a22546f6b656e204e616d65222c227681526630b63ab2911d1160c91b60208201526121056027820187611e08565b90507f227d2c7b2274726169745f74797065223a22546f6b656e2053796d626f6c222c81527f2276616c7565223a220000000000000000000000000000000000000000000000602082015261215d6029820186611e08565b90507f227d2c7b2274726169745f74797065223a22446563696d616c73222c2276616c81527f7565223a223138227d000000000000000000000000000000000000000000000060208201527f2c7b2274726169745f74797065223a2243726561746f72222c2276616c75652260298201527f3a220000000000000000000000000000000000000000000000000000000000006049820152612201604b820185611e08565b7f227d0000000000000000000000000000000000000000000000000000000000008152600201979650505050505050565b5f60c0828403128015612243575f5ffd5b5061224c611c7b565b825161225781611b72565b8152602083015161ffff8116811461226d575f5ffd5b602082015260408381015190820152606080840151908201526080808401519082015260a0928301519281019290925250919050565b7f2c7b2274726169745f74797065223a2243757272656e74205072696365222c2281527f76616c7565223a2200000000000000000000000000000000000000000000000060208201525f6122fa6028830189611e08565b7f222c22646973706c61795f74797065223a226e756d626572227d00000000000081527f2c7b2274726169745f74797065223a22436861696e20537570706c79222c2276601a8201526630b63ab2911d1160c91b603a8201526123606041820189611e08565b90507f222c22646973706c61795f74797065223a226e756d626572227d2c7b2274726181527f69745f74797065223a22476c6f62616c20537570706c79222c2276616c75652260208201527f3a2200000000000000000000000000000000000000000000000000000000000060408201526123de6042820188611e08565b7f222c22646973706c61795f74797065223a226e756d626572227d2c7b2274726181527f69745f74797065223a22537461747573222c2276616c7565223a22000000000060208201529050603b81016125196124f06124ea61249b612495612446868d611e08565b7f227d2c7b2274726169745f74797065223a224261736520506169722053796d6281527f6f6c222c2276616c7565223a22000000000000000000000000000000000000006020820152602d0190565b8a611e08565b7f227d2c7b2274726169745f74797065223a22426173652050616972204164647281527f657373222c2276616c7565223a220000000000000000000000000000000000006020820152602e0190565b87611e08565b7f227d000000000000000000000000000000000000000000000000000000000000815260020190565b9a9950505050505050505050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156103aa576103aa612527565b5f8261256857634e487b7160e01b5f52601260045260245ffd5b500490565b80820281158282048414176103aa576103aa612527565b634e487b7160e01b5f52603260045260245ffd5b5f816125a6576125a6612527565b505f190190565b5f602082840312156125bd575f5ffd5b815167ffffffffffffffff8111156125d3575f5ffd5b8201601f810184136125e3575f5ffd5b80516125f1611d6a82611cd5565b818152856020838501011115612605575f5ffd5b8160208401602083015e5f9181016020019190915294935050505056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122004d128e854659d626dbea689e34ff98df0928a760c5392e4e75baef777ed989d64736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172
-----Decoded View---------------
Arg [0] : _printr (address): 0xb77726291b125515D0A7AfFeeA2b04f2FF243172
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000b77726291b125515d0a7affeea2b04f2ff243172
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.