public bool IsContractDeployed(StorageContext storage, string name) { return(IsContractDeployed(storage, SmartContract.GetAddressForName(name))); }
internal bool TransferToken(RuntimeVM runtimeVM, string symbol, Address source, Address destination, BigInteger tokenID) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (!tokenInfo.Flags.HasFlag(TokenFlags.Transferable)) { throw new Exception("Not transferable"); } if (tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { throw new Exception("Should be non-fungible"); } if (tokenID <= 0) { return(false); } var ownerships = new OwnershipSheet(symbol); if (!ownerships.Take(runtimeVM.ChangeSet, source, tokenID)) { return(false); } if (!ownerships.Give(runtimeVM.ChangeSet, destination, tokenID)) { return(false); } var tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerSend, source, tokenID); if (!tokenTriggerResult) { return(false); } tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerReceive, destination, tokenID); if (!tokenTriggerResult) { return(false); } var accountScript = this.LookUpAddressScript(source); var accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerSend, source, tokenID); if (!accountTriggerResult) { return(false); } accountScript = this.LookUpAddressScript(destination); accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerSend, destination, tokenID); if (!accountTriggerResult) { return(false); } EditNFTLocation(symbol, tokenID, runtimeVM.Chain.Address, destination); return(true); }
/// <summary> /// Uses reflection to set the state field on the contract object. /// </summary> private static void SetStateField(SmartContract smartContract, ISmartContractState contractState) { FieldInfo field = typeof(SmartContract).GetField("state", DefaultBindingFlags); field.SetValue(smartContract, contractState); }
public void SaveTemplate(SmartContract smartContract) { Db.SmartContracts.Add(smartContract); Db.Save(); }
private static void DeployOrUpgrade(string[] args, NexusAPI api, BigInteger minFee, bool isUpgrade) { if (args.Length != 1) { throw new CommandException("Invalid number of arguments, expected file name"); } DoChecks(api); var fileName = args[0]; if (!File.Exists(fileName)) { throw new CommandException("Provided file does not exist"); } var extension = ScriptModule.ScriptExtension; if (!fileName.EndsWith(extension)) { throw new CommandException($"Provided file is not a compiled {extension} script"); } var abiFile = fileName.Replace(extension, ".abi"); if (!File.Exists(abiFile)) { throw new CommandException($"No ABI file {abiFile} that matches provided script file"); } var contractName = Path.GetFileNameWithoutExtension(fileName); var contractScript = File.ReadAllBytes(fileName); var abiBytes = File.ReadAllBytes(abiFile); var abi = ContractInterface.FromBytes(abiBytes); var sb = new ScriptBuilder(); bool isToken = ValidationUtils.IsValidTicker(contractName); var availableFlags = Enum.GetValues(typeof(TokenFlags)).Cast <TokenFlags>().ToArray(); sb.AllowGas(Keys.Address, Address.Null, minFee, 9999); if (isUpgrade) { // check for modification in flags if (isToken) { var symbol = contractName; var resultStr = api.Execute("getToken", new[] { symbol, "false" }); dynamic apiResult = JsonConvert.DeserializeObject <TokenResult>(resultStr); if (apiResult is TokenResult) { var oldToken = (TokenResult)apiResult; var oldFlags = TokenFlags.None; var splitFlags = oldToken.flags.Split(','); foreach (var entry in splitFlags) { TokenFlags flag; if (Enum.TryParse <TokenFlags>(entry, true, out flag)) { oldFlags |= flag; } } foreach (var flag in availableFlags) { var propName = "is" + flag; if (abi.HasMethod(propName)) { var isSet = ExecuteScript(contractScript, abi, propName).AsBool(); var wasSet = oldFlags.HasFlag(flag); if (isSet != wasSet) { throw new CommandException($"Detected '{flag}' flag change: {wasSet} => {isSet}"); } } } } else { throw new CommandException("could not find any deployed token contract for " + symbol); } } sb.CallInterop("Runtime.UpgradeContract", Keys.Address, contractName, contractScript, abiBytes); } else if (isToken) { if (!abi.HasMethod("getName")) { throw new CommandException("token contract is missing required 'name' property"); } var symbol = contractName; var name = ExecuteScript(contractScript, abi, "getName").AsString(); if (string.IsNullOrEmpty(name)) { throw new CommandException("token contract 'name' property is returning an empty value"); } BigInteger maxSupply = abi.HasMethod("getMaxSupply") ? ExecuteScript(contractScript, abi, "getMaxSupply").AsNumber() : 0; BigInteger decimals = abi.HasMethod("getDecimals") ? ExecuteScript(contractScript, abi, "getDecimals").AsNumber() : 0; TokenFlags flags = TokenFlags.None; foreach (var flag in availableFlags) { var propName = "is" + flag; if (abi.HasMethod(propName) && ExecuteScript(contractScript, abi, propName).AsBool()) { flags |= flag; } } sb.CallInterop("Nexus.CreateToken", Keys.Address, symbol, name, maxSupply, decimals, flags, contractScript, abiBytes); contractName = symbol; } else { sb.CallInterop("Runtime.DeployContract", Keys.Address, contractName, contractScript, abiBytes); } sb.SpendGas(Keys.Address); var script = sb.EndScript(); if (!isUpgrade) { var upgradeTrigger = AccountContract.GetTriggerForABI(AccountTrigger.OnUpgrade); if (abi.Implements(upgradeTrigger)) { logger.Message($"{contractName} implements proper triggers, and can be upgraded later."); } else { logger.Warning($"{contractName} does not implements proper triggers, can't be upgraded later."); } } var hash = ExecuteTransaction(api, script, ProofOfWork.Minimal, Keys); if (hash != Hash.Null) { var expectedEvent = isUpgrade ? EventKind.ContractUpgrade : (isToken ? EventKind.TokenCreate : EventKind.ContractDeploy); var expectedEventStr = expectedEvent.ToString(); var events = GetTransactionEvents(hash); if (events.Any(x => x.kind == expectedEventStr)) { var contractAddress = SmartContract.GetAddressForName(contractName); string action = isUpgrade ? "Upgraded" : "Deployed"; logger.Message($"{action} {contractName} at {contractAddress}"); } else { throw new CommandException("Transaction was confirmed but deployment event is missing!"); } } }
public async Task <Balance> GetContractBalance(SmartContract con) { return(await GetContractBalance(con.Address.Raw)); }
public void SpendGas(Address from) { if (Runtime.IsReadOnlyMode()) { return; } Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(_allowanceMap.ContainsKey(from), "no gas allowance found"); var availableAmount = _allowanceMap.Get <Address, BigInteger>(from); var spentGas = Runtime.UsedGas; var requiredAmount = spentGas * Runtime.GasPrice; Runtime.Expect(requiredAmount > 0, "gas fee must exist"); Runtime.Expect(availableAmount >= requiredAmount, "gas allowance is not enough"); /*var token = this.Runtime.Nexus.FuelToken; * Runtime.Expect(token != null, "invalid token"); * Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "must be fungible token"); */ var leftoverAmount = availableAmount - requiredAmount; var targetAddress = _allowanceTargets.Get <Address, Address>(from); BigInteger targetGas; Runtime.Notify(EventKind.GasPayment, from, new GasEventData(targetAddress, Runtime.GasPrice, spentGas)); // return escrowed gas to transaction creator Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, from, availableAmount); Runtime.Expect(spentGas > 1, "gas spent too low"); var burnGas = spentGas / 2; if (burnGas > 0) { Runtime.BurnTokens(DomainSettings.FuelTokenSymbol, from, burnGas); spentGas -= burnGas; } if (!targetAddress.IsNull) { targetGas = spentGas / 2; // 50% for dapps } else { targetGas = 0; } if (targetGas > 0) { var targetPayment = targetGas * Runtime.GasPrice; Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, from, targetAddress, targetPayment); spentGas -= targetGas; } if (spentGas > 0) { var validatorPayment = spentGas * Runtime.GasPrice; var validatorAddress = SmartContract.GetAddressForNative(NativeContractKind.Block); Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, from, validatorAddress, validatorPayment); spentGas = 0; } _allowanceMap.Remove(from); _allowanceTargets.Remove(from); Runtime.Notify(EventKind.GasPayment, Address.Null, new GasEventData(targetAddress, Runtime.GasPrice, spentGas)); if (Runtime.HasGenesis && Runtime.TransactionIndex == 0) { if (_lastInflation.Value == 0) { var genesisTime = Runtime.GetGenesisTime(); _lastInflation = genesisTime; } else { var infDiff = Runtime.Time - _lastInflation; var inflationPeriod = SecondsInDay * 90; if (infDiff >= inflationPeriod) { ApplyInflation(); } } } }
public void SpendGas(Address from) { if (Runtime.IsReadOnlyMode()) { return; } Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(_allowanceMap.ContainsKey(from), "no gas allowance found"); var availableAmount = _allowanceMap.Get <Address, BigInteger>(from); var spentGas = Runtime.UsedGas; var requiredAmount = spentGas * Runtime.GasPrice; Runtime.Expect(requiredAmount > 0, "gas fee must exist"); Runtime.Expect(availableAmount >= requiredAmount, "gas allowance is not enough"); /*var token = this.Runtime.Nexus.FuelToken; * Runtime.Expect(token != null, "invalid token"); * Runtime.Expect(token.Flags.HasFlag(TokenFlags.Fungible), "must be fungible token"); */ var leftoverAmount = availableAmount - requiredAmount; var targetAddress = _allowanceTargets.Get <Address, Address>(from); BigInteger targetGas; // TODO the transfers around here should pass through Nexus.TransferTokens!! // return unused gas to transaction creator if (leftoverAmount > 0) { Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, from, leftoverAmount), "gas leftover return failed"); } Runtime.Expect(spentGas > 1, "gas spent too low"); var bombGas = spentGas / 2; if (bombGas > 0) { var bombPayment = bombGas * Runtime.GasPrice; var bombAddress = SmartContract.GetAddressForNative(NativeContractKind.Bomb); Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, bombAddress, bombPayment), "gas bomb payment failed"); Runtime.Notify(EventKind.GasPayment, bombAddress, new GasEventData() { address = from, price = Runtime.GasPrice, amount = bombGas }); spentGas -= bombGas; } if (!targetAddress.IsNull) { targetGas = spentGas / 2; // 50% for dapps } else { targetGas = 0; } if (targetGas > 0) { var targetPayment = targetGas * Runtime.GasPrice; Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, targetAddress, targetPayment), "gas target payment failed"); Runtime.Notify(EventKind.GasPayment, targetAddress, new GasEventData() { address = from, price = Runtime.GasPrice, amount = targetGas }); spentGas -= targetGas; } if (spentGas > 0) { var validatorPayment = spentGas * Runtime.GasPrice; var validatorAddress = SmartContract.GetAddressForNative(NativeContractKind.Block); Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, validatorAddress, validatorPayment), "gas validator payment failed"); Runtime.Notify(EventKind.GasPayment, validatorAddress, new GasEventData() { address = from, price = Runtime.GasPrice, amount = spentGas }); spentGas = 0; } _allowanceMap.Remove(from); _allowanceTargets.Remove(from); // check if there is an active lend and it is time to pay it if (_loanMap.ContainsKey <Address>(from)) { var loan = _loanMap.Get <Address, GasLoanEntry>(from); Runtime.Expect(_lenderMap.ContainsKey <Address>(loan.lender), "missing lender info"); var gasLender = _lenderMap.Get <Address, GasLender>(loan.lender); if (loan.hash == Runtime.Transaction.Hash) { var unusedLoanAmount = loan.amount - requiredAmount; Runtime.Expect(unusedLoanAmount >= 0, "loan amount overflow"); // here we return the gas to the original pool, not the the payment address, because this is not a payment Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, from, this.Address, unusedLoanAmount), "unspend loan payment failed"); gasLender.balance += unusedLoanAmount; _lenderMap.Set <Address, GasLender>(loan.lender, gasLender); Runtime.Notify(EventKind.GasPayment, loan.borrower, new GasEventData() { address = from, price = 1, amount = unusedLoanAmount }); loan.amount = requiredAmount; loan.interest = (requiredAmount * LendReturn) / 100; _loanMap.Set <Address, GasLoanEntry>(from, loan); } else { Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, from, loan.lender, loan.amount), "loan payment failed"); Runtime.Expect(Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, from, gasLender.paymentAddress, loan.interest), "loan interest failed"); _loanMap.Remove <Address>(from); var list = _loanList.Get <Address, StorageList>(loan.lender); int index = -1; var count = list.Count(); for (int i = 0; i < count; i++) { var temp = list.Get <Address>(i); if (temp == from) { index = i; break; } } Runtime.Expect(index >= 0, "loan missing from list"); list.RemoveAt <Address>(index); Runtime.Notify(EventKind.GasPayment, loan.lender, new GasEventData() { address = from, price = 1, amount = loan.amount }); Runtime.Notify(EventKind.GasPayment, gasLender.paymentAddress, new GasEventData() { address = from, price = 1, amount = loan.interest }); } } }
private static BigInteger _calculateNumericLogicPayment(PbEntity.ConditionalPay _pay, byte[][] _preimages, byte _funcType) { int j = 0; BigInteger amount = 0; bool hasContracCond = false; PbEntity.ConditionType ConditionType = PbEntity.getConditionType(); PbEntity.TransferFunctionType TransferFunctionType = PbEntity.getTransferFunctionType(); PbEntity.Condition[] conditions = _pay.conditions; for (var i = 0; i < conditions.Length; i++) { PbEntity.Condition cond = _pay.conditions[i]; if (cond.conditionType == ConditionType.HASH_LOCK) { BasicMethods.assert(SmartContract.Sha256(_preimages[j]) == cond.hashLock, "wrong preimage"); j++; } else if ( cond.conditionType == ConditionType.DEPLOYED_CONTRACT || cond.conditionType == ConditionType.VIRTUAL_CONTRACT ) { byte[] numericCondHash = _getCondAddress(cond); DynamicCallContract dyncall = (DynamicCallContract)numericCondHash.ToDelegate(); BasicMethods.assert((bool)dyncall("isFinalized", new object[] { cond.argsQueryFinalization }), "Condition is not finalized"); BigInteger outcome = (BigInteger)dyncall("getOutcome", new object[] { cond.argsQueryOutcome }); if (_funcType == TransferFunctionType.NUMERIC_ADD) { amount = amount + outcome; } else if (_funcType == TransferFunctionType.NUMERIC_MAX) { amount = max(amount, outcome); } else if (_funcType == TransferFunctionType.NUMERIC_MIN) { if (hasContracCond) { amount = min(amount, outcome); } else { amount = outcome; } } else { BasicMethods.assert(false, "error"); } hasContracCond = true; } else { BasicMethods.assert(false, "condition type error"); } } PbEntity.TransferFunction transferFunction = _pay.transferFunc; PbEntity.TokenTransfer tokenTransfer = transferFunction.maxTransfer; PbEntity.AccountAmtPair accountAmtPair = tokenTransfer.receiver; if (hasContracCond) { BasicMethods.assert(amount <= accountAmtPair.amt, "exceed max transfer amount"); return(amount); } else { return(accountAmtPair.amt); } }
private static byte[] _calculatePayId(byte[] _payHash, byte[] _setter) { return(SmartContract.Sha256(_payHash.Concat(_setter))); }
public async Task <SmartContract> Create(SmartContract smartContract, List <SmartContractFunction> smartContractFunctions) { SmartContract mutatedSmartContract = null; using (SqlConnection conn = new SqlConnection(DbConfiguration.ConnectionString)) { conn.Open(); var transaction = conn.BeginTransaction(); SqlCommand sqlcmd = new SqlCommand(StoredProcedures.InsertSmartContract, conn); sqlcmd.CommandType = System.Data.CommandType.StoredProcedure; sqlcmd.Parameters.Add(new SqlParameter() { ParameterName = "@name", SqlDbType = System.Data.SqlDbType.VarChar, Value = smartContract.Name }); sqlcmd.Parameters.Add(new SqlParameter() { ParameterName = "@abi", SqlDbType = System.Data.SqlDbType.Text, Value = smartContract.Abi }); sqlcmd.Parameters.Add(new SqlParameter() { ParameterName = "@byteCode", SqlDbType = System.Data.SqlDbType.Text, Value = smartContract.ByteCode }); sqlcmd.Parameters.Add(new SqlParameter() { ParameterName = "@createdByUserLoginId", SqlDbType = System.Data.SqlDbType.VarChar, Value = smartContract.CreatedByUserLoginId }); try { sqlcmd.Connection = conn; sqlcmd.Transaction = transaction; var reader = await sqlcmd.ExecuteReaderAsync(); var result = reader.Read(); if (result) { mutatedSmartContract = new SmartContract(); mutatedSmartContract.SmartContractId = Convert.ToInt32(reader["SmartContractId"].ToString()); mutatedSmartContract.Name = reader["Name"]?.ToString(); mutatedSmartContract.Abi = reader["Abi"]?.ToString(); mutatedSmartContract.ByteCode = reader["ByteCode"]?.ToString(); mutatedSmartContract.CreatedByUserLoginId = reader["CreatedByUserLoginId"]?.ToString(); mutatedSmartContract.CreatedDatetime = string.IsNullOrEmpty(reader["CreatedDatetime"]?.ToString()) ? DateTime.MinValue : Convert.ToDateTime(reader["CreatedDatetime"]); mutatedSmartContract.UpdatedDatetime = string.IsNullOrEmpty(reader["UpdatedDatetime"]?.ToString()) ? DateTime.MinValue : Convert.ToDateTime(reader["UpdatedDatetime"]); } reader.Close(); foreach (var smartContractFunction in smartContractFunctions) { SqlCommand sqlCmdSmartContractFunction = new SqlCommand(StoredProcedures.InsertSmartContractFunction, conn); sqlCmdSmartContractFunction.CommandType = CommandType.StoredProcedure; sqlCmdSmartContractFunction.Transaction = transaction; sqlCmdSmartContractFunction.Parameters.Add(new SqlParameter() { ParameterName = "@smartContractId", SqlDbType = System.Data.SqlDbType.Int, Value = mutatedSmartContract.SmartContractId }); sqlCmdSmartContractFunction.Parameters.Add(new SqlParameter() { ParameterName = "@functionName", SqlDbType = System.Data.SqlDbType.VarChar, Value = smartContractFunction.FunctionName }); sqlCmdSmartContractFunction.Parameters.Add(new SqlParameter() { ParameterName = "@functionType", SqlDbType = System.Data.SqlDbType.VarChar, Value = smartContractFunction.FunctionType }); sqlCmdSmartContractFunction.Parameters.Add(new SqlParameter() { ParameterName = "@sequence", SqlDbType = System.Data.SqlDbType.Int, Value = smartContractFunction.Sequence }); var returnValue = await sqlCmdSmartContractFunction.ExecuteNonQueryAsync(); } transaction.Commit(); conn.Close(); } catch (Exception ex) { transaction.Rollback(); throw ex; } } return(mutatedSmartContract); }
public LifecycleResult(SmartContract obj) { this.Success = true; this.Object = obj; }
public void Read(TProtocol iprot) { iprot.IncrementRecursionDepth(); try { TField field; iprot.ReadStructBegin(); while (true) { field = iprot.ReadFieldBegin(); if (field.Type == TType.Stop) { break; } switch (field.ID) { case 1: if (field.Type == TType.Struct) { Status = new APIResponse(); Status.Read(iprot); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 2: if (field.Type == TType.I32) { Count = iprot.ReadI32(); } else { TProtocolUtil.Skip(iprot, field.Type); } break; case 3: if (field.Type == TType.List) { { SmartContractsList = new List <SmartContract>(); TList _list49 = iprot.ReadListBegin(); for (int _i50 = 0; _i50 < _list49.Count; ++_i50) { SmartContract _elem51; _elem51 = new SmartContract(); _elem51.Read(iprot); SmartContractsList.Add(_elem51); } iprot.ReadListEnd(); } } else { TProtocolUtil.Skip(iprot, field.Type); } break; default: TProtocolUtil.Skip(iprot, field.Type); break; } iprot.ReadFieldEnd(); } iprot.ReadStructEnd(); } finally { iprot.DecrementRecursionDepth(); } }
internal bool TransferTokens(RuntimeVM runtimeVM, string symbol, Address source, Address destination, BigInteger amount) { if (!TokenExists(symbol)) { return(false); } var tokenInfo = GetTokenInfo(symbol); if (!tokenInfo.Flags.HasFlag(TokenFlags.Transferable)) { throw new Exception("Not transferable"); } if (!tokenInfo.Flags.HasFlag(TokenFlags.Fungible)) { throw new Exception("Should be fungible"); } if (amount <= 0) { return(false); } var balances = new BalanceSheet(symbol); if (!balances.Subtract(runtimeVM.ChangeSet, source, amount)) { return(false); } if (!balances.Add(runtimeVM.ChangeSet, destination, amount)) { return(false); } var tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerSend, source, amount); if (!tokenTriggerResult) { return(false); } tokenTriggerResult = SmartContract.InvokeTrigger(runtimeVM, tokenInfo.Script, TokenContract.TriggerReceive, destination, amount); if (!tokenTriggerResult) { return(false); } var accountScript = this.LookUpAddressScript(source); var accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerSend, source, amount); if (!accountTriggerResult) { return(false); } accountScript = this.LookUpAddressScript(destination); accountTriggerResult = SmartContract.InvokeTrigger(runtimeVM, accountScript, AccountContract.TriggerSend, destination, amount); if (!accountTriggerResult) { return(false); } return(true); }
private static byte[] HashChildren(byte[] v, byte[] hash) { byte[] prefix = { 1 }; return(SmartContract.Sha256(prefix.Concat(v).Concat(hash))); }
public static Address GetContractAddress(string symbol) { return(SmartContract.GetAddressForName(symbol)); }
private static byte[] HashLeaf(byte[] value) { byte[] prefix = { 0x00 }; return(SmartContract.Sha256(prefix.Concat(value))); }
public void TestIndexGap() { var test = CreateAPI(); var simulator = test.simulator; var owner = test.owner; var sender = PhantasmaKeys.Generate(); var receiver = PhantasmaKeys.Generate(); var node = PhantasmaKeys.FromWIF(nodeWIF); var nexus = simulator.Nexus; var api = test.api; var contractAddress = SmartContract.GetAddressForName("relay"); simulator.BeginBlock(); simulator.GenerateTransfer(owner, sender.Address, nexus.RootChain, DomainSettings.FuelTokenSymbol, 100000000); simulator.EndBlock(); TopUpChannel(simulator, sender, 1000000); var indexGap = 5; var messageCount = 3; var messages = new RelayMessage[messageCount]; var random = new Random(); for (int i = 0; i < messageCount; i++) { var script = new byte[100]; random.NextBytes(script); var message = new RelayMessage { nexus = nexus.Name, index = i * indexGap, receiver = receiver.Address, //node.Address, script = script, sender = sender.Address, timestamp = Timestamp.Now }; messages[i] = message; var receipt = RelayReceipt.FromMessage(message, sender); string serializedHex = Base16.Encode(receipt.Serialize()); api.RelaySend(serializedHex); } var receipts = (ArrayResult)api.RelayReceive(receiver.Address.Text); Assert.IsTrue(receipts.values.Length == messageCount); for (int i = 0; i < messageCount; i++) { var obj = receipts.values[i]; Assert.IsTrue(obj is ReceiptResult); var receiptResult = (ReceiptResult)obj; Assert.IsTrue(receiptResult.nexus == messages[i].nexus); Assert.IsTrue(new BigInteger(receiptResult.index, 10) == messages[i].index); //Assert.IsTrue(receiptResult.receiver == messages[i].receiver); //Assert.IsTrue(receiptResult.script == messages[i].script); //Assert.IsTrue(receiptResult.sender == messages[i].sender); Assert.IsTrue(receiptResult.timestamp == messages[i].timestamp); } var lastMessage = messages[messageCount - 1]; var lastReceipt = RelayReceipt.FromMessage(lastMessage, sender); var fuelToken = simulator.Nexus.GetTokenInfo(simulator.Nexus.RootStorage, DomainSettings.FuelTokenSymbol); var senderInitialBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, sender.Address); var chainInitialBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, contractAddress); var receiverInitialBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, node.Address); simulator.BeginBlock(); var tx = simulator.GenerateCustomTransaction(sender, ProofOfWork.None, () => ScriptUtils.BeginScript().AllowGas(sender.Address, Address.Null, 1, 9999) .CallContract("relay", nameof(RelayContract.SettleChannel), lastReceipt). SpendGas(sender.Address).EndScript()); simulator.EndBlock(); var txCost = simulator.Nexus.RootChain.GetTransactionFee(tx); var senderFinalBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, sender.Address); var chainFinalBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, contractAddress); var receiverFinalBalance = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, fuelToken, receiver.Address); var expectedFee = RelayFeePerMessage * (lastReceipt.message.index + 1); Assert.IsTrue(senderFinalBalance == senderInitialBalance - txCost); Assert.IsTrue(receiverFinalBalance == receiverInitialBalance + (expectedFee / 2)); Assert.IsTrue(chainFinalBalance == chainInitialBalance - (expectedFee / 2)); //the sender's balance is escrowed in the chain address, so the chain just sends the other half of the fee away to the receiver }
static byte[] nameHashWithSubHash(byte[] roothash, byte[] subhash) { var domain = subhash.Concat(roothash); return(SmartContract.Sha256(domain)); }
//域名转hash算法 //aaa.bb.test =>{"test","bb","aa"} static byte[] nameHash(string domain) { return(SmartContract.Sha256(domain.AsByteArray())); }
public async Task <string> GetSmartContractCode(SmartContract c) { return(await GetSmartContractCode(c.Address.Raw)); }