UPDATE
The Compound cToken API now returns the values for you. See comp_borrow_apy
and comp_supply_apy
when requesting https://api.compound.finance/api/v2/ctoken
OLD METHOD:
- Pick a supported cToken and its underlying asset
- Query https://api.compound.finance/api/v2/governance/comp
- Take the value for
supplier_daily_comp
orborrower_daily_comp
- Query https://api.compound.finance/api/v2/ctoken
- Take the value for
total_supply
orexchange_rate
andtotal_borrows
- Query https://prices.compound.finance/
- Take COMP price
In JavaScript
borrowCompApy = 100 * (Math.pow((1 + (comp_price * borrower_daily_comp / total_borrows)), 365) - 1)
supplyCompApy = 100 * (Math.pow((1 + (comp_price * supplier_daily_comp / (total_supply * exchange_rate))), 365) - 1)
// To use this script, copy it to a file on your machine. (getCompApy.js)
// Insert your Infura project ID on line 12 to access the blockchain
// Install Node.js
// Navigate to the folder of getCompApy.js using the command line
// npm init -y
// npm install @compound-finance/compound-js
// node getCompApy.js
const Compound = require('@compound-finance/compound-js');
const provider = 'https://mainnet.infura.io/v3/' + process.env.infuraApiKey;
const cTokenToGetCompApy = Compound.cUSDC; // Pick an asset
const underlyingDecimals = Compound.decimals[cTokenToGetCompApy.slice(1, 10)];
const cTokenDecimals = 8; // always 8
const comptroller = Compound.util.getAddress(Compound.Comptroller);
const opf = Compound.util.getAddress(Compound.PriceFeed);
const cTokenAddr = Compound.util.getAddress(cTokenToGetCompApy);
const apxBlockSpeedInSeconds = 13.15;
(async function() {
let compSpeed = await Compound.eth.read(
comptroller,
'function compSpeeds(address cToken) public returns (uint)',
[ cTokenAddr ],
{ provider }
);
let compPrice = await Compound.eth.read(
opf,
'function price(string memory symbol) external view returns (uint)',
[ Compound.COMP ],
{ provider }
);
let totalBorrows = await Compound.eth.read(
cTokenAddr,
'function totalBorrowsCurrent() returns (uint)',
[],
{ provider }
);
let totalSupply = await Compound.eth.read(
cTokenAddr,
'function totalSupply() returns (uint)',
[],
{ provider }
);
let exchangeRate = await Compound.eth.read(
cTokenAddr,
'function exchangeRateCurrent() returns (uint)',
[],
{ provider }
);
// Total supply needs to be converted from cTokens
const mantissa = 18 + parseInt(underlyingDecimals) - cTokenDecimals;
exchangeRate = +exchangeRate.toString() / Math.pow(10, mantissa);
compSpeed = compSpeed / 1e18; // COMP has 18 decimal places
compPrice = compPrice / 1e6; // price feed is USD price with 6 decimal places
totalBorrows = +totalBorrows.toString() / (Math.pow(10, underlyingDecimals));
totalSupply = (+totalSupply.toString() * exchangeRate) / (Math.pow(10, underlyingDecimals));
// console.log('compSpeed:', compSpeed);
// console.log('compPrice:', compPrice);
// console.log('totalBorrows:', totalBorrows);
// console.log('totalSupply:', totalSupply);
// console.log('exchangeRate:', exchangeRate);
const compPerDay = compSpeed * parseInt((60 * 60 * 24) / apxBlockSpeedInSeconds);
const compBorrowApy = 100 * (Math.pow((1 + (compPrice * compPerDay / totalBorrows)), 365) - 1);
const compSupplyApy = 100 * (Math.pow((1 + (compPrice * compPerDay / totalSupply)), 365) - 1);
console.log('COMP Borrow APY %:', compBorrowApy);
console.log('COMP Supply APY %:', compSupplyApy);
})().catch(console.error);