122 lines
4.7 KiB
Go
122 lines
4.7 KiB
Go
package aave
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
"time"
|
|
|
|
"git.lehouerou.net/laurent/evm"
|
|
"git.lehouerou.net/laurent/evm/aave/contracts"
|
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/pkg/errors"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
const (
|
|
SECONDSPERYEAR = 31536000
|
|
)
|
|
|
|
type LendingPool struct {
|
|
client evm.Client
|
|
contract *contracts.LendingPool
|
|
}
|
|
|
|
func NewLendingPool(client evm.Client, address common.Address) (*LendingPool, error) {
|
|
contract, err := contracts.NewLendingPool(address, client)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "init contract")
|
|
}
|
|
|
|
return &LendingPool{
|
|
client: client,
|
|
contract: contract,
|
|
}, nil
|
|
}
|
|
|
|
type UserAccountData struct {
|
|
TotalCollateralETH decimal.Decimal
|
|
TotalDebtETH decimal.Decimal
|
|
AvailableBorrowsETH decimal.Decimal
|
|
CurrentLiquidationThreshold decimal.Decimal
|
|
CurrentLtv decimal.Decimal
|
|
MaxLtv decimal.Decimal
|
|
HealthFactor decimal.Decimal
|
|
}
|
|
|
|
func (uad UserAccountData) BorrowAmountToLtv(ltv decimal.Decimal) decimal.Decimal {
|
|
return uad.TotalCollateralETH.Mul(ltv).Div(decimal.NewFromInt(100)).Sub(uad.TotalDebtETH)
|
|
}
|
|
|
|
func (lp *LendingPool) UserAccountDataForAddress(address common.Address) (UserAccountData, error) {
|
|
uad, err := lp.contract.GetUserAccountData(&bind.CallOpts{}, address)
|
|
if err != nil {
|
|
return UserAccountData{}, errors.Wrap(err, "calling contract")
|
|
}
|
|
res := UserAccountData{
|
|
TotalCollateralETH: decimal.NewFromBigInt(uad.TotalCollateralETH, -8),
|
|
TotalDebtETH: decimal.NewFromBigInt(uad.TotalDebtETH, -8),
|
|
AvailableBorrowsETH: decimal.NewFromBigInt(uad.AvailableBorrowsETH, -8),
|
|
CurrentLiquidationThreshold: decimal.NewFromBigInt(uad.CurrentLiquidationThreshold, -2),
|
|
MaxLtv: decimal.NewFromBigInt(uad.Ltv, -2),
|
|
HealthFactor: decimal.NewFromBigInt(uad.HealthFactor, -18),
|
|
}
|
|
res.CurrentLtv = res.TotalDebtETH.Div(res.TotalCollateralETH).Mul(decimal.NewFromInt(100))
|
|
return res, nil
|
|
}
|
|
|
|
type ReserveData struct {
|
|
LiquidityIndex decimal.Decimal
|
|
VariableBorrowIndex decimal.Decimal
|
|
CurrentLiquidityRate decimal.Decimal
|
|
CurrentVariableBorrowRate decimal.Decimal
|
|
CurrentStableBorrowRate decimal.Decimal
|
|
LastUpdateTimestamp time.Time
|
|
ATokenAddress common.Address
|
|
StableDebtTokenAddress common.Address
|
|
VariableDebtTokenAddress common.Address
|
|
InterestRateStrategyAddress common.Address
|
|
Id uint8
|
|
}
|
|
|
|
func (lp *LendingPool) ReserveData(asset evm.Token) (ReserveData, error) {
|
|
rd, err := lp.contract.GetReserveData(&bind.CallOpts{}, asset.Address())
|
|
if err != nil {
|
|
return ReserveData{}, errors.Wrap(err, "calling contract")
|
|
}
|
|
res := ReserveData{
|
|
LiquidityIndex: decimal.NewFromBigInt(rd.LiquidityIndex, -27),
|
|
VariableBorrowIndex: decimal.NewFromBigInt(rd.VariableBorrowIndex, -27),
|
|
CurrentLiquidityRate: decimal.NewFromBigInt(rd.CurrentLiquidityRate, -27),
|
|
CurrentVariableBorrowRate: decimal.NewFromBigInt(rd.CurrentVariableBorrowRate, -27),
|
|
CurrentStableBorrowRate: decimal.NewFromBigInt(rd.CurrentStableBorrowRate, -27),
|
|
LastUpdateTimestamp: time.Unix(rd.LastUpdateTimestamp.Int64(), 0),
|
|
ATokenAddress: rd.ATokenAddress,
|
|
StableDebtTokenAddress: rd.StableDebtTokenAddress,
|
|
VariableDebtTokenAddress: rd.VariableDebtTokenAddress,
|
|
InterestRateStrategyAddress: rd.InterestRateStrategyAddress,
|
|
Id: rd.Id,
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (lp *LendingPool) Borrow(ctx context.Context, asset evm.Token, amount decimal.Decimal, opts ...evm.ExecutionOption) (evm.Transaction, error) {
|
|
return lp.client.Execute(ctx, func(ctx context.Context, opts *evm.TransactOpts) (*types.Transaction, error) {
|
|
return lp.contract.Borrow(opts.TransactOpts, asset.Address(), asset.ValueToBigInt(amount), big.NewInt(2), 0, lp.client.PublicAddress())
|
|
}, opts...)
|
|
}
|
|
|
|
func (lp *LendingPool) Repay(ctx context.Context, asset evm.Token, amount decimal.Decimal, opts ...evm.ExecutionOption) (evm.Transaction, error) {
|
|
balance, err := asset.Balance()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "getting token balance")
|
|
}
|
|
if balance.LessThan(amount) {
|
|
return nil, errors.Wrapf(err, "balance of %s insufficient. need %s have %s", asset.Symbol(), amount, balance)
|
|
}
|
|
return lp.client.Execute(ctx, func(ctx context.Context, opts *evm.TransactOpts) (*types.Transaction, error) {
|
|
return lp.contract.Repay(opts.TransactOpts, asset.Address(), asset.ValueToBigInt(amount), big.NewInt(2), lp.client.PublicAddress())
|
|
}, opts...)
|
|
}
|