- tags: Blockchain, DeFi, ETH, AAVE 收益计算
有了前面的 AAVE 收益计算,我们采用相同的思路来查看如何计算 Compound 的收益1,首先来查看 balanceOf
2
/**
* @notice Query the current positive base balance of an account or zero
* @dev Note: uses updated interest indices to calculate
* @param account The account whose balance to query
* @return The present day base balance magnitude of the account, if positive
*/
function balanceOf(address account) override public view returns (uint256) {
(uint64 baseSupplyIndex_, ) = accruedInterestIndices(getNowInternal() - lastAccrualTime);
int104 principal = userBasic[account].principal;
return principal > 0 ? presentValueSupply(baseSupplyIndex_, unsigned104(principal)) : 0;
}
这里用到两个变量:principal
和 baseSupplyIndex
,principal
可以通过 userBasic(address)
读取3,但是 baseSupplyIndex
只能通过合约读取,无法在链下获取,
仔细研究presentValueSupply
4:
/**
* @dev The principal amount projected forward by the supply index
*/
function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) {
return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE;
}
baseSupplyIndex
可以通过 balance / principal
获取,下面给出 Go 代码获取 principal
:
package main
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
"github.com/shopspring/decimal"
)
func getCompoundUserPrincipal(address string) (decimal.Decimal, error){
userAddress := common.HexToAddress(OperatorEVMAddress)
fun := []byte("userBasic(address)")
hash := crypto.NewKeccakState()
hash.Write(fun)
methodID := hash.Sum(nil)[:4]
var data []byte
data = append(data, methodID...)
data = append(data, common.LeftPadBytes(userAddress.Bytes(), 32)...)
callMsg := map[string]interface{}{
"from": userAddress,
"to": common.HexToAddress(sp.goal.FoundsToken),
"data": hexutil.Bytes(data),
}
var result string
rpcClient, err := rpc.DialHTTP(client.url)
if err != nil {
return decimal.Zero, err
}
err := rpcClient.CallContext(context.TODO(), &result, "eth_call", callMsg,nil)
if err != nil {
return decimal.Zero, err
}
// XXX: 这里不知为什么 int104 占了 uint256 的大小
principal := new(big.Int).SetBytes(common.FromHex(result[:66]))
return principal, nil
}
获取 balance
的代码就省略了,其实可以简单的 balance - principal
即可算出收益。