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 TezToToken(self, recipient: sp.TAddress, tezIn: sp.TNat, minTokensOut: sp.TNat): this = self.data.address sp.verify(tezIn > sp.mutez(0), message="Wrong tezIn") sp.verify(minTokensOut > 0, message="Wrong minTokensOut") fee = sp.fst(sp.ediv(tezIn, self.data.feeRate).open_some()) # TODO: ???? newTezPool = sp.local("newTezPool", self.data.tezPool).value + tezIn tempTezPool = abs(newTezPool - fee) newTokenPool = sp.fst(sp.ediv(sp.local( "newTokenPool", self.data.invariant).value, tempTezPool).open_some()) tokensOut = abs( sp.local("tokensOut", self.data.tokenPool).value - newTokenPool) sp.verify(tokensOut >= minTokensOut, message="Wrong minTokensOut") sp.verify(tokensOut <= self.data.tokenPool, message="Wrong tokenPool") self.data.tezPool = newTezPool self.data.tokenPool = newTokenPool self.data.invariant = sp.split_tokens(newTezPool, newTokenPool, sp.nat(1)) token_contract = sp.contract( sp.TRecord(account_from=sp.TAddress, destination=sp.TAddress, value=sp.TNat), address=self.data.tokenAddress, entry_point="Transfer" ).open_some() sp.transfer(sp.record(account_from=this, destination=recipient, value=tokensOut), sp.mutez(0), token_contract)
def permit(self, params): sp.set_type( params, sp.TList(sp.TPair(sp.TKey, sp.TPair(sp.TSignature, sp.TBytes)))) sp.verify(~self.data.paused) with sp.for_('permit', params) as permit: params_hash = sp.snd(sp.snd(permit)) unsigned = sp.pack( sp.pair(sp.pair(sp.chain_id, sp.self_address), sp.pair(self.data.counter, params_hash))) pk_address = sp.to_address( sp.implicit_account(sp.hash_key(sp.fst(permit)))) permit_key = sp.pair(pk_address, params_hash) permit_exists = self.data.permits.contains(permit_key) effective_expiry = self.getEffectiveExpiry( sp.pair(pk_address, params_hash)) permit_submission_timestamp = self.data.permits[permit_key] sp.verify( ~(permit_exists & (sp.as_nat(sp.now - permit_submission_timestamp) < effective_expiry)), sp.pair("DUP_PERMIT", params_hash)) sp.verify( sp.check_signature(sp.fst(permit), sp.fst(sp.snd(permit)), unsigned), sp.pair("MISSIGNED", unsigned)) self.data.permits[sp.pair(pk_address, params_hash)] = sp.now self.data.counter = self.data.counter + 1
def test(): scenario=sp.test_scenario() scenario.h1("Calls back correctly when a valid asset is provided") scenario.h2("GIVEN a Normalizer contract") assetCode = "XTZ-USD" contract=NormalizerContract(assetCodes=[assetCode]) scenario += contract scenario.h2("AND a contract to call back to") dummyContract = DummyContract() scenario += dummyContract scenario.h2("AND a single data point") start1=sp.timestamp(1595104530) high1=1 low1=2 close1=3 volume1=4 assetCode = "XTZ-USD" scenario += contract.update( makeMap( assetCode=assetCode, start=start1, end=sp.timestamp(1595104531), open=3059701, high=high1, low=low1, close=close1, volume=volume1 ) ).run(sender=defaultOracleContractAddress) scenario.h2("WHEN a request is made") contractHandle = sp.contract( sp.TPair(sp.TString, sp.TPair(sp.TTimestamp, sp.TNat)), dummyContract.address, entry_point = "callback" ).open_some() param = (assetCode, contractHandle) scenario.h2("THEN it succeeds.") scenario += contract.get(param) scenario.h2("AND the dummy contract captured the expected values") scenario.verify(sp.fst(dummyContract.data.capturedCallbackValue) == assetCode) scenario.verify(sp.fst(sp.snd(dummyContract.data.capturedCallbackValue)) == start1) expectedPartialVWAP = Harbinger.computeVWAP( high=high1, low=low1, close=close1, volume=volume1 ) expectedPrice = expectedPartialVWAP // volume1 scenario.verify(sp.snd(sp.snd(dummyContract.data.capturedCallbackValue)) == expectedPrice)
def deposit(self, params): sp.verify(sp.amount > sp.mutez(0), message = "Deposit too low") sp.verify(sp.sender != self.data.issuer, message = "Invalid address") period = self.getPeriod() tokenBalance = sp.local('tokenBalance', 0) requiredCollateral = sp.local('requiredCollateral', sp.tez(0)) expectedReturn = sp.ediv(sp.amount, self.data.schedule[period]) coins = sp.ediv(sp.amount, sp.tez(1)) sp.if (expectedReturn.is_some()) & (coins.is_some()): tokenBalance.value = sp.fst(expectedReturn.open_some()) wholeCoins = sp.fst(coins.open_some()) sp.verify(tokenBalance.value > wholeCoins, message = "Deposit too low") requiredCollateral.value = sp.tez(sp.as_nat(tokenBalance.value - wholeCoins))
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 InvestLiquidity(self, params): minShares = params.minShares candidate = params.candidate sp.verify(sp.amount > sp.mutez(0), message="Wrong amount") sp.verify(minShares > sp.nat(0), message="Wrong tokenAmount") tezPerShare = sp.split_tokens(self.data.tezPool, sp.nat(1), self.data.totalShares) sp.verify(sp.amount >= tezPerShare, message="Wrong tezPerShare") sharesPurchased = sp.fst(sp.ediv(sp.amount, tezPerShare).open_some()) sp.verify(sharesPurchased >= minShares, message="Wrong sharesPurchased") tokensPerShare = self.data.tokenPool / self.data.totalShares tokensRequired = sharesPurchased * tokensPerShare share = sp.local("share", self.data.shares.get(sp.sender, 0)).value self.data.shares[sp.sender] = share + sharesPurchased self.data.tezPool += sp.amount self.data.tokenPool += tokensRequired self.data.invariant = sp.split_tokens(self.data.tezPool, self.data.tokenPool, sp.nat(1)) self.data.totalShares += sharesPurchased sp.if self.data.candidates.contains(sp.sender): prevVotes = self.data.votes.get(self.data.candidates[sp.sender], 0) self.data.votes[self.data.candidates[sp.sender]] = abs( prevVotes - share)
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 custClose(self, params): sp.verify(self.data.custAddr == sp.sender) sp.verify((self.data.status == OPEN) | (self.data.status == MERCH_CLOSE)) # custClose inputs custBal = params.custBal merchBal = params.merchBal revLock = params.revLock s1 = params.s1 s2 = params.s2 # Prepare pairing check inputs g2 = self.data.g2 merchPk0 = self.data.merchPk0 merchPk1 = self.data.merchPk1 merchPk2 = self.data.merchPk2 merchPk3 = self.data.merchPk3 merchPk4 = self.data.merchPk4 chanID = self.data.chanID cust_b = sp.local('cust_b', sp.fst(sp.ediv(custBal, sp.mutez(1)).open_some())) one = sp.local('one', sp.bls12_381_fr("0x01")) cust_bal_b = sp.local("cust_bal_b", sp.mul(cust_b.value, one.value)) merch_b = sp.local('merch_b', sp.fst(sp.ediv(merchBal, sp.mutez(1)).open_some())) merch_bal_b = sp.local("merch_bal_b", sp.mul(merch_b.value, one.value)) revLockConcat = sp.local('revLockConcat', sp.concat([sp.bytes("0x050a00000020"), revLock])) rev_lock_b = sp.local('rev_lock_b', sp.unpack(revLockConcat.value, t = sp.TBls12_381_fr).open_some()) # Verify signature val1 = sp.local("val1", sp.mul(merchPk0, chanID)) val2 = sp.local("val2", sp.mul(merchPk1, rev_lock_b.value)) val3 = sp.local("val3", sp.mul(merchPk2, cust_bal_b.value)) val4 = sp.local("val4", sp.mul(merchPk3, merch_bal_b.value)) prod1 = sp.local("prod1", val1.value + val2.value + val3.value + val4.value + merchPk4) g2_negated = - g2 pair_list = sp.local("pair_list", [sp.pair(s1, prod1.value), sp.pair(s2, g2_negated)]) out = sp.local('out', False) sp.verify(sp.pairing_check(pair_list.value)) # Update on-chain state and transfer merchant's balance self.data.custBal = custBal self.data.revLock = revLock self.data.delayExpiry = sp.now.add_seconds(self.data.selfDelay) sp.send(self.data.merchAddr, merchBal) self.data.merchBal = sp.tez(0) self.data.status = CUST_CLOSE
def deposit(self, params): sp.verify(sp.amount > sp.mutez(0), message = "Deposit too low") contractbal = sp.ediv(sp.balance, sp.tez(1)) sp.if (contractbal.is_some() ): bal = sp.fst(contractbal.open_some()) val = sp.split_tokens( sp.amount, self.data.totalTokens, bal) _natVal = sp.ediv(val, sp.tez(1)) sp.if (_natVal.is_some() ): natVal = sp.fst(_natVal.open_some()) self.data.withdrawBalances[params] = sp.to_int(natVal) self.data.totalTokens += natVal
def setExpiry(self, params): sp.set_type(params, sp.TPair(sp.TAddress, sp.TPair(sp.TNat, sp.TOption( sp.TBytes)))) address = sp.fst(params) new_expiry = sp.fst(sp.snd(params)) possible_bytes = sp.snd(sp.snd(params)) sp.verify(new_expiry <= self.data.permit_data.max_expiry, self.error_message.expiry_exceeds_max()) sp.verify_equal(address, sp.sender, message=self.error_message.user_unauthorized()) sp.if possible_bytes.is_some(): some_permit = possible_bytes.open_some() permit_key = sp.pair(address, some_permit) sp.verify(self.data.permit_data.permits.contains( permit_key), self.error_message.permit_nonexistent()) permit_submission_timestamp = self.data.permit_data.permits[permit_key] effective_expiry = self.getEffectiveExpiry(permit_key) sp.verify(sp.as_nat(sp.now - permit_submission_timestamp) < effective_expiry, self.error_message.permit_revoked()) self.data.permit_data.permit_expiries[permit_key] = sp.some(new_expiry)
def checkIfWinnerAndDisburse(self,cycle): change = sp.local("change",sp.int(0)) change = self.data.cycleData[cycle].endingPrice - self.data.cycleData[cycle].referencePrice changePercentQuotient = sp.local("changePercentQuotient",sp.int(0)) changePercentQuotient.value = sp.mul(change , 10000) changePercentQuotient.value = sp.fst(sp.ediv(changePercentQuotient.value,self.data.cycleData[cycle].referencePrice).open_some()) upperLimit = sp.local("upperLimit",sp.int(0)) lowerLimit = sp.local("lowerLimit",sp.int(0)) betsByCycle = self.data.bettors[sp.sender] lowerLimit = sp.fst(betsByCycle[cycle].range) upperLimit = sp.snd(betsByCycle[cycle].range) sp.if upperLimit != lowerLimit: sp.if lowerLimit<= changePercentQuotient.value: sp.if changePercentQuotient.value<upperLimit: self.hasWon(cycle,betsByCycle[cycle].range)
def getEffectiveExpiry(self, params): b = sp.bind_block() with b: address = sp.fst(params) sp.if self.data.permit_data.permit_expiries.contains(params) & self.data.permit_data.permit_expiries[params].is_some(): permit_expiry = self.data.permit_data.permit_expiries[params].open_some() sp.result(permit_expiry) sp.else: sp.if self.data.permit_data.user_expiries.contains(address) & self.data.permit_data.user_expiries[address].is_some(): user_expiry = self.data.permit_data.user_expiries[address].open_some() sp.result(user_expiry)
def default(self, params): sp.verify(sp.amount == LEADERSHIP_PAYMENT_AMOUNT) sp.verify(self.data.leadership_start_timestamp.add_seconds(sp.to_int(self.data.countdown_milliseconds/1000)) > sp.now) self.data.leader = sp.sender self.data.leadership_start_timestamp = sp.now balance_weight_tenthtez = sp.fst(sp.ediv(sp.balance-INITIAL_BALANCE,sp.mutez(1)).open_some())/sp.nat(100000) # mutez becomes tenth of a tez countdown_drop_milliseconds = (COUNTDOWN_DROP_FACTOR+balance_weight_tenthtez)/balance_weight_tenthtez sp.if self.data.countdown_milliseconds - countdown_drop_milliseconds > sp.to_int(MINIMAL_COUNT_DOWN_MILLISECONDS): self.data.countdown_milliseconds = sp.as_nat(self.data.countdown_milliseconds - countdown_drop_milliseconds)
def permit(self, params): sp.set_type(params, sp.TList( sp.TPair(sp.TKey, sp.TPair(sp.TSignature, sp.TBytes)))) sp.for permit in params: public_key = sp.fst(permit) signature = sp.fst(sp.snd(permit)) params_hash = sp.snd(sp.snd(permit)) #unsigned = sp.blake2b(mi.operator("SELF; ADDRESS; CHAIN_ID; PAIR; PAIR; PACK", [sp.TPair(sp.TNat, sp.TBytes)], [sp.TBytes])(sp.pair(self.data.permit_data.counter, params_hash))) unsigned = sp.pack(sp.pair(sp.pair(sp.chain_id, sp.self_address), sp.pair( self.data.permit_data.counter, params_hash))) pk_address = sp.to_address( sp.implicit_account(sp.hash_key(public_key))) permit_key = sp.pair(pk_address, params_hash) permit_exists = self.data.permit_data.permits.contains(permit_key) permit_submission_timestamp = self.data.permit_data.permits[permit_key] effective_expiry = self.getEffectiveExpiry(permit_key) sp.verify(~ (permit_exists & (sp.as_nat(sp.now - permit_submission_timestamp) < effective_expiry)), sp.pair(self.error_message.duplicate_permit(), params_hash)) sp.verify(sp.check_signature(public_key, signature, unsigned), sp.pair(self.error_message.permit_missigned(), unsigned)) self.data.permit_data.permits[permit_key] = sp.now self.data.permit_data.counter = self.data.permit_data.counter + 1
def collect(self, params): sp.verify( (params.objkt_amount > 0) & (sp.sender != self.data.swaps[params.swap_id].issuer) ) sp.if (self.data.swaps[params.swap_id].xtz_per_objkt != sp.tez(0)): self.objkt_amount = sp.fst(sp.ediv(sp.amount, self.data.swaps[params.swap_id].xtz_per_objkt).open_some()) self.amount = self.objkt_amount * sp.fst(sp.ediv(self.data.swaps[params.swap_id].xtz_per_objkt, sp.mutez(1)).open_some()) sp.verify((params.objkt_amount == self.objkt_amount) & (sp.amount == sp.utils.nat_to_mutez(self.amount)) & (sp.amount > sp.tez(0))) # calculate fees and royalties self.fee = sp.fst(sp.ediv(sp.utils.nat_to_mutez(self.amount), sp.utils.nat_to_mutez(1)).open_some()) * (self.data.royalties[self.data.swaps[params.swap_id].objkt_id].royalties + 25) / 1000 self.royalties = self.data.royalties[self.data.swaps[params.swap_id].objkt_id].royalties * self.fee / (self.data.royalties[self.data.swaps[params.swap_id].objkt_id].royalties + 25) # send royalties to NFT creator sp.send(self.data.royalties[self.data.swaps[params.swap_id].objkt_id].issuer, sp.utils.nat_to_mutez(self.royalties)) # send management fees sp.send(self.data.manager, sp.utils.nat_to_mutez(abs(self.fee - self.royalties))) # send value to issuer sp.send(self.data.swaps[params.swap_id].issuer, sp.amount - sp.utils.nat_to_mutez(self.fee))
def getResponseFromHarbinger(self,response): sp.verify(self.data.admin.contains(sp.source) , "Un-authorized") sp.set_type(response , sp.TPair(sp.TString , sp.TPair(sp.TTimestamp , sp.TNat))) currentPrice=sp.local("currentPrice",sp.int(0)) currentPrice = sp.to_int(sp.fst(sp.ediv(sp.snd(sp.snd(response)) , sp.nat(1000)).open_some())) currentCycle = sp.local("currentCycle" ,sp.int(0)) currentCycle = sp.fst(sp.ediv(sp.level,self.data.blocksPerCycle).open_some()) sp.verify(~self.data.cycleData.contains(currentCycle+self.data.stakingPeriod)) rangeMap = sp.local("rangeMap" , sp.map(tkey = sp.TPair(sp.TInt, sp.TInt) , tvalue = sp.TMutez)) iterator = sp.local("iterator" , sp.int(0)) sp.while iterator.value<=self.data.rangeEnd: sp.if iterator.value+self.data.rangeStep<=self.data.rangeEnd: rangeMap.value[sp.pair(iterator.value,iterator.value+self.data.rangeStep)] =sp.mutez(0) rangeMap.value[(sp.int(-1)*(iterator.value+self.data.rangeStep),sp.int(-1)*iterator.value)] =sp.mutez(0)
def TokenToTokenOut(self, buyer: sp.TAddress, recipient: sp.TAddress, tokensIn: sp.TNat, minTokensOut: sp.TNat, tokenOutAddress: sp.TAddress): this = self.data.address sp.verify(tokensIn > 0, message="Wrong tokensIn") sp.verify(minTokensOut > 0, message="Wrong minTokensOut") fee = tokensIn / self.data.feeRate # TODO: ???? newTokenPool = sp.local( "newTokenPool", self.data.tokenPool).value + tokensIn tempTokenPool = abs(newTokenPool - fee) newTezPool = sp.fst(sp.ediv(sp.local( "newTezPool", self.data.invariant).value, tempTokenPool).open_some()) tezOut = abs(sp.local("tezOut", self.data.tezPool).value - newTezPool) sp.verify(sp.mutez(tezOut) <= self.data.tezPool, message="Wrong tezPool") self.data.tezPool = newTezPool self.data.tokenPool = newTokenPool self.data.invariant = sp.mutez(newTezPool * newTokenPool) token_contract = sp.contract( sp.TRecord(account_from=sp.TAddress, destination=sp.TAddress, value=sp.TNat), address=self.data.tokenAddress, entry_point="Transfer" ).open_some() factory_contract = sp.contract( sp.TRecord(tokenOutAddress=sp.TAddress, recipient=sp.TAddress, minTokensOut=sp.TNat), address=self.data.factoryAddress, entry_point="TokenToExchangeLookup" ).open_some() sp.transfer(sp.record(account_from=buyer, destination=this, value=tokensIn), sp.mutez(0), token_contract) sp.transfer(sp.record(tokenOutAddress=tokenOutAddress, destination=recipient, value=minTokensOut), sp.mutez(tezOut), factory_contract)
def getEffectiveExpiry(self, params): sp.set_type(params, sp.TPair(sp.TAddress, sp.TBytes)) address = sp.fst(params) with sp.if_( self.data.permit_expiries.contains(params) & self.data.permit_expiries[params].is_some()): permit_expiry = self.data.permit_expiries[params].open_some() sp.result(permit_expiry) with sp.else_(): with sp.if_( self.data.user_expiries.contains(address) & self.data.user_expiries[address].is_some()): user_expiry = self.data.user_expiries[address].open_some() sp.result(user_expiry) with sp.else_(): sp.result(self.data.default_expiry)
def hasWon(self,cycle,range): betsByCycle = self.data.bettors[sp.sender] betAmount = sp.local("betAmount",sp.mutez(0)) betAmount = betsByCycle[cycle].amount totalRewards = sp.local("totalRewards",sp.mutez(0)) totalRewards = sp.split_tokens(self.data.cycleData[cycle].totalAmount , sp.as_nat(sp.fst(self.data.cycleData[cycle].roi)) , sp.as_nat(sp.snd(self.data.cycleData[cycle].roi))) totalRewards = sp.split_tokens(totalRewards , sp.nat(98) , sp.nat(100)) reward = sp.split_tokens(totalRewards , sp.fst(sp.ediv(betAmount , sp.mutez(1)).open_some()) , sp.fst(sp.ediv(self.data.cycleData[cycle].amountByRange[range],sp.mutez(1)).open_some()) ) betsByCycle[cycle].withdrawn=True betsByCycle[cycle].withdrawnAmount = betsByCycle[cycle].amount + reward sp.send(sp.sender , betsByCycle[cycle].amount + reward)
def updateContracts(self, newParams): sp.set_type( newParams, sp.TPair( sp.TAddress, sp.TPair( sp.TAddress, sp.TPair(sp.TAddress, sp.TPair(sp.TAddress, sp.TAddress))))) sp.verify(sp.sender == self.data.governorAddress, message="NOT_GOVERNOR") newGovernorContractAddress = sp.fst(newParams) self.data.governorAddress = newGovernorContractAddress
def test(): scenario=sp.test_scenario() scenario.h1("Calls back correctly when a valid asset is provided") scenario.h2("GIVEN a Normalizer contract") assetCode = "XTZ-USD" contract=NormalizerContract(assetCodes=[assetCode]) scenario += contract scenario.h2("AND a contract to call back to") dummyContract = DummyContract() scenario += dummyContract scenario.h2("AND a single data point") start1=sp.timestamp(1595104530) high1=1 low1=2 close1=3 volume1=4 assetCode = "XTZ-USD" scenario += contract.update( makeMap( assetCode=assetCode, start=start1, end=sp.timestamp(1595104531), open=3059701, high=high1, low=low1, close=close1, volume=volume1 ) ).run(sender=defaultOracleContractAddress) scenario.h2("WHEN the onchain view is read") scenario.h2("THEN it the correct data is returned.") scenario.verify(sp.fst(contract.getPrice(assetCode)) == start1) expectedPartialVWAP = Harbinger.computeVWAP( high=high1, low=low1, close=close1, volume=volume1 ) expectedPrice = expectedPartialVWAP // volume1 scenario.verify(sp.snd(contract.getPrice(assetCode)) == expectedPrice)
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 placeBet(self,params): self.checkBettingPaused() self.bettorNotAContract() sp.verify(sp.amount > sp.mutez(0) , message = "Amount should not be 0") currentCycle = sp.local("currentCycle" ,sp.int(0)) currentCycle = sp.fst(sp.ediv(sp.level,self.data.blocksPerCycle).open_some()) self.initializeInternalMapForNewBettor() self.betAlreadyPlacedForParticularCycle(currentCycle+self.data.stakingPeriod) self.betBelowBetLimit() self.isRangeValid(currentCycle+self.data.stakingPeriod , params.top , params.bottom) self.isCycleInitiated(currentCycle+self.data.stakingPeriod) betsByCycle = self.data.bettors[sp.sender] betsByCycle[currentCycle+self.data.stakingPeriod] = sp.record(amount = sp.amount , range = sp.pair(params.top , params.bottom) , withdrawn = sp.bool(False) , withdrawnAmount = sp.mutez(0) , stakedAt = currentCycle) self.data.cycleData[currentCycle+self.data.stakingPeriod].amountByRange[sp.pair(params.top , params.bottom)] += sp.amount self.data.cycleData[currentCycle+self.data.stakingPeriod].totalAmount += sp.amount
def create_certificate(self, params): # 0) verify that lock period is not more than 2 years sp.verify(params.months < 25) # 1) get tez value mintAmount = sp.split_tokens(sp.amount, 100, 100) coins = sp.ediv(mintAmount, sp.mutez(1) ) principal = sp.to_int( sp.fst(coins.open_some()) ) # 2) get timestamp end_time = sp.now.add_days(params.months*30) # 3) calculate payout w = sp.local('w', 1) y = sp.local('y', 0) sp.while y.value < params.months: w.value = 10033*w.value y.value = y.value + 1
def join_hDAO(self, params): sp.verify((sp.amount > sp.mutez(0)) & (sp.balance < sp.tez(730000))) c = sp.contract( sp.TRecord( address=sp.TAddress, amount=sp.TNat, token_id=sp.TNat, token_info=sp.TMap(sp.TString, sp.TBytes) ), self.data.ung, entry_point = "mint").open_some() sp.transfer( sp.record( address=sp.sender, amount=sp.fst(sp.ediv(sp.amount, sp.mutez(1)).open_some()), token_id=1, token_info={"": sp.pack("ipfs://QmS87PA42aKj6WgPM1vQMHxyavKJkswa5ycgAn1wbSrNgi")} ), sp.mutez(0), c) self.data.balance += sp.amount
@sp.entry_point def setManager(self, params): sp.verify(sp.sender == self.data.administrator) self.addAddressIfNecessary(params) self.data.saleManager = params @sp.entry_point def getManager(self, params): sp.transfer(self.data.saleManager, sp.tez(0), sp.contract(sp.TAddress, params.target).open_some()) @sp.entry_point def sale(self, params): sp.verify(self.data.saleStatus) sp.if self.data.balances.contains(sp.sender): sp.verify(~ self.data.balances[sp.sender].lock) natMutez = sp.fst(sp.ediv(sp.amount, sp.mutez(1)).open_some()) intMutez = sp.to_int(natMutez) self.mintSale(sp.sender, intMutez * self.data.ratio) @sp.entry_point def offchainSale(self, params): sp.verify(sp.sender == self.data.saleManager) sp.if self.data.balances.contains(params.address): sp.verify(~ self.data.balances[params.address].lock) self.mintSale(params.address, params.amount) def mintSale(self, address, nbMutoken): sp.verify(self.data.soldToken + nbMutoken <= self.data.saleLimit) self.addAddressIfNecessary(address) self.data.balances[address].balance += nbMutoken self.data.circulatingSupply += nbMutoken
def test(): scenario = sp.test_scenario() scenario.h1("Update with stale asset does not fail") scenario.h2("GIVEN an Oracle contract tracking two assets with an initial update") assetCode1 = "XTZ-USD" assetCode2 = "BTC-USD" contract = OracleContract( publicKey=testAccountPublicKey, initialData=sp.big_map( l={ assetCode1: initialOracleData, assetCode2: initialOracleData }, tkey=sp.TString, tvalue=Harbinger.OracleDataType ) ) scenario += contract start1 = sp.timestamp(1) end1 = sp.timestamp(2) open1 = 3 high1 = 4 low1 = 5 close1 = 6 volume1 = 7 updateData1 = ( start1, (end1, (open1, (high1, (low1, (close1, volume1)))))) asset1Message1 = sp.pack((assetCode1, updateData1)) asset1Signature1 = sp.make_signature( testAccountSecretKey, asset1Message1, message_format='Raw' ) asset2Message1 = sp.pack((assetCode2, updateData1)) asset2Signature1 = sp.make_signature( testAccountSecretKey, asset2Message1, message_format='Raw' ) asset1Update1 = sp.pair(asset1Signature1, updateData1) asset2Update1 = sp.pair(asset2Signature1, updateData1) parameter = sp.map( l={ assetCode1: asset1Update1, assetCode2: asset2Update1, }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter) scenario.h2("WHEN an update is posted to the oracle with only one asset containing new data") start2 = sp.timestamp(2) end2 = sp.timestamp(3) open2 = 8 high2 = 9 low2 = 10 close2 = 11 volume2 = 12 updateData2 = ( start2, (end2, (open2, (high2, (low2, (close2, volume2)))))) asset1Message2 = sp.pack((assetCode1, updateData2)) asset1Signature2 = sp.make_signature( testAccountSecretKey, asset1Message2, message_format='Raw' ) asset1Update2 = sp.pair(asset1Signature2, updateData2) parameter = sp.map( l={ assetCode1: asset1Update2, assetCode2: asset2Update1, }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter) scenario.h2("THEN data for the asset with two updates is the second update.") assetData1 = contract.data.oracleData[assetCode1] endPair1 = sp.snd(assetData1) openPair1 = sp.snd(endPair1) highPair1 = sp.snd(openPair1) lowPair1 = sp.snd(highPair1) closeAndVolumePair1 = sp.snd(lowPair1) oracleStart1 = sp.fst(assetData1) oracleEnd1 = sp.fst(endPair1) oracleOpen1 = sp.fst(openPair1) oracleHigh1 = sp.fst(highPair1) oracleLow1 = sp.fst(lowPair1) oracleClose1 = sp.fst(closeAndVolumePair1) oracleVolume1 = sp.snd(closeAndVolumePair1) scenario.verify(oracleStart1 == start2) scenario.verify(oracleEnd1 == end2) scenario.verify(oracleOpen1 == open2) scenario.verify(oracleHigh1 == high2) scenario.verify(oracleLow1 == low2) scenario.verify(oracleClose1 == close2) scenario.verify(oracleVolume1 == volume2) scenario.h2("THEN data for the asset with two updates is the second update.") assetData2 = contract.data.oracleData[assetCode2] endPair2 = sp.snd(assetData2) openPair2 = sp.snd(endPair2) highPair2 = sp.snd(openPair2) lowPair2 = sp.snd(highPair2) closeAndVolumePair2 = sp.snd(lowPair2) oracleStart2 = sp.fst(assetData2) oracleEnd2 = sp.fst(endPair2) oracleOpen2 = sp.fst(openPair2) oracleHigh2 = sp.fst(highPair2) oracleLow2 = sp.fst(lowPair2) oracleClose2 = sp.fst(closeAndVolumePair2) oracleVolume2 = sp.snd(closeAndVolumePair2) scenario.verify(oracleStart2 == start1) scenario.verify(oracleEnd2 == end1) scenario.verify(oracleOpen2 == open1) scenario.verify(oracleHigh2 == high1) scenario.verify(oracleLow2 == low1) scenario.verify(oracleClose2 == close1) scenario.verify(oracleVolume2 == volume1)
def test(): scenario = sp.test_scenario() scenario.h1("Untracked Asset does not update oracle") scenario.h2("GIVEN an Oracle contract tracking an asset") assetCode = "XTZ-USD" contract = OracleContract( publicKey=testAccountPublicKey, initialData=sp.big_map( l={ assetCode: initialOracleData }, tkey=sp.TString, tvalue=Harbinger.OracleDataType ) ) scenario += contract start1 = sp.timestamp(2) end1 = sp.timestamp(3) open1 = 3 high1 = 4 low1 = 5 close1 = 6 volume1 = 7 updateData1 = ( start1, (end1, (open1, (high1, (low1, (close1, volume1)))))) message1 = sp.pack((assetCode, updateData1)) signature1 = sp.make_signature( testAccountSecretKey, message1, message_format='Raw' ) update1 = sp.pair(signature1, updateData1) parameter1 = sp.map( l={ assetCode: update1 }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter1) scenario.h2("WHEN the oracle is updated with an untracked asset") untrackedAsset = "BTC-USD" start2 = sp.timestamp(4) end2 = sp.timestamp(5) open2 = 8 high2 = 9 low2 = 10 close2 = 11 volume2 = 12 updateData2 = ( start2, (end2, (open2, (high2, (low2, (close2, volume2)))))) message2 = sp.pack((untrackedAsset, updateData2)) signature2 = sp.make_signature( testAccountSecretKey, message2, message_format='Raw' ) update2 = sp.pair(signature2, updateData2) parameter2 = sp.map( l={ untrackedAsset: update2 }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter2) scenario.h2("THEN the oracle only contains the data for the tracked asset.") assetData = contract.data.oracleData[assetCode] endPair = sp.snd(assetData) openPair = sp.snd(endPair) highPair = sp.snd(openPair) lowPair = sp.snd(highPair) closeAndVolumePair = sp.snd(lowPair) oracleStart = sp.fst(assetData) oracleEnd = sp.fst(endPair) oracleOpen = sp.fst(openPair) oracleHigh = sp.fst(highPair) oracleLow = sp.fst(lowPair) oracleClose = sp.fst(closeAndVolumePair) oracleVolume = sp.snd(closeAndVolumePair) scenario.verify(oracleStart == start1) scenario.verify(oracleEnd == end1) scenario.verify(oracleOpen == open1) scenario.verify(oracleHigh == high1) scenario.verify(oracleLow == low1) scenario.verify(oracleClose == close1) scenario.verify(oracleVolume == volume1) scenario.h2("AND does not contain data for the untracked asset") scenario.verify(~contract.data.oracleData.contains(untrackedAsset))
def test(): scenario = sp.test_scenario() scenario.h1("Correctly Processes Updates With Data From The Past") scenario.h2("GIVEN an Oracle contract with some initial data.") assetCode = "XTZ-USD" contract = OracleContract( publicKey=testAccountPublicKey, initialData=sp.big_map( l={ assetCode: initialOracleData }, tkey=sp.TString, tvalue=Harbinger.OracleDataType ) ) scenario += contract start1 = sp.timestamp(3) end1 = sp.timestamp(4) open1 = 3 high1 = 4 low1 = 5 close1 = 6 volume1 = 7 updateData1 = ( start1, (end1, (open1, (high1, (low1, (close1, volume1)))))) message1 = sp.pack((assetCode, updateData1)) signature1 = sp.make_signature( testAccountSecretKey, message1, message_format='Raw' ) update1 = sp.pair(signature1, updateData1) parameter1 = sp.map( l={ assetCode: update1 }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter1) scenario.h2("WHEN the oracle is updated with a time in the past") start2 = sp.timestamp(1) # In past end2 = sp.timestamp(2) open2 = 8 high2 = 9 low2 = 10 close2 = 11 volume2 = 12 updateData2 = ( start2, (end2, (open2, (high2, (low2, (close2, volume2)))))) message2 = sp.pack(updateData2) signature2 = sp.make_signature( testAccountSecretKey, message2, message_format='Raw' ) update2 = sp.pair(signature2, updateData2) parameter2 = sp.map( l={ assetCode: update2 }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario += contract.update(parameter2) scenario.h2("THEN the update in the past does not modify the data.") assetData = contract.data.oracleData[assetCode] endPair = sp.snd(assetData) openPair = sp.snd(endPair) highPair = sp.snd(openPair) lowPair = sp.snd(highPair) closeAndVolumePair = sp.snd(lowPair) oracleStart = sp.fst(assetData) oracleEnd = sp.fst(endPair) oracleOpen = sp.fst(openPair) oracleHigh = sp.fst(highPair) oracleLow = sp.fst(lowPair) oracleClose = sp.fst(closeAndVolumePair) oracleVolume = sp.snd(closeAndVolumePair) scenario.verify(oracleStart == start1) scenario.verify(oracleEnd == end1) scenario.verify(oracleOpen == open1) scenario.verify(oracleHigh == high1) scenario.verify(oracleLow == low1) scenario.verify(oracleClose == close1) scenario.verify(oracleVolume == volume1)