def _post_transfer(self, engine: contracts.ApplicationEngine, account_from: types.UInt160, account_to: types.UInt160, amount: vm.BigInteger, data: vm.StackItem, call_on_payment: bool) -> None: state = vm.ArrayStackItem(vm.ReferenceCounter()) if account_from == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_from.to_array())) if account_to == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_to.to_array())) state.append(vm.IntegerStackItem(amount)) msgrouter.interop_notify(self.hash, "Transfer", state) # wallet or smart contract if not call_on_payment \ or account_to == types.UInt160.zero() \ or contracts.ManagementContract().get_contract(engine.snapshot, account_to) is None: return if account_from == types.UInt160.zero(): from_: vm.StackItem = vm.NullStackItem() else: from_ = vm.ByteStringStackItem(account_from.to_array()) engine.call_from_native( self.hash, account_to, "onNEP17Payment", [from_, vm.IntegerStackItem(amount), data])
def finish(self, engine: contracts.ApplicationEngine) -> None: tx = engine.script_container tx = cast(payloads.Transaction, tx) response = tx.try_get_attribute(payloads.OracleResponse) if response is None: raise ValueError("Oracle response not found") request = self.get_request(engine.snapshot, response.id) if request is None: raise ValueError("Oracle request not found") state = vm.ArrayStackItem( engine.reference_counter, [vm.IntegerStackItem(response.id), vm.ByteStringStackItem(request.original_tx_id.to_array()) ] ) msgrouter.interop_notify(self.hash, "OracleResponse", state) user_data = contracts.BinarySerializer.deserialize(request.user_data, engine.MAX_STACK_SIZE, engine.reference_counter) args: List[vm.StackItem] = [vm.ByteStringStackItem(request.url.encode()), user_data, vm.IntegerStackItem(int(response.code)), vm.ByteStringStackItem(response.result)] engine.call_from_native(self.hash, request.callback_contract, request.callback_method, args)
def contract_create_with_data( self, engine: contracts.ApplicationEngine, nef_file: bytes, manifest: bytes, data: vm.StackItem) -> contracts.ContractState: if not isinstance(engine.script_container, payloads.Transaction): raise ValueError( "Cannot create contract without a Transaction script container" ) nef_len = len(nef_file) manifest_len = len(manifest) if (nef_len == 0 or nef_len > engine.MAX_CONTRACT_LENGTH or manifest_len == 0 or manifest_len > contracts.ContractManifest.MAX_LENGTH): raise ValueError("Invalid NEF or manifest length") engine.add_gas( max(engine.STORAGE_PRICE * (nef_len + manifest_len), self.get_minimum_deployment_fee(engine.snapshot))) nef = contracts.NEF.deserialize_from_bytes(nef_file) parsed_manifest = contracts.ContractManifest.from_json( json.loads(manifest.decode())) self.validate(nef.script, parsed_manifest.abi) sb = vm.ScriptBuilder() sb.emit(vm.OpCode.ABORT) sb.emit_push(engine.script_container.sender.to_array()) sb.emit_push(nef.checksum) sb.emit_push(parsed_manifest.name) hash_ = to_script_hash(sb.to_array()) existing_contract = engine.snapshot.contracts.try_get(hash_) if existing_contract is not None: raise ValueError("Contract already exists") contract = contracts.ContractState( self.get_next_available_id(engine.snapshot), nef, parsed_manifest, 0, hash_) if not contract.manifest.is_valid(hash_): raise ValueError("Error: invalid manifest") engine.snapshot.contracts.put(contract) method_descriptor = contract.manifest.abi.get_method("_deploy", 2) if method_descriptor is not None: engine.call_from_native(self.hash, hash_, method_descriptor.name, [data, vm.BooleanStackItem(False)]) msgrouter.interop_notify( self.hash, "Deploy", vm.ArrayStackItem(engine.reference_counter, vm.ByteStringStackItem( contract.hash.to_array()))) return contract
def contract_update_with_data(self, engine: contracts.ApplicationEngine, nef_file: bytes, manifest: bytes, data: vm.StackItem) -> None: nef_len = len(nef_file) manifest_len = len(manifest) engine.add_gas(engine.STORAGE_PRICE * (nef_len + manifest_len)) contract = engine.snapshot.contracts.try_get(engine.calling_scripthash, read_only=False) if contract is None: raise ValueError("Can't find contract to update") if nef_len == 0: raise ValueError(f"Invalid NEF length: {nef_len}") # update contract contract.nef = contracts.NEF.deserialize_from_bytes(nef_file) if manifest_len == 0 or manifest_len > contracts.ContractManifest.MAX_LENGTH: raise ValueError(f"Invalid manifest length: {manifest_len}") manifest_new = contracts.ContractManifest.from_json( json.loads(manifest.decode())) if manifest_new.name != contract.manifest.name: raise ValueError("Error: cannot change contract name") if not contract.manifest.is_valid(contract.hash): raise ValueError("Error: manifest does not match with script") contract.manifest = manifest_new self.validate(contract.nef.script, contract.manifest.abi) contract.update_counter += 1 if len(nef_file) != 0: method_descriptor = contract.manifest.abi.get_method("_deploy", 2) if method_descriptor is not None: engine.call_from_native(self.hash, contract.hash, method_descriptor.name, [data, vm.BooleanStackItem(True)]) msgrouter.interop_notify( self.hash, "Update", vm.ArrayStackItem(engine.reference_counter, vm.ByteStringStackItem( contract.hash.to_array())))
def _post_transfer(self, engine: contracts.ApplicationEngine, account_from: types.UInt160, account_to: types.UInt160, token_id: bytes) -> None: state = vm.ArrayStackItem(engine.reference_counter) if account_from == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_from.to_array())) if account_to == types.UInt160.zero(): state.append(vm.NullStackItem()) else: state.append(vm.ByteStringStackItem(account_to.to_array())) state.append(vm.IntegerStackItem(1)) state.append(vm.ByteStringStackItem(token_id)) msgrouter.interop_notify(self.hash, "Transfer", state) if account_to != types.UInt160.zero() and \ contracts.ManagementContract().get_contract(engine.snapshot, account_to) is not None: engine.call_from_native(self.hash, account_to, "onNEP17Payment", list(state))