#pragma version 5 // ================================================================================================ // PriceKeeper Approval Program // ================================================================================================ // // App-globals: // sym : byte[] Symbol to keep price for // vaddr : byte[] Validator account // nonce : uint64 last sequence ID // price : byte[] current price // stdev : byte[] current confidence (standard deviation) // ts : uint64 timestamp // // Slots: // 0 Input message block // 1 SHA256-Hashed message // // The Message format must have the packed fields: // // Field size // 9 header Literal "PRICEDATA" // 1 version int8 (Must be 1) // 8 dest This appId // 8 nonce uint64 Sequence identifier // 16 symbol String filled with spaces e.g ("ALGO/USD ") // 8 price Price. 64bit float encoded as big-endian. // 8 conf Confidence (standard-deviation?). 64bit float encoded as big-endian. // 8 ts timestamp of this price // 32 s Signature s-component // 32 r Signature r-component // 1 v Signature v-component (ignored) // // Size: 131 bytes. // // ------------------------------------------------------------------------------------------------ // Application creation. int 0 txn ApplicationID == bnz handle_create // Handle app call: send price message txn OnCompletion int NoOp == bnz handle_call // Handle deletion. txn OnCompletion int DeleteApplication == bnz success // Fail otherwise err handle_create: // ----------------------------------------------------- // Handle creation // Arg 0: Validator address // Arg 1: Symbol to keep price data // ----------------------------------------------------- byte "vaddr" txn ApplicationArgs 0 app_global_put byte "sym" txn ApplicationArgs 1 dup len int 16 == assert app_global_put b success // ----------------------------------------------------- // Receive price message // ----------------------------------------------------- handle_call: // Verify if sender is the data validator txn Sender byte "vaddr" app_global_get == assert // Retrieve message, store in slot 0 txn ApplicationArgs 0 store 0 // ------------------------------------------------------ // Validate message // ------------------------------------------------------ // Check length load 0 len int 131 == assert // Check header byte "PRICEDATA" load 0 extract 0 9 == assert // Check version - must be 1. load 0 extract 9 1 byte 0x01 == assert // Check destination - must be this appId. load 0 extract 10 8 btoi txn ApplicationID == assert // Check nonce load 0 extract 18 8 btoi byte "nonce" app_global_get > assert // Check timestamp order load 0 extract 58 8 btoi global LatestTimestamp <= assert // Hash message block load 0 extract 0 65 sha512_256 store 1 // push data, followed by signature S, signature R, pubkey X, pubkey Y load 0 dup extract 66 32 load 0 extract 98 32 // Unpack pubkey X,Y components byte "vaddr" app_global_get ecdsa_pk_decompress Secp256k1 // Verify signature ecdsa_verify Secp256k1 int 1 == assert // ---------------------------------------------------------------------------- // Verified. Store data to app globals. // ---------------------------------------------------------------------------- byte "nonce" load 0 extract 18 8 app_global_put byte "ts" load 0 extract 58 8 btoi app_global_put byte "price" load 0 extract 42 8 btoi app_global_put byte "stdev" load 0 extract 50 8 btoi app_global_put b success // ---------------------------------------------------------------------------- fail: int 0 return success: int 1 return