wormhole/staging/algorand/backend/publisher/Pricekeeper2Publisher.ts

113 lines
4.7 KiB
TypeScript
Raw Normal View History

Pricecaster V2-alpha (#716) * Removed unnecessary file. Change-Id: Ic85cb42fef37028bc99d266148fae35107d2cf5f * Update sample pyth VAA information on README Change-Id: I2a4d3b23bfbc525d25f3f0360605aece0c104f4b * Test and lib fixes. Change-Id: I4af5e0313ba04b322f428a15a19bc7b30c6ae027 * Check owner balance + Feed ALGOs to stateless account address. Change-Id: Ibf57c66b24153b917f5d33febff97a002c163b59 * Working VAA verification test. Change-Id: Ib44e96ce8979161cdf703b1c4c92742cdc3e9cae * Lot of new tests and a little refactoring. Change-Id: Ic1da9be0a91fc3ace136c80cc5b2329cb3bf2e77 * Removed parts of old Pricekeeper logic Change-Id: Id77f4366d30dac2b89d039cea9b115a46a189e2d * Proper fetching, parsing and unpacking of Pyth-Wormhole data Change-Id: Id3b5002f072873d8161fa619f387171483a3e66c * Pricekeeper V2 PyTEAL contract. Change-Id: Idc1771e1ade371f51befdfd36ab6add55b3081fc * Streamlined and refac support library. Removed old code. Change-Id: I1f9633700527b1e0ca5ea9a38d24d3960e3e2341 * Changes to successfully publish price in target contract. Change-Id: Ie346648cec5b7b0b70786c2a99373df9bf71633d * pclib: Concurrent internal group TXs supported. Change-Id: I78e16d0dbf71c86fbb6be61e956aa370a4c48130 * Fetching and publishing from Wormhole/Spy. Removed most of old Pricekeeper V1 functionality. Simplified code. Change-Id: I197436c52460c04143501a60e3db9609159e9f25 * README + Deployment tool updated Change-Id: Iaf1f76ce69ea303f734c2a79f529f60ebf55a4ca * Modifications to use compiled stateless program. Change-Id: Ibc294412728052c1e29c7df929b3d9e481d714be * Removed old settings file. Change-Id: I1b8ca64426983b0a56f55f99a69304aaca702fee * Implements Randlabs Logger (C3PROT-92) Change-Id: Ia527169dc56bb2622fcde2fcfad53ed2efb5f399 * STEPS updated to 8. Change-Id: I9b092bb321231cde003e12b5a68cf90404f670f8 * Fixed handling double-hashing Change-Id: I5695e2783d439a85a61af44cab03ba99898cb16b * Added option to dump failed TX and diagnostic information in README Change-Id: If3d7b068d8d408851bcaae443ff412dc9cc30c69 * Fixed chainId handling. Change-Id: Id798a2e7afc0d646a179e3bd682204ba738fa53a * Successfully push prices to priceKeeper V2. Change-Id: Ib04da78b819e17579677e0187c9f5bd6bb1e2feb * Fixed price output log Change-Id: I99df39a05c667b5eb1af6cda988326cd768f89ee * Update WIP Tests. Change-Id: I4c2f94306dcaab578c30e487ceb6c140ea902ac3 * Support for VAAs with minimal quorum (> 2/3+1 signers ) Change-Id: I65dc52f6ef531cd24f7d080108451c5302e08524 * Remove old files. Change-Id: I9fd2127d9374617f53cb1cc6f721a2a655b79385 * Removed unnecessary entries in gitignore file Change-Id: I498ee2e192eb87d090767d8a12fd59ac679c8579 Co-authored-by: Josh Siegel <jsiegel@jumptrading.com> Co-authored-by: jumpsiegel <83408952+jumpsiegel@users.noreply.github.com>
2022-01-21 06:37:49 -08:00
import algosdk from 'algosdk'
import { IPublisher, PublishInfo } from './IPublisher'
import { StatusCode } from '../common/statusCodes'
import { PythData } from 'backend/common/basetypes'
const PricecasterLib = require('../../lib/pricecaster')
const tools = require('../../tools/app-tools')
export class Pricekeeper2Publisher implements IPublisher {
private algodClient: algosdk.Algodv2
private pclib: any
private account: algosdk.Account
private vaaProcessorAppId: number
private vaaProcessorOwner: string
private numOfVerifySteps: number = 0
private guardianCount: number = 0
private stepSize: number = 0
private dumpFailedTx: boolean
private dumpFailedTxDirectory: string | undefined
private compiledVerifyProgram: { bytes: Uint8Array, hash: string } = { bytes: new Uint8Array(), hash: '' }
constructor (vaaProcessorAppId: number,
priceKeeperAppId: number,
vaaProcessorOwner: string,
verifyProgramBinary: Uint8Array,
verifyProgramHash: string,
signKey: algosdk.Account,
algoClientToken: string,
algoClientServer: string,
algoClientPort: string,
dumpFailedTx: boolean = false,
dumpFailedTxDirectory: string = './') {
this.account = signKey
this.compiledVerifyProgram.bytes = verifyProgramBinary
this.compiledVerifyProgram.hash = verifyProgramHash
this.vaaProcessorAppId = vaaProcessorAppId
this.vaaProcessorOwner = vaaProcessorOwner
this.dumpFailedTx = dumpFailedTx
this.dumpFailedTxDirectory = dumpFailedTxDirectory
this.algodClient = new algosdk.Algodv2(algoClientToken, algoClientServer, algoClientPort)
this.pclib = new PricecasterLib.PricecasterLib(this.algodClient)
this.pclib.setAppId('vaaProcessor', vaaProcessorAppId)
this.pclib.setAppId('pricekeeper', priceKeeperAppId)
this.pclib.enableDumpFailedTx(this.dumpFailedTx)
this.pclib.setDumpFailedTxDirectory(this.dumpFailedTxDirectory)
}
async start () {
}
stop () {
}
signCallback (sender: string, tx: algosdk.Transaction) {
const txSigned = tx.signTxn(this.account.sk)
return txSigned
}
async publish (data: PythData): Promise<PublishInfo> {
const publishInfo: PublishInfo = { status: StatusCode.OK }
const txParams = await this.algodClient.getTransactionParams().do()
txParams.fee = 1000
txParams.flatFee = true
this.guardianCount = await tools.readAppGlobalStateByKey(this.algodClient, this.vaaProcessorAppId, this.vaaProcessorOwner, 'gscount')
this.stepSize = await tools.readAppGlobalStateByKey(this.algodClient, this.vaaProcessorAppId, this.vaaProcessorOwner, 'vssize')
this.numOfVerifySteps = Math.ceil(this.guardianCount / this.stepSize)
if (this.guardianCount === 0 || this.stepSize === 0) {
throw new Error('cannot get guardian count and/or step-size from global state')
}
//
// (!)
// Stateless programs cannot access state nor stack from stateful programs, so
// for the VAA Verify program to use the guardian set, we pass the global state as TX argument,
// (and check it against the current global list to be sure it's ok). This way it can be read by
// VAA verifier as a stateless program CAN DO READS of call transaction arguments in a group.
// The same technique is used for the note field, where the payload is set.
//
try {
const guardianKeys = []
const buf = Buffer.alloc(8)
for (let i = 0; i < this.guardianCount; i++) {
buf.writeBigUInt64BE(BigInt(i++))
const gk = await tools.readAppGlobalStateByKey(this.algodClient, this.vaaProcessorAppId, this.vaaProcessorOwner, buf.toString())
guardianKeys.push(Buffer.from(gk, 'base64').toString('hex'))
}
const strSig = data.signatures.toString('hex')
const gid = this.pclib.beginTxGroup()
const sigSubsets = []
for (let i = 0; i < this.numOfVerifySteps; i++) {
const st = this.stepSize * i
const sigSetLen = 132 * this.stepSize
const keySubset = guardianKeys.slice(st, i < this.numOfVerifySteps - 1 ? st + this.stepSize : undefined)
sigSubsets.push(strSig.slice(i * sigSetLen, i < this.numOfVerifySteps - 1 ? ((i * sigSetLen) + sigSetLen) : undefined))
this.pclib.addVerifyTx(gid, this.compiledVerifyProgram.hash, txParams, data.vaaBody, keySubset, this.guardianCount)
}
this.pclib.addPriceStoreTx(gid, this.vaaProcessorOwner, txParams, data.symbol, data.vaaBody.slice(51))
const txId = await this.pclib.commitVerifyTxGroup(gid, this.compiledVerifyProgram.bytes, sigSubsets, this.vaaProcessorOwner, this.signCallback.bind(this))
publishInfo.txid = txId
} catch (e: any) {
publishInfo.status = StatusCode.ERROR_SUBMIT_MESSAGE
publishInfo.reason = e.response.text ? e.response.text : e.toString()
return publishInfo
}
return publishInfo
}
}