Skip to content

Commit

Permalink
Integrate new send workflow for Ton blockchain
Browse files Browse the repository at this point in the history
  • Loading branch information
ealymbaev committed Sep 30, 2024
1 parent c792775 commit a63a33a
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12835,7 +12835,7 @@
repositoryURL = "https://github.com/horizontalsystems/TonKit.Swift";
requirement = {
kind = exactVersion;
version = 1.0.9;
version = 1.0.10;
};
};
6BF66DD82BA1A73300963242 /* XCRemoteSwiftPackageReference "ObjectMapper" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,12 @@ extension JettonAdapter: IDepositAdapter {
}

extension JettonAdapter: ISendTonAdapter {
func estimateFee(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) async throws -> Decimal {
func transferData(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) throws -> TransferData {
guard let jettonBalance else {
throw EstimateError.noWalletAddress
throw SendError.noJettonBalance
}

let kitFee = try await tonKit.estimateFee(jettonWallet: jettonBalance.walletAddress, recipient: recipient, amount: sendAmount(jettonBalance: jettonBalance, amount: amount), comment: comment)
return TonAdapter.amount(kitAmount: kitFee)
}

func send(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) async throws {
guard let jettonBalance else {
throw EstimateError.noWalletAddress
}

try await tonKit.send(jettonWallet: jettonBalance.walletAddress, recipient: recipient, amount: sendAmount(jettonBalance: jettonBalance, amount: amount), comment: comment)
return try tonKit.transferData(jettonAddress: jettonBalance.jettonAddress, recipient: recipient, amount: sendAmount(jettonBalance: jettonBalance, amount: amount), comment: comment)
}

private func sendAmount(jettonBalance: JettonBalance, amount: TonAdapter.SendAmount) throws -> BigUInt {
Expand All @@ -152,8 +143,8 @@ extension JettonAdapter: ISendTonAdapter {
}

extension JettonAdapter {
enum EstimateError: Error {
case noWalletAddress
enum SendError: Error {
case noJettonBalance
}

enum AmountError: Error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,8 @@ extension TonAdapter: IDepositAdapter {
}

extension TonAdapter: ISendTonAdapter {
func estimateFee(recipient: FriendlyAddress, amount: SendAmount, comment: String?) async throws -> Decimal {
let kitFee = try await tonKit.estimateFee(recipient: recipient, amount: sendAmount(amount: amount), comment: comment)
return Self.amount(kitAmount: kitFee)
}

func send(recipient: FriendlyAddress, amount: SendAmount, comment: String?) async throws {
try await tonKit.send(recipient: recipient, amount: sendAmount(amount: amount), comment: comment)
func transferData(recipient: FriendlyAddress, amount: SendAmount, comment: String?) throws -> TransferData {
try tonKit.transferData(recipient: recipient, amount: sendAmount(amount: amount), comment: comment)
}

private func sendAmount(amount: SendAmount) throws -> Kit.SendAmount {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,21 @@ class TonKitManager {
return _tonKit
}

let type: TonKit.Kit.WalletType
let address: TonSwift.Address

switch account.type {
case .mnemonic:
guard let seed = account.type.mnemonicSeed else {
throw AdapterError.unsupportedAccount
}

let hdWallet = HDWallet(seed: seed, coinType: 607, xPrivKey: 0, curve: .ed25519)
let privateKey = try hdWallet.privateKey(account: 0)
let privateRaw = Data(privateKey.raw.bytes)
let pair = try TweetNacl.NaclSign.KeyPair.keyPair(fromSeed: privateRaw)
let keyPair = KeyPair(publicKey: .init(data: pair.publicKey), privateKey: .init(data: pair.secretKey))

type = .full(keyPair)
case let .tonAddress(address):
let tonAddress = try TonSwift.Address.parse(address)
type = .watch(tonAddress)
let (publicKey, _) = try Self.keyPair(accountType: account.type)
let contract = Self.contract(publicKey: publicKey)
address = try contract.address()
case let .tonAddress(_address):
address = try TonSwift.Address.parse(_address)
default:
throw AdapterError.unsupportedAccount
}

let tonKit = try TonKit.Kit.instance(
type: type,
walletVersion: .v4,
address: address,
network: .mainNet,
walletId: account.id,
minLogLevel: .error
Expand Down Expand Up @@ -168,6 +158,23 @@ extension TonKitManager {
}
}

extension TonKitManager {
static func contract(publicKey: Data) -> WalletContract {
WalletV4R2(publicKey: publicKey)
}

static func keyPair(accountType: AccountType) throws -> (publicKey: Data, secretKey: Data) {
guard let seed = accountType.mnemonicSeed else {
throw AdapterError.unsupportedAccount
}

let hdWallet = HDWallet(seed: seed, coinType: 607, xPrivKey: 0, curve: .ed25519)
let privateKey = try hdWallet.privateKey(account: 0)
let privateRaw = Data(privateKey.raw.bytes)
return try TweetNacl.NaclSign.KeyPair.keyPair(fromSeed: privateRaw)
}
}

extension Jetton {
var tokenType: TokenType {
.jetton(address: address.toString(bounceable: true))
Expand Down
4 changes: 2 additions & 2 deletions UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import HsToolKit
import MarketKit
import RxSwift
import ThemeKit
import TonKit
import TonSwift
import TronKit
import UIKit
Expand Down Expand Up @@ -102,8 +103,7 @@ protocol ISendTronAdapter {
}

protocol ISendTonAdapter {
func estimateFee(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) async throws -> Decimal
func send(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) async throws
func transferData(recipient: FriendlyAddress, amount: TonAdapter.SendAmount, comment: String?) throws -> TransferData
}

protocol IErc20Adapter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import TonSwift

class TonSendHandler {
private let tonKit: TonKit.Kit
private let contract: WalletContract
private let secretKey: Data
private let token: Token
let baseToken: Token
private let adapter: ISendTonAdapter & IBalanceAdapter
private let amount: Decimal
private let address: FriendlyAddress
private let memo: String?

init(tonKit: TonKit.Kit, token: Token, baseToken: Token, adapter: ISendTonAdapter & IBalanceAdapter, amount: Decimal, address: FriendlyAddress, memo: String?) {
init(tonKit: TonKit.Kit, contract: WalletContract, secretKey: Data, token: Token, baseToken: Token, adapter: ISendTonAdapter & IBalanceAdapter, amount: Decimal, address: FriendlyAddress, memo: String?) {
self.tonKit = tonKit
self.contract = contract
self.secretKey = secretKey
self.token = token
self.baseToken = baseToken
self.adapter = adapter
Expand All @@ -32,6 +36,7 @@ extension TonSendHandler: ISendHandler {
func sendData(transactionSettings _: TransactionSettings?) async throws -> ISendData {
var fee: Decimal?
var transactionError: Error?
var transferData: TransferData?
let tonBalance = TonAdapter.amount(kitAmount: tonKit.account?.balance)

var sendAmount: TonAdapter.SendAmount = .amount(value: amount)
Expand All @@ -43,8 +48,12 @@ extension TonSendHandler: ISendHandler {
var finalAmount = amount

do {
let estimatedFee = try await adapter.estimateFee(recipient: address, amount: sendAmount, comment: memo)
let _transferData = try adapter.transferData(recipient: address, amount: sendAmount, comment: memo)
let result = try await TonKit.Kit.emulate(transferData: _transferData, contract: contract, network: .mainNet)
let estimatedFee = TonAdapter.amount(kitAmount: result.totalFee)

fee = estimatedFee
transferData = _transferData

if token.type.isNative {
switch sendAmount {
Expand Down Expand Up @@ -75,20 +84,16 @@ extension TonSendHandler: ISendHandler {
memo: memo,
fee: fee,
transactionError: transactionError,
sendAmount: sendAmount
transferData: transferData
)
}

func send(data: ISendData) async throws {
guard let data = data as? SendData else {
guard let data = data as? SendData, let transferData = data.transferData else {
throw SendError.invalidData
}

_ = try await adapter.send(
recipient: data.address,
amount: data.sendAmount,
comment: data.memo
)
try await TonKit.Kit.send(transferData: transferData, contract: contract, secretKey: secretKey, network: .mainNet)
}
}

Expand All @@ -100,16 +105,16 @@ extension TonSendHandler {
let memo: String?
private let fee: Decimal?
private let transactionError: Error?
let sendAmount: TonAdapter.SendAmount
let transferData: TransferData?

init(token: Token, amount: Decimal, address: FriendlyAddress, memo: String?, fee: Decimal?, transactionError: Error?, sendAmount: TonAdapter.SendAmount) {
init(token: Token, amount: Decimal, address: FriendlyAddress, memo: String?, fee: Decimal?, transactionError: Error?, transferData: TransferData?) {
self.token = token
self.amount = amount
self.address = address
self.memo = memo
self.fee = fee
self.transactionError = transactionError
self.sendAmount = sendAmount
self.transferData = transferData
}

var feeData: FeeData? {
Expand Down Expand Up @@ -233,8 +238,14 @@ extension TonSendHandler {
return nil
}

guard let account = App.shared.accountManager.activeAccount, let (publicKey, secretKey) = try? TonKitManager.keyPair(accountType: account.type) else {
return nil
}

return TonSendHandler(
tonKit: tonKit,
contract: TonKitManager.contract(publicKey: publicKey),
secretKey: secretKey,
token: token,
baseToken: baseToken,
adapter: adapter,
Expand Down

0 comments on commit a63a33a

Please sign in to comment.