· 6 years ago · Sep 11, 2019, 08:02 AM
1func getLitecoinTransactionHex(for coin: BTMCoin, destination: String, amount: Int64) -> Single<String> {
2 return walletStorage.get()
3 .map { HDWallet(mnemonic: $0.seedPhrase, passphrase: "") }
4 .map { ($0.getExtendedPubKey(purpose: coin.type.purpose, coin: coin.type, version: coin.type.xpubVersion), $0) }
5 .flatMap { [api] xpub, wallet -> Single<(String, [Utxo], HDWallet)> in
6 print("XPUB:", xpub)
7 return Observable.combineLatest(api.getTokens(xpub: xpub).asObservable(),
8 api.getUtxos(xpub: xpub).asObservable())
9 .map { tokens, utxos in
10 print("UTXOS:", utxos)
11 print("TOKENS:", tokens.tokens)
12 let firstPath = tokens.tokens
13 .filter { $0.transfers == 0 }
14 .compactMap { DerivationPath($0.path) }
15 .first { $0.change == 1 }
16
17 guard let path = firstPath,
18 let publicKey = HDWallet.getPublicKeyFromExtended(extended: xpub, derivationPath: path.description)
19 else { throw CreateTransactionError.cantConvertPrivateKey }
20
21 let changeAddress = coin.type.deriveAddressFromPublicKey(publicKey: publicKey)
22
23 print("CHANGE_ADDRESS:", changeAddress)
24
25 return (changeAddress, utxos, wallet)
26 }
27 .asSingle()
28 }
29 .map { [unowned self] changeAddress, utxos, wallet in
30 return try self.getLitecoinTransactionId(changeAddress: changeAddress,
31 toAddress: destination,
32 amount: amount,
33 utxos: utxos,
34 wallet: wallet)
35 }
36 }
37
38 private func getLitecoinTransactionId(changeAddress: String,
39 toAddress: String,
40 amount: Int64,
41 utxos: [Utxo],
42 wallet: HDWallet) throws -> String {
43 var input = BitcoinSigningInput.with {
44 $0.hashType = TWSignatureHashTypeAll
45 $0.amount = amount
46 $0.byteFee = 1
47 $0.changeAddress = changeAddress
48 $0.toAddress = toAddress
49 }
50
51 utxos.compactMap { DerivationPath($0.path) }.forEach {
52 let privateKey = wallet.getKey(at: $0)
53 input.privateKey.append(privateKey.data)
54 }
55
56 utxos.forEach {
57 let redeemScript = BitcoinScript.buildForAddress(address: $0.address, coin: .litecoin)
58 var keyHash = redeemScript.matchPayToPubkeyHash()
59
60 if (redeemScript.isPayToWitnessScriptHash) {
61 keyHash = redeemScript.matchPayToWitnessPublicKeyHash()
62 }
63
64 if let key = keyHash?.hexString {
65 input.scripts[key] = redeemScript.data
66 }
67 }
68
69 try utxos.enumerated().forEach { (index, utxo) in
70 guard let hash = Data(hexString: utxo.txid) else {
71 throw CreateTransactionError.cantConvertOutput
72 }
73 let reversedHash = Data(hash.reversed())
74 let index = UInt32(utxo.vout)
75 let sequence = UInt32.max - UInt32(utxos.count) + index
76
77 let outpoint = BitcoinOutPoint.with {
78 $0.hash = reversedHash
79 $0.index = index
80 $0.sequence = sequence
81 }
82
83 guard let amount = Int64(utxo.value) else {
84 throw CreateTransactionError.cantConvertOutput
85 }
86 let redeemScript = BitcoinScript.buildForAddress(address: utxo.address, coin: .litecoin)
87
88 let utxo0 = BitcoinUnspentTransaction.with {
89 $0.script = redeemScript.data
90 $0.amount = amount
91 $0.outPoint = outpoint
92 }
93 input.utxo.append(utxo0)
94 }
95
96 let signer = BitcoinTransactionSigner(input: input)
97 let result = signer.sign()
98
99 guard let output = try? BitcoinSigningOutput(unpackingAny: result.objects[0]) else {
100 throw CreateTransactionError.cantConvertOutput
101 }
102
103 print(output.encoded.hexString)
104
105 return output.encoded.hexString
106 }