// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
library Cast {
/// @dev Safely cast an uint256 to an uint128
/// @param n the u256 to cast to u128
function u128(uint256 n) internal pure returns (uint128) {
if (n > type(uint128).max) {
revert();
}
return uint128(n);
}
}
// SPDX-License-Identifier: MIT
// Inspired on token.sol from DappHub. Natspec adpated from OpenZeppelin.
pragma solidity 0.8.16;
import 'src/interfaces/IERC20Metadata.sol';
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Calls to {transferFrom} do not check for allowance if the caller is the owner
* of the funds. This allows to reduce the number of approvals that are necessary.
*
* Finally, {transferFrom} does not decrease the allowance if it is set to
* type(uint256).max. This reduces the gas costs without any likely impact.
*/
contract ERC20 is IERC20Metadata {
uint256 internal _totalSupply;
mapping(address => uint256) internal _balanceOf;
mapping(address => mapping(address => uint256)) internal _allowance;
string public override name = '???';
string public override symbol = '???';
uint8 public override decimals = 18;
/**
* @dev Sets the values for {name}, {symbol} and {decimals}.
*/
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) {
name = name_;
symbol = symbol_;
decimals = decimals_;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() external view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address guy)
external
view
virtual
override
returns (uint256)
{
return _balanceOf[guy];
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender)
external
view
virtual
override
returns (uint256)
{
return _allowance[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*/
function approve(address spender, uint256 wad)
external
virtual
override
returns (bool)
{
return _setAllowance(msg.sender, spender, wad);
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - the caller must have a balance of at least `wad`.
*/
function transfer(address dst, uint256 wad)
external
virtual
override
returns (bool)
{
return _transfer(msg.sender, dst, wad);
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `src` must have a balance of at least `wad`.
* - the caller is not `src`, it must have allowance for ``src``'s tokens of at least
* `wad`.
*/
/// if_succeeds {:msg "TransferFrom - decrease allowance"} msg.sender != src ==> old(_allowance[src][msg.sender]) >= wad;
function transferFrom(
address src,
address dst,
uint256 wad
) external virtual override returns (bool) {
_decreaseAllowance(src, wad);
return _transfer(src, dst, wad);
}
/**
* @dev Moves tokens `wad` from `src` to `dst`.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `src` must have a balance of at least `amount`.
*/
/// if_succeeds {:msg "Transfer - src decrease"} old(_balanceOf[src]) >= _balanceOf[src];
/// if_succeeds {:msg "Transfer - dst increase"} _balanceOf[dst] >= old(_balanceOf[dst]);
/// if_succeeds {:msg "Transfer - supply"} old(_balanceOf[src]) + old(_balanceOf[dst]) == _balanceOf[src] + _balanceOf[dst];
function _transfer(
address src,
address dst,
uint256 wad
) internal virtual returns (bool) {
require(_balanceOf[src] >= wad, 'ERC20: Insufficient balance');
unchecked {
_balanceOf[src] = _balanceOf[src] - wad;
}
_balanceOf[dst] = _balanceOf[dst] + wad;
emit Transfer(src, dst, wad);
return true;
}
/**
* @dev Sets the allowance granted to `spender` by `owner`.
*
* Emits an {Approval} event indicating the updated allowance.
*/
function _setAllowance(
address owner,
address spender,
uint256 wad
) internal virtual returns (bool) {
_allowance[owner][spender] = wad;
emit Approval(owner, spender, wad);
return true;
}
/**
* @dev Decreases the allowance granted to the caller by `src`, unless src == msg.sender or _allowance[src][msg.sender] == MAX
*
* Emits an {Approval} event indicating the updated allowance, if the allowance is updated.
*
* Requirements:
*
* - `spender` must have allowance for the caller of at least
* `wad`, unless src == msg.sender
*/
/// if_succeeds {:msg "Decrease allowance - underflow"} old(_allowance[src][msg.sender]) <= _allowance[src][msg.sender];
function _decreaseAllowance(address src, uint256 wad)
internal
virtual
returns (bool)
{
if (src != msg.sender) {
uint256 allowed = _allowance[src][msg.sender];
if (allowed != type(uint256).max) {
require(allowed >= wad, 'ERC20: Insufficient approval');
unchecked {
_setAllowance(src, msg.sender, allowed - wad);
}
}
}
return true;
}
/** @dev Creates `wad` tokens and assigns them to `dst`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*/
/// if_succeeds {:msg "Mint - balance overflow"} old(_balanceOf[dst]) >= _balanceOf[dst];
/// if_succeeds {:msg "Mint - supply overflow"} old(_totalSupply) >= _totalSupply;
function _mint(address dst, uint256 wad) internal virtual returns (bool) {
_balanceOf[dst] = _balanceOf[dst] + wad;
_totalSupply = _totalSupply + wad;
emit Transfer(address(0), dst, wad);
return true;
}
/**
* @dev Destroys `wad` tokens from `src`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `src` must have at least `wad` tokens.
*/
/// if_succeeds {:msg "Burn - balance underflow"} old(_balanceOf[src]) <= _balanceOf[src];
/// if_succeeds {:msg "Burn - supply underflow"} old(_totalSupply) <= _totalSupply;
function _burn(address src, uint256 wad) internal virtual returns (bool) {
unchecked {
require(_balanceOf[src] >= wad, 'ERC20: Insufficient balance');
_balanceOf[src] = _balanceOf[src] - wad;
_totalSupply = _totalSupply - wad;
emit Transfer(src, address(0), wad);
}
return true;
}
}
// SPDX-License-Identifier: MIT
// Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/53516bc555a454862470e7860a9b5254db4d00f5/contracts/token/ERC20/ERC20Permit.sol
pragma solidity 0.8.16;
import 'src/tokens/ERC20.sol';
import 'src/interfaces/IERC2612.sol';
/**
* @dev Extension of {ERC20} that allows token holders to use their tokens
* without sending any transactions by setting {IERC20-allowance} with a
* signature using the {permit} method, and then spend them via
* {IERC20-transferFrom}.
*
* The {permit} signature mechanism conforms to the {IERC2612} interface.
*/
abstract contract ERC20Permit is ERC20, IERC2612 {
mapping(address => uint256) public override nonces;
bytes32 public immutable PERMIT_TYPEHASH =
keccak256(
'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
);
bytes32 private immutable _DOMAIN_SEPARATOR;
uint256 public immutable deploymentChainId;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) ERC20(name_, symbol_, decimals_) {
deploymentChainId = block.chainid;
_DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid);
}
/// @dev Calculate the DOMAIN_SEPARATOR.
function _calculateDomainSeparator(uint256 chainId)
private
view
returns (bytes32)
{
return
keccak256(
abi.encode(
keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
),
keccak256(bytes(name)),
keccak256(bytes(version())),
chainId,
address(this)
)
);
}
/// @dev Return the DOMAIN_SEPARATOR.
function DOMAIN_SEPARATOR() external view returns (bytes32) {
return
block.chainid == deploymentChainId
? _DOMAIN_SEPARATOR
: _calculateDomainSeparator(block.chainid);
}
/// @dev Setting the version as a function so that it can be overriden
function version() public pure virtual returns (string memory) {
return '1';
}
/**
* @dev See {IERC2612-permit}.
*
* In cases where the free option is not a concern, deadline can simply be
* set to uint(-1), so it should be seen as an optional parameter
*/
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override {
require(deadline >= block.timestamp, 'ERC20Permit: expired deadline');
bytes32 hashStruct = keccak256(
abi.encode(
PERMIT_TYPEHASH,
owner,
spender,
amount,
nonces[owner]++,
deadline
)
);
bytes32 hash = keccak256(
abi.encodePacked(
'\x19\x01',
block.chainid == deploymentChainId
? _DOMAIN_SEPARATOR
: _calculateDomainSeparator(block.chainid),
hashStruct
)
);
address signer = ecrecover(hash, v, r, s);
require(
signer != address(0) && signer == owner,
'ERC20Permit: invalid signature'
);
_setAllowance(owner, spender, amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
import 'src/tokens/ERC20Permit.sol';
import 'src/interfaces/IERC5095.sol';
import 'src/interfaces/IRedeemer.sol';
import 'src/interfaces/IMarketPlace.sol';
import 'src/interfaces/IYield.sol';
import 'src/errors/Exception.sol';
import 'src/lib/Cast.sol';
import 'src/lib/Safe.sol';
contract ERC5095 is ERC20Permit, IERC5095 {
/// @dev unix timestamp when the ERC5095 token can be redeemed
uint256 public immutable override maturity;
/// @dev address of the ERC20 token that is returned on ERC5095 redemption
address public immutable override underlying;
/// @dev address of the minting authority
address public immutable lender;
/// @dev address of the "marketplace" YieldSpace AMM router
address public immutable marketplace;
///@dev Interface to interact with the pool
address public pool;
/// @dev address and interface for an external custody contract (necessary for some project's backwards compatability)
address public immutable redeemer;
/// @notice ensures that only a certain address can call the function
/// @param a address that msg.sender must be to be authorized
modifier authorized(address a) {
if (msg.sender != a) {
revert Exception(0, 0, 0, msg.sender, a);
}
_;
}
constructor(
address _underlying,
uint256 _maturity,
address _redeemer,
address _lender,
address _marketplace,
string memory name_,
string memory symbol_,
uint8 decimals_
) ERC20Permit(name_, symbol_, decimals_) {
underlying = _underlying;
maturity = _maturity;
redeemer = _redeemer;
lender = _lender;
marketplace = _marketplace;
pool = address(0);
}
/// @notice Allows the marketplace to set the pool
/// @param p Address of the pool
/// @return bool True if successful
function setPool(address p)
external
authorized(marketplace)
returns (bool)
{
pool = p;
return true;
}
/// @notice Allows the marketplace to spend underlying, principal tokens held by the token
/// @dev This is necessary when MarketPlace calls pool methods to swap tokens
/// @return True if successful
function approveMarketPlace()
external
authorized(marketplace)
returns (bool)
{
// Approve the marketplace to spend the token's underlying
Safe.approve(IERC20(underlying), marketplace, type(uint256).max);
// Approve the marketplace to spend illuminate PTs
Safe.approve(IERC20(address(this)), marketplace, type(uint256).max);
return true;
}
/// @notice Post or at maturity, converts an amount of principal tokens to an amount of underlying that would be returned.
/// @param s The amount of principal tokens to convert
/// @return uint256 The amount of underlying tokens returned by the conversion
function convertToUnderlying(uint256 s)
external
view
override
returns (uint256)
{
if (block.timestamp < maturity) {
return previewRedeem(s);
}
return s;
}
/// @notice Post or at maturity, converts a desired amount of underlying tokens returned to principal tokens needed.
/// @param a The amount of underlying tokens to convert
/// @return uint256 The amount of principal tokens returned by the conversion
function convertToShares(uint256 a)
external
view
override
returns (uint256)
{
if (block.timestamp < maturity) {
return previewWithdraw(a);
}
return a;
}
/// @notice Returns user's PT balance
/// @param o The address of the owner for which redemption is calculated
/// @return uint256 The maximum amount of principal tokens that `owner` can redeem.
function maxRedeem(address o) external view override returns (uint256) {
return _balanceOf[o];
}
/// @notice Post or at maturity, returns user's PT balance. Prior to maturity, returns a previewRedeem for owner's PT balance.
/// @param o The address of the owner for which withdrawal is calculated
/// @return uint256 maximum amount of underlying tokens that `owner` can withdraw.
function maxWithdraw(address o) external view override returns (uint256) {
if (block.timestamp < maturity) {
return previewRedeem(_balanceOf[o]);
}
return _balanceOf[o];
}
/// @notice After maturity, returns 0. Prior to maturity, returns the amount of `shares` when spending `a` in underlying on a YieldSpace AMM.
/// @param a The amount of underlying spent
/// @return uint256 The amount of PT purchased by spending `a` of underlying
function previewDeposit(uint256 a) public view returns (uint256) {
if (block.timestamp < maturity) {
return IYield(pool).sellBasePreview(Cast.u128(a));
}
return 0;
}
/// @notice After maturity, returns 0. Prior to maturity, returns the amount of `assets` in underlying spent on a purchase of `s` in PT on a YieldSpace AMM.
/// @param s The amount of principal tokens bought in the simulation
/// @return uint256 The amount of underlying required to purchase `s` of PT
function previewMint(uint256 s) public view returns (uint256) {
if (block.timestamp < maturity) {
return IYield(pool).buyFYTokenPreview(Cast.u128(s));
}
return 0;
}
/// @notice Post or at maturity, simulates the effects of redemption. Prior to maturity, returns the amount of `assets` from a sale of `s` PTs on a YieldSpace AMM.
/// @param s The amount of principal tokens redeemed in the simulation
/// @return uint256 The amount of underlying returned by `s` of PT redemption
function previewRedeem(uint256 s) public view override returns (uint256) {
if (block.timestamp >= maturity) {
// After maturity, the amount redeemed is based on the Redeemer contract's holdings of the underlying
return
Cast.u128(
s *
Cast.u128(
IRedeemer(redeemer).holdings(underlying, maturity)
)
) / _totalSupply;
}
// Prior to maturity, return a a preview of a swap on the pool
return IYield(pool).sellFYTokenPreview(Cast.u128(s));
}
/// @notice Post or at maturity, simulates the effects of withdrawal at the current block. Prior to maturity, simulates the amount of PTs necessary to receive `a` in underlying from the sale of PTs on a YieldSpace AMM.
/// @param a The amount of underlying tokens withdrawn in the simulation
/// @return uint256 The amount of principal tokens required for the withdrawal of `a`
function previewWithdraw(uint256 a) public view override returns (uint256) {
if (block.timestamp >= maturity) {
// After maturity, the amount redeemed is based on the Redeemer contract's holdings of the underlying
return
(a * _totalSupply) /
IRedeemer(redeemer).holdings(underlying, maturity);
}
// Prior to maturity, return a a preview of a swap on the pool
return IYield(pool).buyBasePreview(Cast.u128(a));
}
/// @notice Before maturity spends `a` of underlying, and sends PTs to `r`. Post or at maturity, reverts.
/// @param a The amount of underlying tokens deposited
/// @param r The receiver of the principal tokens
/// @param m Minimum number of shares that the user will receive
/// @return uint256 The amount of principal tokens purchased
function deposit(
uint256 a,
address r,
uint256 m
) external returns (uint256) {
// Execute the deposit
return _deposit(r, a, m);
}
/// @notice Before maturity spends `assets` of underlying, and sends `shares` of PTs to `receiver`. Post or at maturity, reverts.
/// @param a The amount of underlying tokens deposited
/// @param r The receiver of the principal tokens
/// @return uint256 The amount of principal tokens burnt by the withdrawal
function deposit(uint256 a, address r) external override returns (uint256) {
// Execute the deposit
return _deposit(r, a, 0);
}
/// @notice Before maturity mints `s` of PTs to `r` by spending underlying. Post or at maturity, reverts.
/// @param s The amount of shares being minted
/// @param r The receiver of the underlying tokens being withdrawn
/// @param m Maximum amount of underlying that the user will spend
/// @return uint256 The amount of principal tokens purchased
function mint(
uint256 s,
address r,
uint256 m
) external returns (uint256) {
// Execute the mint
return _mint(r, s, m);
}
/// @notice Before maturity mints `shares` of PTs to `receiver` by spending underlying. Post or at maturity, reverts.
/// @param s The amount of shares being minted
/// @param r The receiver of the underlying tokens being withdrawn
/// @return uint256 The amount of principal tokens purchased
function mint(uint256 s, address r) external override returns (uint256) {
// Execute the mint
return _mint(r, s, type(uint128).max);
}
/// @notice At or after maturity, burns PTs from owner and sends `a` underlying to `r`. Before maturity, sends `a` by selling shares of PT on a YieldSpace AMM.
/// @param a The amount of underlying tokens withdrawn
/// @param r The receiver of the underlying tokens being withdrawn
/// @param o The owner of the underlying tokens
/// @param m Maximum amount of PTs to be sold
/// @return uint256 The amount of principal tokens burnt by the withdrawal
function withdraw(
uint256 a,
address r,
address o,
uint256 m
) external returns (uint256) {
// Execute the withdrawal
return _withdraw(a, r, o, m);
}
/// @notice At or after maturity, burns PTs from owner and sends `a` underlying to `r`. Before maturity, sends `a` by selling shares of PT on a YieldSpace AMM.
/// @param a The amount of underlying tokens withdrawn
/// @param r The receiver of the underlying tokens being withdrawn
/// @param o The owner of the underlying tokens
/// @return uint256 The amount of principal tokens burnt by the withdrawal
function withdraw(
uint256 a,
address r,
address o
) external override returns (uint256) {
// Execute the withdrawal
return _withdraw(a, r, o, type(uint128).max);
}
/// @notice At or after maturity, burns exactly `s` of Principal Tokens from `o` and sends underlying tokens to `r`. Before maturity, sends underlying by selling `s` of PT on a YieldSpace AMM.
/// @param s The number of shares to be burned in exchange for the underlying asset
/// @param r The receiver of the underlying tokens being withdrawn
/// @param o Address of the owner of the shares being burned
/// @param m Minimum amount of underlying that must be received
/// @return uint256 The amount of underlying tokens distributed by the redemption
function redeem(
uint256 s,
address r,
address o,
uint256 m
) external returns (uint256) {
// Execute the redemption
return _redeem(s, r, o, m);
}
/// @notice At or after maturity, burns exactly `shares` of Principal Tokens from `owner` and sends `assets` of underlying tokens to `receiver`. Before maturity, sells `s` of PT on a YieldSpace AMM.
/// @param s The number of shares to be burned in exchange for the underlying asset
/// @param r The receiver of the underlying tokens being withdrawn
/// @param o Address of the owner of the shares being burned
/// @return uint256 The amount of underlying tokens distributed by the redemption
function redeem(
uint256 s,
address r,
address o
) external override returns (uint256) {
// Execute the redemption
return _redeem(s, r, o, 0);
}
/// @param f Address to burn from
/// @param a Amount to burn
/// @return bool true if successful
function authBurn(address f, uint256 a)
external
authorized(redeemer)
returns (bool)
{
_burn(f, a);
return true;
}
/// @param t Address recieving the minted amount
/// @param a The amount to mint
/// @return bool True if successful
function authMint(address t, uint256 a)
external
authorized(lender)
returns (bool)
{
_mint(t, a);
return true;
}
/// @param o Address of the owner of the tokens
/// @param s Address of the spender
/// @param a Amount to be approved
function authApprove(
address o,
address s,
uint256 a
) external authorized(redeemer) returns (bool) {
_allowance[o][s] = a;
return true;
}
function _deposit(
address r,
uint256 a,
uint256 m
) internal returns (uint256) {
// Revert if called at or after maturity
if (block.timestamp >= maturity) {
revert Exception(
21,
block.timestamp,
maturity,
address(0),
address(0)
);
}
// Receive the funds from the sender
Safe.transferFrom(IERC20(underlying), msg.sender, address(this), a);
// Sell the underlying assets for PTs
uint128 returned = IMarketPlace(marketplace).sellUnderlying(
underlying,
maturity,
Cast.u128(a),
Cast.u128(m)
);
// Pass the received shares onto the intended receiver
_transfer(address(this), r, returned);
return returned;
}
function _mint(
address r,
uint256 s,
uint256 m
) internal returns (uint256) {
// Revert if called at or after maturity
if (block.timestamp >= maturity) {
revert Exception(
21,
block.timestamp,
maturity,
address(0),
address(0)
);
}
// Determine how many underlying tokens are needed to mint the shares
uint256 required = IYield(pool).buyFYTokenPreview(Cast.u128(s));
// Transfer the underlying to the token
Safe.transferFrom(
IERC20(underlying),
msg.sender,
address(this),
required
);
// Swap the underlying for principal tokens via the pool
uint128 sold = IMarketPlace(marketplace).buyPrincipalToken(
underlying,
maturity,
Cast.u128(s),
Cast.u128(m)
);
// Transfer the principal tokens to the desired receiver
_transfer(address(this), r, s);
return sold;
}
function _withdraw(
uint256 a,
address r,
address o,
uint256 m
) internal returns (uint256) {
// Determine how many principal tokens are needed to purchase the underlying
uint256 needed = previewWithdraw(a);
// Pre maturity
if (block.timestamp < maturity) {
// Receive the shares from the caller
_transfer(o, address(this), needed);
// If owner is the sender, sell PT without allowance check
if (o == msg.sender) {
uint128 returned = IMarketPlace(marketplace).buyUnderlying(
underlying,
maturity,
Cast.u128(a),
Cast.u128(m)
);
// Transfer the underlying to the desired receiver
Safe.transfer(IERC20(underlying), r, a);
return returned;
} else {
// Else, sell PT with allowance check
// Get the allowance of the user spending the tokens
uint256 allowance = _allowance[o][msg.sender];
// Check for sufficient allowance
if (allowance < needed) {
revert Exception(20, allowance, a, address(0), address(0));
}
// Update the caller's allowance
_allowance[o][msg.sender] = allowance - needed;
// Sell the principal tokens for underlying
uint128 returned = IMarketPlace(marketplace).buyUnderlying(
underlying,
maturity,
Cast.u128(a),
Cast.u128(m)
);
// Transfer the underlying to the desired receiver
Safe.transfer(IERC20(underlying), r, returned);
return returned;
}
}
// Post maturity
else {
// If owner is the sender, redeem PT without allowance check
if (o == msg.sender) {
// Execute the redemption to the desired receiver
return
IRedeemer(redeemer).authRedeem(
underlying,
maturity,
msg.sender,
r,
needed
);
} else {
// Get the allowance of the user spending the tokens
uint256 allowance = _allowance[o][msg.sender];
// Check for sufficient allowance
if (allowance < needed) {
revert Exception(
20,
allowance,
needed,
address(0),
address(0)
);
}
// Update the callers's allowance
_allowance[o][msg.sender] = allowance - needed;
// Execute the redemption to the desired receiver
return
IRedeemer(redeemer).authRedeem(
underlying,
maturity,
o,
r,
needed
);
}
}
}
function _redeem(
uint256 s,
address r,
address o,
uint256 m
) internal returns (uint256) {
// Pre-maturity
if (block.timestamp < maturity) {
// Receive the funds from the user
_transfer(o, address(this), s);
// If owner is the sender, sell PT without allowance check
if (o == msg.sender) {
// Swap principal tokens for the underlying asset
uint128 returned = IMarketPlace(marketplace).sellPrincipalToken(
underlying,
maturity,
Cast.u128(s),
Cast.u128(m)
);
// Transfer underlying to the desired receiver
Safe.transfer(IERC20(underlying), r, returned);
return returned;
// Else, sell PT with allowance check
} else {
// Get the allowance of the user spending the tokens
uint256 allowance = _allowance[o][msg.sender];
// Check for sufficient allowance
if (allowance < s) {
revert Exception(20, allowance, s, address(0), address(0));
}
// Update the caller's allowance
_allowance[o][msg.sender] = allowance - s;
// Sell the principal tokens for the underlying
uint128 returned = IMarketPlace(marketplace).sellPrincipalToken(
underlying,
maturity,
Cast.u128(s),
Cast.u128(m)
);
// Transfer the underlying to the desired receiver
Safe.transfer(IERC20(underlying), r, returned);
return returned;
}
// Post-maturity
} else {
// If owner is the sender, redeem PT without allowance check
if (o == msg.sender) {
// Execute the redemption to the desired receiver
return
IRedeemer(redeemer).authRedeem(
underlying,
maturity,
msg.sender,
r,
s
);
} else {
// Get the allowance of the user spending the tokens
uint256 allowance = _allowance[o][msg.sender];
// Check for sufficient allowance
if (allowance < s) {
revert Exception(20, allowance, s, address(0), address(0));
}
// Update the caller's allowance
_allowance[o][msg.sender] = allowance - s;
// Execute the redemption to the desired receiver
return
IRedeemer(redeemer).authRedeem(
underlying,
maturity,
o,
r,
s
);
}
}
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
/// @dev A single custom error capable of indicating a wide range of detected errors by providing
/// an error code value whose string representation is documented in errors.txt, and any possible other values
/// that are pertinent to the error.
error Exception(uint8, uint256, uint256, address, address);
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Returns the number of decimals the token uses - e.g. 8, means to
* divide the token amount by 100000000 to get its user representation.
*/
function decimals() external view returns (uint8);
/**
* @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
);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
import 'src/interfaces/IERC20.sol';
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
import 'src/interfaces/IERC20Metadata.sol';
/**
* @dev Interface of the ERC2612 standard as defined in the EIP.
*
* Adds the {permit} method, which can be used to change one's
* {IERC20-allowance} without having to send a transaction, by signing a
* message. This allows users to spend tokens without having to hold Ether.
*
* See https://eips.ethereum.org/EIPS/eip-2612.
*/
interface IERC2612 is IERC20Metadata {
/**
* @dev Sets `amount` 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:
*
* - `owner` cannot be the zero address.
* - `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 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current ERC2612 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);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
import 'src/interfaces/IERC2612.sol';
interface IERC5095 is IERC2612 {
function maturity() external view returns (uint256);
function underlying() external view returns (address);
function convertToUnderlying(uint256) external view returns (uint256);
function convertToShares(uint256) external view returns (uint256);
function maxRedeem(address) external view returns (uint256);
function previewRedeem(uint256) external view returns (uint256);
function maxWithdraw(address) external view returns (uint256);
function previewWithdraw(uint256) external view returns (uint256);
function previewDeposit(uint256) external view returns (uint256);
function withdraw(
uint256,
address,
address
) external returns (uint256);
function redeem(
uint256,
address,
address
) external returns (uint256);
function deposit(uint256, address) external returns (uint256);
function mint(uint256, address) external returns (uint256);
function authMint(address, uint256) external returns (bool);
function authBurn(address, uint256) external returns (bool);
function authApprove(
address,
address,
uint256
) external returns (bool);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
interface IMarketPlace {
function markets(
address,
uint256,
uint256
) external returns (address);
function pools(address, uint256) external view returns (address);
function sellPrincipalToken(
address,
uint256,
uint128,
uint128
) external returns (uint128);
function buyPrincipalToken(
address,
uint256,
uint128,
uint128
) external returns (uint128);
function sellUnderlying(
address,
uint256,
uint128,
uint128
) external returns (uint128);
function buyUnderlying(
address,
uint256,
uint128,
uint128
) external returns (uint128);
function redeemer() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;
interface IRedeemer {
function authRedeem(
address underlying,
uint256 maturity,
address from,
address to,
uint256 amount
) external returns (uint256);
function approve(address p) external;
function holdings(address u, uint256 m) external view returns (uint256);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.16;
import 'src/interfaces/IERC20.sol';
interface IYield {
function maturity() external view returns (uint32);
function base() external view returns (IERC20);
function sellBase(address, uint128) external returns (uint128);
function sellBasePreview(uint128) external view returns (uint128);
function fyToken() external returns (address);
function sellFYToken(address, uint128) external returns (uint128);
function sellFYTokenPreview(uint128) external view returns (uint128);
function buyBase(
address,
uint128,
uint128
) external returns (uint128);
function buyBasePreview(uint128) external view returns (uint128);
function buyFYToken(
address,
uint128,
uint128
) external returns (uint128);
function buyFYTokenPreview(uint128) external view returns (uint128);
}
// SPDX-License-Identifier: UNLICENSED
// Adapted from: https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol
pragma solidity ^0.8.13;
import 'src/interfaces/IERC20.sol';
/**
@notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
@author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol)
@dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
*/
library Safe {
/// @param e Erc20 token to execute the call with
/// @param t To address
/// @param a Amount being transferred
function transfer(
IERC20 e,
address t,
uint256 a
) internal {
bool result;
assembly {
// Get a pointer to some free memory.
let pointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(
pointer,
0xa9059cbb00000000000000000000000000000000000000000000000000000000
) // Begin with the function selector.
mstore(
add(pointer, 4),
and(t, 0xffffffffffffffffffffffffffffffffffffffff)
) // Mask and append the "to" argument.
mstore(add(pointer, 36), a) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 68 because the calldata length is 4 + 32 * 2.
result := call(gas(), e, 0, pointer, 68, 0, 0)
}
require(success(result), 'transfer failed');
}
/// @param e Erc20 token to execute the call with
/// @param f From address
/// @param t To address
/// @param a Amount being transferred
function transferFrom(
IERC20 e,
address f,
address t,
uint256 a
) internal {
bool result;
assembly {
// Get a pointer to some free memory.
let pointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(
pointer,
0x23b872dd00000000000000000000000000000000000000000000000000000000
) // Begin with the function selector.
mstore(
add(pointer, 4),
and(f, 0xffffffffffffffffffffffffffffffffffffffff)
) // Mask and append the "from" argument.
mstore(
add(pointer, 36),
and(t, 0xffffffffffffffffffffffffffffffffffffffff)
) // Mask and append the "to" argument.
mstore(add(pointer, 68), a) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 100 because the calldata length is 4 + 32 * 3.
result := call(gas(), e, 0, pointer, 100, 0, 0)
}
require(success(result), 'transfer from failed');
}
/// @notice normalize the acceptable values of true or null vs the unacceptable value of false (or something malformed)
/// @param r Return value from the assembly `call()` to Erc20['selector']
function success(bool r) private pure returns (bool) {
bool result;
assembly {
// Get how many bytes the call returned.
let returnDataSize := returndatasize()
// If the call reverted:
if iszero(r) {
// Copy the revert message into memory.
returndatacopy(0, 0, returnDataSize)
// Revert with the same message.
revert(0, returnDataSize)
}
switch returnDataSize
case 32 {
// Copy the return data into memory.
returndatacopy(0, 0, returnDataSize)
// Set success to whether it returned true.
result := iszero(iszero(mload(0)))
}
case 0 {
// There was no return data.
result := 1
}
default {
// It returned some malformed input.
result := 0
}
}
return result;
}
function approve(
IERC20 token,
address to,
uint256 amount
) internal {
bool callStatus;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(
freeMemoryPointer,
0x095ea7b300000000000000000000000000000000000000000000000000000000
) // Begin with the function selector.
mstore(
add(freeMemoryPointer, 4),
and(to, 0xffffffffffffffffffffffffffffffffffffffff)
) // Mask and append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 68 because the calldata length is 4 + 32 * 2.
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), 'APPROVE_FAILED');
}
/*///////////////////////////////////////////////////////////////
INTERNAL HELPER LOGIC
//////////////////////////////////////////////////////////////*/
function didLastOptionalReturnCallSucceed(bool callStatus)
private
pure
returns (bool)
{
bool result;
assembly {
// Get how many bytes the call returned.
let returnDataSize := returndatasize()
// If the call reverted:
if iszero(callStatus) {
// Copy the revert message into memory.
returndatacopy(0, 0, returnDataSize)
// Revert with the same message.
revert(0, returnDataSize)
}
switch returnDataSize
case 32 {
// Copy the return data into memory.
returndatacopy(0, 0, returnDataSize)
// Set success to whether it returned true.
result := iszero(iszero(mload(0)))
}
case 0 {
// There was no return data.
result := 1
}
default {
// It returned some malformed input.
result := 0
}
}
return result;
}
}
{
"compilationTarget": {
"src/tokens/ERC5095.sol": "ERC5095"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":ds-test/=lib/forge-std/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"uint256","name":"_maturity","type":"uint256"},{"internalType":"address","name":"_redeemer","type":"address"},{"internalType":"address","name":"_lender","type":"address"},{"internalType":"address","name":"_marketplace","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"Exception","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"approveMarketPlace","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"},{"internalType":"address","name":"s","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"authApprove","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"f","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"authBurn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"t","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"}],"name":"authMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"}],"name":"convertToUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deploymentChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"address","name":"r","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketplace","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maturity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"o","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"},{"internalType":"address","name":"r","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"s","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"address","name":"o","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"p","type":"address"}],"name":"setPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"address","name":"o","type":"address"},{"internalType":"uint256","name":"m","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"address","name":"r","type":"address"},{"internalType":"address","name":"o","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]