///<inheritdoc /> public ITransferResult TransferFunds(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, TransferFundsToContract contractDetails) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); // TODO: Spend BaseFee here var balance = smartContractState.GetBalance(); if (balance < amountToTransfer) { this.logger.LogTrace("(-)[INSUFFICIENT_BALANCE]:{0}={1}", nameof(balance), balance); throw new InsufficientBalanceException(); } // Discern whether this is a contract or an ordinary address. byte[] contractCode = this.contractStateRepository.GetCode(addressTo.ToUint160(this.network)); if (contractCode == null || contractCode.Length == 0) { this.internalTransferList.Add(new TransferInfo { From = smartContractState.Message.ContractAddress.ToUint160(this.network), To = addressTo.ToUint160(this.network), Value = amountToTransfer }); this.logger.LogTrace("(-)[TRANSFER_TO_SENDER]:Transfer {0} from {1} to {2}.", smartContractState.Message.ContractAddress, addressTo, amountToTransfer); return(TransferResult.Empty()); } this.logger.LogTrace("(-)[TRANSFER_TO_CONTRACT]"); return(ExecuteTransferFundsToContract(contractCode, smartContractState, addressTo, amountToTransfer, contractDetails)); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); // TODO: Spend BaseFee here EnsureContractHasEnoughBalance(smartContractState, amountToTransfer); // Discern whether this is a contract or an ordinary address. byte[] contractCode = this.contractStateRepository.GetCode(addressTo.ToUint160(this.network)); if (contractCode == null || contractCode.Length == 0) { this.internalTransferList.Add(new TransferInfo { From = smartContractState.Message.ContractAddress.ToUint160(this.network), To = addressTo.ToUint160(this.network), Value = amountToTransfer }); this.logger.LogTrace("(-)[TRANSFER_TO_SENDER]:Transfer {0} from {1} to {2}.", smartContractState.Message.ContractAddress, addressTo, amountToTransfer); return(TransferResult.Empty()); } this.logger.LogTrace("(-)[TRANSFER_TO_CONTRACT]"); // Calling a receive handler: string methodName = MethodCall.ExternalReceiveHandlerName; object[] parameters = new object[] { }; ulong gasBudget = DefaultGasLimit; // for Transfer always send limited gas to prevent re-entrance. return(ExecuteTransferFundsToContract(contractCode, smartContractState, addressTo, amountToTransfer, methodName, parameters, gasBudget)); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); ulong gasBudget = DefaultGasLimit; // for Transfer always send limited gas to prevent re-entrance. var message = new ContractTransferMessage( addressTo.ToUint160(this.network), smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, (Gas)gasBudget ); var result = this.state.Apply(message); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(addressTo), addressTo, nameof(amountToTransfer), amountToTransfer); ulong gasBudget = DefaultGasLimit; // for Transfer always send limited gas to prevent re-entrance. Gas gasRemaining = smartContractState.GasMeter.GasAvailable; if (gasRemaining < gasBudget || gasRemaining < GasPriceList.BaseCost) { return(TransferResult.Failed()); } var message = new ContractTransferMessage( addressTo.ToUint160(this.network), smartContractState.Message.ContractAddress.ToUint160(this.network), amountToTransfer, (Gas)gasBudget ); // Create a snapshot of the current state IState newState = this.state.Snapshot(); // Apply the message to the snapshot StateTransitionResult result = this.stateProcessor.Apply(newState, message); // Transition the current state to the new state if (result.IsSuccess) { this.state.TransitionTo(newState); } smartContractState.GasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
///<inheritdoc /> public ITransferResult Transfer(ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer) { Gas gasRemaining = smartContractState.GasMeter.GasAvailable; if (gasRemaining < GasPriceList.TransferCost) { return(TransferResult.Failed()); } ulong gasBudget = (gasRemaining < DefaultGasLimit) ? gasRemaining // have enough for at least a transfer but not for the DefaultGasLimit : DefaultGasLimit; // have enough for anything var message = new ContractTransferMessage( addressTo.ToUint160(), smartContractState.Message.ContractAddress.ToUint160(), amountToTransfer, (Gas)gasBudget ); // Create a snapshot of the current state IState newState = this.state.Snapshot(); // Apply the message to the snapshot StateTransitionResult result = this.stateProcessor.Apply(newState, message); // Transition the current state to the new state if (result.IsSuccess) { this.state.TransitionTo(newState); } smartContractState.GasMeter.Spend(result.GasConsumed); return(result.IsSuccess ? TransferResult.Empty() : TransferResult.Failed()); }
///<inheritdoc /> public ITransferResult Call( ISmartContractState smartContractState, Address addressTo, ulong amountToTransfer, string methodName, object[] parameters, ulong gasLimit = 0) { // TODO: Spend BaseFee here EnsureContractHasEnoughBalance(smartContractState, amountToTransfer); byte[] contractCode = this.contractStateRepository.GetCode(addressTo.ToUint160(this.network)); if (contractCode == null || contractCode.Length == 0) { return(TransferResult.Empty()); } // Here, we know contract has code, so we execute it // For a method call, send all the gas unless an amount was selected.Should only call trusted methods so re - entrance is less problematic. ulong gasBudget = (gasLimit != 0) ? gasLimit : smartContractState.GasMeter.GasAvailable; return(ExecuteTransferFundsToContract(contractCode, smartContractState, addressTo, amountToTransfer, methodName, parameters, gasBudget)); }