def update(self, params): # If there is no value for the public key, the oracle is revoked. Ignore updates. sp.verify(self.data.publicKey.is_some(), "revoked") # Iterate over assets in the input map. keyValueList = params.items() sp.for assetData in keyValueList: # Extract asset names, signatures, and the new data. assetName = assetData.key signature = sp.compute(sp.fst(assetData.value)) newData = sp.compute(sp.snd(assetData.value)) # Verify Oracle is tracking this asset. sp.if self.data.oracleData.contains(assetName): # Verify start timestamp is newer than the last update. oldData = sp.compute(self.data.oracleData[assetName]) oldStartTime = sp.compute(sp.fst(oldData)) newStartTime = sp.compute(sp.fst(newData)) sp.if newStartTime > oldStartTime: # Verify signature. bytes = sp.pack((assetName, newData)) sp.verify( sp.check_signature( self.data.publicKey.open_some(), signature, bytes ), "bad sig" ) # Replace the data. self.data.oracleData[assetName] = newData
def token_metadata(self, params): sp.verify( ~self.is_paused() ) sp.set_type(params, sp.TRecord( token_ids = sp.TList(sp.TNat), handler = sp.TLambda( sp.TList(self.token_meta_data.get_type()), sp.TUnit) ).layout(("token_ids", "handler"))) def f_on_request(req): self.token_meta_data.set_type_and_layout(self.data.token_metadata[req]) sp.result(self.data.token_metadata[req]) sp.compute(params.handler(params.token_ids.map(f_on_request)))
def receiveNft(self, nft): sp.set_type(nft, sp.TTicket(sp.TNat)) ticket_data, ticket_next = sp.read_ticket(nft) qty = sp.compute(sp.snd(sp.snd(ticket_data))) originator = sp.compute(sp.fst(ticket_data)) id = sp.compute(sp.fst(sp.snd(ticket_data))) sp.verify(qty == 1, "Only send 1 Nft to this entrypoint") sp.verify(sp.source == self.data.admin, "Ticket needs to be sent by wallet admin") current_id = self.data.current_id new_map = sp.update_map(self.data.tickets, current_id, sp.some(ticket_next)) self.data.tickets = new_map self.data.current_id = current_id + 1
def update(self, updateMap): sp.set_type(updateMap, sp.TBigMap(sp.TString, Harbinger.OracleDataType)) # Verify the sender is the whitelisted oracle contract. sp.verify( sp.sender == self.data.oracleContract, message="bad sender" ) # Iterate over assets this normalizer is tracking sp.for assetCode in self.data.assetCodes: # Only process updates if this normalizer is tracking the asset code. sp.if updateMap.contains(assetCode): assetData = updateMap.get(assetCode) # Only process updates that are monotonically increasing in start times. updateStartTime = sp.compute(sp.fst(assetData)) sp.if updateStartTime > self.data.assetMap[assetCode].lastUpdateTime: # Extract required information endPair = sp.compute(sp.snd(assetData)) openPair = sp.compute(sp.snd(endPair)) highPair = sp.compute(sp.snd(openPair)) lowPair = sp.compute(sp.snd(highPair)) closeAndVolumePair = sp.compute(sp.snd(lowPair)) high = sp.compute(sp.fst(highPair)) low = sp.compute(sp.fst(lowPair)) close = sp.compute(sp.fst(closeAndVolumePair)) volume = sp.compute(sp.snd(closeAndVolumePair)) # Ignore candles with zero volumes. sp.if volume > 0: # Calculate the the price for this data point. # average price * volume volumePrice = ((high + low + close) / 3) * volume # Update the last updated time. self.data.assetMap[assetCode].lastUpdateTime = updateStartTime # Push the latest items to the FIFO queue fifoDT.push(self.data.assetMap[assetCode].prices, volumePrice) fifoDT.push(self.data.assetMap[assetCode].volumes, volume) # Trim the queue if it exceeds the number of data points. sp.if fifoDT.len(self.data.assetMap[assetCode].prices) > self.data.numDataPoints: fifoDT.pop(self.data.assetMap[assetCode].prices) fifoDT.pop(self.data.assetMap[assetCode].volumes)
def get(self, requestPair): sp.set_type(requestPair, sp.TPair(sp.TString, sp.TContract(sp.TPair(sp.TString, sp.TPair(sp.TTimestamp, sp.TNat))))) # Destructure the arguments. requestedAsset = sp.compute(sp.fst(requestPair)) callback = sp.compute(sp.snd(requestPair)) # Verify this normalizer has data for the requested asset. sp.verify( self.data.assetMap.contains(requestedAsset), message="bad request" ) # Callback with the requested data. assetData = self.data.assetMap[requestedAsset] normalizedPrice = assetData.computedPrice lastUpdateTime = assetData.lastUpdateTime callbackParam = (requestedAsset, (lastUpdateTime, normalizedPrice)) sp.transfer(callbackParam, sp.mutez(0), callback)
def cancel_request(self, client_request_id): # We do not want to check active here (it would be bad for the client). # sp.sender needs to be validated; this process is done through the use of the reverse_request_key. reverse_request_key = sp.compute(sp.record(client = sp.sender, client_request_id = client_request_id)) request_id = sp.local('request_id', self.data.reverse_requests[reverse_request_key]).value request = sp.local('request', self.data.requests[request_id]).value sp.verify(request.timeout <= sp.now, message = "TTL not met") token = sp.contract(self.token_contract.batch_transfer.get_type(), self.data.token, entry_point = "transfer").open_some(message = "Incompatible token interface") sp.transfer([sp.record(from_ = sp.to_address(sp.self), txs = [sp.record(to_ = request.client, token_id = 0, amount = request.amount)])], sp.tez(0), token) del self.data.requests[request_id] del self.data.reverse_requests[reverse_request_key]
def create_request(self, client, params): sp.verify(sp.sender == self.data.token, message = "Invalid source") sp.verify(self.data.active, message = "Inactive") amount = params.amount target = params.target job_id = params.job_id parameters = params.parameters timeout = params.timeout sp.verify(self.data.min_amount <= amount, message = "Invalid payment") sp.verify(sp.now.add_minutes(self.data.min_timeout_minutes) <= timeout, message = "Invalid timeout") client_request_id = params.client_request_id new_request = sp.record(client = client, target = target, job_id = job_id, parameters = parameters, amount = amount, timeout = timeout, client_request_id = client_request_id) reverse_request_key = sp.compute(sp.record(client = client, client_request_id = client_request_id)) sp.verify(~self.data.reverse_requests.contains(reverse_request_key), message = "Bad request key") self.data.reverse_requests[reverse_request_key] = self.data.next_id self.data.requests[self.data.next_id] = new_request self.data.next_id += 1
def collect(self, amount): sp.verify(sp.sender == self.data.owner, 'Only owner can collect.') max_collect = sp.compute(sp.split_tokens(sp.balance,sp.nat(100),self.data.max_collect_percent)) sp.verify(amount <= max_collect, 'Withdrawal amount exceeds allowed limit.') sp.if (self.data.next_collect.is_some()): sp.verify(sp.some(sp.now) > self.data.next_collect, 'Withdrawal frequency exceeds limit.')