#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 // // Size: 130 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 byte "nonce" int 0 app_global_put b success // ----------------------------------------------------- // Handle app call // ----------------------------------------------------- handle_call: // Group size must be 3 to raise computational allowance to 2100 global GroupSize int 3 == assert // if this is one of dummy transactions(0 or 1), exit with success txn GroupIndex int 2 != bnz success // 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 130 == 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 // ed25519verify args in stack: // data (hash of message) load 0 extract 0 65 sha512_256 // (B) signature load 0 extract 66 64 // validator-address byte "vaddr" app_global_get // Verify signature ed25519verify int 1 == assert // ---------------------------------------------------------------------------- // Verified. Store data to app globals. // ---------------------------------------------------------------------------- byte "nonce" load 0 extract 18 8 btoi app_global_put byte "ts" load 0 extract 58 8 btoi app_global_put byte "price" load 0 extract 42 8 app_global_put byte "stdev" load 0 extract 50 8 app_global_put b success // ---------------------------------------------------------------------------- fail: int 0 return success: int 1 return