Skip to content
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

Add SDR calculation #30

Merged
merged 15 commits into from
Sep 17, 2024
2 changes: 2 additions & 0 deletions feeder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ ENV ORACLE_FEEDER_KEY_PATH=voter.json
ENV ORACLE_FEEDER_COIN_TYPE=330
ENV ORACLE_FEEDER_ADDR_PREFIX=terra

ENV ORACLE_SDR_BASKET=USD:0.57813,EUR:0.37379,JPY:13.452,CNY:1.0993,GBP:0.080870

WORKDIR /app

COPY package*.json ./
Expand Down
16 changes: 16 additions & 0 deletions feeder/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ function registerCommands(parser: ArgumentParser): void {
defaultValue: `voter`,
})

voteCommand.addArgument(['-s', '--sdr-basket'], {
help: `SDR basket information`,
dest: `sdrBasket`,
defaultValue: '',
})

// Updating Key command
const keyCommand = subparsers.addParser(`add-key`, { addHelp: true })

Expand Down Expand Up @@ -123,6 +129,16 @@ async function main(): Promise<void> {
args.validators || (process.env.ORACLE_FEEDER_VALIDATORS && process.env.ORACLE_FEEDER_VALIDATORS.split(','))
args.keyName = process.env.ORACLE_FEEDER_KEY_NAME ? process.env.ORACLE_FEEDER_KEY_NAME : args.keyName

args.sdrBasket = args.sdrBasket || process.env.ORACLE_SDR_BASKET || ''
// convert basket data into json object
if (args.sdrBasket !== '') {
args.sdrBasket = args.sdrBasket.split(',').reduce((acc: { string: string }, curr: string) => {
const [key, value] = curr.split(':')
acc[key] = value
return acc
}, {})
}

await vote(args)
} else if (args.subparser_name === `add-key`) {
await addKey(args.keyPath, args.coinType, args.keyName)
Expand Down
59 changes: 57 additions & 2 deletions feeder/src/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,49 @@ interface Price {
price: string
}

async function getPrices(sources: string[]): Promise<Price[]> {
function calculateSDR(prices: Price[], sdrBasket: string): Price | undefined {
if (!sdrBasket) {
return undefined
}

// check if all prices from the basket are available
for (const denom of Object.keys(sdrBasket)) {
if (denom === 'USD') {
continue
}
if (!prices.find((p) => p.denom === denom)) {
logger.error(`getPrices: price for ${denom} not found`)
return undefined
}
}

// calculate SDR price
let sdrPrice: BigNumber | undefined = undefined

try {
sdrPrice = Object.entries(sdrBasket).reduce((acc, [denom, weight]) => {
const price = denom === 'USD' ? { price: '1.0' } : prices.find((p) => p.denom === denom)
if (!price) {
throw new Error(`price for ${denom} not found`)
}
return acc.plus(new BigNumber(price.price).times(weight))
}, new BigNumber(0))
} catch (err) {
logger.error(`getPrices: error calculating SDR price: ${err.message}`)
return undefined
}

if (!sdrPrice) {
return undefined
StrathCole marked this conversation as resolved.
Show resolved Hide resolved
}

return {
denom: 'SDR',
price: sdrPrice.toString(),
}
}

async function getPrices(sources: string[], sdrBasket: string): Promise<Price[]> {
const results = await Bluebird.some(
sources.map((s) => ax.get(s)),
1
Expand All @@ -99,6 +141,18 @@ async function getPrices(sources: string[]): Promise<Price[]> {
return []
}

if (results[0].data.prices.find((p) => p.denom === 'SDR')) {
logger.info(`[VOTE] SDR price found from price server`)
return results[0].data.prices
}

const sdr = calculateSDR(results[0].data.prices, sdrBasket)
logger.info(`[VOTE] SDR price: ${sdr?.price}`)

if (sdr) {
results[0].data.prices.push(sdr)
}

return results[0].data.prices
}

Expand Down Expand Up @@ -189,7 +243,7 @@ export async function processVote(

// Print timestamp before start
logger.info(`[VOTE] Requesting prices from price server ${args.dataSourceUrl.join(',')}`)
const _prices = await getPrices(args.dataSourceUrl)
const _prices = await getPrices(args.dataSourceUrl, args.sdrBasket)

// Removes non-whitelisted currencies and abstain for not fetched currencies
const prices = preparePrices(_prices, oracleWhitelist)
Expand Down Expand Up @@ -302,6 +356,7 @@ interface VoteArgs {
password: string
keyPath: string
keyName: string
sdrBasket: string
}

function buildLCDClientConfig(args: VoteArgs, lcdIndex: number): Record<string, LCDClientConfig> {
Expand Down