diff --git a/lib/pricecaster.js b/lib/pricecaster.js index ed8abc3b..41fc8ce9 100644 --- a/lib/pricecaster.js +++ b/lib/pricecaster.js @@ -8,7 +8,7 @@ const approvalProgramFilename = 'teal/pricekeeper.teal' const clearProgramFilename = 'teal/clearstate.teal' class PricecasterLib { - constructor (algodClient, ownerAddr = undefined) { + constructor(algodClient, ownerAddr = undefined) { this.algodClient = algodClient this.ownerAddr = ownerAddr this.minFee = 1000 @@ -139,8 +139,8 @@ class PricecasterLib { this.createApp = async function (sender, validatorAddr, symbol, signCallback) { const localInts = 0 const localBytes = 0 - const globalInts = 2 - const globalBytes = 4 + const globalInts = 6 + const globalBytes = 2 // declare onComplete as NoOp const onComplete = algosdk.OnApplicationComplete.NoOpOC @@ -204,6 +204,51 @@ class PricecasterLib { return txId } + /** + * Internal function. + * Call application specifying args and accounts. Do it in a group of dummy TXs for maximizing computations. + * @param {String} sender caller address + * @param {Array} appArgs array of arguments to pass to application call + * @param {Array} appAccounts array of accounts to pass to application call + * @param {Function} signCallback callback with prototype signCallback(sender, tx) used to sign transactions + * @param {number} dummyTxCount the number of dummyTx to submit, with the real call last. + * @return {String} transaction id of the transaction + */ + this.callAppInDummyGroup = async function (sender, appArgs, appAccounts, signCallback, dummyTxCount) { + // get node suggested parameters + const params = await this.algodClient.getTransactionParams().do() + + params.fee = this.minFee + params.flatFee = true + + console.log(appArgs) + + const txns = [] + const enc = new TextEncoder() + for (let i = 0; i < dummyTxCount; ++i) { + txns.push(algosdk.makeApplicationNoOpTxn(sender, + params, + this.appId, + undefined, undefined, undefined, undefined, + enc.encode(`dummy_TX_${i}`))) + } + const appTx = algosdk.makeApplicationNoOpTxn(sender, params, this.appId, appArgs) + txns.push(appTx) + algosdk.assignGroupID(txns) + const txId = appTx.txID().toString() + + // Sign the transactions + const signedTxns = [] + for (const tx of txns) { + signedTxns.push(signCallback(sender, tx)) + } + + // Submit the transaction + await this.algodClient.sendRawTransaction(signedTxns).do() + + return txId + } + /** * ClearState sender. Remove all the sender associated local data. * @param {String} sender account to ClearState @@ -305,29 +350,34 @@ class PricecasterLib { * Creates a message with price data for the PriceKeeper contract * @param {BigInt} nonce Sequence number * @param {String} symbol Symbol, must match appid support, 16-char UTF long - * @param {number} price Price, expected in 64-bit floating-point format. - * @param {number} confidence Confidence, expected in 64-bit floating-point format. + * @param {BigInt} price Aggregated price + * @param {BigInt} confidence Confidence + * @param {BigInt} exp Exponent (positive) + * @param {BigInt} slot Valid-slot of price aggregation * @param {Uint8Array} sk Signing key. * @returns A base64-encoded message. */ - this.createMessage = function (nonce, symbol, price, confidence, sk) { - const buf = Buffer.alloc(130) + this.createMessage = function (nonce, symbol, price, exp, confidence, slot, sk) { + const buf = Buffer.alloc(146) buf.write('PRICEDATA', 0) buf.writeInt8(1, 9) buf.writeBigUInt64BE(BigInt(this.appId), 10) buf.writeBigUInt64BE(nonce, 18) buf.write(symbol, 26) - buf.writeDoubleBE(price, 42) - buf.writeDoubleBE(confidence, 50) - buf.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)), 58) + buf.writeBigUInt64BE(price, 42) + buf.writeBigUInt64BE(exp, 50) + buf.writeBigUInt64BE(confidence, 58) + buf.writeBigUInt64BE(slot, 66) + buf.writeBigUInt64BE(BigInt(Math.floor(Date.now() / 1000)), 74) - const digestu8 = Buffer.from(sha512_256(buf.slice(0, 65)), 'hex') - console.log(digestu8.toString('base64')) - console.log(this.approvalProgramHash) + const digestu8 = Buffer.from(sha512_256(buf.slice(0, 82)), 'hex') + // console.log(digestu8.toString('base64')) + // console.log(this.approvalProgramHash) const signature = Buffer.from(algosdk.tealSign(sk, digestu8, this.approvalProgramHash)) - console.log(Buffer.from(signature).toString('base64')) - signature.copy(buf, 66) - return buf.toString('base64') + // console.log(Buffer.from(signature).toString('base64')) + signature.copy(buf, 82) + // console.log(buf.toString('base64')) + return buf } /** @@ -336,8 +386,10 @@ class PricecasterLib { * @param {*} msgb64 Base64-encoded message. * @returns Transaction identifier (txid) */ - this.submitMessage = async function (sender, msgb64, signCallback) { - return await this.callApp(sender, [new Uint8Array(msgb64)], [], signCallback) + this.submitMessage = async function (sender, msgBuffer, signCallback) { + const appArgs = [] + appArgs.push(new Uint8Array(msgBuffer)) + return await this.callAppInDummyGroup(sender, appArgs, [], signCallback, 3) } } }