Address Contract Verified
Address
0x997FBC511a8Ad11F84a400feACD66E2A3fa805d2
Balance
0 ETH
Nonce
1
Code Size
6310 bytes
Creator
0x00000000...9497 at tx 0x19f877b8...2ec2f1
Indexed Transactions
0 (1 on-chain, 1.4% indexed)
Contract Bytecode
6310 bytes
0x604060808152600480361015610013575f80fd5b5f3560e01c8063eb3a7d471461086b5763fa483e7214610031575f80fd5b346101ef577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6060813601126101ef5760449081359083359067ffffffffffffffff602480358286116101ef57366023870112156101ef57858801358381116101ef5782870190833691890101116101ef5780356100ae81610a5b565b806102055750505050505061013f6064926100ca60209361176d565b945f73ffffffffffffffffffffffffffffffffffffffff89519687809681957fdb74aa15000000000000000000000000000000000000000000000000000000008352870135338d840190602090939293604083019473ffffffffffffffffffffffffffffffffffffffff809216845216910152565b03940135165af19081156101fb575f916101c5575b501061015c57005b6101c191519182917f08c379a0000000000000000000000000000000000000000000000000000000008352820160609060208152601f60208201527f536c6970706167653a20494e53554646494349454e545f50545f52455041590060408201520190565b0390fd5b90506020813d6020116101f3575b816101e060209383610984565b810103126101ef57515f610154565b5f80fd5b3d91506101d3565b84513d5f823e3d90fd5b610217819b9994969b97939597610a5b565b6001810361054c5750506064860135926102308461166a565b90805f039a8115918c057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14821715610521575f8c126101ef57899384516102778161091f565b6002815260209d8e9485830196883689378851966102948861091f565b60028852870198368a378083029283041417156104f657670de0b6b3a764000090818101908181116104ca57670de0b6b3a763ffff0190811161049e57046102db8561170b565b52336102e68261170b565b525f82126101ef579b99918d9261031e8e61030f87956103088c9b9a9961170b565b5190610abe565b61031886611745565b52611745565b9073ffffffffffffffffffffffffffffffffffffffff97889101351690528b519c8d977fb0d889810000000000000000000000000000000000000000000000000000000089528801908d8d8a0152518091526064880194905f5b81811061047757505050868403018887015251918281520191905f5b8c82821061046057505050505f8094928480930393165af180156101fb576103b9575b005b3d805f873e6103c88187610984565b85019486818703126101ef578051908382116101ef57019285601f850112156101ef5783519283116104365750508481819260051b94519061040c83870183610984565b815201928201019283116101ef578301905b82821061042757005b8151815290830190830161041e565b6041907f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b835185528c96509384019390920191600101610394565b929488995080919496839899600194511681520196019101908d97969594928f9492610378565b508960118f7f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b8f60118d917f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b8960118f7f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b8660118c7f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b9295509296985096945061055f81610a5b565b600281036106bc57509561058c610597959697906020820135916040810135916080606083013592013590565b99929790919861176d565b915f81126101ef575f916105d36105b08b602094610abe565b9173ffffffffffffffffffffffffffffffffffffffff8091169c1691828d6111a7565b858551809481937fbcb7ea5d000000000000000000000000000000000000000000000000000000008352338c8401525af19081156106b2575f91610680575b501061062557505050506103b7926111a7565b91601f7f536c6970706167653a20494e53554646494349454e545f53595f5245504159009260206064969551957f08c379a0000000000000000000000000000000000000000000000000000000008752860152840152820152fd5b90506020813d6020116106aa575b8161069b60209383610984565b810103126101ef57515f610612565b3d915061068e565b83513d5f823e3d90fd5b6003919294969395506106ce81610a5b565b03610840579261077a92610707926106fc602096906020820135916040810135916080606083013592013590565b98929196909361176d565b97895f73ffffffffffffffffffffffffffffffffffffffff8d51809b819682957fdb74aa150000000000000000000000000000000000000000000000000000000084523390840190602090939293604083019473ffffffffffffffffffffffffffffffffffffffff809216845216910152565b0393165af1948515610836575f95610802575b5084106107a7575050906107a0916116fe565b1061015c57005b7f536c6970706167653a20494e53554646494349454e545f59545f4f5554000000606492601d889360208b51957f08c379a0000000000000000000000000000000000000000000000000000000008752860152840152820152fd5b9094506020813d60201161082e575b8161081e60209383610984565b810103126101ef5751935f61078d565b3d9150610811565b88513d5f823e3d90fd5b826001867f4e487b71000000000000000000000000000000000000000000000000000000005f52525ffd5b5090346101ef5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101ef5760643567ffffffffffffffff81116101ef57366023820112156101ef5780830135926108c7846109c5565b906108d484519283610984565b84825236602486850101116101ef575f60208661091b97602461090897018387013784010152604435906024359035610af8565b90519182916020835260208301906109ff565b0390f35b6060810190811067ffffffffffffffff82111761093b57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6080810190811067ffffffffffffffff82111761093b57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761093b57604052565b67ffffffffffffffff811161093b57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b91908251928382525f5b848110610a475750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6020809697860101520116010190565b602081830181015184830182015201610a09565b60041115610a6557565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b908160209103126101ef575173ffffffffffffffffffffffffffffffffffffffff811681036101ef5790565b91908203918211610acb57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b918215908161116f575b81611166575b5061114757825192608081602095810103126101ef578381015192600490818510156101ef57604094858401519073ffffffffffffffffffffffffffffffffffffffff92838316968784036101ef57608060608801519701519485168095036101ef57610b7483610a5b565b821593848015611134575b15610ef257610b8d9061166a565b90670de0b6b3a764000090818102918183041490151715610ec65781610bb2916116fe565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111610ec6578115610e9a5790610bee929104610abe565b948511610e3e5786517fafd27bf5000000000000000000000000000000000000000000000000000000008152888186818a5afa9081156108365791610c438789610c48948d9897965f91610e21575b506111a7565b610a5b565b15610d7c5785517fdb74aa150000000000000000000000000000000000000000000000000000000081523084820190815273ffffffffffffffffffffffffffffffffffffffff909216602083015291908290819060400103815f885af1908115610d72579086915f91610d43575b50938551928380927fd94073d40000000000000000000000000000000000000000000000000000000082525afa9081156101fb5790610cfe915f91610d16575b5033906113a6565b825193840152818301528152610d138161091f565b90565b610d369150863d8811610d3c575b610d2e8183610984565b810190610a92565b5f610cf6565b503d610d24565b82819392503d8311610d6b575b610d5a8183610984565b810103126101ef578590515f610cb6565b503d610d50565b85513d5f823e3d90fd5b85517fdb74aa1500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116928101928352306020840152918290819060400103815f875af180156101fb575f90610df2575b610ded91509233906113a6565b610cfe565b508481813d8311610e1a575b610e088183610984565b810103126101ef57610ded9051610de0565b503d610dfe565b610e389150893d8b11610d3c57610d2e8183610984565b5f610c3d565b606484898951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601f60248201527f536c6970706167653a20494e53554646494349454e545f53595f4c494d4954006044820152fd5b6012877f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b6011877f4e487b71000000000000000000000000000000000000000000000000000000005f525260245ffd5b5092509485949394116110d85780610f0b600192610a5b565b0361107657610f1b8486806111a7565b85517fbcb7ea5d000000000000000000000000000000000000000000000000000000008152308382015287816024815f8a5af190811561106c575f9161103f575b50808211610fe4578791610f6f91610abe565b948651928380927fafd27bf50000000000000000000000000000000000000000000000000000000082525afa908115610d72579084610cfe93925f92610fc3575b508192610fbc926111a7565b33906113a6565b610fbc9250610fde90893d8b11610d3c57610d2e8183610984565b91610fb0565b60648389808a51927f08c379a000000000000000000000000000000000000000000000000000000000845283015260248201527f536c6970706167653a20494e53554646494349454e545f50595f52454445454d6044820152fd5b90508781813d8311611065575b6110568183610984565b810103126101ef57515f610f5c565b503d61104c565b87513d5f823e3d90fd5b85517fd94073d400000000000000000000000000000000000000000000000000000000815287818481895afa90811561106c57866110bc9287925f916110c157506111a7565b610f1b565b610e3891508b3d8d11610d3c57610d2e8183610984565b606483898951917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601f60248201527f536c6970706167653a20494e53554646494349454e545f50595f4c494d4954006044820152fd5b5061113e84610a5b565b60028414610b7f565b5050506040515f60208201525f604082015260408152610d138161091f565b9050155f610b08565b82159150610b02565b3d156111a2573d90611189826109c5565b916111976040519384610984565b82523d5f602084013e565b606090565b82156113a15773ffffffffffffffffffffffffffffffffffffffff908116806112425750505f80809381935af16111dc611178565b50156111e457565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6574682073656e64206661696c656400000000000000000000000000000000006044820152fd5b60409391935191602094858401947fa9059cbb00000000000000000000000000000000000000000000000000000000865216602484015260448301526044825261128b82610968565b604051916040830183811067ffffffffffffffff82111761093b576040528483527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656483860152516112ec935f91829182855af16112e6611178565b916117a4565b805190828215928315611389575b505050156113055750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6113999350820181019101611755565b5f82816112fa565b505050565b9073ffffffffffffffffffffffffffffffffffffffff9081831692831561166457604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff841660248201526020959193918690829060449082905afa80156101fb575f9061162b575b6b7fffffffffffffffffffffff91501061144a575b5050505050565b8251935f80878701927f095ea7b300000000000000000000000000000000000000000000000000000000948585521692836024890152604497828982015288815261149481610968565b519082875af16114a2611178565b816115fb575b501561159f57915f929183809386519089820193845260248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff888201528781526114f481610968565b51925af1611500611178565b8161156f575b5015611513578080611443565b606492917f5361666520417070726f766500000000000000000000000000000000000000009151927f08c379a00000000000000000000000000000000000000000000000000000000084526004840152600c6024840152820152fd5b80518015925085908315611587575b5050505f611506565b6115979350820181019101611755565b5f848161157e565b6064867f5361666520417070726f76650000000000000000000000000000000000000000878751927f08c379a00000000000000000000000000000000000000000000000000000000084526004840152600c6024840152820152fd5b80518015925088908315611613575b5050505f6114a8565b6116239350820181019101611755565b5f878161160a565b508581813d831161165d575b6116418183610984565b810103126101ef576b7fffffffffffffffffffffff905161142e565b503d611637565b50505050565b602073ffffffffffffffffffffffffffffffffffffffff60045f9360405194859384927f1d52edc4000000000000000000000000000000000000000000000000000000008452165af19081156116f3575f916116c4575090565b90506020813d6020116116eb575b816116df60209383610984565b810103126101ef575190565b3d91506116d2565b6040513d5f823e3d90fd5b91908201809211610acb57565b8051156117185760200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b8051600110156117185760400190565b908160209103126101ef575180151581036101ef5790565b5f8113156117785790565b7f80000000000000000000000000000000000000000000000000000000000000008114610acb575f0390565b9192901561181f57508151156117b8575090565b3b156117c15790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156118325750805190602001fd5b6101c1906040519182917f08c379a00000000000000000000000000000000000000000000000000000000083526020600484015260248301906109ff56fea2646970667358221220f08372ffe29ea0510d93d8e6fbccd4e962481250f3231e6996e90650ddb060a964736f6c63430008180033
Verified Source Code Full Match
Compiler: v0.8.24+commit.e11b9ed9
EVM: shanghai
Optimization: Yes (1000000 runs)
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}
IWETH.sol 34 lines
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
Errors.sol 182 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
library Errors {
// BulkSeller
error BulkInsufficientSyForTrade(uint256 currentAmount, uint256 requiredAmount);
error BulkInsufficientTokenForTrade(uint256 currentAmount, uint256 requiredAmount);
error BulkInSufficientSyOut(uint256 actualSyOut, uint256 requiredSyOut);
error BulkInSufficientTokenOut(uint256 actualTokenOut, uint256 requiredTokenOut);
error BulkInsufficientSyReceived(uint256 actualBalance, uint256 requiredBalance);
error BulkNotMaintainer();
error BulkNotAdmin();
error BulkSellerAlreadyExisted(address token, address SY, address bulk);
error BulkSellerInvalidToken(address token, address SY);
error BulkBadRateTokenToSy(uint256 actualRate, uint256 currentRate, uint256 eps);
error BulkBadRateSyToToken(uint256 actualRate, uint256 currentRate, uint256 eps);
// APPROX
error ApproxFail();
error ApproxParamsInvalid(uint256 guessMin, uint256 guessMax, uint256 eps);
error ApproxBinarySearchInputInvalid(
uint256 approxGuessMin,
uint256 approxGuessMax,
uint256 minGuessMin,
uint256 maxGuessMax
);
// MARKET + MARKET MATH CORE
error MarketExpired();
error MarketZeroAmountsInput();
error MarketZeroAmountsOutput();
error MarketZeroLnImpliedRate();
error MarketInsufficientPtForTrade(int256 currentAmount, int256 requiredAmount);
error MarketInsufficientPtReceived(uint256 actualBalance, uint256 requiredBalance);
error MarketInsufficientSyReceived(uint256 actualBalance, uint256 requiredBalance);
error MarketZeroTotalPtOrTotalAsset(int256 totalPt, int256 totalAsset);
error MarketExchangeRateBelowOne(int256 exchangeRate);
error MarketProportionMustNotEqualOne();
error MarketRateScalarBelowZero(int256 rateScalar);
error MarketScalarRootBelowZero(int256 scalarRoot);
error MarketProportionTooHigh(int256 proportion, int256 maxProportion);
error OracleUninitialized();
error OracleTargetTooOld(uint32 target, uint32 oldest);
error OracleZeroCardinality();
error MarketFactoryExpiredPt();
error MarketFactoryInvalidPt();
error MarketFactoryMarketExists();
error MarketFactoryLnFeeRateRootTooHigh(uint80 lnFeeRateRoot, uint256 maxLnFeeRateRoot);
error MarketFactoryOverriddenFeeTooHigh(uint80 overriddenFee, uint256 marketLnFeeRateRoot);
error MarketFactoryReserveFeePercentTooHigh(uint8 reserveFeePercent, uint8 maxReserveFeePercent);
error MarketFactoryZeroTreasury();
error MarketFactoryInitialAnchorTooLow(int256 initialAnchor, int256 minInitialAnchor);
error MFNotPendleMarket(address addr);
// ROUTER
error RouterInsufficientLpOut(uint256 actualLpOut, uint256 requiredLpOut);
error RouterInsufficientSyOut(uint256 actualSyOut, uint256 requiredSyOut);
error RouterInsufficientPtOut(uint256 actualPtOut, uint256 requiredPtOut);
error RouterInsufficientYtOut(uint256 actualYtOut, uint256 requiredYtOut);
error RouterInsufficientPYOut(uint256 actualPYOut, uint256 requiredPYOut);
error RouterInsufficientTokenOut(uint256 actualTokenOut, uint256 requiredTokenOut);
error RouterInsufficientSyRepay(uint256 actualSyRepay, uint256 requiredSyRepay);
error RouterInsufficientPtRepay(uint256 actualPtRepay, uint256 requiredPtRepay);
error RouterNotAllSyUsed(uint256 netSyDesired, uint256 netSyUsed);
error RouterTimeRangeZero();
error RouterCallbackNotPendleMarket(address caller);
error RouterInvalidAction(bytes4 selector);
error RouterInvalidFacet(address facet);
error RouterKyberSwapDataZero();
error SimulationResults(bool success, bytes res);
// YIELD CONTRACT
error YCExpired();
error YCNotExpired();
error YieldContractInsufficientSy(uint256 actualSy, uint256 requiredSy);
error YCNothingToRedeem();
error YCPostExpiryDataNotSet();
error YCNoFloatingSy();
// YieldFactory
error YCFactoryInvalidExpiry();
error YCFactoryYieldContractExisted();
error YCFactoryZeroExpiryDivisor();
error YCFactoryZeroTreasury();
error YCFactoryInterestFeeRateTooHigh(uint256 interestFeeRate, uint256 maxInterestFeeRate);
error YCFactoryRewardFeeRateTooHigh(uint256 newRewardFeeRate, uint256 maxRewardFeeRate);
// SY
error SYInvalidTokenIn(address token);
error SYInvalidTokenOut(address token);
error SYZeroDeposit();
error SYZeroRedeem();
error SYInsufficientSharesOut(uint256 actualSharesOut, uint256 requiredSharesOut);
error SYInsufficientTokenOut(uint256 actualTokenOut, uint256 requiredTokenOut);
// SY-specific
error SYQiTokenMintFailed(uint256 errCode);
error SYQiTokenRedeemFailed(uint256 errCode);
error SYQiTokenRedeemRewardsFailed(uint256 rewardAccruedType0, uint256 rewardAccruedType1);
error SYQiTokenBorrowRateTooHigh(uint256 borrowRate, uint256 borrowRateMax);
error SYCurveInvalidPid();
error SYCurve3crvPoolNotFound();
error SYApeDepositAmountTooSmall(uint256 amountDeposited);
error SYBalancerInvalidPid();
error SYInvalidRewardToken(address token);
error SYStargateRedeemCapExceeded(uint256 amountLpDesired, uint256 amountLpRedeemable);
error SYBalancerReentrancy();
error NotFromTrustedRemote(uint16 srcChainId, bytes path);
error ApxETHNotEnoughBuffer();
// Liquidity Mining
error VCInactivePool(address pool);
error VCPoolAlreadyActive(address pool);
error VCZeroVePendle(address user);
error VCExceededMaxWeight(uint256 totalWeight, uint256 maxWeight);
error VCEpochNotFinalized(uint256 wTime);
error VCPoolAlreadyAddAndRemoved(address pool);
error VEInvalidNewExpiry(uint256 newExpiry);
error VEExceededMaxLockTime();
error VEInsufficientLockTime();
error VENotAllowedReduceExpiry();
error VEZeroAmountLocked();
error VEPositionNotExpired();
error VEZeroPosition();
error VEZeroSlope(uint128 bias, uint128 slope);
error VEReceiveOldSupply(uint256 msgTime);
error GCNotPendleMarket(address caller);
error GCNotVotingController(address caller);
error InvalidWTime(uint256 wTime);
error ExpiryInThePast(uint256 expiry);
error ChainNotSupported(uint256 chainId);
error FDTotalAmountFundedNotMatch(uint256 actualTotalAmount, uint256 expectedTotalAmount);
error FDEpochLengthMismatch();
error FDInvalidPool(address pool);
error FDPoolAlreadyExists(address pool);
error FDInvalidNewFinishedEpoch(uint256 oldFinishedEpoch, uint256 newFinishedEpoch);
error FDInvalidStartEpoch(uint256 startEpoch);
error FDInvalidWTimeFund(uint256 lastFunded, uint256 wTime);
error FDFutureFunding(uint256 lastFunded, uint256 currentWTime);
error BDInvalidEpoch(uint256 epoch, uint256 startTime);
// Cross-Chain
error MsgNotFromSendEndpoint(uint16 srcChainId, bytes path);
error MsgNotFromReceiveEndpoint(address sender);
error InsufficientFeeToSendMsg(uint256 currentFee, uint256 requiredFee);
error ApproxDstExecutionGasNotSet();
error InvalidRetryData();
// GENERIC MSG
error ArrayLengthMismatch();
error ArrayEmpty();
error ArrayOutOfBounds();
error ZeroAddress();
error FailedToSendEther();
error InvalidMerkleProof();
error OnlyLayerZeroEndpoint();
error OnlyYT();
error OnlyYCFactory();
error OnlyWhitelisted();
// Swap Aggregator
error SAInsufficientTokenIn(address tokenIn, uint256 amountExpected, uint256 amountActual);
error UnsupportedSelector(uint256 aggregatorType, bytes4 selector);
}
IPYieldToken.sol 62 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IRewardManager.sol";
import "./IPInterestManagerYT.sol";
interface IPYieldToken is IERC20Metadata, IRewardManager, IPInterestManagerYT {
event NewInterestIndex(uint256 indexed newIndex);
event Mint(
address indexed caller,
address indexed receiverPT,
address indexed receiverYT,
uint256 amountSyToMint,
uint256 amountPYOut
);
event Burn(address indexed caller, address indexed receiver, uint256 amountPYToRedeem, uint256 amountSyOut);
event RedeemRewards(address indexed user, uint256[] amountRewardsOut);
event RedeemInterest(address indexed user, uint256 interestOut);
event CollectRewardFee(address indexed rewardToken, uint256 amountRewardFee);
function mintPY(address receiverPT, address receiverYT) external returns (uint256 amountPYOut);
function redeemPY(address receiver) external returns (uint256 amountSyOut);
function redeemPYMulti(
address[] calldata receivers,
uint256[] calldata amountPYToRedeems
) external returns (uint256[] memory amountSyOuts);
function redeemDueInterestAndRewards(
address user,
bool redeemInterest,
bool redeemRewards
) external returns (uint256 interestOut, uint256[] memory rewardsOut);
function rewardIndexesCurrent() external returns (uint256[] memory);
function pyIndexCurrent() external returns (uint256);
function pyIndexStored() external view returns (uint256);
function getRewardTokens() external view returns (address[] memory);
function SY() external view returns (address);
function PT() external view returns (address);
function factory() external view returns (address);
function expiry() external view returns (uint256);
function isExpired() external view returns (bool);
function doCacheIndexSameBlock() external view returns (bool);
function pyIndexLastUpdatedBlock() external view returns (uint128);
}
ActionCallbackV3.sol 142 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../interfaces/IPActionCallbackV3.sol";
import "../core/libraries/Errors.sol";
import "./base/CallbackHelper.sol";
import "../core/libraries/TokenHelper.sol";
contract ActionCallbackV3 is IPLimitOrderType, IPActionCallbackV3, CallbackHelper, TokenHelper {
using PMath for int256;
using PMath for uint256;
using PYIndexLib for PYIndex;
using PYIndexLib for IPYieldToken;
function swapCallback(int256 ptToAccount, int256 syToAccount, bytes calldata data) external override {
ActionType swapType = _getActionType(data);
if (swapType == ActionType.SwapExactSyForYt) {
_callbackSwapExactSyForYt(ptToAccount, syToAccount, data);
} else if (swapType == ActionType.SwapYtForSy) {
_callbackSwapYtForSy(ptToAccount, syToAccount, data);
} else if (swapType == ActionType.SwapExactYtForPt) {
_callbackSwapExactYtForPt(ptToAccount, syToAccount, data);
} else if (swapType == ActionType.SwapExactPtForYt) {
_callbackSwapExactPtForYt(ptToAccount, syToAccount, data);
} else {
assert(false);
}
}
function limitRouterCallback(
uint256 actualMaking,
uint256 actualTaking,
uint256 totalFee,
bytes memory data
)
external
returns (
bytes memory // encode as netTransferToLimit, netOutputFromLimit
)
{
bool isEmptyFill = (actualMaking == 0 && actualTaking == 0 && totalFee == 0);
if (isEmptyFill) {
return abi.encode(0, 0);
}
(OrderType orderType, IPYieldToken YT, uint256 netRemaining, address receiver) = abi.decode(
data,
(OrderType, IPYieldToken, uint256, address)
);
if (orderType == OrderType.SY_FOR_PT || orderType == OrderType.SY_FOR_YT) {
PYIndex index = YT.newIndex();
uint256 totalSyToMintPy = index.assetToSyUp(actualTaking);
uint256 additionalSyToMint = totalSyToMintPy - actualMaking;
require(additionalSyToMint <= netRemaining, "Slippage: INSUFFICIENT_SY_LIMIT");
_transferOut(YT.SY(), address(YT), additionalSyToMint);
uint256 netPyToReceiver;
if (orderType == OrderType.SY_FOR_PT) {
netPyToReceiver = YT.mintPY(address(this), receiver);
_safeApproveInf(YT.PT(), msg.sender);
} else {
netPyToReceiver = YT.mintPY(receiver, address(this));
_safeApproveInf(address(YT), msg.sender);
}
return abi.encode(additionalSyToMint, netPyToReceiver);
} else {
require(actualMaking <= netRemaining, "Slippage: INSUFFICIENT_PY_LIMIT");
if (orderType == OrderType.PT_FOR_SY) {
_transferOut(address(YT), address(YT), actualMaking);
} else {
_transferOut(YT.PT(), address(YT), actualMaking);
}
uint256 netSyRedeemed = IPYieldToken(YT).redeemPY(address(this));
require(actualTaking <= netSyRedeemed, "Slippage: INSUFFICIENT_PY_REDEEM");
uint256 netSyToReceiver = netSyRedeemed - actualTaking;
address SY = YT.SY();
_transferOut(SY, receiver, netSyToReceiver);
_safeApproveInf(SY, msg.sender);
return abi.encode(actualMaking, netSyToReceiver);
}
}
function _callbackSwapExactSyForYt(int256 ptToAccount, int256, /*syToAccount*/ bytes calldata data) internal {
(address receiver, IPYieldToken YT) = _decodeSwapExactSyForYt(data);
uint256 ptOwed = ptToAccount.abs();
uint256 netPyOut = YT.mintPY(msg.sender, receiver);
if (netPyOut < ptOwed) revert("Slippage: INSUFFICIENT_PT_REPAY");
}
function _callbackSwapYtForSy(int256 ptToAccount, int256 syToAccount, bytes calldata data) internal {
(address receiver, IPYieldToken YT) = _decodeSwapYtForSy(data);
PYIndex pyIndex = YT.newIndex();
uint256 syOwed = syToAccount.neg().Uint();
address[] memory receivers = new address[](2);
uint256[] memory amountPYToRedeems = new uint256[](2);
(receivers[0], amountPYToRedeems[0]) = (msg.sender, pyIndex.syToAssetUp(syOwed));
(receivers[1], amountPYToRedeems[1]) = (receiver, ptToAccount.Uint() - amountPYToRedeems[0]);
YT.redeemPYMulti(receivers, amountPYToRedeems);
}
function _callbackSwapExactPtForYt(int256 ptToAccount, int256, /*syToAccount*/ bytes calldata data) internal {
(address receiver, uint256 exactPtIn, uint256 minYtOut, IPYieldToken YT) = _decodeSwapExactPtForYt(data);
uint256 netPtOwed = ptToAccount.abs();
uint256 netPyOut = YT.mintPY(msg.sender, receiver);
if (netPyOut < minYtOut) revert("Slippage: INSUFFICIENT_YT_OUT");
if (exactPtIn + netPyOut < netPtOwed) revert("Slippage: INSUFFICIENT_PT_REPAY");
}
function _callbackSwapExactYtForPt(int256 ptToAccount, int256 syToAccount, bytes calldata data) internal {
(address receiver, uint256 netPtOut, IPPrincipalToken PT, IPYieldToken YT) = _decodeSwapExactYtForPt(data);
uint256 netSyOwed = syToAccount.abs();
uint256 netPtRedeemSy = ptToAccount.Uint() - netPtOut;
_transferOut(address(PT), address(YT), netPtRedeemSy);
uint256 netSyToMarket = YT.redeemPY(msg.sender);
if (netSyToMarket < netSyOwed) revert("Slippage: INSUFFICIENT_SY_REPAY");
_transferOut(address(PT), receiver, netPtOut);
}
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
IPLimitRouter.sol 134 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../core/StandardizedYield/PYIndex.sol";
interface IPLimitOrderType {
enum OrderType {
SY_FOR_PT,
PT_FOR_SY,
SY_FOR_YT,
YT_FOR_SY
}
// Fixed-size order part with core information
struct StaticOrder {
uint256 salt;
uint256 expiry;
uint256 nonce;
OrderType orderType;
address token;
address YT;
address maker;
address receiver;
uint256 makingAmount;
uint256 lnImpliedRate;
uint256 failSafeRate;
}
struct FillResults {
uint256 totalMaking;
uint256 totalTaking;
uint256 totalFee;
uint256 totalNotionalVolume;
uint256[] netMakings;
uint256[] netTakings;
uint256[] netFees;
uint256[] notionalVolumes;
}
}
struct Order {
uint256 salt;
uint256 expiry;
uint256 nonce;
IPLimitOrderType.OrderType orderType;
address token;
address YT;
address maker;
address receiver;
uint256 makingAmount;
uint256 lnImpliedRate;
uint256 failSafeRate;
bytes permit;
}
struct FillOrderParams {
Order order;
bytes signature;
uint256 makingAmount;
}
interface IPLimitRouterCallback is IPLimitOrderType {
function limitRouterCallback(
uint256 actualMaking,
uint256 actualTaking,
uint256 totalFee,
bytes memory data
) external returns (bytes memory);
}
interface IPLimitRouter is IPLimitOrderType {
struct OrderStatus {
uint128 filledAmount;
uint128 remaining;
}
event OrderCanceled(address indexed maker, bytes32 indexed orderHash);
event OrderFilledV2(
bytes32 indexed orderHash,
OrderType indexed orderType,
address indexed YT,
address token,
uint256 netInputFromMaker,
uint256 netOutputToMaker,
uint256 feeAmount,
uint256 notionalVolume,
address maker,
address taker
);
// @dev actualMaking, actualTaking are in the SY form
function fill(
FillOrderParams[] memory params,
address receiver,
uint256 maxTaking,
bytes calldata optData,
bytes calldata callback
) external returns (uint256 actualMaking, uint256 actualTaking, uint256 totalFee, bytes memory callbackReturn);
function feeRecipient() external view returns (address);
function hashOrder(Order memory order) external view returns (bytes32);
function cancelSingle(Order calldata order) external;
function cancelBatch(Order[] calldata orders) external;
function orderStatusesRaw(
bytes32[] memory orderHashes
) external view returns (uint256[] memory remainingsRaw, uint256[] memory filledAmounts);
function orderStatuses(
bytes32[] memory orderHashes
) external view returns (uint256[] memory remainings, uint256[] memory filledAmounts);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function simulate(address target, bytes calldata data) external payable;
/* --- Deprecated events --- */
// deprecate on 7/1/2024, prior to official launch
event OrderFilled(
bytes32 indexed orderHash,
OrderType indexed orderType,
address indexed YT,
address token,
uint256 netInputFromMaker,
uint256 netOutputToMaker,
uint256 feeAmount,
uint256 notionalVolume
);
}
PMath.sol 184 lines
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
/* solhint-disable private-vars-leading-underscore, reason-string */
library PMath {
uint256 internal constant ONE = 1e18; // 18 decimal places
int256 internal constant IONE = 1e18; // 18 decimal places
function subMax0(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return (a >= b ? a - b : 0);
}
}
function subNoNeg(int256 a, int256 b) internal pure returns (int256) {
require(a >= b, "negative");
return a - b; // no unchecked since if b is very negative, a - b might overflow
}
function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 product = a * b;
unchecked {
return product / ONE;
}
}
function mulDown(int256 a, int256 b) internal pure returns (int256) {
int256 product = a * b;
unchecked {
return product / IONE;
}
}
function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 aInflated = a * ONE;
unchecked {
return aInflated / b;
}
}
function divDown(int256 a, int256 b) internal pure returns (int256) {
int256 aInflated = a * IONE;
unchecked {
return aInflated / b;
}
}
function rawDivUp(uint256 a, uint256 b) internal pure returns (uint256) {
return (a + b - 1) / b;
}
// @author Uniswap
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
function square(uint256 x) internal pure returns (uint256) {
return x * x;
}
function squareDown(uint256 x) internal pure returns (uint256) {
return mulDown(x, x);
}
function abs(int256 x) internal pure returns (uint256) {
return uint256(x > 0 ? x : -x);
}
function neg(int256 x) internal pure returns (int256) {
return x * (-1);
}
function neg(uint256 x) internal pure returns (int256) {
return Int(x) * (-1);
}
function max(uint256 x, uint256 y) internal pure returns (uint256) {
return (x > y ? x : y);
}
function max(int256 x, int256 y) internal pure returns (int256) {
return (x > y ? x : y);
}
function min(uint256 x, uint256 y) internal pure returns (uint256) {
return (x < y ? x : y);
}
function min(int256 x, int256 y) internal pure returns (int256) {
return (x < y ? x : y);
}
/*///////////////////////////////////////////////////////////////
SIGNED CASTS
//////////////////////////////////////////////////////////////*/
function Int(uint256 x) internal pure returns (int256) {
require(x <= uint256(type(int256).max));
return int256(x);
}
function Int128(int256 x) internal pure returns (int128) {
require(type(int128).min <= x && x <= type(int128).max);
return int128(x);
}
function Int128(uint256 x) internal pure returns (int128) {
return Int128(Int(x));
}
/*///////////////////////////////////////////////////////////////
UNSIGNED CASTS
//////////////////////////////////////////////////////////////*/
function Uint(int256 x) internal pure returns (uint256) {
require(x >= 0);
return uint256(x);
}
function Uint32(uint256 x) internal pure returns (uint32) {
require(x <= type(uint32).max);
return uint32(x);
}
function Uint64(uint256 x) internal pure returns (uint64) {
require(x <= type(uint64).max);
return uint64(x);
}
function Uint112(uint256 x) internal pure returns (uint112) {
require(x <= type(uint112).max);
return uint112(x);
}
function Uint96(uint256 x) internal pure returns (uint96) {
require(x <= type(uint96).max);
return uint96(x);
}
function Uint128(uint256 x) internal pure returns (uint128) {
require(x <= type(uint128).max);
return uint128(x);
}
function Uint192(uint256 x) internal pure returns (uint192) {
require(x <= type(uint192).max);
return uint192(x);
}
function isAApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return mulDown(b, ONE - eps) <= a && a <= mulDown(b, ONE + eps);
}
function isAGreaterApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return a >= b && a <= mulDown(b, ONE + eps);
}
function isASmallerApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return a <= b && a >= mulDown(b, ONE - eps);
}
}
IRewardManager.sol 6 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IRewardManager {
function userReward(address token, address user) external view returns (uint128 index, uint128 accrued);
}
TokenHelper.sol 71 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../../interfaces/IWETH.sol";
abstract contract TokenHelper {
using SafeERC20 for IERC20;
address internal constant NATIVE = address(0);
uint256 internal constant LOWER_BOUND_APPROVAL = type(uint96).max / 2; // some tokens use 96 bits for approval
function _transferIn(address token, address from, uint256 amount) internal {
if (token == NATIVE) require(msg.value == amount, "eth mismatch");
else if (amount != 0) IERC20(token).safeTransferFrom(from, address(this), amount);
}
function _transferFrom(IERC20 token, address from, address to, uint256 amount) internal {
if (amount != 0) token.safeTransferFrom(from, to, amount);
}
function _transferOut(address token, address to, uint256 amount) internal {
if (amount == 0) return;
if (token == NATIVE) {
(bool success, ) = to.call{value: amount}("");
require(success, "eth send failed");
} else {
IERC20(token).safeTransfer(to, amount);
}
}
function _transferOut(address[] memory tokens, address to, uint256[] memory amounts) internal {
uint256 numTokens = tokens.length;
require(numTokens == amounts.length, "length mismatch");
for (uint256 i = 0; i < numTokens; ) {
_transferOut(tokens[i], to, amounts[i]);
unchecked {
i++;
}
}
}
function _selfBalance(address token) internal view returns (uint256) {
return (token == NATIVE) ? address(this).balance : IERC20(token).balanceOf(address(this));
}
function _selfBalance(IERC20 token) internal view returns (uint256) {
return token.balanceOf(address(this));
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev PLS PAY ATTENTION to tokens that requires the approval to be set to 0 before changing it
function _safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Safe Approve");
}
function _safeApproveInf(address token, address to) internal {
if (token == NATIVE) return;
if (IERC20(token).allowance(address(this), to) < LOWER_BOUND_APPROVAL) {
_safeApprove(token, to, 0);
_safeApprove(token, to, type(uint256).max);
}
}
function _wrap_unwrap_ETH(address tokenIn, address tokenOut, uint256 netTokenIn) internal {
if (tokenIn == NATIVE) IWETH(tokenOut).deposit{value: netTokenIn}();
else IWETH(tokenIn).withdraw(netTokenIn);
}
}
CallbackHelper.sol 130 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../../interfaces/IPYieldToken.sol";
import "../../interfaces/IPPrincipalToken.sol";
import "../../interfaces/IStandardizedYield.sol";
abstract contract CallbackHelper {
enum ActionType {
SwapExactSyForYt,
SwapYtForSy,
SwapExactYtForPt,
SwapExactPtForYt
}
/// ------------------------------------------------------------
/// SwapExactSyForYt
/// ------------------------------------------------------------
function _encodeSwapExactSyForYt(address receiver, IPYieldToken YT) internal pure returns (bytes memory res) {
res = new bytes(96);
uint256 actionType = uint256(ActionType.SwapExactSyForYt);
assembly {
mstore(add(res, 32), actionType)
mstore(add(res, 64), receiver)
mstore(add(res, 96), YT)
}
}
function _decodeSwapExactSyForYt(bytes calldata data) internal pure returns (address receiver, IPYieldToken YT) {
assembly {
// first 32 bytes is ActionType
receiver := calldataload(add(data.offset, 32))
YT := calldataload(add(data.offset, 64))
}
}
/// ------------------------------------------------------------
/// SwapYtForSy (common encode & decode)
/// ------------------------------------------------------------
function _encodeSwapYtForSy(address receiver, IPYieldToken YT) internal pure returns (bytes memory res) {
res = new bytes(96);
uint256 actionType = uint256(ActionType.SwapYtForSy);
assembly {
mstore(add(res, 32), actionType)
mstore(add(res, 64), receiver)
mstore(add(res, 96), YT)
}
}
function _decodeSwapYtForSy(bytes calldata data) internal pure returns (address receiver, IPYieldToken YT) {
assembly {
// first 32 bytes is ActionType
receiver := calldataload(add(data.offset, 32))
YT := calldataload(add(data.offset, 64))
}
}
function _encodeSwapExactYtForPt(
address receiver,
uint256 netPtOut,
IPPrincipalToken PT,
IPYieldToken YT
) internal pure returns (bytes memory res) {
res = new bytes(160);
uint256 actionType = uint256(ActionType.SwapExactYtForPt);
assembly {
mstore(add(res, 32), actionType)
mstore(add(res, 64), receiver)
mstore(add(res, 96), netPtOut)
mstore(add(res, 128), PT)
mstore(add(res, 160), YT)
}
}
function _decodeSwapExactYtForPt(
bytes calldata data
) internal pure returns (address receiver, uint256 netPtOut, IPPrincipalToken PT, IPYieldToken YT) {
assembly {
// first 32 bytes is ActionType
receiver := calldataload(add(data.offset, 32))
netPtOut := calldataload(add(data.offset, 64))
PT := calldataload(add(data.offset, 96))
YT := calldataload(add(data.offset, 128))
}
}
function _encodeSwapExactPtForYt(
address receiver,
uint256 exactPtIn,
uint256 minYtOut,
IPYieldToken YT
) internal pure returns (bytes memory res) {
res = new bytes(160);
uint256 actionType = uint256(ActionType.SwapExactPtForYt);
assembly {
mstore(add(res, 32), actionType)
mstore(add(res, 64), receiver)
mstore(add(res, 96), exactPtIn)
mstore(add(res, 128), minYtOut)
mstore(add(res, 160), YT)
}
}
function _decodeSwapExactPtForYt(
bytes calldata data
) internal pure returns (address receiver, uint256 exactPtIn, uint256 minYtOut, IPYieldToken YT) {
assembly {
// first 32 bytes is ActionType
receiver := calldataload(add(data.offset, 32))
exactPtIn := calldataload(add(data.offset, 64))
minYtOut := calldataload(add(data.offset, 96))
YT := calldataload(add(data.offset, 128))
}
}
/// ------------------------------------------------------------
/// Misc functions
/// ------------------------------------------------------------
function _getActionType(bytes calldata data) internal pure returns (ActionType actionType) {
assembly {
actionType := calldataload(data.offset)
}
}
}
IPPrincipalToken.sol 21 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IPPrincipalToken is IERC20Metadata {
function burnByYT(address user, uint256 amount) external;
function mintByYT(address user, uint256 amount) external;
function initialize(address _YT) external;
function SY() external view returns (address);
function YT() external view returns (address);
function factory() external view returns (address);
function expiry() external view returns (uint256);
function isExpired() external view returns (bool);
}
IPActionCallbackV3.sol 7 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "./IPMarketSwapCallback.sol";
import "./IPLimitRouter.sol";
interface IPActionCallbackV3 is IPMarketSwapCallback, IPLimitRouterCallback {}
IStandardizedYield.sol 167 lines
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IStandardizedYield is IERC20Metadata {
/// @dev Emitted when any base tokens is deposited to mint shares
event Deposit(
address indexed caller,
address indexed receiver,
address indexed tokenIn,
uint256 amountDeposited,
uint256 amountSyOut
);
/// @dev Emitted when any shares are redeemed for base tokens
event Redeem(
address indexed caller,
address indexed receiver,
address indexed tokenOut,
uint256 amountSyToRedeem,
uint256 amountTokenOut
);
/// @dev check `assetInfo()` for more information
enum AssetType {
TOKEN,
LIQUIDITY
}
/// @dev Emitted when (`user`) claims their rewards
event ClaimRewards(address indexed user, address[] rewardTokens, uint256[] rewardAmounts);
/**
* @notice mints an amount of shares by depositing a base token.
* @param receiver shares recipient address
* @param tokenIn address of the base tokens to mint shares
* @param amountTokenToDeposit amount of base tokens to be transferred from (`msg.sender`)
* @param minSharesOut reverts if amount of shares minted is lower than this
* @return amountSharesOut amount of shares minted
* @dev Emits a {Deposit} event
*
* Requirements:
* - (`tokenIn`) must be a valid base token.
*/
function deposit(
address receiver,
address tokenIn,
uint256 amountTokenToDeposit,
uint256 minSharesOut
) external payable returns (uint256 amountSharesOut);
/**
* @notice redeems an amount of base tokens by burning some shares
* @param receiver recipient address
* @param amountSharesToRedeem amount of shares to be burned
* @param tokenOut address of the base token to be redeemed
* @param minTokenOut reverts if amount of base token redeemed is lower than this
* @param burnFromInternalBalance if true, burns from balance of `address(this)`, otherwise burns from `msg.sender`
* @return amountTokenOut amount of base tokens redeemed
* @dev Emits a {Redeem} event
*
* Requirements:
* - (`tokenOut`) must be a valid base token.
*/
function redeem(
address receiver,
uint256 amountSharesToRedeem,
address tokenOut,
uint256 minTokenOut,
bool burnFromInternalBalance
) external returns (uint256 amountTokenOut);
/**
* @notice exchangeRate * syBalance / 1e18 must return the asset balance of the account
* @notice vice-versa, if a user uses some amount of tokens equivalent to X asset, the amount of sy
he can mint must be X * exchangeRate / 1e18
* @dev SYUtils's assetToSy & syToAsset should be used instead of raw multiplication
& division
*/
function exchangeRate() external view returns (uint256 res);
/**
* @notice claims reward for (`user`)
* @param user the user receiving their rewards
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
* @dev
* Emits a `ClaimRewards` event
* See {getRewardTokens} for list of reward tokens
*/
function claimRewards(address user) external returns (uint256[] memory rewardAmounts);
/**
* @notice get the amount of unclaimed rewards for (`user`)
* @param user the user to check for
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
*/
function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts);
function rewardIndexesCurrent() external returns (uint256[] memory indexes);
function rewardIndexesStored() external view returns (uint256[] memory indexes);
/**
* @notice returns the list of reward token addresses
*/
function getRewardTokens() external view returns (address[] memory);
/**
* @notice returns the address of the underlying yield token
*/
function yieldToken() external view returns (address);
/**
* @notice returns all tokens that can mint this SY
*/
function getTokensIn() external view returns (address[] memory res);
/**
* @notice returns all tokens that can be redeemed by this SY
*/
function getTokensOut() external view returns (address[] memory res);
function isValidTokenIn(address token) external view returns (bool);
function isValidTokenOut(address token) external view returns (bool);
function previewDeposit(
address tokenIn,
uint256 amountTokenToDeposit
) external view returns (uint256 amountSharesOut);
function previewRedeem(
address tokenOut,
uint256 amountSharesToRedeem
) external view returns (uint256 amountTokenOut);
/**
* @notice This function contains information to interpret what the asset is
* @return assetType the type of the asset (0 for ERC20 tokens, 1 for AMM liquidity tokens,
2 for bridged yield bearing tokens like wstETH, rETH on Arbi whose the underlying asset doesn't exist on the chain)
* @return assetAddress the address of the asset
* @return assetDecimals the decimals of the asset
*/
function assetInfo() external view returns (AssetType assetType, address assetAddress, uint8 assetDecimals);
}
PYIndex.sol 50 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../../interfaces/IPYieldToken.sol";
import "../../interfaces/IPPrincipalToken.sol";
import "./SYUtils.sol";
import "../libraries/math/PMath.sol";
type PYIndex is uint256;
library PYIndexLib {
using PMath for uint256;
using PMath for int256;
function newIndex(IPYieldToken YT) internal returns (PYIndex) {
return PYIndex.wrap(YT.pyIndexCurrent());
}
function syToAsset(PYIndex index, uint256 syAmount) internal pure returns (uint256) {
return SYUtils.syToAsset(PYIndex.unwrap(index), syAmount);
}
function assetToSy(PYIndex index, uint256 assetAmount) internal pure returns (uint256) {
return SYUtils.assetToSy(PYIndex.unwrap(index), assetAmount);
}
function assetToSyUp(PYIndex index, uint256 assetAmount) internal pure returns (uint256) {
return SYUtils.assetToSyUp(PYIndex.unwrap(index), assetAmount);
}
function syToAssetUp(PYIndex index, uint256 syAmount) internal pure returns (uint256) {
uint256 _index = PYIndex.unwrap(index);
return SYUtils.syToAssetUp(_index, syAmount);
}
function syToAsset(PYIndex index, int256 syAmount) internal pure returns (int256) {
int256 sign = syAmount < 0 ? int256(-1) : int256(1);
return sign * (SYUtils.syToAsset(PYIndex.unwrap(index), syAmount.abs())).Int();
}
function assetToSy(PYIndex index, int256 assetAmount) internal pure returns (int256) {
int256 sign = assetAmount < 0 ? int256(-1) : int256(1);
return sign * (SYUtils.assetToSy(PYIndex.unwrap(index), assetAmount.abs())).Int();
}
function assetToSyUp(PYIndex index, int256 assetAmount) internal pure returns (int256) {
int256 sign = assetAmount < 0 ? int256(-1) : int256(1);
return sign * (SYUtils.assetToSyUp(PYIndex.unwrap(index), assetAmount.abs())).Int();
}
}
SYUtils.sol 22 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
library SYUtils {
uint256 internal constant ONE = 1e18;
function syToAsset(uint256 exchangeRate, uint256 syAmount) internal pure returns (uint256) {
return (syAmount * exchangeRate) / ONE;
}
function syToAssetUp(uint256 exchangeRate, uint256 syAmount) internal pure returns (uint256) {
return (syAmount * exchangeRate + ONE - 1) / ONE;
}
function assetToSy(uint256 exchangeRate, uint256 assetAmount) internal pure returns (uint256) {
return (assetAmount * ONE) / exchangeRate;
}
function assetToSyUp(uint256 exchangeRate, uint256 assetAmount) internal pure returns (uint256) {
return (assetAmount * ONE + exchangeRate - 1) / exchangeRate;
}
}
IPInterestManagerYT.sol 8 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IPInterestManagerYT {
event CollectInterestFee(uint256 amountInterestFee);
function userInterest(address user) external view returns (uint128 lastPYIndex, uint128 accruedInterest);
}
IPMarketSwapCallback.sol 6 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
interface IPMarketSwapCallback {
function swapCallback(int256 ptToAccount, int256 syToAccount, bytes calldata data) external;
}
IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
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);
}
Write Contract 2 functions
These functions modify contract state and require a wallet transaction to execute.
limitRouterCallback 0xeb3a7d47
uint256 actualMaking
uint256 actualTaking
uint256 totalFee
bytes data
returns: bytes
swapCallback 0xfa483e72
int256 ptToAccount
int256 syToAccount
bytes data
Recent Transactions
This address has 1 on-chain transactions, but only 1.4% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →