-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add figure markets #15501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add figure markets #15501
Changes from all commits
4ebcd0a
eee0bd2
804e211
fe285f4
bc8aa7d
cd1647c
c18d835
03c8067
3de9eee
19a6ca7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
const { mapTokens } = require("../helper/chain/provenance") | ||
const { get } = require("../helper/http") | ||
|
||
const tokenMapper = { | ||
"HASH" : 'hash-2', | ||
"LINK": 'chainlink', | ||
"UNI": 'uniswap', | ||
"BTC": 'bitcoin', | ||
"ETH": 'ethereum', | ||
"XRP": 'ripple', | ||
"SOL": 'solana', | ||
"LRWA": 'usd-coin', | ||
"YLDS": 'uylds.fcc', | ||
"USDC": 'usd-coin', | ||
"USD": 'usd-coin', | ||
"USDT": 'tether', | ||
} | ||
|
||
// Returns all leveraged pools in Figure Markets Democratized Prime | ||
// https://www.figuremarkets.com/c/democratized-prime/lending-pools | ||
const leveragePoolsUrl = 'https://www.figuremarkets.com/service-lending/api/v1/leverage-pools?location=US' | ||
|
||
// Returns offer information for a specific asset | ||
const offersUrl = (asset) => `https://www.figuremarkets.com/service-lending/api/v1/offers?asset=${asset}&location=US` | ||
|
||
// Returns all assets, including lending facilities (specific to YLDS) | ||
const lendingFacilities = `https://www.figuremarkets.com/service-hft-exchange/api/v1/assets?page=1&size=100&include_lending_facility_assets=true` | ||
|
||
const getBalances = async () => { | ||
const balances = {} | ||
// Get all available pools | ||
const pools = (await get(leveragePoolsUrl)).map(p => p.asset) | ||
await Promise.all(pools.map(async p => { | ||
if (p !== 'YLDS') { | ||
// Get offers on each type that isn't YLDS | ||
const details = (await get(offersUrl(p))) | ||
// For collateral, subtracted the loan amount from the total amount | ||
balances[p] = { collateral: Number(details.totalOfferAmount) - Number(details.totalLoanAmount), borrowed: details.totalLoanAmount } | ||
} else { | ||
// For YLDS, get all existing lending facility pools | ||
const facilities = (await get(lendingFacilities)).data.filter(l => l.type === 'LENDING_FACILITY') | ||
// Reduce existing pools into a single amount, which represents the total pool collateral in the protocol | ||
const totalLendingFacilitiesValue = facilities.reduce((acc, cur) => acc += Number(cur.lendingFacilitiesDetails.unpaidBalance), 0) | ||
// Also pull the existing YLDS loan amount | ||
const borrowed = (await get(offersUrl(p))).totalLoanAmount | ||
// Convert final YLDS to uylds (exponent of 6) | ||
balances[p] = {collateral: (totalLendingFacilitiesValue - Number(borrowed)) * 1e6, borrowed: borrowed * 1e6 } | ||
} | ||
})) | ||
return balances | ||
} | ||
|
||
const tvl = async (api) => { | ||
const balances = await getBalances() | ||
let collateral = {} | ||
Object.keys(balances).map(b => collateral[tokenMapper[b]] = balances[b].collateral) | ||
Object.keys(collateral).map(coin => mapTokens(collateral, coin, api )) | ||
} | ||
|
||
const borrowed = async (api) => { | ||
const balances = (await getBalances()) | ||
let borrowed = {} | ||
Object.keys(balances).map(b => borrowed[tokenMapper[b]] = balances[b].borrowed) | ||
Object.keys(borrowed).map(coin => mapTokens(borrowed, coin, api )) | ||
} | ||
|
||
module.exports = { | ||
timetravel: false, | ||
doublecounted: true, | ||
misrepresentedTokens: true, | ||
methodology: 'Figure Markets Democratized Prime calculates the loan pool amount as TVL, with outstanding loans as the borrowed amount.', | ||
provenance: { | ||
tvl, | ||
borrowed, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
const { convertToCoinGeckoApiId, tokenMapping, mapTokens } = require("../helper/chain/provenance"); | ||
const { get } = require("../helper/http") | ||
|
||
const paginationLimit = 1000; | ||
|
||
const commitmentsQuery = (nextKey) => | ||
`https://api.provenance.io/provenance/exchange/v1/commitments?pagination.limit=${ | ||
paginationLimit | ||
}${ | ||
nextKey ? `&pagination.key=${nextKey}` : "" | ||
}`; | ||
|
||
/** | ||
* Tokens are committed to Provenance's Exchange Module in order to conduct | ||
* decentralized exchanges. This functions accumulates a an object of committed | ||
* denoms and the amount within the Provenance Exchange Module. | ||
*/ | ||
const getCommittedTokens = async (acc, key) => { | ||
// Retrieve all the commitments across all markets | ||
const nextTokens = await get(commitmentsQuery(key)); | ||
// const nextTokens = await nextTokensRequest.json() | ||
// Update the accumulator with each denom in the commitments | ||
nextTokens.commitments.map((c) => | ||
c.amount.map((a) => { | ||
const denom = a.denom; | ||
if (acc[denom]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be replaced with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated, will push as soon as we answer the below question. |
||
acc[denom] += Number(a.amount); | ||
} else { | ||
acc[denom] = Number(a.amount); | ||
} | ||
}) | ||
); | ||
let nextKey = nextTokens.pagination.next_key; | ||
if (nextKey) { | ||
// convert base64 to URL-safe pagination key. We aren't using | ||
// Buffer here because base64url removes padding. | ||
nextKey = nextKey.replace(/\+/g, "-").replace(/\//g, "_"); | ||
return getCommittedTokens(acc, nextKey); | ||
} | ||
return acc; | ||
}; | ||
|
||
const tvl = async (api) => { | ||
const tokens = await getCommittedTokens({}, null) | ||
await convertToCoinGeckoApiId(tokens) | ||
Object.keys(tokens).map(coin => mapTokens(tokens, coin, api)) | ||
} | ||
|
||
module.exports = { | ||
timetravel: true, | ||
misrepresentedTokens: true, | ||
methodology: "Figure Markets TVL is calculated by the tokens committed in the Provenance Exchange module.", | ||
provenance: { tvl }, | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this file can be removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed locally, will push once the below question is answered. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* Token Mapping for Provenance. Note that | ||
* YLDS is pending on CoinGecko, but is a stablecoin. | ||
* Additionally, LRWA and REIT are also 1:1 with USD | ||
*/ | ||
const tokenMapping = { | ||
hash: "hash-2", | ||
"eth.figure.se": "ethereum", | ||
"usd.trading": "usd-coin", | ||
"usdc.figure.se": "usd-coin", | ||
// "ylds.fcc": "ylds", | ||
"usdt.figure.se": "tether", | ||
"xrp.figure.se": "ripple", | ||
"sol.figure.se": "solana", | ||
"btc.figure.se": "bitcoin", | ||
"uni.figure.se": "uniswap", | ||
"lrwa.figure.markets": "usd-coin", | ||
"link.figure.se": "chainlink", | ||
'reit.figure.markets': "usd-coin", | ||
}; | ||
|
||
/** | ||
* Denoms are listed as their base unit. For example, HASH is returned as | ||
* nhash, and needs to be converted to it's CoinGecko Value. | ||
* We do this by querying the denom metadata and using the provided | ||
* exponent and base unit to convert. | ||
* @param tokenObject An object with key: token name (in base units) | ||
* and value: amount of tokens | ||
* Example: { | ||
* nhash: 100000000 | ||
* } | ||
*/ | ||
const convertToCoinGeckoApiId = async (tokenObject) => | ||
await Promise.all( | ||
Object.keys(tokenObject).map(async (t) => { | ||
// Get the denom exponent information | ||
const response = await fetch( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, this is really bad, this will fetch denom metadata each time, use this structure instead: https://github.com/DefiLlama/DefiLlama-Adapters/blob/main/projects/helper/tokenMapping.js#L41 then you can do
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated locally, pushing after we answer the below question. |
||
`https://api.provenance.io/cosmos/bank/v1beta1/denoms_metadata/${t}` | ||
); | ||
const denomExponent = (await response.json()).metadata?.denom_units[1] | ||
// If a denom is present and we have mapped the token to the CoinGecko Equivalent... | ||
if (denomExponent && tokenMapping[denomExponent.denom]) { | ||
// Map these tokens to coingecko | ||
const key = tokenMapping[denomExponent.denom] | ||
if (tokenObject[key]) { | ||
const incomingAmount = BigInt(tokenObject[t]) / BigInt(Math.pow(10, denomExponent.exponent)) | ||
const newVal = BigInt(tokenObject[key]) + incomingAmount | ||
tokenObject[key] = newVal.toString(); | ||
} else { | ||
tokenObject[key] = (BigInt(tokenObject[t]) / BigInt(Math.pow(10, denomExponent.exponent))).toString(); | ||
} | ||
delete tokenObject[t]; | ||
} | ||
}) | ||
); | ||
|
||
// Map tokens. If they exist in coingecko, add to coingecko. | ||
// Otherwise, keep in provenance | ||
const mapTokens = (tokens, coin, api) => | ||
Object.values(tokenMapping).includes(coin) ? | ||
api.addCGToken(coin, tokens[coin]) : api.add(coin, tokens[coin]) | ||
|
||
module.exports = { | ||
tokenMapping, | ||
convertToCoinGeckoApiId, | ||
mapTokens, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -310,6 +310,7 @@ | |
"posi", | ||
"prom", | ||
"proton", | ||
"provenance", | ||
"pryzm", | ||
"pulse", | ||
"q", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leverage pools is derivatives trading? I wouldnt mix it with lending, also, how to get info of both on chain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on this. I mislabeled that, it should have read lending pools.