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 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 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 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 update_signatory(self, update_signatory_request): sp.set_type(update_signatory_request, UpdateSignatoryRequest.get_type()) signing_payload = UpdateSignatoryRequest.get_signing_payload(sp.chain_id, sp.self_address, self.data.nonce+sp.nat(1), update_signatory_request.signers_threshold, update_signatory_request.operator_public_keys ) valid_signatures_counter = sp.local('valid_signatures_counter', sp.nat(0)) sp.for operator_public_key in self.data.operator_public_keys: operator_hash_key = sp.hash_key(operator_public_key) sp.if update_signatory_request.signatures.contains(operator_hash_key) & sp.check_signature(operator_public_key, update_signatory_request.signatures[operator_hash_key], sp.pack(signing_payload)): valid_signatures_counter.value += 1
def execute(self, execution_request): sp.set_type(execution_request, ExecutionRequest.get_type()) signing_payload = ExecutionRequest.get_signing_payload(sp.chain_id, sp.self_address, self.data.nonce+sp.nat(1), execution_request.execution_payload) valid_signatures_counter = sp.local('valid_signatures_counter', sp.nat(0)) sp.for operator_public_key in self.data.operator_public_keys: operator_hash_key = sp.hash_key(operator_public_key) sp.if execution_request.signatures.contains(operator_hash_key) & sp.check_signature(operator_public_key, execution_request.signatures[operator_hash_key], sp.pack(signing_payload)): valid_signatures_counter.value += 1
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 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 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 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 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