Source Code
Latest 25 from a total of 5,086 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Update Atomic Re... | 24147284 | 63 days ago | IN | 0 ETH | 0.00000409 | ||||
| Update Atomic Re... | 24133649 | 65 days ago | IN | 0 ETH | 0.00003213 | ||||
| Update Atomic Re... | 24122889 | 66 days ago | IN | 0 ETH | 0.00000185 | ||||
| Update Atomic Re... | 24099215 | 70 days ago | IN | 0 ETH | 0.00007083 | ||||
| Update Atomic Re... | 24096598 | 70 days ago | IN | 0 ETH | 0.00000254 | ||||
| Update Atomic Re... | 24096273 | 70 days ago | IN | 0 ETH | 0.00010662 | ||||
| Update Atomic Re... | 24092617 | 71 days ago | IN | 0 ETH | 0.00000148 | ||||
| Update Atomic Re... | 24050222 | 77 days ago | IN | 0 ETH | 0.00000142 | ||||
| Update Atomic Re... | 24040848 | 78 days ago | IN | 0 ETH | 0.00010547 | ||||
| Update Atomic Re... | 24036242 | 79 days ago | IN | 0 ETH | 0.00010553 | ||||
| Update Atomic Re... | 24033054 | 79 days ago | IN | 0 ETH | 0.00007572 | ||||
| Update Atomic Re... | 24033036 | 79 days ago | IN | 0 ETH | 0.00007763 | ||||
| Update Atomic Re... | 24026275 | 80 days ago | IN | 0 ETH | 0.00001255 | ||||
| Update Atomic Re... | 24011638 | 82 days ago | IN | 0 ETH | 0.00000265 | ||||
| Update Atomic Re... | 24008040 | 82 days ago | IN | 0 ETH | 0.00000154 | ||||
| Update Atomic Re... | 24003578 | 83 days ago | IN | 0 ETH | 0.00000128 | ||||
| Update Atomic Re... | 23970115 | 88 days ago | IN | 0 ETH | 0.00004241 | ||||
| Update Atomic Re... | 23970099 | 88 days ago | IN | 0 ETH | 0.00002449 | ||||
| Update Atomic Re... | 23943971 | 91 days ago | IN | 0 ETH | 0.00000154 | ||||
| Update Atomic Re... | 23943961 | 91 days ago | IN | 0 ETH | 0.00000159 | ||||
| Update Atomic Re... | 23937698 | 92 days ago | IN | 0 ETH | 0.00010549 | ||||
| Update Atomic Re... | 23937681 | 92 days ago | IN | 0 ETH | 0.00010558 | ||||
| Update Atomic Re... | 23934954 | 93 days ago | IN | 0 ETH | 0.00002779 | ||||
| Update Atomic Re... | 23932921 | 93 days ago | IN | 0 ETH | 0.00000196 | ||||
| Update Atomic Re... | 23929196 | 94 days ago | IN | 0 ETH | 0.00010564 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60806040 | 20982333 | 505 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AtomicQueue
Compiler Version
v0.8.25+commit.b61c2a91
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2024-10-17
*/
// SPDX-License-Identifier: Apache-2.0
pragma solidity =0.8.25 >=0.8.0;
// lib/solmate/src/tokens/ERC20.sol
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
// lib/solmate/src/utils/FixedPointMathLib.sol
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
// lib/solmate/src/utils/ReentrancyGuard.sol
/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
// lib/solmate/src/utils/SafeTransferLib.sol
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
// src/atomic-queue/IAtomicSolver.sol
interface IAtomicSolver {
/**
* @notice This function must be implemented in order for an address to be a `solver`
* for the AtomicQueue
* @param runData arbitrary bytes data that is dependent on how each solver is setup
* it could contain swap data, or flash loan data, etc..
* @param initiator the address that initiated a solve
* @param offer the ERC20 asset sent to the solver
* @param want the ERC20 asset the solver must approve the queue for
* @param assetsToOffer the amount of `offer` sent to the solver
* @param assetsForWant the amount of `want` the solver must approve the queue for
*/
function finishSolve(
bytes calldata runData,
address initiator,
ERC20 offer,
ERC20 want,
uint256 assetsToOffer,
uint256 assetsForWant
)
external;
}
// src/atomic-queue/AtomicQueue.sol
/**
* @title AtomicQueue
* @notice Allows users to create `AtomicRequests` that specify an ERC20 asset to `offer`
* and an ERC20 asset to `want` in return.
* @notice Making atomic requests where the exchange rate between offer and want is not
* relatively stable is effectively the same as placing a limit order between
* those assets, so requests can be filled at a rate worse than the current market rate.
* @notice It is possible for a user to make multiple requests that use the same offer asset.
* If this is done it is important that the user has approved the queue to spend the
* total amount of assets aggregated from all their requests, and to also have enough
* `offer` asset to cover the aggregate total request of `offerAmount`.
* @author crispymangoes
* @custom:security-contact [email protected]
*/
contract AtomicQueue is ReentrancyGuard {
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
// ========================================= STRUCTS =========================================
/**
* @notice Stores request information needed to fulfill a users atomic request.
* @param deadline unix timestamp for when request is no longer valid
* @param atomicPrice the price in terms of `want` asset the user wants their `offer` assets "sold" at
* @dev atomicPrice MUST be in terms of `want` asset decimals.
* @param offerAmount the amount of `offer` asset the user wants converted to `want` asset
* @param inSolve bool used during solves to prevent duplicate users, and to prevent redoing multiple checks
*/
struct AtomicRequest {
uint64 deadline; // deadline to fulfill request
uint88 atomicPrice; // In terms of want asset decimals
uint96 offerAmount; // The amount of offer asset the user wants to sell.
bool inSolve; // Indicates whether this user is currently having their request fulfilled.
}
/**
* @notice Used in `viewSolveMetaData` helper function to return data in a clean struct.
* @param user the address of the user
* @param flags 8 bits indicating the state of the user only the first 4 bits are used XXXX0000
* Either all flags are false(user is solvable) or only 1 is true(an error occurred).
* From right to left
* - 0: indicates user deadline has passed.
* - 1: indicates user request has zero offer amount.
* - 2: indicates user does not have enough offer asset in wallet.
* - 3: indicates user has not given AtomicQueue approval.
* @param assetsToOffer the amount of offer asset to solve
* @param assetsForWant the amount of assets users want for their offer assets
*/
struct SolveMetaData {
address user;
uint8 flags;
uint256 assetsToOffer;
uint256 assetsForWant;
}
// ========================================= GLOBAL STATE =========================================
/**
* @notice Maps user address to offer asset to want asset to a AtomicRequest struct.
*/
mapping(address => mapping(ERC20 => mapping(ERC20 => AtomicRequest))) public userAtomicRequest;
//============================== ERRORS ===============================
error AtomicQueue__UserRepeated(address user);
error AtomicQueue__RequestDeadlineExceeded(address user);
error AtomicQueue__UserNotInSolve(address user);
error AtomicQueue__ZeroOfferAmount(address user);
//============================== EVENTS ===============================
/**
* @notice Emitted when `updateAtomicRequest` is called.
*/
event AtomicRequestUpdated(
address user,
address offerToken,
address wantToken,
uint256 amount,
uint256 deadline,
uint256 minPrice,
uint256 timestamp
);
/**
* @notice Emitted when `solve` exchanges a users offer asset for their want asset.
*/
event AtomicRequestFulfilled(
address user,
address offerToken,
address wantToken,
uint256 offerAmountSpent,
uint256 wantAmountReceived,
uint256 timestamp
);
//============================== USER FUNCTIONS ===============================
/**
* @notice Get a users Atomic Request.
* @param user the address of the user to get the request for
* @param offer the ERC0 token they want to exchange for the want
* @param want the ERC20 token they want in exchange for the offer
*/
function getUserAtomicRequest(address user, ERC20 offer, ERC20 want) external view returns (AtomicRequest memory) {
return userAtomicRequest[user][offer][want];
}
/**
* @notice Helper function that returns either
* true: Withdraw request is valid.
* false: Withdraw request is not valid.
* @dev It is possible for a withdraw request to return false from this function, but using the
* request in `updateAtomicRequest` will succeed, but solvers will not be able to include
* the user in `solve` unless some other state is changed.
* @param offer the ERC0 token they want to exchange for the want
* @param user the address of the user making the request
* @param userRequest the request struct to validate
*/
function isAtomicRequestValid(
ERC20 offer,
address user,
AtomicRequest calldata userRequest
)
external
view
returns (bool)
{
// Validate amount.
if (userRequest.offerAmount > offer.balanceOf(user)) return false;
// Validate deadline.
if (block.timestamp > userRequest.deadline) return false;
// Validate approval.
if (offer.allowance(user, address(this)) < userRequest.offerAmount) return false;
// Validate offerAmount is nonzero.
if (userRequest.offerAmount == 0) return false;
// Validate atomicPrice is nonzero.
if (userRequest.atomicPrice == 0) return false;
return true;
}
/**
* @notice Allows user to add/update their withdraw request.
* @notice It is possible for a withdraw request with a zero atomicPrice to be made, and solved.
* If this happens, users will be selling their shares for no assets in return.
* To determine a safe atomicPrice, share.previewRedeem should be used to get
* a good share price, then the user can lower it from there to make their request fill faster.
* @param offer the ERC20 token the user is offering in exchange for the want
* @param want the ERC20 token the user wants in exchange for offer
* @param userRequest the users request
*/
function updateAtomicRequest(ERC20 offer, ERC20 want, AtomicRequest calldata userRequest) external nonReentrant {
AtomicRequest storage request = userAtomicRequest[msg.sender][offer][want];
request.deadline = userRequest.deadline;
request.atomicPrice = userRequest.atomicPrice;
request.offerAmount = userRequest.offerAmount;
// Emit full amount user has.
emit AtomicRequestUpdated(
msg.sender,
address(offer),
address(want),
userRequest.offerAmount,
userRequest.deadline,
userRequest.atomicPrice,
block.timestamp
);
}
//============================== SOLVER FUNCTIONS ===============================
/**
* @notice Called by solvers in order to exchange offer asset for want asset.
* @notice Solvers are optimistically transferred the offer asset, then are required to
* approve this contract to spend enough of want assets to cover all requests.
* @dev It is very likely `solve` TXs will be front run if broadcasted to public mem pools,
* so solvers should use private mem pools.
* @param offer the ERC20 offer token to solve for
* @param want the ERC20 want token to solve for
* @param users an array of user addresses to solve for
* @param runData extra data that is passed back to solver when `finishSolve` is called
* @param solver the address to make `finishSolve` callback to
*/
function solve(
ERC20 offer,
ERC20 want,
address[] calldata users,
bytes calldata runData,
address solver
)
external
nonReentrant
{
// Save offer asset decimals.
uint8 offerDecimals = offer.decimals();
uint256 assetsToOffer;
uint256 assetsForWant;
for (uint256 i; i < users.length; ++i) {
AtomicRequest storage request = userAtomicRequest[users[i]][offer][want];
if (request.inSolve) revert AtomicQueue__UserRepeated(users[i]);
if (block.timestamp > request.deadline) revert AtomicQueue__RequestDeadlineExceeded(users[i]);
if (request.offerAmount == 0) revert AtomicQueue__ZeroOfferAmount(users[i]);
// User gets whatever their atomic price * offerAmount is.
assetsForWant += _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);
// If all checks above passed, the users request is valid and should be fulfilled.
assetsToOffer += request.offerAmount;
request.inSolve = true;
// Transfer shares from user to solver.
offer.safeTransferFrom(users[i], solver, request.offerAmount);
}
IAtomicSolver(solver).finishSolve(runData, msg.sender, offer, want, assetsToOffer, assetsForWant);
for (uint256 i; i < users.length; ++i) {
AtomicRequest storage request = userAtomicRequest[users[i]][offer][want];
if (request.inSolve) {
// We know that the minimum price and deadline arguments are satisfied since this can only be true if
// they were.
// Send user their share of assets.
uint256 assetsToUser = _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);
want.safeTransferFrom(solver, users[i], assetsToUser);
emit AtomicRequestFulfilled(
users[i], address(offer), address(want), request.offerAmount, assetsToUser, block.timestamp
);
// Set shares to withdraw to 0.
request.offerAmount = 0;
request.inSolve = false;
} else {
revert AtomicQueue__UserNotInSolve(users[i]);
}
}
}
/**
* @notice Helper function solvers can use to determine if users are solvable, and the required amounts to do so.
* @notice Repeated users are not accounted for in this setup, so if solvers have repeat users in their `users`
* array the results can be wrong.
* @dev Since a user can have multiple requests with the same offer asset but different want asset, it is
* possible for `viewSolveMetaData` to report no errors, but for a solve to fail, if any solves were done
* between the time `viewSolveMetaData` and before `solve` is called.
* @param offer the ERC20 offer token to check for solvability
* @param want the ERC20 want token to check for solvability
* @param users an array of user addresses to check for solvability
*/
function viewSolveMetaData(
ERC20 offer,
ERC20 want,
address[] calldata users
)
external
view
returns (SolveMetaData[] memory metaData, uint256 totalAssetsForWant, uint256 totalAssetsToOffer)
{
// Save offer asset decimals.
uint8 offerDecimals = offer.decimals();
// Setup meta data.
metaData = new SolveMetaData[](users.length);
for (uint256 i; i < users.length; ++i) {
AtomicRequest memory request = userAtomicRequest[users[i]][offer][want];
metaData[i].user = users[i];
if (block.timestamp > request.deadline) {
metaData[i].flags |= uint8(1);
}
if (request.offerAmount == 0) {
metaData[i].flags |= uint8(1) << 1;
}
if (offer.balanceOf(users[i]) < request.offerAmount) {
metaData[i].flags |= uint8(1) << 2;
}
if (offer.allowance(users[i], address(this)) < request.offerAmount) {
metaData[i].flags |= uint8(1) << 3;
}
metaData[i].assetsToOffer = request.offerAmount;
// User gets whatever their execution share price is.
uint256 userAssets = _calculateAssetAmount(request.offerAmount, request.atomicPrice, offerDecimals);
metaData[i].assetsForWant = userAssets;
// If flags is zero, no errors occurred.
if (metaData[i].flags == 0) {
totalAssetsForWant += userAssets;
totalAssetsToOffer += request.offerAmount;
}
}
}
//============================== INTERNAL FUNCTIONS ===============================
/**
* @notice Helper function to calculate the amount of want assets a users wants in exchange for
* `offerAmount` of offer asset.
*/
function _calculateAssetAmount(
uint256 offerAmount,
uint256 atomicPrice,
uint8 offerDecimals
)
internal
pure
returns (uint256)
{
return atomicPrice.mulDivDown(offerAmount, 10 ** offerDecimals);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"AtomicQueue__RequestDeadlineExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"AtomicQueue__UserNotInSolve","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"AtomicQueue__UserRepeated","type":"error"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"AtomicQueue__ZeroOfferAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"offerToken","type":"address"},{"indexed":false,"internalType":"address","name":"wantToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"offerAmountSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wantAmountReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AtomicRequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"offerToken","type":"address"},{"indexed":false,"internalType":"address","name":"wantToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AtomicRequestUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract ERC20","name":"offer","type":"address"},{"internalType":"contract ERC20","name":"want","type":"address"}],"name":"getUserAtomicRequest","outputs":[{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"uint88","name":"atomicPrice","type":"uint88"},{"internalType":"uint96","name":"offerAmount","type":"uint96"},{"internalType":"bool","name":"inSolve","type":"bool"}],"internalType":"struct AtomicQueue.AtomicRequest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"offer","type":"address"},{"internalType":"address","name":"user","type":"address"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"uint88","name":"atomicPrice","type":"uint88"},{"internalType":"uint96","name":"offerAmount","type":"uint96"},{"internalType":"bool","name":"inSolve","type":"bool"}],"internalType":"struct AtomicQueue.AtomicRequest","name":"userRequest","type":"tuple"}],"name":"isAtomicRequestValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"offer","type":"address"},{"internalType":"contract ERC20","name":"want","type":"address"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"bytes","name":"runData","type":"bytes"},{"internalType":"address","name":"solver","type":"address"}],"name":"solve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"offer","type":"address"},{"internalType":"contract ERC20","name":"want","type":"address"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"uint88","name":"atomicPrice","type":"uint88"},{"internalType":"uint96","name":"offerAmount","type":"uint96"},{"internalType":"bool","name":"inSolve","type":"bool"}],"internalType":"struct AtomicQueue.AtomicRequest","name":"userRequest","type":"tuple"}],"name":"updateAtomicRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract ERC20","name":"","type":"address"},{"internalType":"contract ERC20","name":"","type":"address"}],"name":"userAtomicRequest","outputs":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"uint88","name":"atomicPrice","type":"uint88"},{"internalType":"uint96","name":"offerAmount","type":"uint96"},{"internalType":"bool","name":"inSolve","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"offer","type":"address"},{"internalType":"contract ERC20","name":"want","type":"address"},{"internalType":"address[]","name":"users","type":"address[]"}],"name":"viewSolveMetaData","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"flags","type":"uint8"},{"internalType":"uint256","name":"assetsToOffer","type":"uint256"},{"internalType":"uint256","name":"assetsForWant","type":"uint256"}],"internalType":"struct AtomicQueue.SolveMetaData[]","name":"metaData","type":"tuple[]"},{"internalType":"uint256","name":"totalAssetsForWant","type":"uint256"},{"internalType":"uint256","name":"totalAssetsToOffer","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405260015f553480156012575f80fd5b50611713806100205f395ff3fe608060405234801561000f575f80fd5b5060043610610060575f3560e01c80632788dd94146100645780632ae2f0711461008c578063433a8534146100ae5780637abf631d146101b35780637c88eaa11461025c578063d93fc20314610271575b5f80fd5b610077610072366004611206565b610284565b60405190151581526020015b60405180910390f35b61009f61009a366004611292565b610428565b604051610083939291906112f2565b6101636100bc36600461136b565b60408051608080820183525f808352602080840182905283850182905260609384018290526001600160a01b0397881682526001815284822096881682529586528381209490961686529284529381902081519283018252546001600160401b0381168352600160401b81046001600160581b031693830193909352600160981b83046001600160601b031690820152600160f81b90910460ff1615159181019190915290565b604051610083919081516001600160401b031681526020808301516001600160581b0316908201526040808301516001600160601b03169082015260609182015115159181019190915260800190565b61021a6101c136600461136b565b600160209081525f93845260408085208252928452828420905282529020546001600160401b03811690600160401b81046001600160581b031690600160981b81046001600160601b031690600160f81b900460ff1684565b604080516001600160401b0390951685526001600160581b0390931660208501526001600160601b039091169183019190915215156060820152608001610083565b61026f61026a366004611206565b610935565b005b61026f61027f3660046113b3565b610b09565b6040516370a0823160e01b81526001600160a01b0383811660048301525f91908516906370a0823190602401602060405180830381865afa1580156102cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef919061147b565b6102ff6060840160408501611492565b6001600160601b0316111561031557505f610421565b61032260208301836114b8565b6001600160401b031642111561033957505f610421565b6103496060830160408401611492565b604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301526001600160601b03929092169186169063dd62ed3e90604401602060405180830381865afa1580156103a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103c4919061147b565b10156103d157505f610421565b6103e16060830160408401611492565b6001600160601b03165f036103f757505f610421565b61040760408301602084016114de565b6001600160581b03165f0361041d57505f610421565b5060015b9392505050565b60605f805f876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610469573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061048d9190611504565b9050846001600160401b038111156104a7576104a7611524565b6040519080825280602002602001820160405280156104f757816020015b604080516080810182525f8082526020808301829052928201819052606082015282525f199092019101816104c55790505b5093505f5b85811015610929575f60015f89898581811061051a5761051a611538565b905060200201602081019061052f919061154c565b6001600160a01b03908116825260208083019390935260409182015f9081208e831682528452828120918d168152908352819020815160808101835290546001600160401b0381168252600160401b81046001600160581b031693820193909352600160981b83046001600160601b031691810191909152600160f81b90910460ff161515606082015290508787838181106105cd576105cd611538565b90506020020160208101906105e2919061154c565b8683815181106105f4576105f4611538565b60209081029190910101516001600160a01b03909116905280516001600160401b031642111561064b57600186838151811061063257610632611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03165f0361068f57855160029087908490811061067657610676611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03168a6001600160a01b03166370a082318a8a868181106106be576106be611538565b90506020020160208101906106d3919061154c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610715573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610739919061147b565b101561076f57855160049087908490811061075657610756611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03168a6001600160a01b031663dd62ed3e8a8a8681811061079e5761079e611538565b90506020020160208101906107b3919061154c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156107fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081f919061147b565b101561085557855160089087908490811061083c5761083c611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b031686838151811061087557610875611538565b602002602001015160400181815250505f6108ab82604001516001600160601b031683602001516001600160581b0316866110f6565b9050808784815181106108c0576108c0611538565b602002602001015160600181815250508683815181106108e2576108e2611538565b60200260200101516020015160ff165f0361091f57610901818761157b565b955081604001516001600160601b03168561091c919061157b565b94505b50506001016104fc565b50509450945094915050565b5f546001146109785760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b60025f9081553381526001602090815260408083206001600160a01b03878116855290835281842090861684528252909120906109b7908301836114b8565b815467ffffffffffffffff19166001600160401b03919091161781556109e360408301602084016114de565b81546001600160581b0391909116600160401b0272ffffffffffffffffffffff000000000000000019909116178155610a226060830160408401611492565b81546001600160601b0391909116600160981b026bffffffffffffffffffffffff60981b199091161781557f9537495a2390e1a29f5f7e71b8540f5140bba27065f173615b770ad79d2f7960338585610a816060870160408801611492565b610a8e60208801886114b8565b610a9e6040890160208a016114de565b604080516001600160a01b039788168152958716602087015293909516928401929092526001600160601b031660608301526001600160401b031660808201526001600160581b0390911660a08201524260c082015260e00160405180910390a1505060015f555050565b5f54600114610b475760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161096f565b60025f819055505f876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b8b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610baf9190611504565b90505f805f5b87811015610e35575f60015f8b8b85818110610bd357610bd3611538565b9050602002016020810190610be8919061154c565b6001600160a01b03166001600160a01b031681526020019081526020015f205f8d6001600160a01b03166001600160a01b031681526020019081526020015f205f8c6001600160a01b03166001600160a01b031681526020019081526020015f209050805f01601f9054906101000a900460ff1615610cb057898983818110610c7357610c73611538565b9050602002016020810190610c88919061154c565b6040516001627c10bd60e11b031981526001600160a01b03909116600482015260240161096f565b80546001600160401b0316421115610d0e57898983818110610cd457610cd4611538565b9050602002016020810190610ce9919061154c565b6040516342a646e960e01b81526001600160a01b03909116600482015260240161096f565b8054600160981b90046001600160601b03165f03610d7257898983818110610d3857610d38611538565b9050602002016020810190610d4d919061154c565b60405163aeb7e20360e01b81526001600160a01b03909116600482015260240161096f565b8054610d9f90600160981b81046001600160601b031690600160401b90046001600160581b0316876110f6565b610da9908461157b565b8154909350610dc890600160981b90046001600160601b03168561157b565b81546001600160f81b0316600160f81b1782559350610e2c8a8a84818110610df257610df2611538565b9050602002016020810190610e07919061154c565b82546001600160a01b038f1691908990600160981b90046001600160601b0316611116565b50600101610bb5565b50836001600160a01b0316632ddd62ce8787338e8e88886040518863ffffffff1660e01b8152600401610e6e9796959493929190611594565b5f604051808303815f87803b158015610e85575f80fd5b505af1158015610e97573d5f803e3d5ffd5b505050505f5b878110156110e5575f60015f8b8b85818110610ebb57610ebb611538565b9050602002016020810190610ed0919061154c565b6001600160a01b03166001600160a01b031681526020019081526020015f205f8d6001600160a01b03166001600160a01b031681526020019081526020015f205f8c6001600160a01b03166001600160a01b031681526020019081526020015f209050805f01601f9054906101000a900460ff16156110905780545f90610f7890600160981b81046001600160601b031690600160401b90046001600160581b0316886110f6565b9050610fb7878c8c86818110610f9057610f90611538565b9050602002016020810190610fa5919061154c565b6001600160a01b038f16919084611116565b7fa4e3f90ef19273220b37cbbbcfe402a6eadd9559c54813b9be52ea0c9612d6c98b8b85818110610fea57610fea611538565b9050602002016020810190610fff919061154c565b8e8e855f0160139054906101000a90046001600160601b03168542604051611069969594939291906001600160a01b03968716815294861660208601529290941660408401526001600160601b03166060830152608082019290925260a081019190915260c00190565b60405180910390a150805472ffffffffffffffffffffffffffffffffffffff1681556110dc565b8989838181106110a2576110a2611538565b90506020020160208101906110b7919061154c565b60405163d698186360e01b81526001600160a01b03909116600482015260240161096f565b50600101610e9d565b505060015f55505050505050505050565b5f61110e8461110684600a6116cf565b8591906111ae565b949350505050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806111a75760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161096f565b5050505050565b5f825f1904841183021582026111c2575f80fd5b5091020490565b6001600160a01b03811681146111dd575f80fd5b50565b80356111eb816111c9565b919050565b5f60808284031215611200575f80fd5b50919050565b5f805f60c08486031215611218575f80fd5b8335611223816111c9565b92506020840135611233816111c9565b915061124285604086016111f0565b90509250925092565b5f8083601f84011261125b575f80fd5b5081356001600160401b03811115611271575f80fd5b6020830191508360208260051b850101111561128b575f80fd5b9250929050565b5f805f80606085870312156112a5575f80fd5b84356112b0816111c9565b935060208501356112c0816111c9565b925060408501356001600160401b038111156112da575f80fd5b6112e68782880161124b565b95989497509550505050565b606080825284518282018190525f9190608090818501906020808a01865b8381101561135357815180516001600160a01b031686528381015160ff168487015260408082015190870152870151878601529385019390820190600101611310565b50505050602085019690965250505060400152919050565b5f805f6060848603121561137d575f80fd5b8335611388816111c9565b92506020840135611398816111c9565b915060408401356113a8816111c9565b809150509250925092565b5f805f805f805f60a0888a0312156113c9575f80fd5b87356113d4816111c9565b965060208801356113e4816111c9565b955060408801356001600160401b03808211156113ff575f80fd5b61140b8b838c0161124b565b909750955060608a0135915080821115611423575f80fd5b818a0191508a601f830112611436575f80fd5b813581811115611444575f80fd5b8b6020828501011115611455575f80fd5b60208301955080945050505061146d608089016111e0565b905092959891949750929550565b5f6020828403121561148b575f80fd5b5051919050565b5f602082840312156114a2575f80fd5b81356001600160601b0381168114610421575f80fd5b5f602082840312156114c8575f80fd5b81356001600160401b0381168114610421575f80fd5b5f602082840312156114ee575f80fd5b81356001600160581b0381168114610421575f80fd5b5f60208284031215611514575f80fd5b815160ff81168114610421575f80fd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f6020828403121561155c575f80fd5b8135610421816111c9565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561158e5761158e611567565b92915050565b60c081528660c0820152868860e08301375f60e08883018101919091526001600160a01b0396871660208301529486166040820152929094166060830152608082015260a0810192909252601f909201601f19160101919050565b600181815b8085111561162957815f190482111561160f5761160f611567565b8085161561161c57918102915b93841c93908002906115f4565b509250929050565b5f8261163f5750600161158e565b8161164b57505f61158e565b8160018114611661576002811461166b57611687565b600191505061158e565b60ff84111561167c5761167c611567565b50506001821b61158e565b5060208310610133831016604e8410600b84101617156116aa575081810a61158e565b6116b483836115ef565b805f19048211156116c7576116c7611567565b029392505050565b5f61042160ff84168361163156fea2646970667358221220c9735f413ec4cec7a1d5356319a1dbd883e2699ed9d2a0a4adbbc7c00cc33c6a64736f6c63430008190033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610060575f3560e01c80632788dd94146100645780632ae2f0711461008c578063433a8534146100ae5780637abf631d146101b35780637c88eaa11461025c578063d93fc20314610271575b5f80fd5b610077610072366004611206565b610284565b60405190151581526020015b60405180910390f35b61009f61009a366004611292565b610428565b604051610083939291906112f2565b6101636100bc36600461136b565b60408051608080820183525f808352602080840182905283850182905260609384018290526001600160a01b0397881682526001815284822096881682529586528381209490961686529284529381902081519283018252546001600160401b0381168352600160401b81046001600160581b031693830193909352600160981b83046001600160601b031690820152600160f81b90910460ff1615159181019190915290565b604051610083919081516001600160401b031681526020808301516001600160581b0316908201526040808301516001600160601b03169082015260609182015115159181019190915260800190565b61021a6101c136600461136b565b600160209081525f93845260408085208252928452828420905282529020546001600160401b03811690600160401b81046001600160581b031690600160981b81046001600160601b031690600160f81b900460ff1684565b604080516001600160401b0390951685526001600160581b0390931660208501526001600160601b039091169183019190915215156060820152608001610083565b61026f61026a366004611206565b610935565b005b61026f61027f3660046113b3565b610b09565b6040516370a0823160e01b81526001600160a01b0383811660048301525f91908516906370a0823190602401602060405180830381865afa1580156102cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102ef919061147b565b6102ff6060840160408501611492565b6001600160601b0316111561031557505f610421565b61032260208301836114b8565b6001600160401b031642111561033957505f610421565b6103496060830160408401611492565b604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301526001600160601b03929092169186169063dd62ed3e90604401602060405180830381865afa1580156103a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103c4919061147b565b10156103d157505f610421565b6103e16060830160408401611492565b6001600160601b03165f036103f757505f610421565b61040760408301602084016114de565b6001600160581b03165f0361041d57505f610421565b5060015b9392505050565b60605f805f876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610469573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061048d9190611504565b9050846001600160401b038111156104a7576104a7611524565b6040519080825280602002602001820160405280156104f757816020015b604080516080810182525f8082526020808301829052928201819052606082015282525f199092019101816104c55790505b5093505f5b85811015610929575f60015f89898581811061051a5761051a611538565b905060200201602081019061052f919061154c565b6001600160a01b03908116825260208083019390935260409182015f9081208e831682528452828120918d168152908352819020815160808101835290546001600160401b0381168252600160401b81046001600160581b031693820193909352600160981b83046001600160601b031691810191909152600160f81b90910460ff161515606082015290508787838181106105cd576105cd611538565b90506020020160208101906105e2919061154c565b8683815181106105f4576105f4611538565b60209081029190910101516001600160a01b03909116905280516001600160401b031642111561064b57600186838151811061063257610632611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03165f0361068f57855160029087908490811061067657610676611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03168a6001600160a01b03166370a082318a8a868181106106be576106be611538565b90506020020160208101906106d3919061154c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610715573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610739919061147b565b101561076f57855160049087908490811061075657610756611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b03168a6001600160a01b031663dd62ed3e8a8a8681811061079e5761079e611538565b90506020020160208101906107b3919061154c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604401602060405180830381865afa1580156107fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081f919061147b565b101561085557855160089087908490811061083c5761083c611538565b6020908102919091018101510180519190911760ff1690525b80604001516001600160601b031686838151811061087557610875611538565b602002602001015160400181815250505f6108ab82604001516001600160601b031683602001516001600160581b0316866110f6565b9050808784815181106108c0576108c0611538565b602002602001015160600181815250508683815181106108e2576108e2611538565b60200260200101516020015160ff165f0361091f57610901818761157b565b955081604001516001600160601b03168561091c919061157b565b94505b50506001016104fc565b50509450945094915050565b5f546001146109785760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b60448201526064015b60405180910390fd5b60025f9081553381526001602090815260408083206001600160a01b03878116855290835281842090861684528252909120906109b7908301836114b8565b815467ffffffffffffffff19166001600160401b03919091161781556109e360408301602084016114de565b81546001600160581b0391909116600160401b0272ffffffffffffffffffffff000000000000000019909116178155610a226060830160408401611492565b81546001600160601b0391909116600160981b026bffffffffffffffffffffffff60981b199091161781557f9537495a2390e1a29f5f7e71b8540f5140bba27065f173615b770ad79d2f7960338585610a816060870160408801611492565b610a8e60208801886114b8565b610a9e6040890160208a016114de565b604080516001600160a01b039788168152958716602087015293909516928401929092526001600160601b031660608301526001600160401b031660808201526001600160581b0390911660a08201524260c082015260e00160405180910390a1505060015f555050565b5f54600114610b475760405162461bcd60e51b815260206004820152600a6024820152695245454e5452414e435960b01b604482015260640161096f565b60025f819055505f876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b8b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610baf9190611504565b90505f805f5b87811015610e35575f60015f8b8b85818110610bd357610bd3611538565b9050602002016020810190610be8919061154c565b6001600160a01b03166001600160a01b031681526020019081526020015f205f8d6001600160a01b03166001600160a01b031681526020019081526020015f205f8c6001600160a01b03166001600160a01b031681526020019081526020015f209050805f01601f9054906101000a900460ff1615610cb057898983818110610c7357610c73611538565b9050602002016020810190610c88919061154c565b6040516001627c10bd60e11b031981526001600160a01b03909116600482015260240161096f565b80546001600160401b0316421115610d0e57898983818110610cd457610cd4611538565b9050602002016020810190610ce9919061154c565b6040516342a646e960e01b81526001600160a01b03909116600482015260240161096f565b8054600160981b90046001600160601b03165f03610d7257898983818110610d3857610d38611538565b9050602002016020810190610d4d919061154c565b60405163aeb7e20360e01b81526001600160a01b03909116600482015260240161096f565b8054610d9f90600160981b81046001600160601b031690600160401b90046001600160581b0316876110f6565b610da9908461157b565b8154909350610dc890600160981b90046001600160601b03168561157b565b81546001600160f81b0316600160f81b1782559350610e2c8a8a84818110610df257610df2611538565b9050602002016020810190610e07919061154c565b82546001600160a01b038f1691908990600160981b90046001600160601b0316611116565b50600101610bb5565b50836001600160a01b0316632ddd62ce8787338e8e88886040518863ffffffff1660e01b8152600401610e6e9796959493929190611594565b5f604051808303815f87803b158015610e85575f80fd5b505af1158015610e97573d5f803e3d5ffd5b505050505f5b878110156110e5575f60015f8b8b85818110610ebb57610ebb611538565b9050602002016020810190610ed0919061154c565b6001600160a01b03166001600160a01b031681526020019081526020015f205f8d6001600160a01b03166001600160a01b031681526020019081526020015f205f8c6001600160a01b03166001600160a01b031681526020019081526020015f209050805f01601f9054906101000a900460ff16156110905780545f90610f7890600160981b81046001600160601b031690600160401b90046001600160581b0316886110f6565b9050610fb7878c8c86818110610f9057610f90611538565b9050602002016020810190610fa5919061154c565b6001600160a01b038f16919084611116565b7fa4e3f90ef19273220b37cbbbcfe402a6eadd9559c54813b9be52ea0c9612d6c98b8b85818110610fea57610fea611538565b9050602002016020810190610fff919061154c565b8e8e855f0160139054906101000a90046001600160601b03168542604051611069969594939291906001600160a01b03968716815294861660208601529290941660408401526001600160601b03166060830152608082019290925260a081019190915260c00190565b60405180910390a150805472ffffffffffffffffffffffffffffffffffffff1681556110dc565b8989838181106110a2576110a2611538565b90506020020160208101906110b7919061154c565b60405163d698186360e01b81526001600160a01b03909116600482015260240161096f565b50600101610e9d565b505060015f55505050505050505050565b5f61110e8461110684600a6116cf565b8591906111ae565b949350505050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806111a75760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161096f565b5050505050565b5f825f1904841183021582026111c2575f80fd5b5091020490565b6001600160a01b03811681146111dd575f80fd5b50565b80356111eb816111c9565b919050565b5f60808284031215611200575f80fd5b50919050565b5f805f60c08486031215611218575f80fd5b8335611223816111c9565b92506020840135611233816111c9565b915061124285604086016111f0565b90509250925092565b5f8083601f84011261125b575f80fd5b5081356001600160401b03811115611271575f80fd5b6020830191508360208260051b850101111561128b575f80fd5b9250929050565b5f805f80606085870312156112a5575f80fd5b84356112b0816111c9565b935060208501356112c0816111c9565b925060408501356001600160401b038111156112da575f80fd5b6112e68782880161124b565b95989497509550505050565b606080825284518282018190525f9190608090818501906020808a01865b8381101561135357815180516001600160a01b031686528381015160ff168487015260408082015190870152870151878601529385019390820190600101611310565b50505050602085019690965250505060400152919050565b5f805f6060848603121561137d575f80fd5b8335611388816111c9565b92506020840135611398816111c9565b915060408401356113a8816111c9565b809150509250925092565b5f805f805f805f60a0888a0312156113c9575f80fd5b87356113d4816111c9565b965060208801356113e4816111c9565b955060408801356001600160401b03808211156113ff575f80fd5b61140b8b838c0161124b565b909750955060608a0135915080821115611423575f80fd5b818a0191508a601f830112611436575f80fd5b813581811115611444575f80fd5b8b6020828501011115611455575f80fd5b60208301955080945050505061146d608089016111e0565b905092959891949750929550565b5f6020828403121561148b575f80fd5b5051919050565b5f602082840312156114a2575f80fd5b81356001600160601b0381168114610421575f80fd5b5f602082840312156114c8575f80fd5b81356001600160401b0381168114610421575f80fd5b5f602082840312156114ee575f80fd5b81356001600160581b0381168114610421575f80fd5b5f60208284031215611514575f80fd5b815160ff81168114610421575f80fd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f6020828403121561155c575f80fd5b8135610421816111c9565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561158e5761158e611567565b92915050565b60c081528660c0820152868860e08301375f60e08883018101919091526001600160a01b0396871660208301529486166040820152929094166060830152608082015260a0810192909252601f909201601f19160101919050565b600181815b8085111561162957815f190482111561160f5761160f611567565b8085161561161c57918102915b93841c93908002906115f4565b509250929050565b5f8261163f5750600161158e565b8161164b57505f61158e565b8160018114611661576002811461166b57611687565b600191505061158e565b60ff84111561167c5761167c611567565b50506001821b61158e565b5060208310610133831016604e8410600b84101617156116aa575081810a61158e565b6116b483836115ef565b805f19048211156116c7576116c7611567565b029392505050565b5f61042160ff84168361163156fea2646970667358221220c9735f413ec4cec7a1d5356319a1dbd883e2699ed9d2a0a4adbbc7c00cc33c6a64736f6c63430008190033
Deployed Bytecode Sourcemap
26232:13072:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30877:749;;;;;;:::i;:::-;;:::i;:::-;;;1193:14:1;;1186:22;1168:41;;1156:2;1141:18;30877:749:0;;;;;;;;37087:1676;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;30058:176::-;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30190:23:0;;;;;:17;:23;;;;;:30;;;;;;;;;;;:36;;;;;;;;;;;;;30183:43;;;;;;;;-1:-1:-1;;;;;30183:43:0;;;;-1:-1:-1;;;30183:43:0;;-1:-1:-1;;;;;30183:43:0;;;;;;;;-1:-1:-1;;;30183:43:0;;-1:-1:-1;;;;;30183:43:0;;;;;-1:-1:-1;;;30183:43:0;;;;;;;;;;;;;;;30058:176;;;;;;;4306:13:1;;-1:-1:-1;;;;;4302:38:1;4284:57;;4401:4;4389:17;;;4383:24;-1:-1:-1;;;;;4379:55:1;4357:20;;;4350:85;4495:4;4483:17;;;4477:24;-1:-1:-1;;;;;4473:57:1;4451:20;;;4444:87;4601:4;4589:17;;;4583:24;4576:32;4569:40;4547:20;;;4540:70;;;;4271:3;4256:19;;4077:539;28572:94:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28572:94:0;;;-1:-1:-1;;;28572:94:0;;-1:-1:-1;;;;;28572:94:0;;-1:-1:-1;;;28572:94:0;;-1:-1:-1;;;;;28572:94:0;;-1:-1:-1;;;28572:94:0;;;;;;;;;;-1:-1:-1;;;;;4858:31:1;;;4840:50;;-1:-1:-1;;;;;4926:37:1;;;4921:2;4906:18;;4899:65;-1:-1:-1;;;;;5000:39:1;;;4980:18;;;4973:67;;;;5083:14;5076:22;5071:2;5056:18;;5049:50;4827:3;4812:19;28572:94:0;4621:484:1;32314:680:0;;;;;;:::i;:::-;;:::i;:::-;;33860:2403;;;;;;:::i;:::-;;:::i;30877:749::-;31135:21;;-1:-1:-1;;;31135:21:0;;-1:-1:-1;;;;;7148:32:1;;;31135:21:0;;;7130:51:1;31054:4:0;;31135:15;;;;;;7103:18:1;;31135:21:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;31109:23;;;;;;;;:::i;:::-;-1:-1:-1;;;;;31109:47:0;;31105:65;;;-1:-1:-1;31165:5:0;31158:12;;31105:65;31234:20;;;;:11;:20;:::i;:::-;-1:-1:-1;;;;;31216:38:0;:15;:38;31212:56;;;-1:-1:-1;31263:5:0;31256:12;;31212:56;31353:23;;;;;;;;:::i;:::-;31314:36;;-1:-1:-1;;;31314:36:0;;-1:-1:-1;;;;;8197:15:1;;;31314:36:0;;;8179:34:1;31344:4:0;8229:18:1;;;8222:43;-1:-1:-1;;;;;31314:62:0;;;;;:15;;;;;8114:18:1;;31314:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:62;31310:80;;;-1:-1:-1;31385:5:0;31378:12;;31310:80;31450:23;;;;;;;;:::i;:::-;-1:-1:-1;;;;;31450:28:0;31477:1;31450:28;31446:46;;-1:-1:-1;31487:5:0;31480:12;;31446:46;31552:23;;;;;;;;:::i;:::-;-1:-1:-1;;;;;31552:28:0;31579:1;31552:28;31548:46;;-1:-1:-1;31589:5:0;31582:12;;31548:46;-1:-1:-1;31614:4:0;30877:749;;;;;;:::o;37087:1676::-;37249:31;37282:26;37310;37393:19;37415:5;-1:-1:-1;;;;;37415:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;37393:38;-1:-1:-1;37504:5:0;-1:-1:-1;;;;;37484:33:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37484:33:0;;-1:-1:-1;;37484:33:0;;;;;;;;;;;;37473:44;;37535:9;37530:1226;37546:16;;;37530:1226;;;37584:28;37615:17;:27;37633:5;;37639:1;37633:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;37615:27:0;;;;;;;;;;;;;;;;;-1:-1:-1;37615:27:0;;;:34;;;;;;;;;;:40;;;;;;;;;;;37584:71;;;;;;;;;-1:-1:-1;;;;;37584:71:0;;;;-1:-1:-1;;;37584:71:0;;-1:-1:-1;;;;;37584:71:0;;;;;;;;-1:-1:-1;;;37584:71:0;;-1:-1:-1;;;;;37584:71:0;;;;;;;;-1:-1:-1;;;37584:71:0;;;;;;;;;;;;-1:-1:-1;37691:5:0;;37697:1;37691:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;37672;37681:1;37672:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;37672:27:0;;;;;37738:16;;-1:-1:-1;;;;;37720:34:0;:15;:34;37716:104;;;37802:1;37775:8;37784:1;37775:11;;;;;;;;:::i;:::-;;;;;;;;;;;;:17;:29;;;;;;;;;;37716:104;37838:7;:19;;;-1:-1:-1;;;;;37838:24:0;37861:1;37838:24;37834:99;;37883:11;;37904:13;;37883:8;;37892:1;;37883:11;;;;;;:::i;:::-;;;;;;;;;;;;:17;:34;;;;;;;;;;37834:99;37979:7;:19;;;-1:-1:-1;;;;;37951:47:0;:5;-1:-1:-1;;;;;37951:15:0;;37967:5;;37973:1;37967:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;37951:25;;-1:-1:-1;;;;;;37951:25:0;;;;;;;-1:-1:-1;;;;;7148:32:1;;;37951:25:0;;;7130:51:1;7103:18;;37951:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;37947:122;;;38019:11;;38040:13;;38019:8;;38028:1;;38019:11;;;;;;:::i;:::-;;;;;;;;;;;;:17;:34;;;;;;;;;;37947:122;38130:7;:19;;;-1:-1:-1;;;;;38087:62:0;:5;-1:-1:-1;;;;;38087:15:0;;38103:5;;38109:1;38103:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;38087:40;;-1:-1:-1;;;;;;38087:40:0;;;;;;;-1:-1:-1;;;;;8197:15:1;;;38087:40:0;;;8179:34:1;38121:4:0;8229:18:1;;;8222:43;8114:18;;38087:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:62;38083:137;;;38170:11;;38191:13;;38170:8;;38179:1;;38170:11;;;;;;:::i;:::-;;;;;;;;;;;;:17;:34;;;;;;;;;;38083:137;38264:7;:19;;;-1:-1:-1;;;;;38236:47:0;:8;38245:1;38236:11;;;;;;;;:::i;:::-;;;;;;;:25;;:47;;;;;38367:18;38388:78;38410:7;:19;;;-1:-1:-1;;;;;38388:78:0;38431:7;:19;;;-1:-1:-1;;;;;38388:78:0;38452:13;38388:21;:78::i;:::-;38367:99;;38509:10;38481:8;38490:1;38481:11;;;;;;;;:::i;:::-;;;;;;;:25;;:38;;;;;38594:8;38603:1;38594:11;;;;;;;;:::i;:::-;;;;;;;:17;;;:22;;38615:1;38594:22;38590:155;;38637:32;38659:10;38637:32;;:::i;:::-;;;38710:7;:19;;;-1:-1:-1;;;;;38688:41:0;;;;;;:::i;:::-;;;38590:155;-1:-1:-1;;37564:3:0;;37530:1226;;;;37343:1420;37087:1676;;;;;;;;:::o;32314:680::-;17853:6;;17863:1;17853:11;17845:34;;;;-1:-1:-1;;;17845:34:0;;9836:2:1;17845:34:0;;;9818:21:1;9875:2;9855:18;;;9848:30;-1:-1:-1;;;9894:18:1;;;9887:40;9944:18;;17845:34:0;;;;;;;;;17901:1;17892:6;:10;;;32487::::1;32469:29:::0;;:17:::1;:29;::::0;;;;;;;-1:-1:-1;;;;;32469:36:0;;::::1;::::0;;;;;;;;:42;;::::1;::::0;;;;;;;;32543:20:::1;::::0;;::::1;:11:::0;:20:::1;:::i;:::-;32524:39:::0;;-1:-1:-1;;32524:39:0::1;-1:-1:-1::0;;;;;32524:39:0;;;::::1;;::::0;;32596:23:::1;::::0;;;::::1;::::0;::::1;;:::i;:::-;32574:45:::0;;-1:-1:-1;;;;;32574:45:0;;;::::1;-1:-1:-1::0;;;32574:45:0::1;-1:-1:-1::0;;32574:45:0;;::::1;;::::0;;32652:23:::1;::::0;;;::::1;::::0;::::1;;:::i;:::-;32630:45:::0;;-1:-1:-1;;;;;32630:45:0;;;::::1;-1:-1:-1::0;;;32630:45:0::1;-1:-1:-1::0;;;;32630:45:0;;::::1;;::::0;;32732:254:::1;32767:10;32800:5:::0;32829:4;32849:23:::1;::::0;;;::::1;::::0;::::1;;:::i;:::-;32887:20;;::::0;::::1;:11:::0;:20:::1;:::i;:::-;32922:23;::::0;;;::::1;::::0;::::1;;:::i;:::-;32732:254;::::0;;-1:-1:-1;;;;;10341:15:1;;;10323:34;;10393:15;;;10388:2;10373:18;;10366:43;10445:15;;;;10425:18;;;10418:43;;;;-1:-1:-1;;;;;10497:39:1;10492:2;10477:18;;10470:67;-1:-1:-1;;;;;10574:31:1;10568:3;10553:19;;10546:60;-1:-1:-1;;;;;10643:37:1;;;10303:3;10622:19;;10615:66;32960:15:0::1;10712:3:1::0;10697:19;;10690:35;10272:3;10257:19;32732:254:0::1;;;;;;;-1:-1:-1::0;;17938:1:0;17929:6;:10;-1:-1:-1;;32314:680:0:o;33860:2403::-;17853:6;;17863:1;17853:11;17845:34;;;;-1:-1:-1;;;17845:34:0;;9836:2:1;17845:34:0;;;9818:21:1;9875:2;9855:18;;;9848:30;-1:-1:-1;;;9894:18:1;;;9887:40;9944:18;;17845:34:0;9634:334:1;17845:34:0;17901:1;17892:6;:10;;;;34113:19:::1;34135:5;-1:-1:-1::0;;;;;34135:14:0::1;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;34113:38;;34164:21;34196::::0;34233:9:::1;34228:915;34244:16:::0;;::::1;34228:915;;;34282:29;34314:17;:27;34332:5;;34338:1;34332:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;34314:27:0::1;-1:-1:-1::0;;;;;34314:27:0::1;;;;;;;;;;;;:34;34342:5;-1:-1:-1::0;;;;;34314:34:0::1;-1:-1:-1::0;;;;;34314:34:0::1;;;;;;;;;;;;:40;34349:4;-1:-1:-1::0;;;;;34314:40:0::1;-1:-1:-1::0;;;;;34314:40:0::1;;;;;;;;;;;;34282:72;;34375:7;:15;;;;;;;;;;;;34371:63;;;34425:5;;34431:1;34425:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;34399:35;::::0;-1:-1:-1;;;;;;34399:35:0;;-1:-1:-1;;;;;7148:32:1;;;34399:35:0::1;::::0;::::1;7130:51:1::0;7103:18;;34399:35:0::1;6984:203:1::0;34371:63:0::1;34471:16:::0;;-1:-1:-1;;;;;34471:16:0::1;34453:15;:34;34449:93;;;34533:5;;34539:1;34533:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;34496:46;::::0;-1:-1:-1;;;34496:46:0;;-1:-1:-1;;;;;7148:32:1;;;34496:46:0::1;::::0;::::1;7130:51:1::0;7103:18;;34496:46:0::1;6984:203:1::0;34449:93:0::1;34561:19:::0;;-1:-1:-1;;;34561:19:0;::::1;-1:-1:-1::0;;;;;34561:19:0::1;;:24:::0;34557:75:::1;;34623:5;;34629:1;34623:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;34594:38;::::0;-1:-1:-1;;;34594:38:0;;-1:-1:-1;;;;;7148:32:1;;;34594:38:0::1;::::0;::::1;7130:51:1::0;7103:18;;34594:38:0::1;6984:203:1::0;34557:75:0::1;34760:19:::0;;34738:78:::1;::::0;-1:-1:-1;;;34760:19:0;::::1;-1:-1:-1::0;;;;;34760:19:0::1;::::0;-1:-1:-1;;;34781:19:0;::::1;-1:-1:-1::0;;;;;34781:19:0::1;34802:13:::0;34738:21:::1;:78::i;:::-;34721:95;::::0;;::::1;:::i;:::-;34946:19:::0;;34721:95;;-1:-1:-1;34929:36:0::1;::::0;-1:-1:-1;;;34946:19:0;::::1;-1:-1:-1::0;;;;;34946:19:0::1;34929:36:::0;::::1;:::i;:::-;34980:22:::0;;-1:-1:-1;;;;;34980:22:0::1;-1:-1:-1::0;;;34980:22:0::1;::::0;;34929:36;-1:-1:-1;35070:61:0::1;35093:5:::0;;35099:1;35093:8;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;35111:19:::0;;-1:-1:-1;;;;;35070:22:0;::::1;::::0;;35103:6;;-1:-1:-1;;;35111:19:0;::::1;-1:-1:-1::0;;;;;35111:19:0::1;35070:22;:61::i;:::-;-1:-1:-1::0;34262:3:0::1;;34228:915;;;;35169:6;-1:-1:-1::0;;;;;35155:33:0::1;;35189:7;;35198:10;35210:5;35217:4;35223:13;35238;35155:97;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;35270:9;35265:991;35281:16:::0;;::::1;35265:991;;;35319:29;35351:17;:27;35369:5;;35375:1;35369:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;35351:27:0::1;-1:-1:-1::0;;;;;35351:27:0::1;;;;;;;;;;;;:34;35379:5;-1:-1:-1::0;;;;;35351:34:0::1;-1:-1:-1::0;;;;;35351:34:0::1;;;;;;;;;;;;:40;35386:4;-1:-1:-1::0;;;;;35351:40:0::1;-1:-1:-1::0;;;;;35351:40:0::1;;;;;;;;;;;;35319:72;;35412:7;:15;;;;;;;;;;;;35408:837;;;35698:19:::0;;35653:20:::1;::::0;35676:78:::1;::::0;-1:-1:-1;;;35698:19:0;::::1;-1:-1:-1::0;;;;;35698:19:0::1;::::0;-1:-1:-1;;;35719:19:0;::::1;-1:-1:-1::0;;;;;35719:19:0::1;35740:13:::0;35676:21:::1;:78::i;:::-;35653:101;;35775:53;35797:6;35805:5;;35811:1;35805:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;35775:21:0;::::1;::::0;:53;35815:12;35775:21:::1;:53::i;:::-;35854:155;35899:5;;35905:1;35899:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;35917:5;35933:4;35940:7;:19;;;;;;;;;;-1:-1:-1::0;;;;;35940:19:0::1;35961:12;35975:15;35854:155;;;;;;;;;;-1:-1:-1::0;;;;;11926:15:1;;;11908:34;;11978:15;;;11973:2;11958:18;;11951:43;12030:15;;;;12025:2;12010:18;;12003:43;-1:-1:-1;;;;;12082:39:1;12077:2;12062:18;;12055:67;12153:3;12138:19;;12131:35;;;;11888:3;12182:19;;12175:35;;;;11857:3;11842:19;;11584:632;35854:155:0::1;;;;;;;;-1:-1:-1::0;36079:23:0;;36121;;;;35408:837:::1;;;36220:5;;36226:1;36220:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;36192:37;::::0;-1:-1:-1;;;36192:37:0;;-1:-1:-1;;;;;7148:32:1;;;36192:37:0::1;::::0;::::1;7130:51:1::0;7103:18;;36192:37:0::1;6984:203:1::0;35408:837:0::1;-1:-1:-1::0;35299:3:0::1;;35265:991;;;-1:-1:-1::0;;17938:1:0;17929:6;:10;-1:-1:-1;;;;;;;;;33860:2403:0:o;39027:274::-;39205:7;39237:56;39260:11;39273:19;39279:13;39273:2;:19;:::i;:::-;39237:11;;:56;:22;:56::i;:::-;39230:63;39027:274;-1:-1:-1;;;;39027:274:0:o;19243:1814::-;19387:12;19562:4;19556:11;-1:-1:-1;;;19688:17:0;19681:93;-1:-1:-1;;;;;19826:4:0;19822:53;19818:1;19799:17;19795:25;19788:88;-1:-1:-1;;;;;19969:2:0;19965:51;19960:2;19941:17;19937:26;19930:87;20104:6;20099:2;20080:17;20076:26;20069:42;20968:2;20965:1;20960:3;20941:17;20938:1;20931:5;20924;20919:52;20482:16;20475:24;20469:2;20451:16;20448:24;20444:1;20440;20434:8;20431:15;20427:46;20424:76;20221:765;20210:776;;;21017:7;21009:40;;;;-1:-1:-1;;;21009:40:0;;13800:2:1;21009:40:0;;;13782:21:1;13839:2;13819:18;;;13812:30;-1:-1:-1;;;13858:18:1;;;13851:50;13918:18;;21009:40:0;13598:344:1;21009:40:0;19376:1681;19243:1814;;;;:::o;8642:541::-;8762:9;9014:1;-1:-1:-1;;8997:19:0;8994:1;8991:26;8988:1;8984:34;8977:42;8964:11;8960:60;8950:118;;9051:1;9048;9041:12;8950:118;-1:-1:-1;9142:9:0;;9138:27;;8642:541::o;14:138:1:-;-1:-1:-1;;;;;96:31:1;;86:42;;76:70;;142:1;139;132:12;76:70;14:138;:::o;157:141::-;225:20;;254:38;225:20;254:38;:::i;:::-;157:141;;;:::o;303:162::-;369:5;414:3;405:6;400:3;396:16;392:26;389:46;;;431:1;428;421:12;389:46;-1:-1:-1;453:6:1;303:162;-1:-1:-1;303:162:1:o;470:553::-;592:6;600;608;661:3;649:9;640:7;636:23;632:33;629:53;;;678:1;675;668:12;629:53;717:9;704:23;736:38;768:5;736:38;:::i;:::-;793:5;-1:-1:-1;850:2:1;835:18;;822:32;863:40;822:32;863:40;:::i;:::-;922:7;-1:-1:-1;948:69:1;1009:7;1004:2;989:18;;948:69;:::i;:::-;938:79;;470:553;;;;;:::o;1220:367::-;1283:8;1293:6;1347:3;1340:4;1332:6;1328:17;1324:27;1314:55;;1365:1;1362;1355:12;1314:55;-1:-1:-1;1388:20:1;;-1:-1:-1;;;;;1420:30:1;;1417:50;;;1463:1;1460;1453:12;1417:50;1500:4;1492:6;1488:17;1476:29;;1560:3;1553:4;1543:6;1540:1;1536:14;1528:6;1524:27;1520:38;1517:47;1514:67;;;1577:1;1574;1567:12;1514:67;1220:367;;;;;:::o;1592:753::-;1722:6;1730;1738;1746;1799:2;1787:9;1778:7;1774:23;1770:32;1767:52;;;1815:1;1812;1805:12;1767:52;1854:9;1841:23;1873:38;1905:5;1873:38;:::i;:::-;1930:5;-1:-1:-1;1987:2:1;1972:18;;1959:32;2000:40;1959:32;2000:40;:::i;:::-;2059:7;-1:-1:-1;2117:2:1;2102:18;;2089:32;-1:-1:-1;;;;;2133:30:1;;2130:50;;;2176:1;2173;2166:12;2130:50;2215:70;2277:7;2268:6;2257:9;2253:22;2215:70;:::i;:::-;1592:753;;;;-1:-1:-1;2304:8:1;-1:-1:-1;;;;1592:753:1:o;2350:1141::-;2637:2;2689:21;;;2759:13;;2662:18;;;2781:22;;;2608:4;;2637:2;2822:3;;2841:19;;;;2879:4;2906:17;;;2608:4;2951:424;2965:6;2962:1;2959:13;2951:424;;;3024:13;;3066:9;;-1:-1:-1;;;;;3062:35:1;3050:48;;3142:11;;;3136:18;3156:4;3132:29;3118:12;;;3111:51;3185:4;3229:11;;;3223:18;3209:12;;;3202:40;3282:11;;3276:18;3262:12;;;3255:40;3315:12;;;;3350:15;;;;3094:1;2980:9;2951:424;;;-1:-1:-1;;;;3426:4:1;3411:20;;3404:36;;;;-1:-1:-1;;;3471:4:1;3456:20;3449:36;3392:3;2350:1141;-1:-1:-1;2350:1141:1:o;3496:576::-;3599:6;3607;3615;3668:2;3656:9;3647:7;3643:23;3639:32;3636:52;;;3684:1;3681;3674:12;3636:52;3723:9;3710:23;3742:38;3774:5;3742:38;:::i;:::-;3799:5;-1:-1:-1;3856:2:1;3841:18;;3828:32;3869:40;3828:32;3869:40;:::i;:::-;3928:7;-1:-1:-1;3987:2:1;3972:18;;3959:32;4000:40;3959:32;4000:40;:::i;:::-;4059:7;4049:17;;;3496:576;;;;;:::o;5681:1298::-;5840:6;5848;5856;5864;5872;5880;5888;5941:3;5929:9;5920:7;5916:23;5912:33;5909:53;;;5958:1;5955;5948:12;5909:53;5997:9;5984:23;6016:38;6048:5;6016:38;:::i;:::-;6073:5;-1:-1:-1;6130:2:1;6115:18;;6102:32;6143:40;6102:32;6143:40;:::i;:::-;6202:7;-1:-1:-1;6260:2:1;6245:18;;6232:32;-1:-1:-1;;;;;6313:14:1;;;6310:34;;;6340:1;6337;6330:12;6310:34;6379:70;6441:7;6432:6;6421:9;6417:22;6379:70;:::i;:::-;6468:8;;-1:-1:-1;6353:96:1;-1:-1:-1;6556:2:1;6541:18;;6528:32;;-1:-1:-1;6572:16:1;;;6569:36;;;6601:1;6598;6591:12;6569:36;6639:8;6628:9;6624:24;6614:34;;6686:7;6679:4;6675:2;6671:13;6667:27;6657:55;;6708:1;6705;6698:12;6657:55;6748:2;6735:16;6774:2;6766:6;6763:14;6760:34;;;6790:1;6787;6780:12;6760:34;6835:7;6830:2;6821:6;6817:2;6813:15;6809:24;6806:37;6803:57;;;6856:1;6853;6846:12;6803:57;6887:2;6883;6879:11;6869:21;;6909:6;6899:16;;;;;6934:39;6968:3;6957:9;6953:19;6934:39;:::i;:::-;6924:49;;5681:1298;;;;;;;;;;:::o;7192:184::-;7262:6;7315:2;7303:9;7294:7;7290:23;7286:32;7283:52;;;7331:1;7328;7321:12;7283:52;-1:-1:-1;7354:16:1;;7192:184;-1:-1:-1;7192:184:1:o;7381:292::-;7439:6;7492:2;7480:9;7471:7;7467:23;7463:32;7460:52;;;7508:1;7505;7498:12;7460:52;7547:9;7534:23;-1:-1:-1;;;;;7590:5:1;7586:38;7579:5;7576:49;7566:77;;7639:1;7636;7629:12;7678:284;7736:6;7789:2;7777:9;7768:7;7764:23;7760:32;7757:52;;;7805:1;7802;7795:12;7757:52;7844:9;7831:23;-1:-1:-1;;;;;7887:5:1;7883:30;7876:5;7873:41;7863:69;;7928:1;7925;7918:12;8276:290;8334:6;8387:2;8375:9;8366:7;8362:23;8358:32;8355:52;;;8403:1;8400;8393:12;8355:52;8442:9;8429:23;-1:-1:-1;;;;;8485:5:1;8481:36;8474:5;8471:47;8461:75;;8532:1;8529;8522:12;8571:273;8639:6;8692:2;8680:9;8671:7;8667:23;8663:32;8660:52;;;8708:1;8705;8698:12;8660:52;8740:9;8734:16;8790:4;8783:5;8779:16;8772:5;8769:27;8759:55;;8810:1;8807;8800:12;8849:127;8910:10;8905:3;8901:20;8898:1;8891:31;8941:4;8938:1;8931:15;8965:4;8962:1;8955:15;8981:127;9042:10;9037:3;9033:20;9030:1;9023:31;9073:4;9070:1;9063:15;9097:4;9094:1;9087:15;9113:254;9172:6;9225:2;9213:9;9204:7;9200:23;9196:32;9193:52;;;9241:1;9238;9231:12;9193:52;9280:9;9267:23;9299:38;9331:5;9299:38;:::i;9372:127::-;9433:10;9428:3;9424:20;9421:1;9414:31;9464:4;9461:1;9454:15;9488:4;9485:1;9478:15;9504:125;9569:9;;;9590:10;;;9587:36;;;9603:18;;:::i;:::-;9504:125;;;;:::o;10736:843::-;11059:3;11048:9;11041:22;11100:6;11094:3;11083:9;11079:19;11072:35;11158:6;11150;11144:3;11133:9;11129:19;11116:49;11215:1;11209:3;11185:22;;;11181:32;;11174:43;;;;-1:-1:-1;;;;;11365:15:1;;;11358:4;11343:20;;11336:45;11417:15;;;11412:2;11397:18;;11390:43;11469:15;;;;11464:2;11449:18;;11442:43;11516:3;11501:19;;11494:35;11316:3;11545:19;;11538:35;;;;11278:2;11257:15;;;-1:-1:-1;;11253:29:1;11238:45;11234:55;;;-1:-1:-1;10736:843:1:o;12221:416::-;12310:1;12347:5;12310:1;12361:270;12382:7;12372:8;12369:21;12361:270;;;12441:4;12437:1;12433:6;12429:17;12423:4;12420:27;12417:53;;;12450:18;;:::i;:::-;12500:7;12490:8;12486:22;12483:55;;;12520:16;;;;12483:55;12599:22;;;;12559:15;;;;12361:270;;;12365:3;12221:416;;;;;:::o;12642:806::-;12691:5;12721:8;12711:80;;-1:-1:-1;12762:1:1;12776:5;;12711:80;12810:4;12800:76;;-1:-1:-1;12847:1:1;12861:5;;12800:76;12892:4;12910:1;12905:59;;;;12978:1;12973:130;;;;12885:218;;12905:59;12935:1;12926:10;;12949:5;;;12973:130;13010:3;13000:8;12997:17;12994:43;;;13017:18;;:::i;:::-;-1:-1:-1;;13073:1:1;13059:16;;13088:5;;12885:218;;13187:2;13177:8;13174:16;13168:3;13162:4;13159:13;13155:36;13149:2;13139:8;13136:16;13131:2;13125:4;13122:12;13118:35;13115:77;13112:159;;;-1:-1:-1;13224:19:1;;;13256:5;;13112:159;13303:34;13328:8;13322:4;13303:34;:::i;:::-;13373:6;13369:1;13365:6;13361:19;13352:7;13349:32;13346:58;;;13384:18;;:::i;:::-;13422:20;;12642:806;-1:-1:-1;;;12642:806:1:o;13453:140::-;13511:5;13540:47;13581:4;13571:8;13567:19;13561:4;13540:47;:::i
Swarm Source
ipfs://c9735f413ec4cec7a1d5356319a1dbd883e2699ed9d2a0a4adbbc7c00cc33c6a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.73
Net Worth in ETH
0.000369
Token Allocations
PUFETH
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $2,117.7 | 0.00034481 | $0.7302 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.