// send to external chain public void WithdrawTokens(Address from, Address to, string symbol, BigInteger amount) { Runtime.Expect(amount > 0, "amount must be positive and greater than zero"); Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(from.IsUser, "source must be user address"); Runtime.Expect(to.IsInterop, "destination must be interop address"); Runtime.Expect(Runtime.TokenExists(symbol), "invalid token"); var transferTokenInfo = this.Runtime.GetToken(symbol); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.Transferable), "transfer token must be transferable"); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.External), "transfer token must be external"); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.Fungible), "transfer token must be fungible"); string platform; byte[] dummy; to.DecodeInterop(out platform, out dummy, 0); Runtime.Expect(platform != DomainSettings.PlatformName, "must be external platform"); Runtime.Expect(Runtime.PlatformExists(platform), "invalid platform"); var platformInfo = Runtime.GetPlatform(platform); Runtime.Expect(to != platformInfo.Address, "invalid target address"); var feeSymbol = platformInfo.Symbol; Runtime.Expect(Runtime.TokenExists(feeSymbol), "invalid fee token"); var feeTokenInfo = this.Runtime.GetToken(feeSymbol); Runtime.Expect(feeTokenInfo.Flags.HasFlag(TokenFlags.Fungible), "fee token must be fungible"); Runtime.Expect(feeTokenInfo.Flags.HasFlag(TokenFlags.Transferable), "fee token must be transferable"); var basePrice = UnitConversion.GetUnitValue(DomainSettings.FiatTokenDecimals) / InteropFeeRacio; // 50cents var feeAmount = Runtime.GetTokenQuote(DomainSettings.FiatTokenSymbol, feeSymbol, basePrice); Runtime.Expect(feeAmount > 0, "fee is too small"); Runtime.Expect(Runtime.TransferTokens(feeSymbol, from, this.Address, feeAmount), "fee transfer failed"); Runtime.Expect(Runtime.TransferTokens(symbol, from, platformInfo.Address, amount), "burn failed"); var collateralAmount = Runtime.GetTokenQuote(DomainSettings.FiatTokenSymbol, DomainSettings.FuelTokenSymbol, basePrice); var withdraw = new InteropWithdraw() { destination = to, transferAmount = amount, transferSymbol = symbol, feeAmount = feeAmount, feeSymbol = feeSymbol, hash = Runtime.Transaction.Hash, broker = Address.Null, collateralAmount = collateralAmount, timestamp = Runtime.Time }; _withdraws.Add <InteropWithdraw>(withdraw); Runtime.Notify(EventKind.TokenSend, from, new TokenEventData() { chainAddress = this.Address, value = amount, symbol = symbol }); Runtime.Notify(EventKind.TokenEscrow, from, new TokenEventData() { chainAddress = this.Address, value = feeAmount, symbol = symbol }); Runtime.Notify(EventKind.BrokerRequest, from, to); }
// send to external chain public void WithdrawTokens(Address from, Address to, string symbol, BigInteger amount) { Runtime.Expect(amount > 0, "amount must be positive and greater than zero"); Runtime.Expect(Runtime.IsWitness(from), "invalid witness"); Runtime.Expect(from.IsUser, "source must be user address"); Runtime.Expect(to.IsInterop, "destination must be interop address"); Runtime.Expect(Runtime.TokenExists(symbol), "invalid token"); var transferTokenInfo = this.Runtime.GetToken(symbol); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.Transferable), "transfer token must be transferable"); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.External), "transfer token must be external"); Runtime.Expect(transferTokenInfo.Flags.HasFlag(TokenFlags.Fungible), "transfer token must be fungible"); byte platformID; byte[] dummy; to.DecodeInterop(out platformID, out dummy); Runtime.Expect(platformID > 0, "invalid platform ID"); var platform = Runtime.GetPlatformByIndex(platformID); Runtime.Expect(platform != null, "invalid platform"); int interopIndex = -1; for (int i = 0; i < platform.InteropAddresses.Length; i++) { if (platform.InteropAddresses[i].LocalAddress == to) { interopIndex = i; break; } } Runtime.Expect(interopIndex == -1, "invalid target address"); var feeSymbol = platform.Symbol; Runtime.Expect(Runtime.TokenExists(feeSymbol), "invalid fee token"); var feeTokenInfo = this.Runtime.GetToken(feeSymbol); Runtime.Expect(feeTokenInfo.Flags.HasFlag(TokenFlags.Fungible), "fee token must be fungible"); Runtime.Expect(feeTokenInfo.Flags.HasFlag(TokenFlags.Transferable), "fee token must be transferable"); var basePrice = Runtime.GetGovernanceValue(InteropFeeTag); var feeAmount = Runtime.GetTokenQuote(DomainSettings.FiatTokenSymbol, feeSymbol, basePrice); Runtime.Expect(feeAmount > 0, "fee is too small"); Runtime.TransferTokens(feeSymbol, from, this.Address, feeAmount); // TODO support NFT Runtime.SwapTokens(Runtime.Chain.Name, from, platform.Name, to, symbol, amount, null, null); var withdraw = new InteropWithdraw() { destination = to, transferAmount = amount, transferSymbol = symbol, feeAmount = feeAmount, feeSymbol = feeSymbol, hash = Runtime.Transaction.Hash, timestamp = Runtime.Time }; _withdraws.Add <InteropWithdraw>(withdraw); }