async function CompoundLib({abi, address, uint, array, Enum, Struct}, env, vars) {
const {
Comptroller = 'Comptroller',
defaultFrom = address('$0')
} = vars || {};
const EVM = await env.library(EVMLib)
const ERC20 = await env.library(ERC20Lib)
const LiquidityStat = new Struct('LiquidityStat', {error: uint, liquidity: uint, shortfall: uint})
const $enterMarkets = (markets) => ({send: 'enterMarkets', to: Comptroller, args: [array(address)(markets.map(address))]})
const $exitMarket = (market) => ({send: 'exitMarket', to: Comptroller, args: [address(market)]})
const $getAccountLiquidity = (account) => ({call: 'getAccountLiquidity', on: Comptroller, args: [address(account)], returns: LiquidityStat})
const $underlying = (cToken) => ({call: 'underlying', on: cToken, args: [], returns: maybe('address')})
const $mint = (cToken, amount) => ({send: 'mint', to: cToken, args: [amount]})
const $redeem = (cToken, tokens) => ({send: 'redeem', to: cToken, args: [tokens]})
const $redeemUnderlying = (cToken, amount) => ({send: 'redeemUnderlying', to: cToken, args: [amount]})
const $borrow = (cToken, amount) => ({send: 'borrow', to: cToken, args: [amount]})
const $repayBorrow = (cToken, amount) => ({send: 'repayBorrow', to: cToken, args: [amount]})
const $repayBorrowBehalf = (cToken, borrower, repayAmount) => (
{send: 'repayBrorowBehalf', to: cToken, args: [borrower, repayAmount]}
)
const $liquidateBorrow = (cTokenBorrowed, borrower, repayAmount, cTokenCollateral) => (
{send: 'liquidateBorrow', to: cTokenBorrowed, args: [borrower, repayAmount, address(cTokenCollateral)]}
)
const $mintEth = (cToken, amount) => ({send: 'mint', to: cToken, value: amount})
const $repayBorrowEth = (cToken, amount) => ({send: 'repayBorrow', to: cToken, value: amount})
const $repayBorrowBehalfEth = (cToken, borrower, repayAmount) => (
{send: 'repayBorrowBehalf', to: cToken, args: [borrower], value: repayAmount}
)
const $liquidateBorrowEth = (cTokenBorrowed, borrower, repayAmount, cTokenCollateral) => (
{send: 'liquidateBorrow', to: cTokenBorrowed, args: [borrower, address(cTokenCollateral)], value: repayAmount}
)
const $$basicMint = (cToken, mintAmount, from = defaultFrom) => [
async (world) => {
const underlying = await world.exec($underlying(cToken))
if (underlying)
return world.exec([
{...ERC20.$approve(underlying, cToken, mintAmount), from},
{...$mint(cToken, mintAmount), from, emits: 'Mint'}
])
return world.exec({...$mintEth(cToken, mintAmount), from, emits: 'Mint'})
},
]
const $$basicRedeem = (cToken, mintAmount, redeemAmount, from = defaultFrom) => [
$$basicMint(cToken, mintAmount, from),
{...$redeemUnderlying(cToken, redeemAmount), from, emits: 'Redeem'}
]
const $$basicBorrow = (cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, from = defaultFrom) => [
$$basicMint(cTokenCollateral, mintAmount, from),
{...$enterMarkets([cTokenCollateral]), from},
{...$getAccountLiquidity(from), expect: r => r.liquidity >= borrowAmount},
{...$borrow(cTokenBorrowed, borrowAmount), from, emits: 'Borrow'}
]
const $$basicRepay = (cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, repayAmount, from = defaultFrom) => [
$$basicBorrow(cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, from),
async (world) => {
const underlying = await world.exec($underlying(cTokenBorrowed))
if (underlying)
return world.exec([
{...ERC20.$approve(underlying, cTokenBorrowed, repayAmount), from},
{...$repayBorrow(cTokenBorrowed, repayAmount), from, emits: 'RepayBorrow'}
])
return world.exec({...$repayBorrowEth(cTokenBorrowed, repayAmount), from, emits: 'RepayBorrow'})
}
]
const $$basicRepayBehalf = (borrower, cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, repayAmount, from = defaultFrom) => [
$$basicBorrow(cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, from),
async (world) => {
const underlying = await world.exec($underlying(cTokenBorrowed))
if (underlying)
return world.exec([
{...ERC20.$approve(underlying, cTokenBorrowed, repayAmount), from},
{...$repayBorrowBehalf(cTokenBorrowed, borrower, repayAmount), from, emits: 'RepayBorrow'}
])
return world.exec(
{...$repayBorrowBehalfEth(cTokenBorrowed, borrower, repayAmount), from, emits: 'RepayBorrow'}
)
}
]
const $$basicLiquidate = (borrower, cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, repayAmount, from = defaultFrom, interestBlocks = 10e6) => [
$$basicBorrow(cTokenCollateral, mintAmount, cTokenBorrowed, borrowAmount, borrower),
EVM.$$advanceBlocks(interestBlocks),
async (world) => {
const underlying = await world.exec($underlying(cTokenBorrowed))
if (underlying)
return world.exec([
{...ERC20.$approve(underlying, cTokenBorrowed, repayAmount), from},
{...$liquidateBorrow(cTokenBorrowed, borrower, repayAmount, cTokenCollateral), from, emits: 'LiquidateBorrow'}
])
return world.exec(
{...$liquidateBorrowEth(cTokenBorrowed, borrower, repayAmount, cTokenCollateral), from, emits: 'LiquidateBorrow'}
)
}
]
return {
...ERC20,
$enterMarkets,
$exitMarket,
$getAccountLiquidity,
$underlying,
$mint,
$redeem,
$redeemUnderlying,
$borrow,
$repayBorrow,
$repayBorrowBehalf,
$liquidateBorrow,
$mintEth,
$repayBorrowEth,
$repayBorrowBehalfEth,
$liquidateBorrowEth,
$$basicMint,
$$basicRedeem,
$$basicBorrow,
$$basicRepay,
$$basicRepayBehalf,
$$basicLiquidate
}
}