def mutualClose(self, params): sp.verify(self.data.status == OPEN) # Check customer signature sp.verify(sp.check_signature(self.data.custPk, params.custSig, sp.pack(sp.record( chanID = self.data.chanID, custAddr = self.data.custAddr, merchAddr = self.data.merchAddr, custBal = params.custBal, merchBal = params.merchBal) ) )) # Check merchant signature sp.verify(sp.check_signature(self.data.merchPk, params.merchSig, sp.pack(sp.record( chanID = self.data.chanID, custAddr = self.data.custAddr, merchAddr = self.data.merchAddr, custBal = params.custBal, merchBal = params.merchBal) ) )) self.data.custBal = params.custBal self.data.merchBal = params.merchBal sp.send(self.data.custAddr, self.data.custBal) sp.send(self.data.merchAddr, self.data.merchBal) self.data.custBal = sp.tez(0) self.data.merchBal = sp.tez(0) self.data.status = CLOSED
def test(): c = myContract() secret = sp.string('My secret message') password = sp.string('avada_kedavra') packed = sp.pack(secret) + sp.pack(password) hashed = sp.sha256(packed) scenario = sp.test_scenario() scenario.register(c, show=True) # same as scenario += c c.store_hash(hashed)
def channelAccuseDoubleMove(self, params): sp.verify(self.data.active) self.data.active = False sp.verify(params.msg1.seq == params.msg2.seq) sp.set_type(params.msg1.seq, sp.TInt) sp.set_type(params.msg1.state, sp.type_of(self.data.baseState)) sp.set_type(params.msg2.state, sp.type_of(self.data.baseState)) sp.verify(sp.pack(params.msg1) != sp.pack(params.msg2)) sp.if params.party == 1: self.checkHasDoubleSigned(self.data.party1, params) sp.send(self.data.party2.address, self.data.party1.bond + self.data.party2.bond)
def test(): scenario = sp.test_scenario() rightful_owner = sp.test_account("Alice") attacker = sp.test_account("Robert") c1 = TestCheckSignature(rightful_owner.public_key) scenario += c1 # Let's build a successful call: # scenario.h2("Successful Call") first_message_packed = sp.pack( sp.record(o="Hello World", n="should work", c=0)) sig_from_alice = sp.make_signature(secret_key=rightful_owner.secret_key, message=first_message_packed, message_format="Raw") scenario += c1.setCurrentValue( newValue="should work", userSignature=sig_from_alice).run(valid=True) # scenario.h2("Replay Attack") scenario.p( "Trying to reuse the same signature is blocked by the value of the counter." ) scenario += c1.setCurrentValue( newValue="should work", userSignature=sig_from_alice).run(valid=False) # # scenario.h2("Signature From Wrong Secret Key") scenario.p("Signing the right thing from a different secret-key.") # # # Gives: second_message_packed = sp.pack( sp.record(o="should work", n="Hello again World", c=1)) sig_from_bob = sp.make_signature(secret_key=attacker.secret_key, message=second_message_packed, message_format="Raw") scenario += c1.setCurrentValue(newValue="Hello again World", userSignature=sig_from_bob).run(valid=False) # scenario.h2("Second Successful Call") scenario.p( "Showing that the previous call failed <b>because</b> of the secret-key (signing same bytes)." ) sig_from_alice = sp.make_signature(secret_key=rightful_owner.secret_key, message=second_message_packed, message_format="Raw") scenario += c1.setCurrentValue( newValue="Hello again World", userSignature=sig_from_alice).run(valid=True)
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 meta_transfer(self, params): sp.verify(sp.sender == self.data.administrator) sp.set_type(params, BatchMetaTransfer.get_type()) sp.for meta_transfer in params: source_account_key_hash = sp.hash_key( meta_transfer.from_public_key) source_account = sp.to_address( sp.implicit_account(source_account_key_hash)) sp.verify(self.data.nonces.get( source_account, 0)+1 == meta_transfer.nonce) packed_data = sp.pack( BatchMetaTransfer.get_signing_payload(meta_transfer)) sp.verify(sp.check_signature(meta_transfer.from_public_key, meta_transfer.signature, packed_data), message=ErrorMessage.invalid_signature()) self.data.nonces[source_account] = meta_transfer.nonce sp.for tx in meta_transfer.txs: from_user = LedgerKey.make(source_account, tx.token_id) to_user = LedgerKey.make(tx.to_, tx.token_id) sp.verify(tx.amount > 0, message=ErrorMessage.transfer_of_zero()) sp.verify(self.data.ledger[from_user] >= tx.amount, message=ErrorMessage.insufficient_balance()) self.data.ledger[from_user] = sp.as_nat( self.data.ledger[from_user] - tx.amount) self.data.ledger[to_user] = self.data.ledger.get( to_user, 0) + tx.amount sp.if self.data.ledger[from_user] == 0: del self.data.ledger[from_user]
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 transfer_presigned(self, params): sp.set_type( params, sp.TRecord(from_=sp.TAddress, to_=sp.TAddress, value=sp.TNat)) params_hash = sp.blake2b(sp.pack(params)) #unsigned = sp.blake2b(mi.operator("SELF; ADDRESS; CHAIN_ID; PAIR; PAIR; PACK", [sp.TPair(sp.TNat, sp.TBytes)], [sp.TBytes])(sp.pair(self.data.counter, params_hash))) permit_key = sp.pair(params.from_, params_hash) effective_expiry = sp.local("effective_expiry", 0) with sp.if_(self.data.permits.contains(permit_key)): permit_submission_timestamp = self.data.permits[permit_key] with sp.if_( self.data.permit_expiries.contains(permit_key) & self.data.permit_expiries[permit_key].is_some()): effective_expiry.value = self.data.permit_expiries[ permit_key].open_some() with sp.else_(): with sp.if_( self.data.user_expiries.contains(params.from_) & self.data.user_expiries[params.from_].is_some()): effective_expiry.value = self.data.user_expiries[ params.from_].open_some() with sp.else_(): effective_expiry.value = self.data.default_expiry # Deleting permit regardless of whether or not its expired with sp.if_( sp.as_nat(sp.now - permit_submission_timestamp) >= effective_expiry.value): # Expired self.delete_permit(permit_key) sp.result(sp.bool(False)) with sp.else_(): self.delete_permit(permit_key) sp.result(sp.bool(True)) with sp.else_(): sp.result(sp.bool(False))
def bobSignsState(): scenario.p("Bob signs the current state.") result = sp.make_signature(bob.secret_key, sp.pack( sp.record(id=c1.data.id, name="state", seq=cBob.data.seq, state=cBob.data.baseState))) result = scenario.compute(result) scenario.show(sp.record(seq=cBob.data.seq, sig=result)) return result
def make_key(self, owner, operator): metakey = sp.record(owner=owner, operator=operator) metakey = sp.set_type_expr(metakey, self.inner_type()) if self.config.readable: return metakey else: return sp.pack(metakey)
def channelRenounce(self, params): sp.verify(self.data.active) self.data.active = False sp. if params.party == 1: if 1 not in self.no_checks: sig = params.sig.open_some() if self.no_checks else params.sig sp.verify( sp.check_signature(self.data.party1.pk, sig, sp.pack(sp.record(id=self.data.id, name="renounce")))) sp.send(self.data.party2.address, self.data.party1.bond + self.data.party2.bond - self.data.party1.looserClaim) sp.send(self.data.party1.address, self.data.party1.looserClaim) sp. else: if 2 not in self.no_checks: sig = params.sig.open_some() if self.no_checks else params.sig sp.verify(sp.check_signature(self.data.party2.pk, sig, sp.pack(sp.record(id=self.data.id, name="renounce")))) sp.send(self.data.party1.address, self.data.party1.bond + self.data.party2.bond - self.data.party2.looserClaim) sp.send(self.data.party2.address, self.data.party2.looserClaim)
def make(user, token): sp.set_type(user, sp.TAddress) sp.set_type(token, token_id_type) result = sp.pair(user, token) if readable: return result else: return sp.pack(result)
def changeQuote(self, params): thingToSign = sp.pack( sp.record(o=params.newOwner, n=params.newQuote, c=self.data.nonce)) sp.verify( sp.check_signature(params.newOwner, params.userSignature, thingToSign)) self.data.currentQuote = params.newQuote self.data.owner = params.newOwner self.data.nonce = self.data.nonce + 1
def make(self, user): user = sp.set_type_expr(user, sp.TAddress) result = user if self.config.readable: return result else: return sp.pack(result)
def test(): scenario = sp.test_scenario() scenario.h1("Update Fails With Bad Signature") scenario.h2("GIVEN an Oracle contract") assetCode = "XTZ-USD" contract = OracleContract( publicKey=testAccountPublicKey, initialData=sp.big_map( l={ assetCode: initialOracleData }, tkey=sp.TString, tvalue=Harbinger.OracleDataType ) ) scenario += contract scenario.h2("AND an update signed by an alternative key") alternativeAccount = sp.test_account("AlternativeAccount") alternativeSecretKey = alternativeAccount.secret_key start = sp.timestamp(1) end = sp.timestamp(2) open = 3 high = 4 low = 5 close = 6 volume = 7 updateData = ( start, (end, (open, (high, (low, (close, volume)))))) message = sp.pack(updateData) signature = sp.make_signature( alternativeSecretKey, message, message_format='Raw' ) scenario.h2("WHEN the oracle is updated") update = sp.pair(signature, updateData) parameter = sp.map( l={ assetCode: update }, tkey=sp.TString, tvalue=SignedOracleDataType ) scenario.h2("THEN the update fails") scenario += contract.update(parameter).run(valid=False)
def transfer_presigned(self, params): sp.set_type(params, sp.TRecord( from_=sp.TAddress, to_=sp.TAddress, value=sp.TNat)) params_hash = sp.blake2b(sp.pack(params)) #unsigned = sp.blake2b(mi.operator("SELF; ADDRESS; CHAIN_ID; PAIR; PAIR; PACK", [sp.TPair(sp.TNat, sp.TBytes)], [sp.TBytes])(sp.pair(self.data.counter, params_hash))) permit_key = sp.pair(params.from_, params_hash) effective_expiry = sp.local("effective_expiry", 0) sp.if self.data.permits.contains(permit_key): permit_submission_timestamp = self.data.permits[permit_key] sp.if self.data.permit_expiries.contains(permit_key) & self.data.permit_expiries[permit_key].is_some(): effective_expiry.value = self.data.permit_expiries[permit_key].open_some()
def setCurrentValue(self, params): # We will also need Michelson SELF and CHAIN_ID to avoid all replay attacks: thingToSign = sp.pack( sp.record(o=self.data.currentValue, n=params.newValue, c=self.data.counter)) sp.verify( sp.check_signature(self.data.bossPublicKey, params.userSignature, thingToSign)) self.data.currentValue = params.newValue self.data.counter = self.data.counter + 1
def make(self, user, token): user = sp.set_type_expr(user, sp.TAddress) # token = sp.set_type_expr(token, token_id_type) if self.config.single_asset: result = user else: result = user if self.config.readable: return result else: return sp.pack(result)
def request_fortune(self, params): self.data.client_requests[self.data.next_request_id] = sp.sender self.request_helper(params.payment, self.data.fortune_job_id, sp.map(l = {"sender": sp.variant("bytes", sp.pack(sp.sender))}), self.data.oracle, self.data.waiting_fortune_id, sp.self_entry_point("receive_fortune"), params.timeout)
def transfer_presigned(self, params): sp.set_type(params, sp.TRecord( from_=sp.TAddress, to_=sp.TAddress, value=sp.TNat)) params_hash = sp.blake2b(sp.pack(params)) permit_key = sp.pair(params.from_, params_hash) sp.if self.data.permit_data.permits.contains(permit_key): permit_submission_timestamp = self.data.permit_data.permits[permit_key] effective_expiry = self.getEffectiveExpiry(permit_key) # Deleting permit regardless of whether or not its expired sp.if sp.as_nat(sp.now - permit_submission_timestamp) >= effective_expiry: # Expired self.delete_permit(permit_key) sp.result(sp.bool(False))
def revealBid(self, params): sp.verify(self.data.started) sp.verify(~self.data.ended) # verify now is more than round end time = start_time + round_time but # less than start time + twice of round time sp.verify(sp.now > self.data.start_time.add_seconds(self.data.round_time)) sp.verify(sp.now < self.data.start_time.add_seconds(2 * self.data.round_time)) # bidder sends amt committed previusly minus amt locked as participation fee # if this doesn't match, possibly penalise the participant by seizing his deposit sp.verify(sp.mutez(params.value + self.data.deposit) == sp.amount) sp.verify(sp.sha256(sp.pack(params.value + self.data.deposit)) == self.data.sealed_bids[sp.sender]) sp.if ~self.data.first_revealed: self.data.first_revealed = sp.bool(True)
def test(): c = myContract() alice = sp.test_account('Alice') scenario = sp.test_scenario() scenario += c scenario.show(alice) c.new_user().run(sender = alice.address) c.new_user().run(sender = alice.address, valid = False) secret = 'This is my secret.' message = sp.sha256(sp.sha256(sp.pack(secret))) sig = sp.make_signature(alice.secret_key, message, message_format = 'Raw') scenario.show(sig) check = sp.check_signature(alice.public_key, sig, message) scenario.show(check) c.add_record(message = message, sig = sig).run(sender = alice.address) c.add_record(message = message, sig = sig).run(sender = alice.address, valid = False) bob = sp.test_account('Bob') secret = '[{a:b, c:d},{e:f}]' message = sp.sha256(sp.sha256(sp.pack(secret))) sig = sp.make_signature(bob.secret_key, message, message_format = 'Raw') c.add_record(message = message, sig = sig).run(sender = bob.address, valid = False) c.new_user().run(sender = bob.address) c.add_record(message = message, sig = sig).run(sender = bob.address) bob = sp.test_account('Bob') # an alternative follows that combines the secret with the public key hash secret = sp.pack('This is my secret.') + sp.pack(bob.public_key_hash) message = sp.sha256(sp.sha256(secret)) sig = sp.make_signature(bob.secret_key, message, message_format = 'Raw') c.add_record(message = message, sig = sig).run(sender = bob.address)
def test(): scenario = sp.test_scenario() scenario.h1("Quote Updation SC with on-chain sig verification") first_owner = sp.test_account("Aniket") second_owner = sp.test_account("Sachin") # Let's display the accounts: scenario.h2("Accounts") scenario.show([first_owner, second_owner]) c1 = QuoteDapp(first_owner.public_key) scenario += c1 # Successful call: scenario.h2("Successful Call") scenario.p( "when the second owner is the signer and the pkh provided is also of the second_owner" ) first_message_packed = sp.pack( sp.record(o=second_owner.public_key, n="should work", c=0)) sig_from_sachin = sp.make_signature(secret_key=second_owner.secret_key, message=first_message_packed, message_format="Raw") scenario += c1.changeQuote( newQuote="should work", userSignature=sig_from_sachin, newOwner=second_owner.public_key).run(valid=True) scenario.h2("Replay Attack") scenario.p( "Trying to reuse the same signature is blocked by the value of the nonce." ) scenario += c1.changeQuote( newQuote="seems like a replay attack", userSignature=sig_from_sachin, newOwner=second_owner.public_key).run(valid=False) scenario.h2("Un-successful Call") scenario.p( "when the second owner is the signer and the pkh provided is also of the first_owner, then in this case the call should fail" ) scenario += c1.changeQuote( newQuote="should not work", userSignature=sig_from_sachin, newOwner=first_owner.public_key).run(valid=False)
def revoke(self, param): # Recreate the message which should have been signed. message = sp.set_type_expr(sp.none, sp.TOption(sp.TKey)) bytes = sp.pack(message) # Verify that the message is signed correctly. publicKey = self.data.publicKey.open_some() sp.verify(sp.check_signature(publicKey, param, bytes)) # Revoke the Oracle's public Key. self.data.publicKey = sp.none # Remove all entries in the Oracle's map. self.data.oracleData = sp.big_map( l={}, tkey=sp.TString, tvalue=Harbinger.OracleDataType )
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 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
def test(): scenario = sp.test_scenario() scenario.h1("FA1.2 template - Fungible assets") scenario.table_of_contents() # sp.test_account generates ED25519 key-pairs deterministically: admin = sp.test_account("Administrator") alice = sp.test_account("Alice") bob = sp.test_account("Robert") carlos = sp.test_account("Carlos") # Let's display the accounts: scenario.h1("Accounts") scenario.show([admin, alice, bob, carlos]) scenario.h1("Contract") c1 = FA12(admin.address) scenario.h1("Entry points") scenario += c1 scenario.h2("Admin mints a few coins") scenario += c1.mint(address=alice.address, value=12).run(sender=admin) scenario += c1.mint(address=alice.address, value=3).run(sender=admin) scenario += c1.mint(address=alice.address, value=3).run(sender=admin) scenario.verify(c1.data.balances[alice.address].balance == 18) scenario.h2("Alice transfers to Bob") scenario += c1.transfer(from_=alice.address, to_=bob.address, value=4).run(sender=alice) scenario.verify(c1.data.balances[alice.address].balance == 14) scenario.h2( "Bob tries to transfer from Alice but he doesn't have her approval" ) scenario += c1.transfer(from_=alice.address, to_=bob.address, value=4).run(sender=bob, valid=False) scenario.h2("Alice approves Bob and Bob transfers") scenario += c1.approve(spender=bob.address, value=5).run(sender=alice) scenario += c1.transfer(from_=alice.address, to_=bob.address, value=4).run(sender=bob) scenario.h2("Bob tries to over-transfer from Alice") scenario += c1.transfer(from_=alice.address, to_=bob.address, value=4).run(sender=bob, valid=False) scenario.h2("Admin burns Bob token") scenario += c1.burn(address=bob.address, value=1).run(sender=admin) scenario.verify(c1.data.balances[alice.address].balance == 10) scenario.h2("Alice tries to burn Bob token") scenario += c1.burn(address=bob.address, value=1).run(sender=alice, valid=False) scenario.h2( "Admin pauses the contract and Alice cannot transfer anymore") scenario += c1.setPause(True).run(sender=admin) scenario += c1.transfer(from_=alice.address, to_=bob.address, value=4).run(sender=alice, valid=False) scenario.verify(c1.data.balances[alice.address].balance == 10) scenario.h2("Admin transfers while on pause") scenario += c1.transfer(from_=alice.address, to_=bob.address, value=1).run(sender=admin) scenario.h2("Admin unpauses the contract and transfers are allowed") scenario += c1.setPause(False).run(sender=admin) scenario.verify(c1.data.balances[alice.address].balance == 9) scenario += c1.transfer(from_=alice.address, to_=bob.address, value=1).run(sender=alice) scenario.verify(c1.data.totalSupply == 17) scenario.verify(c1.data.balances[alice.address].balance == 8) scenario.verify(c1.data.balances[bob.address].balance == 9) scenario.h2("Permit Submissions") scenario += c1.mint(address=carlos.address, value=10).run(sender=admin) scenario.verify(c1.data.balances[carlos.address].balance == 10) # add permit for transfer of 10 from carlos to bob. alice submits with correct info and also calls. params_bytes_1 = sp.pack( sp.pair(carlos.address, sp.pair(bob.address, 10))) params_bytes_2 = sp.pack( sp.pair(bob.address, sp.pair(carlos.address, 10))) params_hash_1 = sp.blake2b(params_bytes_1) params_hash_2 = sp.blake2b(params_bytes_2) unsigned_1 = sp.pack( sp.pair(sp.pair(sp.chain_id_cst("0x9caecab9"), c1.address), sp.pair(0, params_hash_1))) signature_1 = sp.make_signature(secret_key=carlos.secret_key, message=unsigned_1, message_format="Raw") unsigned_2 = sp.pack( sp.pair(sp.pair(sp.chain_id_cst("0x9caecab9"), c1.address), sp.pair(1, params_hash_2))) signature_2 = sp.make_signature(secret_key=bob.secret_key, message=unsigned_2, message_format="Raw") scenario += c1.permit([ sp.pair(carlos.public_key, sp.pair(signature_1, params_hash_1)), sp.pair(bob.public_key, sp.pair(signature_2, params_hash_2)) ]).run(sender=alice, now=sp.timestamp(1571761674), chain_id=sp.chain_id_cst("0x9caecab9")) scenario.verify(c1.data.counter == 2) scenario.verify_equal( c1.data.permits[(sp.pair(carlos.address, params_hash_1))], sp.timestamp(1571761674)) scenario.verify_equal( c1.data.permits[(sp.pair(bob.address, params_hash_2))], sp.timestamp(1571761674)) scenario.h2("Execute transfer using permit") scenario += c1.transfer(from_=carlos.address, to_=bob.address, value=10).run(sender=bob, now=sp.timestamp(1571761674)) scenario.verify(c1.data.balances[carlos.address].balance == 0) scenario.verify(c1.data.balances[bob.address].balance == 19) # Permit deleted scenario.verify( ~c1.data.permits.contains(sp.pair(carlos.address, params_hash_1))) scenario += c1.transfer(from_=bob.address, to_=carlos.address, value=10).run(sender=carlos, now=sp.timestamp(1571761674)) scenario.verify(c1.data.balances[carlos.address].balance == 10) scenario.verify(c1.data.balances[bob.address].balance == 9) # Permit deleted scenario.verify( ~c1.data.permits.contains(sp.pair(bob.address, params_hash_2))) # Set Expiry to 0 and try to execute transfer at time less than submission_time + default_expiry, expect invalid transfer scenario.h2("Expired Permit") unsigned_3 = sp.pack( sp.pair(sp.pair(sp.chain_id_cst("0x9caecab9"), c1.address), sp.pair(2, params_hash_1))) signature_3 = sp.make_signature(secret_key=carlos.secret_key, message=unsigned_3, message_format="Raw") scenario += c1.permit([ sp.pair(carlos.public_key, sp.pair(signature_3, params_hash_1)) ]).run(sender=alice, now=sp.timestamp(1571761674), chain_id=sp.chain_id_cst("0x9caecab9")) scenario.verify(c1.data.counter == 3) scenario.verify_equal( c1.data.permits[(sp.pair(carlos.address, params_hash_1))], sp.timestamp(1571761674)) scenario += c1.setExpiry(address=carlos.address, seconds=0, permit=sp.some(params_hash_1)).run( sender=carlos, now=sp.timestamp(1571761674)) scenario.verify(c1.data.permit_expiries[sp.pair( carlos.address, params_hash_1)].open_some() == 0) scenario += c1.transfer(from_=carlos.address, to_=bob.address, value=10).run( sender=bob, now=sp.timestamp(1571761680), valid=False) # Uses later time stamp scenario.h2("Delete Expired Permit") scenario += c1.delete_permits([sp.pair(carlos.address, params_hash_1) ]).run(now=sp.timestamp(1571761680)) scenario.verify(~c1.data.permit_expiries.contains( sp.pair(carlos.address, params_hash_1))) scenario.verify( ~c1.data.permits.contains(sp.pair(carlos.address, params_hash_1))) scenario.h1("Views") scenario.h2("Balance") view_balance = Viewer(sp.TNat) scenario += view_balance scenario += c1.getBalance(arg=sp.record(owner=alice.address), target=view_balance.address) scenario.verify_equal(view_balance.data.last, sp.some(8)) scenario.h2("Administrator") view_administrator = Viewer(sp.TAddress) scenario += view_administrator scenario += c1.getAdministrator(target=view_administrator.address) scenario.verify_equal(view_administrator.data.last, sp.some(admin.address)) scenario.h2("Total Supply") view_totalSupply = Viewer(sp.TNat) scenario += view_totalSupply scenario += c1.getTotalSupply(target=view_totalSupply.address) scenario.verify_equal(view_totalSupply.data.last, sp.some(27)) scenario.h2("Allowance") view_allowance = Viewer(sp.TNat) scenario += view_allowance scenario += c1.getAllowance(arg=sp.record(owner=alice.address, spender=bob.address), target=view_allowance.address) scenario.verify_equal(view_allowance.data.last, sp.some(1)) scenario.h2("Counter") view_counter = Viewer(sp.TNat) scenario += view_counter scenario += c1.getCounter(target=view_counter.address) scenario.verify_equal(view_counter.data.last, sp.some(3)) scenario.h2("Default Expiry") view_defaultExpiry = Viewer(sp.TNat) scenario += view_defaultExpiry scenario += c1.getDefaultExpiry(target=view_defaultExpiry.address) scenario.verify_equal(view_defaultExpiry.data.last, sp.some(50000))
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 checkSeqStateSignature(self, party, sig, seq, state): sp.verify(sp.check_signature(party.pk, sig, sp.pack(sp.record(id = self.data.id, name = "state", seq = seq, state = state))))
# At any point, a party can renounce. # Doing so means that they keep their looserClaim. @sp.entry_point def channelRenounce(self, params): sp.verify(self.data.active) self.data.active = False sp.if params.party == 1: if 1 not in self.no_checks: sig = params.sig.open_some() if self.no_checks else params.sig sp.verify(sp.check_signature(self.data.party1.pk, sig, sp.pack(sp.record(id = self.data.id, name = "renounce")))) sp.send(self.data.party2.address, self.data.party1.bond + self.data.party2.bond - self.data.party1.looserClaim) sp.send(self.data.party1.address, self.data.party1.looserClaim) sp.else: if 2 not in self.no_checks: sig = params.sig.open_some() if self.no_checks else params.sig sp.verify(sp.check_signature(self.data.party2.pk, sig, sp.pack(sp.record(id = self.data.id, name = "renounce")))) sp.send(self.data.party1.address, self.data.party1.bond + self.data.party2.bond - self.data.party2.looserClaim) sp.send(self.data.party2.address, self.data.party2.looserClaim) # When a party wants to come back on-chain from off-chain interactions, # it can do two different things: renounce or call channelNewState. # channelNewState is called with a state that has been agreed upon off-chain and # two signatures to prove the agreement. @sp.entry_point def channelNewState(self, params): sp.verify(self.data.active) sp.verify(self.data.seq < params.msg.seq) self.data.seq = params.msg.seq self.checkSeqStateSignature(self.data.party1, params.sig1, params.msg.seq, params.msg.state) self.checkSeqStateSignature(self.data.party2, params.sig2, params.msg.seq, params.msg.state) self.data.baseState = params.msg.state