From 7516e935afb11762185743220c9b5f3bac93ac28 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Thu, 22 Aug 2024 16:44:53 +0200 Subject: [PATCH 01/25] IOS-7718 Add Filecoin blockchain --- BlockchainSdk.xcodeproj/project.pbxproj | 12 + .../xcshareddata/swiftpm/Package.resolved | 236 +----------------- .../FilecoinExternalLinkProvider.swift | 26 ++ .../API/TestnetAPINodeInfoProvider.swift | 2 +- .../Common/Address/AddressTypesConfig.swift | 3 +- BlockchainSdk/Common/Blockchain.swift | 16 +- .../Blockchain/Blockchain+AllCases.swift | 2 + .../Derivations/DerivationConfigV1.swift | 2 + .../Derivations/DerivationConfigV2.swift | 2 + .../Derivations/DerivationConfigV3.swift | 2 + .../Factories/AddressServiceFactory.swift | 3 + .../EstimationFeeAddressFactory.swift | 2 + .../ExternalLinkProviderFactory.swift | 2 + BlockchainSdk/Extensions/TWCoin+.swift | 2 + 14 files changed, 73 insertions(+), 239 deletions(-) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 2d18bfa2d..75b505f5a 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -472,6 +472,7 @@ DA0E98D42C0472DB00C92985 /* KoinosTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0E98D32C0472DB00C92985 /* KoinosTarget.swift */; }; DA0E98D62C04755C00C92985 /* KoinosMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0E98D52C04755C00C92985 /* KoinosMethod.swift */; }; DA11507727DB217200CDC879 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA11507627DB217200CDC879 /* Launch Screen.storyboard */; }; + DA15D1EA2C77830E00FD733B /* FilecoinExternalLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */; }; DA18C4A9297AC63600EC4C05 /* NowNodesBlockBookConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA18C4A8297AC63600EC4C05 /* NowNodesBlockBookConfig.swift */; }; DA198B5629E3F6D300DB6EEA /* CosmosModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA198B5529E3F6D300DB6EEA /* CosmosModels.swift */; }; DA198B5929E3F6E400DB6EEA /* CosmosTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA198B5829E3F6E400DB6EEA /* CosmosTests.swift */; }; @@ -1398,6 +1399,7 @@ DA0E98D32C0472DB00C92985 /* KoinosTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTarget.swift; sourceTree = ""; }; DA0E98D52C04755C00C92985 /* KoinosMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosMethod.swift; sourceTree = ""; }; DA11507627DB217200CDC879 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; + DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinExternalLinkProvider.swift; sourceTree = ""; }; DA18C4A8297AC63600EC4C05 /* NowNodesBlockBookConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowNodesBlockBookConfig.swift; sourceTree = ""; }; DA198B5529E3F6D300DB6EEA /* CosmosModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CosmosModels.swift; sourceTree = ""; }; DA198B5829E3F6E400DB6EEA /* CosmosTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CosmosTests.swift; sourceTree = ""; }; @@ -2272,6 +2274,7 @@ 5DC7DD5C243F8375008F83F2 /* XRP */, DACAAB4F2BE8BA8A0039ED3D /* Koinos */, DA1BA9A52C454AEE006F6839 /* Mantle */, + DA15D1E82C7782F300FD733B /* Filecoin */, ); path = Blockchains; sourceTree = ""; @@ -3368,6 +3371,14 @@ path = Pods; sourceTree = ""; }; + DA15D1E82C7782F300FD733B /* Filecoin */ = { + isa = PBXGroup; + children = ( + DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, + ); + path = Filecoin; + sourceTree = ""; + }; DA18C4A7297AC62600EC4C05 /* Implementations */ = { isa = PBXGroup; children = ( @@ -5179,6 +5190,7 @@ DC5E652A2B1650F400E81AA5 /* OP_VER.swift in Sources */, DC5E65322B1650F400E81AA5 /* OP_VERIF.swift in Sources */, B6C5A60C2BF627B3008586B3 /* HederaNetworkResult.TransactionsInfo.swift in Sources */, + DA15D1EA2C77830E00FD733B /* FilecoinExternalLinkProvider.swift in Sources */, 2D24F5C82B6D2C7100D502A0 /* AptosProviderTarget.swift in Sources */, B64B728C2AEC9C7B005C8C7C /* Lock.swift in Sources */, 5DC7DD62244077D7008F83F2 /* XRPNetworkService.swift in Sources */, diff --git a/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved index 63bdb0b5f..50f3c9a46 100644 --- a/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,105 +1,6 @@ { - "originHash" : "de1af1fe46575050340d4c1e3bff712b85f35f88e3b4a5357c5bd0afe10705fe", + "originHash" : "1cf5dd977524809e063852014ed42f1e17e990112a76550ad375a7406eca0914", "pins" : [ - { - "identity" : "anyasyncsequence", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vsanthanam/AnyAsyncSequence.git", - "state" : { - "revision" : "9fee8443252bb25e191b0b3b03a006aabac44088", - "version" : "1.0.2" - } - }, - { - "identity" : "base32", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Jarema/Base32.git", - "state" : { - "revision" : "7f723a2e55f1c76e7c79263aebf89dbfcd58e77d", - "version" : "0.10.2" - } - }, - { - "identity" : "bigint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/attaswift/BigInt", - "state" : { - "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version" : "5.3.0" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", - "state" : { - "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version" : "1.8.1" - } - }, - { - "identity" : "float16", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SusanDoggie/Float16.git", - "state" : { - "revision" : "936ae66adccf1c91bcaeeb9c0cddde78a13695c3", - "version" : "1.1.1" - } - }, - { - "identity" : "grpc-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tangem/grpc-swift.git", - "state" : { - "revision" : "d1d312e2547f0091341efb9f465791dd8380a24c", - "version" : "1.21.0-tangem1" - } - }, - { - "identity" : "hedera-sdk-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tangem/hedera-sdk-swift.git", - "state" : { - "revision" : "4363eee442377ba3bb4254330bb567bb75780ec1", - "version" : "0.26.0-tangem3" - } - }, - { - "identity" : "icpkit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tangem/IcpKit", - "state" : { - "revision" : "02aad763a1ebb0847b1f0eaff755159b3a95707a", - "version" : "0.1.2-tangem3" - } - }, - { - "identity" : "potentcodables", - "kind" : "remoteSourceControl", - "location" : "https://github.com/outfoxx/PotentCodables.git", - "state" : { - "revision" : "660e33e84e00b9bf07bd41dd99ff800600e435e7", - "version" : "3.5.0" - } - }, - { - "identity" : "regex", - "kind" : "remoteSourceControl", - "location" : "https://github.com/sharplet/Regex.git", - "state" : { - "revision" : "76c2b73d4281d77fc3118391877efd1bf972f515", - "version" : "2.1.1" - } - }, - { - "identity" : "scalecodec.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tesseract-one/ScaleCodec.swift", - "state" : { - "revision" : "bd39b2d68d87126a61b62a071ee4c065e2a1fe30", - "version" : "0.2.1" - } - }, { "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", @@ -109,114 +10,6 @@ "version" : "0.12.2" } }, - { - "identity" : "swift-asn1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-asn1.git", - "state" : { - "revision" : "eb11d30c1de3b896f55aefdb3745dd5e7e1f319f", - "version" : "0.3.0" - } - }, - { - "identity" : "swift-atomics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-atomics.git", - "state" : { - "revision" : "cd142fd2f64be2100422d658e7411e39489da985", - "version" : "1.2.0" - } - }, - { - "identity" : "swift-collections", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-collections.git", - "state" : { - "revision" : "d029d9d39c87bed85b1c50adee7c41795261a192", - "version" : "1.0.6" - } - }, - { - "identity" : "swift-http-types", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-types", - "state" : { - "revision" : "12358d55a3824bd5fed310b999ea8cf83a9a1a65", - "version" : "1.0.3" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5", - "version" : "1.5.4" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "635b2589494c97e48c62514bc8b37ced762e0a62", - "version" : "2.63.0" - } - }, - { - "identity" : "swift-nio-extras", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-extras.git", - "state" : { - "revision" : "363da63c1966405764f380c627409b2f9d9e710b", - "version" : "1.21.0" - } - }, - { - "identity" : "swift-nio-http2", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-http2.git", - "state" : { - "revision" : "0904bf0feb5122b7e5c3f15db7df0eabe623dd87", - "version" : "1.30.0" - } - }, - { - "identity" : "swift-nio-ssl", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-ssl.git", - "state" : { - "revision" : "7c381eb6083542b124a6c18fae742f55001dc2b5", - "version" : "2.26.0" - } - }, - { - "identity" : "swift-nio-transport-services", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-transport-services.git", - "state" : { - "revision" : "6cbe0ed2b394f21ab0d46b9f0c50c6be964968ce", - "version" : "1.20.1" - } - }, - { - "identity" : "swift-numberkit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/objecthub/swift-numberkit.git", - "state" : { - "revision" : "0f9c918dcea73f6ff4ff762b8e83a0991ca668d9", - "version" : "2.4.2" - } - }, - { - "identity" : "swift-numerics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-numerics", - "state" : { - "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", - "version" : "1.0.2" - } - }, { "identity" : "swift-protobuf-binaries", "kind" : "remoteSourceControl", @@ -226,24 +19,6 @@ "version" : "1.25.2-tangem1" } }, - { - "identity" : "swift-system", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-system.git", - "state" : { - "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", - "version" : "1.2.1" - } - }, - { - "identity" : "ton-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tangem/ton-swift.git", - "state" : { - "revision" : "7030234ff239796c5f71f0e65eb4e9ffec5a83cb", - "version" : "1.0.10-tangem1" - } - }, { "identity" : "tweetnacl-swiftwrap", "kind" : "remoteSourceControl", @@ -252,15 +27,6 @@ "revision" : "f8fd111642bf2336b11ef9ea828510693106e954", "version" : "1.1.0" } - }, - { - "identity" : "wallet-core-binaries-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tangem/wallet-core-binaries-ios.git", - "state" : { - "revision" : "67be5876186284e85a5f5f8757de209ba53d5729", - "version" : "4.0.46-tangem1" - } } ], "version" : 3 diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift new file mode 100644 index 000000000..9aaffbed9 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift @@ -0,0 +1,26 @@ +// +// FilecoinExternalLinkProvider.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 22.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinExternalLinkProvider: ExternalLinkProvider { + private let baseExplorerUrl = "https://filfox.info" + + var testnetFaucetURL: URL? { + URL(string: "https://faucet.calibnet.chainsafe-fil.io") + } + + func url(transaction hash: String) -> URL? { + // TODO: [FILECOIN] Unsupported ? + nil + } + + func url(address: String, contractAddress: String?) -> URL? { + URL(string: "\(baseExplorerUrl)/address/\(address)") + } +} diff --git a/BlockchainSdk/Common/API/TestnetAPINodeInfoProvider.swift b/BlockchainSdk/Common/API/TestnetAPINodeInfoProvider.swift index a3c900e78..75c7a23a9 100644 --- a/BlockchainSdk/Common/API/TestnetAPINodeInfoProvider.swift +++ b/BlockchainSdk/Common/API/TestnetAPINodeInfoProvider.swift @@ -219,7 +219,7 @@ struct TestnetAPINodeInfoProvider { case .bitcoin, .litecoin, .disChain, .rsk, .bitcoinCash, .binance, .cardano, .xrp, .ducatus, .tezos, .dogecoin, .solana, .kusama, .dash, .gnosis, .kaspa, .terraV1, .terraV2, .cronos, .octa, .playa3ullGames, .radiant, .joystream, - .bittensor, .internetComputer: + .bittensor, .internetComputer, .filecoin: return nil } } diff --git a/BlockchainSdk/Common/Address/AddressTypesConfig.swift b/BlockchainSdk/Common/Address/AddressTypesConfig.swift index 726a63d2e..5f693a434 100644 --- a/BlockchainSdk/Common/Address/AddressTypesConfig.swift +++ b/BlockchainSdk/Common/Address/AddressTypesConfig.swift @@ -82,7 +82,8 @@ struct AddressTypesConfig { .internetComputer, .koinos, .cyber, - .blast: + .blast, + .filecoin: return [.default] } } diff --git a/BlockchainSdk/Common/Blockchain.swift b/BlockchainSdk/Common/Blockchain.swift index cad56a4e1..71a594d0e 100644 --- a/BlockchainSdk/Common/Blockchain.swift +++ b/BlockchainSdk/Common/Blockchain.swift @@ -82,6 +82,7 @@ public indirect enum Blockchain: Equatable, Hashable { case internetComputer case cyber(testnet: Bool) case blast(testnet: Bool) + case filecoin public var isTestnet: Bool { switch self { @@ -142,7 +143,8 @@ public indirect enum Blockchain: Equatable, Hashable { .kaspa, .joystream, .internetComputer, - .bittensor: + .bittensor, + .filecoin: return false case .stellar(_, let testnet), .hedera(_, let testnet), @@ -269,7 +271,8 @@ public indirect enum Blockchain: Equatable, Hashable { .taraxa, .base, .cyber, - .blast: + .blast, + .filecoin: return 18 case .cardano, .xrp, @@ -429,6 +432,8 @@ public indirect enum Blockchain: Equatable, Hashable { return isTestnet ? "tKOIN" : "KOIN" case .internetComputer: return "ICP" + case .filecoin: + return "FIL" } } @@ -886,6 +891,7 @@ extension Blockchain: Codable { case .internetComputer: return "internet-computer" case .cyber: return "cyber" case .blast: return "blast" + case .filecoin: return "filecoin" } } @@ -976,6 +982,7 @@ extension Blockchain: Codable { case "internet-computer": self = .internetComputer case "cyber": self = .cyber(testnet: isTestnet) case "blast": self = .blast(testnet: isTestnet) + case "filecoin": self = .filecoin default: throw BlockchainSdkError.decodingFailed } @@ -1189,6 +1196,8 @@ private extension Blockchain { case .network: return "blast" case .coin: return "blast-ethereum" } + case .filecoin: + return "filecoin" } } @@ -1297,6 +1306,9 @@ extension Blockchain { return MantleWalletAssembly() case .internetComputer: return ICPWalletAssembly() + case .filecoin: + // TODO: [FILECOIN] + fatalError("Not implemented") } } } diff --git a/BlockchainSdk/Common/Blockchain/Blockchain+AllCases.swift b/BlockchainSdk/Common/Blockchain/Blockchain+AllCases.swift index b8f27a2a8..43c798485 100644 --- a/BlockchainSdk/Common/Blockchain/Blockchain+AllCases.swift +++ b/BlockchainSdk/Common/Blockchain/Blockchain+AllCases.swift @@ -80,6 +80,7 @@ public extension Blockchain { case .internetComputer: break case .cyber: break case .blast: break + case .filecoin: break // READ BELOW: // // Did you get a compilation error here? If so, add your new blockchain to the array below @@ -153,6 +154,7 @@ public extension Blockchain { .internetComputer, .cyber(testnet: false), .blast(testnet: false), + .filecoin, ] } } diff --git a/BlockchainSdk/Common/Derivations/DerivationConfigV1.swift b/BlockchainSdk/Common/Derivations/DerivationConfigV1.swift index f5f2b5ddc..751c60d06 100644 --- a/BlockchainSdk/Common/Derivations/DerivationConfigV1.swift +++ b/BlockchainSdk/Common/Derivations/DerivationConfigV1.swift @@ -133,6 +133,8 @@ public struct DerivationConfigV1: DerivationConfig { return "m/44'/659'/0'/0/0" case .internetComputer: return "m/44'/223'/0'/0/0" + case .filecoin: + return "m/44'/461'/0'/0/0" } } } diff --git a/BlockchainSdk/Common/Derivations/DerivationConfigV2.swift b/BlockchainSdk/Common/Derivations/DerivationConfigV2.swift index eabe309a7..9ac4a6bfc 100644 --- a/BlockchainSdk/Common/Derivations/DerivationConfigV2.swift +++ b/BlockchainSdk/Common/Derivations/DerivationConfigV2.swift @@ -120,6 +120,8 @@ public struct DerivationConfigV2: DerivationConfig { return "m/44'/659'/0'/0/0" case .internetComputer: return "m/44'/223'/0'/0/0" + case .filecoin: + return "m/44'/461'/0'/0/0" } } } diff --git a/BlockchainSdk/Common/Derivations/DerivationConfigV3.swift b/BlockchainSdk/Common/Derivations/DerivationConfigV3.swift index 881297892..34d638011 100644 --- a/BlockchainSdk/Common/Derivations/DerivationConfigV3.swift +++ b/BlockchainSdk/Common/Derivations/DerivationConfigV3.swift @@ -125,6 +125,8 @@ public struct DerivationConfigV3: DerivationConfig { return "m/44'/659'/0'/0/0" case .internetComputer: return "m/44'/223'/0'/0/0" + case .filecoin: + return "m/44'/461'/0'/0/0" } } } diff --git a/BlockchainSdk/Common/Factories/AddressServiceFactory.swift b/BlockchainSdk/Common/Factories/AddressServiceFactory.swift index 1bd5e200a..4015ccf37 100644 --- a/BlockchainSdk/Common/Factories/AddressServiceFactory.swift +++ b/BlockchainSdk/Common/Factories/AddressServiceFactory.swift @@ -130,6 +130,9 @@ public struct AddressServiceFactory { case .koinos: let network: BitcoinNetwork = isTestnet ? .testnet : .mainnet return KoinosAddressService(networkParams: network.networkParams) + case .filecoin: + // TODO: [FILECOIN] Implement + fatalError("Not implemented") } } } diff --git a/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift b/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift index ae03dd265..2fd4a98c2 100644 --- a/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift +++ b/BlockchainSdk/Common/Factories/EstimationFeeAddressFactory.swift @@ -96,6 +96,8 @@ struct EstimationFeeAddressFactory { return "EQAY92urFDKejoDRdi_EfRKLGB1JkGjD8z1inj_DhgBaD0Xo" case .koinos: return "1C423Vbd44zjghhJR5fKJdLFS3rgVFUc9A" + case .filecoin: + return "f1wxdu6d25dc4hmebdfgriswooum22plhmmpxibzq" } } } diff --git a/BlockchainSdk/Common/Factories/ExternalLinkProviderFactory.swift b/BlockchainSdk/Common/Factories/ExternalLinkProviderFactory.swift index 983fd4380..bd1bd568e 100644 --- a/BlockchainSdk/Common/Factories/ExternalLinkProviderFactory.swift +++ b/BlockchainSdk/Common/Factories/ExternalLinkProviderFactory.swift @@ -149,6 +149,8 @@ public struct ExternalLinkProviderFactory { return CyberExternalLinkProvider(isTestnet: isTestnet) case .blast: return BlastExternalLinkProvider(isTestnet: isTestnet) + case .filecoin: + return FilecoinExternalLinkProvider() } } } diff --git a/BlockchainSdk/Extensions/TWCoin+.swift b/BlockchainSdk/Extensions/TWCoin+.swift index c2c9ff3eb..791d40a8d 100644 --- a/BlockchainSdk/Extensions/TWCoin+.swift +++ b/BlockchainSdk/Extensions/TWCoin+.swift @@ -82,6 +82,8 @@ extension CoinType { self = .hedera case .internetComputer: self = .internetComputer + case .filecoin: + self = .filecoin case .ethereumPoW, .disChain, .rsk, From bb770e1de58465df3b25a302da80589ecd077e1f Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Thu, 22 Aug 2024 16:46:12 +0200 Subject: [PATCH 02/25] IOS-7718 Revert Package.resolved --- .../xcshareddata/swiftpm/Package.resolved | 236 +++++++++++++++++- 1 file changed, 235 insertions(+), 1 deletion(-) diff --git a/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved b/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved index 50f3c9a46..63bdb0b5f 100644 --- a/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/BlockchainSdk.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,105 @@ { - "originHash" : "1cf5dd977524809e063852014ed42f1e17e990112a76550ad375a7406eca0914", + "originHash" : "de1af1fe46575050340d4c1e3bff712b85f35f88e3b4a5357c5bd0afe10705fe", "pins" : [ + { + "identity" : "anyasyncsequence", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vsanthanam/AnyAsyncSequence.git", + "state" : { + "revision" : "9fee8443252bb25e191b0b3b03a006aabac44088", + "version" : "1.0.2" + } + }, + { + "identity" : "base32", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Jarema/Base32.git", + "state" : { + "revision" : "7f723a2e55f1c76e7c79263aebf89dbfcd58e77d", + "version" : "0.10.2" + } + }, + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", + "version" : "1.8.1" + } + }, + { + "identity" : "float16", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SusanDoggie/Float16.git", + "state" : { + "revision" : "936ae66adccf1c91bcaeeb9c0cddde78a13695c3", + "version" : "1.1.1" + } + }, + { + "identity" : "grpc-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tangem/grpc-swift.git", + "state" : { + "revision" : "d1d312e2547f0091341efb9f465791dd8380a24c", + "version" : "1.21.0-tangem1" + } + }, + { + "identity" : "hedera-sdk-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tangem/hedera-sdk-swift.git", + "state" : { + "revision" : "4363eee442377ba3bb4254330bb567bb75780ec1", + "version" : "0.26.0-tangem3" + } + }, + { + "identity" : "icpkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tangem/IcpKit", + "state" : { + "revision" : "02aad763a1ebb0847b1f0eaff755159b3a95707a", + "version" : "0.1.2-tangem3" + } + }, + { + "identity" : "potentcodables", + "kind" : "remoteSourceControl", + "location" : "https://github.com/outfoxx/PotentCodables.git", + "state" : { + "revision" : "660e33e84e00b9bf07bd41dd99ff800600e435e7", + "version" : "3.5.0" + } + }, + { + "identity" : "regex", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sharplet/Regex.git", + "state" : { + "revision" : "76c2b73d4281d77fc3118391877efd1bf972f515", + "version" : "2.1.1" + } + }, + { + "identity" : "scalecodec.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tesseract-one/ScaleCodec.swift", + "state" : { + "revision" : "bd39b2d68d87126a61b62a071ee4c065e2a1fe30", + "version" : "0.2.1" + } + }, { "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", @@ -10,6 +109,114 @@ "version" : "0.12.2" } }, + { + "identity" : "swift-asn1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-asn1.git", + "state" : { + "revision" : "eb11d30c1de3b896f55aefdb3745dd5e7e1f319f", + "version" : "0.3.0" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "cd142fd2f64be2100422d658e7411e39489da985", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "d029d9d39c87bed85b1c50adee7c41795261a192", + "version" : "1.0.6" + } + }, + { + "identity" : "swift-http-types", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-types", + "state" : { + "revision" : "12358d55a3824bd5fed310b999ea8cf83a9a1a65", + "version" : "1.0.3" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5", + "version" : "1.5.4" + } + }, + { + "identity" : "swift-nio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio.git", + "state" : { + "revision" : "635b2589494c97e48c62514bc8b37ced762e0a62", + "version" : "2.63.0" + } + }, + { + "identity" : "swift-nio-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-extras.git", + "state" : { + "revision" : "363da63c1966405764f380c627409b2f9d9e710b", + "version" : "1.21.0" + } + }, + { + "identity" : "swift-nio-http2", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-http2.git", + "state" : { + "revision" : "0904bf0feb5122b7e5c3f15db7df0eabe623dd87", + "version" : "1.30.0" + } + }, + { + "identity" : "swift-nio-ssl", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-ssl.git", + "state" : { + "revision" : "7c381eb6083542b124a6c18fae742f55001dc2b5", + "version" : "2.26.0" + } + }, + { + "identity" : "swift-nio-transport-services", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-nio-transport-services.git", + "state" : { + "revision" : "6cbe0ed2b394f21ab0d46b9f0c50c6be964968ce", + "version" : "1.20.1" + } + }, + { + "identity" : "swift-numberkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/objecthub/swift-numberkit.git", + "state" : { + "revision" : "0f9c918dcea73f6ff4ff762b8e83a0991ca668d9", + "version" : "2.4.2" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", + "version" : "1.0.2" + } + }, { "identity" : "swift-protobuf-binaries", "kind" : "remoteSourceControl", @@ -19,6 +226,24 @@ "version" : "1.25.2-tangem1" } }, + { + "identity" : "swift-system", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-system.git", + "state" : { + "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", + "version" : "1.2.1" + } + }, + { + "identity" : "ton-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tangem/ton-swift.git", + "state" : { + "revision" : "7030234ff239796c5f71f0e65eb4e9ffec5a83cb", + "version" : "1.0.10-tangem1" + } + }, { "identity" : "tweetnacl-swiftwrap", "kind" : "remoteSourceControl", @@ -27,6 +252,15 @@ "revision" : "f8fd111642bf2336b11ef9ea828510693106e954", "version" : "1.1.0" } + }, + { + "identity" : "wallet-core-binaries-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tangem/wallet-core-binaries-ios.git", + "state" : { + "revision" : "67be5876186284e85a5f5f8757de209ba53d5729", + "version" : "4.0.46-tangem1" + } } ], "version" : 3 From b81a6cef395ec0bde6817767d9d72f08128f115e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:31:49 +0100 Subject: [PATCH 03/25] Bump rexml from 3.2.8 to 3.3.6 (#811) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e3f6aa31b..fc9d44c0b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,8 +238,8 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.6) + strscan rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -269,13 +269,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.24.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) From bf272b3175ae33b3add0ac8f72c527a431708afe Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sun, 25 Aug 2024 21:52:54 +0200 Subject: [PATCH 04/25] Revert "Merge branch 'develop' into feature/IOS-7718_filecoin_blockchain" This reverts commit 43be0dcb792874f232b2525c6e74c2c8e5db434b, reversing changes made to bb770e1de58465df3b25a302da80589ecd077e1f. --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index fc9d44c0b..e3f6aa31b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,8 +238,8 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.3.6) - strscan + rexml (3.2.8) + strscan (>= 3.0.9) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -269,13 +269,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.25.0) + xcodeproj (1.24.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (>= 3.3.2, < 4.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) From c43e5b0f5dbd1fa693917d39b19644266b8a5b46 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sun, 25 Aug 2024 22:04:10 +0200 Subject: [PATCH 05/25] IOS-7718 Fix comment --- .../Blockchains/Filecoin/FilecoinExternalLinkProvider.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift index 9aaffbed9..3f6b0987d 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift @@ -16,7 +16,10 @@ struct FilecoinExternalLinkProvider: ExternalLinkProvider { } func url(transaction hash: String) -> URL? { - // TODO: [FILECOIN] Unsupported ? + /// This method returns `nil` because Filecoin does not use transaction hashes as message identifiers. + /// In other blockchains, a transaction hash can be directly used to generate a URL to explore the transaction details. + /// However, in Filecoin, message IDs (which are used to identify transactions) are not derived from transaction hashes. + /// Therefore, constructing a URL in the format `"\(baseExplorerUrl)/message/\(hash)"` is not applicable. nil } From f897f62fde9c7d77ba8daf7a3cec748e9af87494 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sun, 25 Aug 2024 22:06:52 +0200 Subject: [PATCH 06/25] IOS-7718 Add TODO for WalletAssembly --- BlockchainSdk.xcodeproj/project.pbxproj | 4 ++++ .../Filecoin/FilecoinWalletAssembly.swift | 16 ++++++++++++++++ BlockchainSdk/Common/Blockchain.swift | 3 +-- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 75b505f5a..014beb766 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -484,6 +484,7 @@ DA1BA9A72C454AFB006F6839 /* MantleWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BA9A62C454AFB006F6839 /* MantleWalletManager.swift */; }; DA1BA9A92C454C53006F6839 /* MantleWalletAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BA9A82C454C53006F6839 /* MantleWalletAssembly.swift */; }; DA1D3B7B2B57B8FB00247393 /* BigUInt+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1D3B7A2B57B8FB00247393 /* BigUInt+.swift */; }; + DA20BD6A2C7BC5E9000F02DF /* FilecoinWalletAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */; }; DA2309D52C123510002A930C /* FeeResourceRestrictable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2309D42C123510002A930C /* FeeResourceRestrictable.swift */; }; DA2E770029769BF6001FF957 /* TransactionCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E76FF29769BF5001FF957 /* TransactionCreator.swift */; }; DA3081322817EC1A00DE41F1 /* TronTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3081312817EC1A00DE41F1 /* TronTransactionBuilder.swift */; }; @@ -1411,6 +1412,7 @@ DA1BA9A62C454AFB006F6839 /* MantleWalletManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MantleWalletManager.swift; sourceTree = ""; }; DA1BA9A82C454C53006F6839 /* MantleWalletAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MantleWalletAssembly.swift; sourceTree = ""; }; DA1D3B7A2B57B8FB00247393 /* BigUInt+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BigUInt+.swift"; sourceTree = ""; }; + DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinWalletAssembly.swift; sourceTree = ""; }; DA2309D42C123510002A930C /* FeeResourceRestrictable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeeResourceRestrictable.swift; sourceTree = ""; }; DA2E76FF29769BF5001FF957 /* TransactionCreator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionCreator.swift; sourceTree = ""; }; DA3081312817EC1A00DE41F1 /* TronTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronTransactionBuilder.swift; sourceTree = ""; }; @@ -3375,6 +3377,7 @@ isa = PBXGroup; children = ( DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, + DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, ); path = Filecoin; sourceTree = ""; @@ -5161,6 +5164,7 @@ EFB9523D2A6FDB2A00996D16 /* TransactionHistoryProvider.swift in Sources */, 2D9E28042B95E66200DDE63D /* BitcoinWalletCoreAddressAdapter.swift in Sources */, EF3B19162AA5C9530084AA1C /* ExternalLinkProvider.swift in Sources */, + DA20BD6A2C7BC5E9000F02DF /* FilecoinWalletAssembly.swift in Sources */, 0AF90CDD2B87658600772F04 /* AuroraExternalLinkProvider.swift in Sources */, 0A0E225D2B9B366400075FF1 /* MoonbeamExternalLinkProvider.swift in Sources */, B6F3AA722ADD925D0059C99A /* NEARTarget.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift new file mode 100644 index 000000000..e5a4f4a0e --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift @@ -0,0 +1,16 @@ +// +// FilecoinWalletAssembly.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 25.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinWalletAssembly: WalletManagerAssembly { + func make(with input: WalletManagerAssemblyInput) throws -> WalletManager { + // TODO: [FILECOIN] https://tangem.atlassian.net/browse/IOS-7738 + fatalError("Not implemented") + } +} diff --git a/BlockchainSdk/Common/Blockchain.swift b/BlockchainSdk/Common/Blockchain.swift index 71a594d0e..3283fdfbe 100644 --- a/BlockchainSdk/Common/Blockchain.swift +++ b/BlockchainSdk/Common/Blockchain.swift @@ -1307,8 +1307,7 @@ extension Blockchain { case .internetComputer: return ICPWalletAssembly() case .filecoin: - // TODO: [FILECOIN] - fatalError("Not implemented") + return FilecoinWalletAssembly() } } } From 503be344598d6e1c8140a33e46e98bd6f73fbcc5 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sun, 25 Aug 2024 22:09:59 +0200 Subject: [PATCH 07/25] IOS-7718 Fix tests --- BlockchainSdkTests/Extensions/TWPublicKeyType+.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BlockchainSdkTests/Extensions/TWPublicKeyType+.swift b/BlockchainSdkTests/Extensions/TWPublicKeyType+.swift index 20ec193cf..b019109bb 100644 --- a/BlockchainSdkTests/Extensions/TWPublicKeyType+.swift +++ b/BlockchainSdkTests/Extensions/TWPublicKeyType+.swift @@ -26,7 +26,8 @@ extension PublicKeyType { .terraV1, .terraV2, .radiant, - .koinos: + .koinos, + .filecoin: self = PublicKeyType.secp256k1 case .ethereum, .bsc, From 69202d6282b9272590c90fc6e6fcabebe2356803 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sun, 25 Aug 2024 22:14:52 +0200 Subject: [PATCH 08/25] IOS-7718 Add AddressTests --- BlockchainSdk.xcodeproj/project.pbxproj | 12 +++++++++++ .../Factories/AddressServiceFactory.swift | 3 +-- .../Filecoin/FilecoinAddressTests.swift | 21 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 BlockchainSdkTests/Filecoin/FilecoinAddressTests.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 014beb766..9fc3e18f5 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -485,6 +485,7 @@ DA1BA9A92C454C53006F6839 /* MantleWalletAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1BA9A82C454C53006F6839 /* MantleWalletAssembly.swift */; }; DA1D3B7B2B57B8FB00247393 /* BigUInt+.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1D3B7A2B57B8FB00247393 /* BigUInt+.swift */; }; DA20BD6A2C7BC5E9000F02DF /* FilecoinWalletAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */; }; + DA20BD6D2C7BC7AF000F02DF /* FilecoinAddressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA20BD6C2C7BC7AF000F02DF /* FilecoinAddressTests.swift */; }; DA2309D52C123510002A930C /* FeeResourceRestrictable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2309D42C123510002A930C /* FeeResourceRestrictable.swift */; }; DA2E770029769BF6001FF957 /* TransactionCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E76FF29769BF5001FF957 /* TransactionCreator.swift */; }; DA3081322817EC1A00DE41F1 /* TronTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3081312817EC1A00DE41F1 /* TronTransactionBuilder.swift */; }; @@ -1413,6 +1414,7 @@ DA1BA9A82C454C53006F6839 /* MantleWalletAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MantleWalletAssembly.swift; sourceTree = ""; }; DA1D3B7A2B57B8FB00247393 /* BigUInt+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BigUInt+.swift"; sourceTree = ""; }; DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinWalletAssembly.swift; sourceTree = ""; }; + DA20BD6C2C7BC7AF000F02DF /* FilecoinAddressTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinAddressTests.swift; sourceTree = ""; }; DA2309D42C123510002A930C /* FeeResourceRestrictable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeeResourceRestrictable.swift; sourceTree = ""; }; DA2E76FF29769BF5001FF957 /* TransactionCreator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionCreator.swift; sourceTree = ""; }; DA3081312817EC1A00DE41F1 /* TronTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronTransactionBuilder.swift; sourceTree = ""; }; @@ -2235,6 +2237,7 @@ DAE343C42BF3630A001B3F38 /* Koinos */, DAD62DE42C4676E8008509BE /* Mantle */, 0A7E10B72C4E8DEC00644977 /* ICP */, + DA20BD6B2C7BC79D000F02DF /* Filecoin */, 5D14E47E2397B80F00C15FC8 /* Info.plist */, ); path = BlockchainSdkTests; @@ -3429,6 +3432,14 @@ path = Mantle; sourceTree = ""; }; + DA20BD6B2C7BC79D000F02DF /* Filecoin */ = { + isa = PBXGroup; + children = ( + DA20BD6C2C7BC7AF000F02DF /* FilecoinAddressTests.swift */, + ); + path = Filecoin; + sourceTree = ""; + }; DA3081222817AEB800DE41F1 /* protobuf */ = { isa = PBXGroup; children = ( @@ -5414,6 +5425,7 @@ EF0DA78428523FAC0081092A /* EthereumTests.swift in Sources */, EF0DA78A28523FAC0081092A /* PolkadotTests.swift in Sources */, DA46E6992C05DD1A002BCE7F /* KoinosMethodResponseDecodingTests.swift in Sources */, + DA20BD6D2C7BC7AF000F02DF /* FilecoinAddressTests.swift in Sources */, EF0DA78328523FAC0081092A /* AddressTests.swift in Sources */, B626D11F2AF02C40003A8929 /* TWPublicKeyType+.swift in Sources */, EF0DA78728523FAC0081092A /* TronTests.swift in Sources */, diff --git a/BlockchainSdk/Common/Factories/AddressServiceFactory.swift b/BlockchainSdk/Common/Factories/AddressServiceFactory.swift index 4015ccf37..209eb241b 100644 --- a/BlockchainSdk/Common/Factories/AddressServiceFactory.swift +++ b/BlockchainSdk/Common/Factories/AddressServiceFactory.swift @@ -131,8 +131,7 @@ public struct AddressServiceFactory { let network: BitcoinNetwork = isTestnet ? .testnet : .mainnet return KoinosAddressService(networkParams: network.networkParams) case .filecoin: - // TODO: [FILECOIN] Implement - fatalError("Not implemented") + return WalletCoreAddressService(blockchain: .filecoin) } } } diff --git a/BlockchainSdkTests/Filecoin/FilecoinAddressTests.swift b/BlockchainSdkTests/Filecoin/FilecoinAddressTests.swift new file mode 100644 index 000000000..10e835829 --- /dev/null +++ b/BlockchainSdkTests/Filecoin/FilecoinAddressTests.swift @@ -0,0 +1,21 @@ +// +// FilecoinAddressTests.swift +// BlockchainSdkTests +// +// Created by Aleksei Muraveinik on 25.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import XCTest +@testable import BlockchainSdk + +final class FilecoinAddressTests: XCTestCase { + private let addressService = WalletCoreAddressService(blockchain: .filecoin) + + func testMakeAddress() throws { + let publicKey = Data(hex: "038A3F02BEBAFD04C1FA82184BA3950C801015A0B61A0922110D7CEE42A2A13763") + let expectedAddress = "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi" + + XCTAssertEqual(try addressService.makeAddress(from: publicKey).value, expectedAddress) + } +} From 66bba5b83186c9b9d6bee8be9558eaa1b2505cf7 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 27 Aug 2024 13:55:49 +0200 Subject: [PATCH 09/25] IOS-7718 Add NetworkProvider --- BlockchainSdk.xcodeproj/project.pbxproj | 56 ++++++++++ .../Filecoin/FilecoinNetworkProvider.swift | 51 +++++++++ .../Network/DTO/FilecoinAccountInfo.swift | 14 +++ .../Network/DTO/FilecoinDTOMapper.swift | 23 ++++ .../Network/DTO/FilecoinResponse.swift | 29 +++++ .../DTO/FilecoinSignedTransactionBody.swift | 29 +++++ .../Network/DTO/FilecoinTransactionBody.swift | 29 +++++ .../Network/DTO/FilecoinTxGasInfo.swift | 15 +++ .../Filecoin/Network/DTO/FilecoinTxInfo.swift | 16 +++ .../Network/FilecoinNetworkService.swift | 66 +++++++++++ .../Filecoin/Network/FilecoinTarget.swift | 104 ++++++++++++++++++ 11 files changed, 432 insertions(+) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinAccountInfo.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift create mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 9fc3e18f5..66442d900 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -554,6 +554,15 @@ DACAAB532BE8BDED0039ED3D /* KoinosAddressService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACAAB522BE8BDED0039ED3D /* KoinosAddressService.swift */; }; DACAAB552BE8C2F30039ED3D /* KoinosExternalLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACAAB542BE8C2F30039ED3D /* KoinosExternalLinkProvider.swift */; }; DACFA7D12BA2DB1600ABEF02 /* SolanaFeeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DACFA7D02BA2DB1600ABEF02 /* SolanaFeeParameters.swift */; }; + DAD156592C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */; }; + DAD1565C2C7DCFBD00DE52B3 /* FilecoinTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */; }; + DAD1565F2C7DD16B00DE52B3 /* FilecoinResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */; }; + DAD156632C7DD21B00DE52B3 /* FilecoinTransactionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */; }; + DAD156652C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */; }; + DAD156692C7DD65400DE52B3 /* FilecoinAccountInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */; }; + DAD1566B2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */; }; + DAD1566E2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */; }; + DAD156702C7DE0D000DE52B3 /* FilecoinDTOMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */; }; DAD555292BFB4110000030E5 /* KoinosTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD555282BFB4110000030E5 /* KoinosTransactionBuilder.swift */; }; DAD555382BFB463C000030E5 /* KoinosAccountNonce.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD555372BFB463C000030E5 /* KoinosAccountNonce.swift */; }; DAD5CDF72C0F3A8900DC4909 /* KoinosWalletManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5CDF62C0F3A8900DC4909 /* KoinosWalletManagerTests.swift */; }; @@ -574,6 +583,7 @@ DAE657E62BFC732400D7D63A /* value.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E22BFC732400D7D63A /* value.pb.swift */; }; DAE657E72BFC732400D7D63A /* token.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E32BFC732400D7D63A /* token.pb.swift */; }; DAE657E92BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */; }; + DAED18A22C7DF3D900522056 /* FilecoinNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */; }; DAED921F27A150E500F188D7 /* PolkadotAddressService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */; }; DAF0866E27A942D60024312E /* PolkadotWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */; }; DAF0867027A9438C0024312E /* PolkadotNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866F27A9438C0024312E /* PolkadotNetworkService.swift */; }; @@ -1483,6 +1493,15 @@ DACAAB522BE8BDED0039ED3D /* KoinosAddressService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosAddressService.swift; sourceTree = ""; }; DACAAB542BE8C2F30039ED3D /* KoinosExternalLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosExternalLinkProvider.swift; sourceTree = ""; }; DACFA7D02BA2DB1600ABEF02 /* SolanaFeeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaFeeParameters.swift; sourceTree = ""; }; + DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FilecoinNetworkProvider.swift; path = ../FilecoinNetworkProvider.swift; sourceTree = ""; }; + DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTarget.swift; sourceTree = ""; }; + DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinResponse.swift; sourceTree = ""; }; + DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTransactionBody.swift; sourceTree = ""; }; + DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinSignedTransactionBody.swift; sourceTree = ""; }; + DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinAccountInfo.swift; sourceTree = ""; }; + DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTxGasInfo.swift; sourceTree = ""; }; + DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTxInfo.swift; sourceTree = ""; }; + DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FilecoinDTOMapper.swift; path = DTO/FilecoinDTOMapper.swift; sourceTree = ""; }; DAD555282BFB4110000030E5 /* KoinosTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTransactionBuilder.swift; sourceTree = ""; }; DAD555372BFB463C000030E5 /* KoinosAccountNonce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosAccountNonce.swift; sourceTree = ""; }; DAD5CDF62C0F3A8900DC4909 /* KoinosWalletManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosWalletManagerTests.swift; sourceTree = ""; }; @@ -1504,6 +1523,7 @@ DAE657E22BFC732400D7D63A /* value.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = value.pb.swift; sourceTree = ""; }; DAE657E32BFC732400D7D63A /* token.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = token.pb.swift; sourceTree = ""; }; DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTransactionBuilderTests.swift; sourceTree = ""; }; + DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinNetworkService.swift; sourceTree = ""; }; DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotAddressService.swift; sourceTree = ""; }; DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotWalletManager.swift; sourceTree = ""; }; DAF0866F27A9438C0024312E /* PolkadotNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotNetworkService.swift; sourceTree = ""; }; @@ -3379,6 +3399,7 @@ DA15D1E82C7782F300FD733B /* Filecoin */ = { isa = PBXGroup; children = ( + DAD1565A2C7DCFAD00DE52B3 /* Network */, DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, ); @@ -3592,6 +3613,31 @@ path = Koinos; sourceTree = ""; }; + DAD1565A2C7DCFAD00DE52B3 /* Network */ = { + isa = PBXGroup; + children = ( + DAD1565D2C7DD15E00DE52B3 /* DTO */, + DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */, + DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */, + DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */, + DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */, + ); + path = Network; + sourceTree = ""; + }; + DAD1565D2C7DD15E00DE52B3 /* DTO */ = { + isa = PBXGroup; + children = ( + DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */, + DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */, + DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */, + DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */, + DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */, + DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */, + ); + path = DTO; + sourceTree = ""; + }; DAD555342BFB45E8000030E5 /* Models */ = { isa = PBXGroup; children = ( @@ -4833,6 +4879,7 @@ EF3B19302AA85CBF0084AA1C /* XRPExternalLinkProvider.swift in Sources */, B605AC582B7A867300878B64 /* AccountCreator.swift in Sources */, EF2D9DA42BC3F6770055C485 /* EthereumResponse.swift in Sources */, + DAED18A22C7DF3D900522056 /* FilecoinNetworkService.swift in Sources */, EFD717CA2A25EA8500E5430D /* WalletCoreABIEncoder.swift in Sources */, 2DA13A042A8AD83B00E3C374 /* ChiaProviderRequests.swift in Sources */, B6BA937F2AEA0F4800F84E36 /* NEARNetworkResult.TransactionSendAwait.swift in Sources */, @@ -4919,6 +4966,7 @@ EF3B194A2AA85E7B0084AA1C /* DashExternalLinkProvider.swift in Sources */, 2DDE5BA229C4F8D200A5B708 /* BinanceWalletAssembly.swift in Sources */, B00DF9912BBEA9DA004397CB /* APIModels.swift in Sources */, + DAD156632C7DD21B00DE52B3 /* FilecoinTransactionBody.swift in Sources */, DC5E64F62B1650F400E81AA5 /* OP_LESSTHAN.swift in Sources */, 5DEAFA90244473460032E316 /* Transaction.swift in Sources */, 5D977BB623FAEB4500575BE4 /* DucatusNetworkService.swift in Sources */, @@ -5110,6 +5158,7 @@ EF2D9DA22BC3F6770055C485 /* EthereumAdditionalInfoProvider.swift in Sources */, EF2D9DA12BC3F6770055C485 /* EthereumTransactionDataBuilder.swift in Sources */, B6F89EAD2BB20DB50009A453 /* SubscanAPIResult.Error.swift in Sources */, + DAD156702C7DE0D000DE52B3 /* FilecoinDTOMapper.swift in Sources */, 2DCAEE4F2B147E2800C87E09 /* DecimalPlainAddress.swift in Sources */, DC5E652C2B1650F400E81AA5 /* OP_RETURN.swift in Sources */, EF3B19382AA85D090084AA1C /* PolygonExternalLinkProvider.swift in Sources */, @@ -5146,6 +5195,7 @@ 5DED72BA239FE2F8006D79AE /* Int+.swift in Sources */, DA63B0A229CB3FC700AC6E49 /* KaspaWalletManager.swift in Sources */, EF31EA1429DC31E000A59FBE /* RavencoinTestNetworkParams.swift in Sources */, + DAD1565C2C7DCFBD00DE52B3 /* FilecoinTarget.swift in Sources */, B675E95D2B320D52004AF179 /* VeChainNetworkParams.swift in Sources */, B06C6793264286390037E7AD /* BlockchairAddressBlockMapper.swift in Sources */, EF666C322A2F43370044986F /* PolkadotAddress.swift in Sources */, @@ -5195,6 +5245,7 @@ 0A158C052B74E4680004DC23 /* BitcoinCashNowNodesNetworkProvider.swift in Sources */, DC3550F12B57013F00A93DBA /* XDCExternalLinkProvider.swift in Sources */, EFAD40A52A965BA800364D65 /* BlockBookNode.swift in Sources */, + DAD156652C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift in Sources */, DA5339A52BFCBE8600BA3D80 /* KoinosProtocol.swift in Sources */, DC5E65012B1650F400E81AA5 /* OP_NEGATE.swift in Sources */, EF3B191E2AA85C150084AA1C /* CardanoExternalLinkProvider.swift in Sources */, @@ -5255,6 +5306,7 @@ 5DC7DD6824408266008F83F2 /* XrpResponse.swift in Sources */, 2D24F5C42B6D2C7100D502A0 /* AptosResponse.swift in Sources */, DCDF56D02C6F4F9800028424 /* TronInventoryItems.pb.swift in Sources */, + DAD1565F2C7DD16B00DE52B3 /* FilecoinResponse.swift in Sources */, DC5E65052B1650F400E81AA5 /* OP_MIN.swift in Sources */, 5D7D243D25136254001B9A4F /* Serializer.swift in Sources */, B6181AE32B757AA50046A976 /* HederaError.swift in Sources */, @@ -5292,7 +5344,9 @@ DAE657E72BFC732400D7D63A /* token.pb.swift in Sources */, B6417DDC2BA2354D00B9B61D /* PolygonTransactionHistoryProvider.swift in Sources */, DAE657E52BFC732400D7D63A /* protocol.pb.swift in Sources */, + DAD1566B2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift in Sources */, B6BA93792AEA0F0C00F84E36 /* NEARNetworkResult.GasPrice.swift in Sources */, + DAD1566E2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift in Sources */, B6B2EB6D2B56AAB9005FBE8E /* VeChainNetworkResult.ContractCall.swift in Sources */, EF57BEC82A1E13BE00C2A493 /* DerivationConfig.swift in Sources */, DA0E98D62C04755C00C92985 /* KoinosMethod.swift in Sources */, @@ -5358,6 +5412,7 @@ EF32FEC22A3072B9002ED43F /* CashAddrService.swift in Sources */, EF2BC62729DAD65F003D3F18 /* RavencoinTransactionInfo.swift in Sources */, EF666C2E2A2F3EE90044986F /* BitcoinLegacyAddressService.swift in Sources */, + DAD156692C7DD65400DE52B3 /* FilecoinAccountInfo.swift in Sources */, DA570CEF27A802BE007F34EB /* SolanaError+.swift in Sources */, 5D4B33D323F7DF1F00C93A84 /* BinanceNetworkService.swift in Sources */, B6FC9DC52B62A3AC00448D8A /* HederaWalletAssembly.swift in Sources */, @@ -5388,6 +5443,7 @@ EF32FEDB2A38C288002ED43F /* BitcoinScriptAddressProvider.swift in Sources */, DA82433D27A2B06500CFC2C0 /* PolkadotJsonRpcProvider.swift in Sources */, EF57BEDA2A1E625400C2A493 /* DerivationConfigV2.swift in Sources */, + DAD156592C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift in Sources */, EF1339BA2AB4B38000B78BA3 /* ApproveERC20TokenMethod.swift in Sources */, 0A3FDED52C6F6A5A0023B717 /* EthereumStakeKitTransactionHelper.swift in Sources */, B6DC28482B62BB580070F1D2 /* HederaRESTNetworkProvider.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift new file mode 100644 index 000000000..84136696d --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift @@ -0,0 +1,51 @@ +// +// FilecoinNetworkProvider.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Combine +import Foundation + +final class FilecoinNetworkProvider: HostProvider { + var host: String { + node.url.absoluteString + } + + private let node: NodeInfo + private let provider: NetworkProvider + + init( + node: NodeInfo, + configuration: NetworkProviderConfiguration + ) { + self.node = node + provider = NetworkProvider(configuration: configuration) + } + + func getActorInfo(address: String) -> AnyPublisher { + requestPublisher(for: .getActorInfo(address: address)) + } + + func getGasUnitPrice(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + requestPublisher(for: .getGasUnitPrice(transactionInfo: transactionInfo)) + } + + func getGasLimit(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + requestPublisher(for: .getGasLimit(transactionInfo: transactionInfo)) + } + + func submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) -> AnyPublisher { + requestPublisher(for: .submitTransaction(signedTransactionBody: signedTransactionBody)) + } + + private func requestPublisher(for target: FilecoinTarget.FilecoinTargetType) -> AnyPublisher { + provider.requestPublisher(FilecoinTarget(node: node, target)) + .filterSuccessfulStatusAndRedirectCodes() + .map(JSONRPC.Response.self, using: .withSnakeCaseStrategy) + .tryMap { try $0.result.get() } + .eraseToAnyPublisher() + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinAccountInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinAccountInfo.swift new file mode 100644 index 000000000..6a98d77cd --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinAccountInfo.swift @@ -0,0 +1,14 @@ +// +// FilecoinAccountInfo.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinAccountInfo { + let balance: Decimal + let nonce: UInt64 +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift new file mode 100644 index 000000000..a10f60eaf --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift @@ -0,0 +1,23 @@ +// +// FilecoinTransactionBodyConverter.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +enum FilecoinDTOMapper { + static func convertTransactionBody(from transactionInfo: FilecoinTxInfo) -> FilecoinTransactionBody { + FilecoinTransactionBody( + sourceAddress: transactionInfo.sourceAddress, + destinationAddress: transactionInfo.destinationAddress, + amount: "\(transactionInfo.amount)", + nonce: transactionInfo.nonce, + gasUnitPrice: nil, + gasLimit: nil, + gasPremium: nil + ) + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift new file mode 100644 index 000000000..944d90894 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift @@ -0,0 +1,29 @@ +// +// FilecoinRpcResponseResult.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +enum FilecoinResponse { + struct GetActorInfo: Decodable { + let balance: String + let nonce: UInt64 + + enum CodingKeys: String, CodingKey { + case balance = "Balance" + case nonce = "Nonce" + } + } + + struct SubmitTransaction: Decodable { + let hash: String + + enum CodingKeys: String, CodingKey { + case hash = "/" + } + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift new file mode 100644 index 000000000..23a834d8e --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift @@ -0,0 +1,29 @@ +// +// FilecoinSignedTransactionBody.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinSignedTransactionBody: Encodable { + struct Signature: Encodable { + let type: Int + let signature: String + + enum CodingKeys: String, CodingKey { + case type = "Type" + case signature = "Data" + } + } + + let transactionBody: FilecoinTransactionBody + let signature: Signature + + enum CodingKeys: String, CodingKey { + case transactionBody = "Message" + case signature = "Signature" + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift new file mode 100644 index 000000000..21187eb85 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift @@ -0,0 +1,29 @@ +// +// FilecoinTransactionBody.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinTransactionBody: Encodable { + let sourceAddress: String + let destinationAddress: String + let amount: String + let nonce: UInt64 + let gasUnitPrice: String? + let gasLimit: UInt64? + let gasPremium: String? + + enum CodingKeys: String, CodingKey { + case sourceAddress = "From" + case destinationAddress = "To" + case amount = "Value" + case nonce = "Nonce" + case gasUnitPrice = "GasFeeCap" + case gasLimit = "GasLimit" + case gasPremium = "GasPremium" + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift new file mode 100644 index 000000000..b32ef09d5 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift @@ -0,0 +1,15 @@ +// +// FilecoinTxGasInfo.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinTxGasInfo { + let gasUnitPrice: UInt64 + let gasLimit: UInt64 + let gasPremium: UInt64 +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift new file mode 100644 index 000000000..7b19fcf45 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift @@ -0,0 +1,16 @@ +// +// FilecoinTxInfo.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation + +struct FilecoinTxInfo { + let sourceAddress: String + let destinationAddress: String + let amount: UInt64 + let nonce: UInt64 +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift new file mode 100644 index 000000000..cdcab3155 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift @@ -0,0 +1,66 @@ +// +// FilecoinNetworkService.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Combine + +class FilecoinNetworkService: MultiNetworkProvider { + let providers: [FilecoinNetworkProvider] + var currentProviderIndex = 0 + + init(providers: [FilecoinNetworkProvider]) { + self.providers = providers + } + + func getAccountInfo(address: String) -> AnyPublisher { + providerPublisher { provider in + provider + .getActorInfo(address: address) + .tryMap { response in + guard let balance = Decimal(stringValue: response.balance) else { + throw WalletError.failedToParseNetworkResponse() + } + + return FilecoinAccountInfo( + balance: balance, + nonce: response.nonce + ) + } + .eraseToAnyPublisher() + } + } + + func getGasUnitPrice(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + providerPublisher { provider in + provider + .getGasUnitPrice(transactionInfo: transactionInfo) + .tryMap { response in + guard let price = UInt64(response) else { + throw WalletError.failedToParseNetworkResponse() + } + return price + } + .eraseToAnyPublisher() + } + } + + func getGasLimit(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + providerPublisher { provider in + provider + .getGasLimit(transactionInfo: transactionInfo) + } + } + + func submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) -> AnyPublisher { + providerPublisher { provider in + provider + .submitTransaction(signedTransactionBody: signedTransactionBody) + .map(\.hash) + .eraseToAnyPublisher() + } + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift new file mode 100644 index 000000000..3a8814443 --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift @@ -0,0 +1,104 @@ +// +// FilecoinTarget.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 27.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import Foundation +import Moya + +struct FilecoinTarget: TargetType { + enum FilecoinTargetType { + case getActorInfo(address: String) + case getGasUnitPrice(transactionInfo: FilecoinTxInfo) + case getGasLimit(transactionInfo: FilecoinTxInfo) + case submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) + + var method: String { + switch self { + case .getActorInfo: + "Filecoin.StateGetActor" + case .getGasUnitPrice: + "Filecoin.GasEstimateFeeCap" + case .getGasLimit: + "Filecoin.GasEstimateGasLimit" + case .submitTransaction: + "Filecoin.MpoolPush" + } + } + } + + let node: NodeInfo + let type: FilecoinTargetType + + init(node: NodeInfo, _ type: FilecoinTargetType) { + self.node = node + self.type = type + } + + var baseURL: URL { + node.url + } + + var path: String { + "" + } + + var method: Moya.Method { + .post + } + + var task: Task { + switch type { + case .getActorInfo(let address): + .requestJSONRPC( + id: Constants.jsonRPCMethodId, + method: type.method, + params: [ + address, + nil + ] + ) + + case .getGasUnitPrice(let transactionInfo): + .requestJSONRPC( + id: Constants.jsonRPCMethodId, + method: type.method, + params: [ + FilecoinDTOMapper.convertTransactionBody(from: transactionInfo), + nil, + nil + ] + ) + + case .getGasLimit(let transactionInfo): + .requestJSONRPC( + id: Constants.jsonRPCMethodId, + method: type.method, + params: [ + FilecoinDTOMapper.convertTransactionBody(from: transactionInfo), + nil + ] + ) + + case .submitTransaction(let signedTransactionBody): + .requestJSONRPC( + id: Constants.jsonRPCMethodId, + method: type.method, + params: [ + signedTransactionBody + ] + ) + } + } + + var headers: [String : String]? +} + +private extension FilecoinTarget { + enum Constants { + static let jsonRPCMethodId: Int = 1 + } +} From bc59262ac53e90c4a58a8d2ac640958d18ba1abc Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Thu, 29 Aug 2024 18:30:09 +0200 Subject: [PATCH 10/25] IOS-7718 Add TransactionBuilder --- BlockchainSdk.xcodeproj/project.pbxproj | 8 ++ .../Filecoin/FilecoinTransactionBuilder.swift | 95 ++++++++++++++++ .../DTO/FilecoinSignedTransactionBody.swift | 4 +- .../Network/DTO/FilecoinTransactionBody.swift | 2 +- .../FilecoinTransactionBuilderTests.swift | 106 ++++++++++++++++++ 5 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift create mode 100644 BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 66442d900..e8333fc44 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -539,6 +539,8 @@ DA82434127A2B0AD00CFC2C0 /* PolkadotTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA82434027A2B0AD00CFC2C0 /* PolkadotTarget.swift */; }; DA82434327A2B0C100CFC2C0 /* PolkadotResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA82434227A2B0C100CFC2C0 /* PolkadotResponse.swift */; }; DA9EA73F29EE958500CAE6F2 /* CosmosTransactionParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9EA73E29EE958500CAE6F2 /* CosmosTransactionParams.swift */; }; + DA9F15F22C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */; }; + DA9F15F42C80BDC700EA7FAF /* FilecoinTransactionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9F15F32C80BDC700EA7FAF /* FilecoinTransactionBuilderTests.swift */; }; DA9F76E927EC8AEB00F0665C /* TronAddressService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9F76E827EC8AEB00F0665C /* TronAddressService.swift */; }; DA9F76EC27EC9A2900F0665C /* TronWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9F76EB27EC9A2900F0665C /* TronWalletManager.swift */; }; DA9F76EF27EC9BCD00F0665C /* TronNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9F76EE27EC9BCD00F0665C /* TronNetworkService.swift */; }; @@ -1478,6 +1480,8 @@ DA82434027A2B0AD00CFC2C0 /* PolkadotTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotTarget.swift; sourceTree = ""; }; DA82434227A2B0C100CFC2C0 /* PolkadotResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotResponse.swift; sourceTree = ""; }; DA9EA73E29EE958500CAE6F2 /* CosmosTransactionParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CosmosTransactionParams.swift; sourceTree = ""; }; + DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTransactionBuilder.swift; sourceTree = ""; }; + DA9F15F32C80BDC700EA7FAF /* FilecoinTransactionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTransactionBuilderTests.swift; sourceTree = ""; }; DA9F76E827EC8AEB00F0665C /* TronAddressService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronAddressService.swift; sourceTree = ""; }; DA9F76EB27EC9A2900F0665C /* TronWalletManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronWalletManager.swift; sourceTree = ""; }; DA9F76EE27EC9BCD00F0665C /* TronNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TronNetworkService.swift; sourceTree = ""; }; @@ -3402,6 +3406,7 @@ DAD1565A2C7DCFAD00DE52B3 /* Network */, DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, + DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */, ); path = Filecoin; sourceTree = ""; @@ -3457,6 +3462,7 @@ isa = PBXGroup; children = ( DA20BD6C2C7BC7AF000F02DF /* FilecoinAddressTests.swift */, + DA9F15F32C80BDC700EA7FAF /* FilecoinTransactionBuilderTests.swift */, ); path = Filecoin; sourceTree = ""; @@ -4890,6 +4896,7 @@ 5D88C80B256BCDBB00020028 /* StellarTransactionParams.swift in Sources */, B69824772B7175EA00E1333D /* HederaTransactionParams.swift in Sources */, 5D88838927D3BB8B008744E1 /* WalletError.swift in Sources */, + DA9F15F22C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift in Sources */, B64A680D2BCE9E82009ED960 /* EthereumOptimisticRollupWalletAssembly.swift in Sources */, EF72577E2A8D42A100EA8CB2 /* TransactionHistory.swift in Sources */, DA4B80252BBA66F900CE50B7 /* BitcoinTransactionFeeCalculator.swift in Sources */, @@ -5471,6 +5478,7 @@ DA1D3B7B2B57B8FB00247393 /* BigUInt+.swift in Sources */, 2D535E872A0CC5FA0081EB76 /* AddressesValidationTests.swift in Sources */, DAD62DE62C467718008509BE /* MantleTests.swift in Sources */, + DA9F15F42C80BDC700EA7FAF /* FilecoinTransactionBuilderTests.swift in Sources */, B62BCBAC2B3D978F007494CF /* VeChainTests.swift in Sources */, EF0DA78928523FAC0081092A /* LitecoinTests.swift in Sources */, EF0DA78828523FAC0081092A /* BitcoinTests.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift new file mode 100644 index 000000000..f79562fef --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -0,0 +1,95 @@ +// +// FilecoinTransactionBuilder.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 29.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import BigInt +import Foundation +import TangemSdk +import WalletCore + +struct FilecoinFeeParameters: FeeParameters { + let gasUnitPrice: BigUInt + let gasLimit: Int64 + let gasPremium: BigUInt +} + +class FilecoinTransactionBuilder { + private let wallet: Wallet + + init(wallet: Wallet) { + self.wallet = wallet + } + + func buildForSign(transaction: Transaction, nonce: UInt64) throws -> Data { + guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { + throw WalletError.failedToBuildTx + } + + let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) + let txInputData = try input.serializedData() + + let preImageHashes = TransactionCompiler.preImageHashes(coinType: .filecoin, txInputData: txInputData) + let preSigningOutput = try TxCompilerPreSigningOutput(serializedData: preImageHashes) + + if preSigningOutput.error != .ok { + Log.debug("FilecoinPreSigningOutput has a error: \(preSigningOutput.errorMessage)") + // TODO: [FILECOIN] Make FilecoinTransactionBuilderError + throw EthereumTransactionBuilderError.walletCoreError(message: preSigningOutput.errorMessage) + } + + return preSigningOutput.dataHash + } + + func buildForSend( + transaction: Transaction, + nonce: UInt64, + signatureInfo: SignatureInfo + ) throws -> FilecoinSignedTransactionBody { + guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { + throw WalletError.failedToBuildTx + } + + let signatures = DataVector() + signatures.add(data: signatureInfo.signature) // Should be already unmarshalled + + let publicKeys = DataVector() + publicKeys.add(data: try Secp256k1Key(with: signatureInfo.publicKey).decompress()) + + let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) + let txInputData = try input.serializedData() + + let compiledWithSignatures = TransactionCompiler.compileWithSignatures( + coinType: .filecoin, + txInputData: txInputData, + signatures: signatures, + publicKeys: publicKeys + ) + + let signingOutput = try FilecoinSigningOutput(serializedData: compiledWithSignatures) + + return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: signingOutput.json.data(using: .utf8)!) + } + + private func makeSigningInput( + transaction: Transaction, + nonce: UInt64, + feeParameters: FilecoinFeeParameters + ) throws -> FilecoinSigningInput { + try FilecoinSigningInput.with { input in + input.to = transaction.destinationAddress + input.nonce = nonce + + input.value = transaction.amount.bigUIntValue!.serialize() + + input.gasFeeCap = feeParameters.gasUnitPrice.serialize() + input.gasLimit = feeParameters.gasLimit + input.gasPremium = feeParameters.gasPremium.serialize() + + input.publicKey = try Secp256k1Key(with: wallet.publicKey.blockchainKey).decompress() + } + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift index 23a834d8e..e58d36ddb 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift @@ -8,8 +8,8 @@ import Foundation -struct FilecoinSignedTransactionBody: Encodable { - struct Signature: Encodable { +struct FilecoinSignedTransactionBody: Codable, Equatable { + struct Signature: Codable, Equatable { let type: Int let signature: String diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift index 21187eb85..f0127535e 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift @@ -8,7 +8,7 @@ import Foundation -struct FilecoinTransactionBody: Encodable { +struct FilecoinTransactionBody: Codable, Equatable { let sourceAddress: String let destinationAddress: String let amount: String diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift new file mode 100644 index 000000000..e47d98d60 --- /dev/null +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -0,0 +1,106 @@ +// +// FilecoinTransactionBuilderTests.swift +// BlockchainSdkTests +// +// Created by Aleksei Muraveinik on 29.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import XCTest +import WalletCore +@testable import BlockchainSdk + +final class FilecoinTransactionBuilderTests: XCTestCase { + private enum Constants { + static let publicKey = Data(hex: "0374D0F81F42DDFE34114D533E95E6AE5FE6EA271C96F1FA505199FDC365AE9720") + static let signature = Data(hex: "06881E97DA3DCEF5D44FEB02FA75697221B21DF071586E95E3EC4E6B03FA62B014D4E21B89FBC41E9453FC495A92FD97EA6" + + "7D491B433A5AAEF7361F22416D74701") + + static let transaction = Transaction( + amount: Amount( + with: .filecoin, + type: .coin, + value: 0.01 + ), + fee: Fee( + Amount( + with: .filecoin, + type: .coin, + value: (101225 * 1526328) / Blockchain.filecoin.decimalValue + ), + parameters: FilecoinFeeParameters( + gasUnitPrice: 101225, + gasLimit: 1526328, + gasPremium: 50612 + ) + ), + sourceAddress: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi", + destinationAddress: "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i", + changeAddress: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi" + ) + } + + private let transactionBuilder = FilecoinTransactionBuilder( + wallet: Wallet( + blockchain: .filecoin, + addresses: [ + .default: PlainAddress( + value: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi", + publicKey: Wallet.PublicKey( + seedKey: Constants.publicKey, + derivationType: nil + ), + type: .default + ) + ] + ) + ) + + func testBuildForSign() throws { + let expected = Data(hex: "BEB93CCF5C85273B327AC5DCDD58CBF3066F57FC84B87CD20DC67DF69EC2D0A9") + + let nonce: UInt64 = 2 + let actual = try transactionBuilder.buildForSign( + transaction: Constants.transaction, + nonce: nonce + ) + + XCTAssertEqual(expected, actual) + } + + func testBuildForSend() throws { + let expected = FilecoinSignedTransactionBody( + transactionBody: FilecoinTransactionBody( + // Why this source address differs from the one from transaction + sourceAddress: "f1flbddhx4vwox3y3ux5bwgsgq2frzeiuvvdrjo7i", + destinationAddress: "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i", + amount: "10000000000000000", + nonce: 2, + gasUnitPrice: "101225", + gasLimit: 1526328, + gasPremium: "50612" + ), + signature: FilecoinSignedTransactionBody.Signature( + type: 1, + signature: "Bogel9o9zvXUT+sC+nVpciGyHfBxWG6V4+xOawP6YrAU1OIbifvEHpRT/Elakv2X6mfUkbQzparvc2HyJBbXRwE=" + ) + ) + + let nonce: UInt64 = 2 + let transaction = Constants.transaction + + let hashToSign = try transactionBuilder.buildForSign(transaction: transaction, nonce: nonce) + + let actual = try transactionBuilder.buildForSend( + transaction: transaction, + nonce: nonce, + signatureInfo: SignatureInfo( + signature: Constants.signature, + publicKey: Constants.publicKey, + hash: hashToSign + ) + ) + + XCTAssertEqual(expected, actual) + } +} From 1462f26bc6f08b77ef83146db0cd54544432bc0d Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Fri, 30 Aug 2024 12:02:43 +0200 Subject: [PATCH 11/25] IOS-7718 Fix address in tests --- BlockchainSdk.xcodeproj/project.pbxproj | 4 + .../Filecoin/FilecoinFeeParameters.swift | 15 ++++ .../Filecoin/FilecoinTransactionBuilder.swift | 32 ++++---- .../FilecoinTransactionBuilderTests.swift | 75 +++++++++---------- 4 files changed, 68 insertions(+), 58 deletions(-) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index e8333fc44..aebb43fda 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -585,6 +585,7 @@ DAE657E62BFC732400D7D63A /* value.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E22BFC732400D7D63A /* value.pb.swift */; }; DAE657E72BFC732400D7D63A /* token.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E32BFC732400D7D63A /* token.pb.swift */; }; DAE657E92BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */; }; + DAE864BB2C81CF1700A2D51A /* FilecoinFeeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */; }; DAED18A22C7DF3D900522056 /* FilecoinNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */; }; DAED921F27A150E500F188D7 /* PolkadotAddressService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */; }; DAF0866E27A942D60024312E /* PolkadotWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */; }; @@ -1527,6 +1528,7 @@ DAE657E22BFC732400D7D63A /* value.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = value.pb.swift; sourceTree = ""; }; DAE657E32BFC732400D7D63A /* token.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = token.pb.swift; sourceTree = ""; }; DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTransactionBuilderTests.swift; sourceTree = ""; }; + DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinFeeParameters.swift; sourceTree = ""; }; DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinNetworkService.swift; sourceTree = ""; }; DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotAddressService.swift; sourceTree = ""; }; DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotWalletManager.swift; sourceTree = ""; }; @@ -3407,6 +3409,7 @@ DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */, + DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */, ); path = Filecoin; sourceTree = ""; @@ -4842,6 +4845,7 @@ B0C2C89D25FBCF0200A61622 /* RosettaTarget.swift in Sources */, B62011042B7AAC2100155235 /* Collection+.swift in Sources */, EFD717DF2A27310E00E5430D /* AddressType.swift in Sources */, + DAE864BB2C81CF1700A2D51A /* FilecoinFeeParameters.swift in Sources */, B69F21E62B86CD4A00A1177B /* UnixTimestamp.swift in Sources */, EFF607C72BD000D000C37210 /* EthereumAddressService.swift in Sources */, 0A7624E32C296969002FA139 /* ICPWalletManager.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift new file mode 100644 index 000000000..876b7de3c --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift @@ -0,0 +1,15 @@ +// +// FilecoinFeeParameters.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 30.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import BigInt + +struct FilecoinFeeParameters: FeeParameters { + let gasUnitPrice: BigUInt + let gasLimit: Int64 + let gasPremium: BigUInt +} diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index f79562fef..b5e1acfea 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -6,18 +6,10 @@ // Copyright © 2024 Tangem AG. All rights reserved. // -import BigInt -import Foundation import TangemSdk import WalletCore -struct FilecoinFeeParameters: FeeParameters { - let gasUnitPrice: BigUInt - let gasLimit: Int64 - let gasPremium: BigUInt -} - -class FilecoinTransactionBuilder { +final class FilecoinTransactionBuilder { private let wallet: Wallet init(wallet: Wallet) { @@ -34,12 +26,6 @@ class FilecoinTransactionBuilder { let preImageHashes = TransactionCompiler.preImageHashes(coinType: .filecoin, txInputData: txInputData) let preSigningOutput = try TxCompilerPreSigningOutput(serializedData: preImageHashes) - - if preSigningOutput.error != .ok { - Log.debug("FilecoinPreSigningOutput has a error: \(preSigningOutput.errorMessage)") - // TODO: [FILECOIN] Make FilecoinTransactionBuilderError - throw EthereumTransactionBuilderError.walletCoreError(message: preSigningOutput.errorMessage) - } return preSigningOutput.dataHash } @@ -54,7 +40,7 @@ class FilecoinTransactionBuilder { } let signatures = DataVector() - signatures.add(data: signatureInfo.signature) // Should be already unmarshalled + signatures.add(data: signatureInfo.signature) let publicKeys = DataVector() publicKeys.add(data: try Secp256k1Key(with: signatureInfo.publicKey).decompress()) @@ -71,7 +57,11 @@ class FilecoinTransactionBuilder { let signingOutput = try FilecoinSigningOutput(serializedData: compiledWithSignatures) - return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: signingOutput.json.data(using: .utf8)!) + guard let jsonData = signingOutput.json.data(using: .utf8) else { + throw WalletError.failedToBuildTx + } + + return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: jsonData) } private func makeSigningInput( @@ -79,11 +69,15 @@ class FilecoinTransactionBuilder { nonce: UInt64, feeParameters: FilecoinFeeParameters ) throws -> FilecoinSigningInput { - try FilecoinSigningInput.with { input in + guard let value = transaction.amount.bigUIntValue else { + throw WalletError.failedToBuildTx + } + + return try FilecoinSigningInput.with { input in input.to = transaction.destinationAddress input.nonce = nonce - input.value = transaction.amount.bigUIntValue!.serialize() + input.value = value.serialize() input.gasFeeCap = feeParameters.gasUnitPrice.serialize() input.gasLimit = feeParameters.gasLimit diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift index e47d98d60..9ca0e5564 100644 --- a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -7,16 +7,27 @@ // import XCTest -import WalletCore @testable import BlockchainSdk final class FilecoinTransactionBuilderTests: XCTestCase { - private enum Constants { - static let publicKey = Data(hex: "0374D0F81F42DDFE34114D533E95E6AE5FE6EA271C96F1FA505199FDC365AE9720") - static let signature = Data(hex: "06881E97DA3DCEF5D44FEB02FA75697221B21DF071586E95E3EC4E6B03FA62B014D4E21B89FBC41E9453FC495A92FD97EA6" + - "7D491B433A5AAEF7361F22416D74701") - - static let transaction = Transaction( + private let transactionBuilder = FilecoinTransactionBuilder( + wallet: Wallet( + blockchain: .filecoin, + addresses: [ + .default: PlainAddress( + value: Constants.sourceAddress, + publicKey: Wallet.PublicKey( + seedKey: Constants.publicKey, + derivationType: nil + ), + type: .default + ) + ] + ) + ) + + private var transaction: Transaction { + Transaction( amount: Amount( with: .filecoin, type: .coin, @@ -34,48 +45,27 @@ final class FilecoinTransactionBuilderTests: XCTestCase { gasPremium: 50612 ) ), - sourceAddress: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi", - destinationAddress: "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i", - changeAddress: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi" + sourceAddress: Constants.sourceAddress, + destinationAddress: Constants.destinationAddress, + changeAddress: Constants.sourceAddress ) } - private let transactionBuilder = FilecoinTransactionBuilder( - wallet: Wallet( - blockchain: .filecoin, - addresses: [ - .default: PlainAddress( - value: "f1hbyibpq4mea6l3no7aag24hxpwgf4zwp6msepwi", - publicKey: Wallet.PublicKey( - seedKey: Constants.publicKey, - derivationType: nil - ), - type: .default - ) - ] - ) - ) - func testBuildForSign() throws { let expected = Data(hex: "BEB93CCF5C85273B327AC5DCDD58CBF3066F57FC84B87CD20DC67DF69EC2D0A9") - - let nonce: UInt64 = 2 - let actual = try transactionBuilder.buildForSign( - transaction: Constants.transaction, - nonce: nonce - ) + let actual = try transactionBuilder.buildForSign(transaction: transaction, nonce: 2) XCTAssertEqual(expected, actual) } func testBuildForSend() throws { + let nonce: UInt64 = 2 let expected = FilecoinSignedTransactionBody( transactionBody: FilecoinTransactionBody( - // Why this source address differs from the one from transaction - sourceAddress: "f1flbddhx4vwox3y3ux5bwgsgq2frzeiuvvdrjo7i", - destinationAddress: "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i", + sourceAddress: Constants.sourceAddress, + destinationAddress: Constants.destinationAddress, amount: "10000000000000000", - nonce: 2, + nonce: nonce, gasUnitPrice: "101225", gasLimit: 1526328, gasPremium: "50612" @@ -86,9 +76,6 @@ final class FilecoinTransactionBuilderTests: XCTestCase { ) ) - let nonce: UInt64 = 2 - let transaction = Constants.transaction - let hashToSign = try transactionBuilder.buildForSign(transaction: transaction, nonce: nonce) let actual = try transactionBuilder.buildForSend( @@ -104,3 +91,13 @@ final class FilecoinTransactionBuilderTests: XCTestCase { XCTAssertEqual(expected, actual) } } + +private extension FilecoinTransactionBuilderTests { + enum Constants { + static let publicKey = Data(hex: "0374D0F81F42DDFE34114D533E95E6AE5FE6EA271C96F1FA505199FDC365AE9720") + static let signature = Data(hex: "06881E97DA3DCEF5D44FEB02FA75697221B21DF071586E95E3EC4E6B03FA62B014D4E21B89FBC41E9453FC495A92FD97EA67D491B433A5AAEF7361F22416D74701") + + static let sourceAddress = "f1flbddhx4vwox3y3ux5bwgsgq2frzeiuvvdrjo7i" + static let destinationAddress = "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i" + } +} From 4e7918d373b4c3de9d97e2f01ad7b8c1856e4c86 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Fri, 30 Aug 2024 14:04:54 +0200 Subject: [PATCH 12/25] IOS-7738 Add WalletManager --- BlockchainSdk.xcodeproj/project.pbxproj | 4 + .../Filecoin/FilecoinNetworkProvider.swift | 8 +- .../Filecoin/FilecoinWalletManager.swift | 135 ++++++++++++++++++ .../Network/DTO/FilecoinTxGasInfo.swift | 10 +- .../Network/FilecoinNetworkService.swift | 19 +-- .../Filecoin/Network/FilecoinTarget.swift | 21 +-- 6 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index aebb43fda..16aac378c 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -586,6 +586,7 @@ DAE657E72BFC732400D7D63A /* token.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E32BFC732400D7D63A /* token.pb.swift */; }; DAE657E92BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */; }; DAE864BB2C81CF1700A2D51A /* FilecoinFeeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */; }; + DAE864BD2C81D13F00A2D51A /* FilecoinWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE864BC2C81D13F00A2D51A /* FilecoinWalletManager.swift */; }; DAED18A22C7DF3D900522056 /* FilecoinNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */; }; DAED921F27A150E500F188D7 /* PolkadotAddressService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */; }; DAF0866E27A942D60024312E /* PolkadotWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */; }; @@ -1529,6 +1530,7 @@ DAE657E32BFC732400D7D63A /* token.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = token.pb.swift; sourceTree = ""; }; DAE657E82BFCA3E400D7D63A /* KoinosTransactionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTransactionBuilderTests.swift; sourceTree = ""; }; DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinFeeParameters.swift; sourceTree = ""; }; + DAE864BC2C81D13F00A2D51A /* FilecoinWalletManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinWalletManager.swift; sourceTree = ""; }; DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinNetworkService.swift; sourceTree = ""; }; DAED921E27A150E500F188D7 /* PolkadotAddressService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotAddressService.swift; sourceTree = ""; }; DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotWalletManager.swift; sourceTree = ""; }; @@ -3410,6 +3412,7 @@ DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */, DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */, + DAE864BC2C81D13F00A2D51A /* FilecoinWalletManager.swift */, ); path = Filecoin; sourceTree = ""; @@ -4832,6 +4835,7 @@ DC5E65072B1650F400E81AA5 /* OP_2DIV.swift in Sources */, 2DA4A4422BB5431700E55526 /* RadiantTransactionBuilder.swift in Sources */, 0A3BF8EA2C69F5D900163492 /* CosmosProtoMessage.swift in Sources */, + DAE864BD2C81D13F00A2D51A /* FilecoinWalletManager.swift in Sources */, EF3B19342AA85CE90084AA1C /* DogecoinExternalLinkProvider.swift in Sources */, EF2D9DA52BC3F6770055C485 /* EthereumTransactionParams.swift in Sources */, EF0DA78C285246A90081092A /* DashMainNetworkParams.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift index 84136696d..9920d18e0 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift @@ -29,12 +29,8 @@ final class FilecoinNetworkProvider: HostProvider { requestPublisher(for: .getActorInfo(address: address)) } - func getGasUnitPrice(transactionInfo: FilecoinTxInfo) -> AnyPublisher { - requestPublisher(for: .getGasUnitPrice(transactionInfo: transactionInfo)) - } - - func getGasLimit(transactionInfo: FilecoinTxInfo) -> AnyPublisher { - requestPublisher(for: .getGasLimit(transactionInfo: transactionInfo)) + func getMessageGas(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + requestPublisher(for: .getMessageGas(transactionInfo: transactionInfo)) } func submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) -> AnyPublisher { diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift new file mode 100644 index 000000000..3aa78922c --- /dev/null +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -0,0 +1,135 @@ +// +// FilecoinWalletManager.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 30.08.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import BigInt +import Combine + +class FilecoinWalletManager: BaseManager, WalletManager { + var currentHost: String { + networkService.host + } + + var allowsFeeSelection: Bool { + false + } + + private let networkService: FilecoinNetworkService + private let transactionBuilder: FilecoinTransactionBuilder + + private var nonce: UInt64 = 0 + + init( + wallet: Wallet, + networkService: FilecoinNetworkService, + transactionBuilder: FilecoinTransactionBuilder + ) { + self.networkService = networkService + self.transactionBuilder = transactionBuilder + super.init(wallet: wallet) + } + + override func update(completion: @escaping (Result) -> Void) { + cancellable = networkService + .getAccountInfo(address: wallet.address) + .withWeakCaptureOf(self) + .sink( + receiveCompletion: { + _ in + + }, + receiveValue: { walletManager, accountInfo in + if accountInfo.nonce != walletManager.nonce { + walletManager.wallet.clearPendingTransaction() + } + + walletManager.wallet.add( + amount: Amount( + with: .filecoin, + type: .coin, + value: accountInfo.balance / walletManager.wallet.blockchain.decimalValue + ) + ) + + walletManager.nonce = accountInfo.nonce + } + ) + } + + func getFee(amount: Amount, destination: String) -> AnyPublisher<[Fee], any Error> { + let transactionInfo = FilecoinTxInfo( + sourceAddress: wallet.address, + destinationAddress: destination, + amount: amount.value.uint64Value, + nonce: nonce + ) + + return networkService + .getMessageGas(transactionInfo: transactionInfo) + .withWeakCaptureOf(self) + .tryMap { (walletManager: FilecoinWalletManager, gasInfo) -> [Fee] in + guard let gasLimitDecimal = gasInfo.gasLimit.decimal, + let gasUnitPriceDecimal = gasInfo.gasUnitPrice.decimal + else { + throw WalletError.failedToGetFee + } + + return [ + Fee( + Amount( + with: .filecoin, + type: .coin, + value: (gasLimitDecimal * gasUnitPriceDecimal) / walletManager.wallet.blockchain.decimalValue + ), + parameters: FilecoinFeeParameters( + gasUnitPrice: gasInfo.gasUnitPrice, + gasLimit: gasLimitDecimal.int64Value, + gasPremium: gasInfo.gasPremium + ) + ) + ] + } + .eraseToAnyPublisher() + } + + func send(_ transaction: Transaction, signer: any TransactionSigner) -> AnyPublisher { + Result { + try transactionBuilder.buildForSign(transaction: transaction, nonce: nonce) + } + .publisher + .withWeakCaptureOf(self) + .flatMap { walletManager, hashToSign in + signer + .sign(hash: hashToSign, walletPublicKey: walletManager.wallet.publicKey) + .withWeakCaptureOf(walletManager) + .tryMap { walletManager, signature in + try walletManager.transactionBuilder.buildForSend( + transaction: transaction, + nonce: walletManager.nonce, + signatureInfo: SignatureInfo( + signature: signature, + publicKey: walletManager.wallet.publicKey.blockchainKey, + hash: hashToSign + ) + ) + } + } + .withWeakCaptureOf(self) + .flatMap { walletManager, body in + walletManager.networkService.submitTransaction(signedTransactionBody: body) + } + .withWeakCaptureOf(self) + .map { walletManager, txId in + let mapper = PendingTransactionRecordMapper() + let record = mapper.mapToPendingTransactionRecord(transaction: transaction, hash: txId) + walletManager.wallet.addPendingTransaction(record) + return TransactionSendResult(hash: txId) + } + .mapError { SendTxError(error: $0) } + .eraseToAnyPublisher() + } +} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift index b32ef09d5..14ff4737b 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift @@ -6,10 +6,10 @@ // Copyright © 2024 Tangem AG. All rights reserved. // -import Foundation +import BigInt -struct FilecoinTxGasInfo { - let gasUnitPrice: UInt64 - let gasLimit: UInt64 - let gasPremium: UInt64 +struct FilecoinTxGasInfo: Decodable { + let gasUnitPrice: BigUInt + let gasLimit: BigUInt + let gasPremium: BigUInt } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift index cdcab3155..c2dd9e1e5 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift @@ -34,24 +34,9 @@ class FilecoinNetworkService: MultiNetworkProvider { } } - func getGasUnitPrice(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + func getMessageGas(transactionInfo: FilecoinTxInfo) -> AnyPublisher { providerPublisher { provider in - provider - .getGasUnitPrice(transactionInfo: transactionInfo) - .tryMap { response in - guard let price = UInt64(response) else { - throw WalletError.failedToParseNetworkResponse() - } - return price - } - .eraseToAnyPublisher() - } - } - - func getGasLimit(transactionInfo: FilecoinTxInfo) -> AnyPublisher { - providerPublisher { provider in - provider - .getGasLimit(transactionInfo: transactionInfo) + provider.getMessageGas(transactionInfo: transactionInfo) } } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift index 3a8814443..5f2e03fad 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift @@ -12,18 +12,15 @@ import Moya struct FilecoinTarget: TargetType { enum FilecoinTargetType { case getActorInfo(address: String) - case getGasUnitPrice(transactionInfo: FilecoinTxInfo) - case getGasLimit(transactionInfo: FilecoinTxInfo) + case getMessageGas(transactionInfo: FilecoinTxInfo) case submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) var method: String { switch self { case .getActorInfo: "Filecoin.StateGetActor" - case .getGasUnitPrice: - "Filecoin.GasEstimateFeeCap" - case .getGasLimit: - "Filecoin.GasEstimateGasLimit" + case .getMessageGas: + "Filecoin.GasEstimateMessageGas" case .submitTransaction: "Filecoin.MpoolPush" } @@ -62,7 +59,7 @@ struct FilecoinTarget: TargetType { ] ) - case .getGasUnitPrice(let transactionInfo): + case .getMessageGas(let transactionInfo): .requestJSONRPC( id: Constants.jsonRPCMethodId, method: type.method, @@ -73,16 +70,6 @@ struct FilecoinTarget: TargetType { ] ) - case .getGasLimit(let transactionInfo): - .requestJSONRPC( - id: Constants.jsonRPCMethodId, - method: type.method, - params: [ - FilecoinDTOMapper.convertTransactionBody(from: transactionInfo), - nil - ] - ) - case .submitTransaction(let signedTransactionBody): .requestJSONRPC( id: Constants.jsonRPCMethodId, From e0b4aa8e2aa2a98c3361ae9aa1bc07b1eadeb727 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Fri, 30 Aug 2024 14:26:42 +0200 Subject: [PATCH 13/25] IOS-7779 CR fixes --- .../Filecoin/FilecoinTransactionBuilder.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index b5e1acfea..534b9e274 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -9,6 +9,12 @@ import TangemSdk import WalletCore +enum FilecoinTransactionBuilderError: Error { + case filecoinFeeParametersNotFound + case failedToConvertAmountToBigUInt + case failedToGetDataFromJSON +} + final class FilecoinTransactionBuilder { private let wallet: Wallet @@ -18,7 +24,7 @@ final class FilecoinTransactionBuilder { func buildForSign(transaction: Transaction, nonce: UInt64) throws -> Data { guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { - throw WalletError.failedToBuildTx + throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) @@ -36,7 +42,7 @@ final class FilecoinTransactionBuilder { signatureInfo: SignatureInfo ) throws -> FilecoinSignedTransactionBody { guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { - throw WalletError.failedToBuildTx + throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } let signatures = DataVector() @@ -58,7 +64,7 @@ final class FilecoinTransactionBuilder { let signingOutput = try FilecoinSigningOutput(serializedData: compiledWithSignatures) guard let jsonData = signingOutput.json.data(using: .utf8) else { - throw WalletError.failedToBuildTx + throw FilecoinTransactionBuilderError.failedToGetDataFromJSON } return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: jsonData) @@ -70,7 +76,7 @@ final class FilecoinTransactionBuilder { feeParameters: FilecoinFeeParameters ) throws -> FilecoinSigningInput { guard let value = transaction.amount.bigUIntValue else { - throw WalletError.failedToBuildTx + throw FilecoinTransactionBuilderError.failedToConvertAmountToBigUInt } return try FilecoinSigningInput.with { input in From 640b8c5aad37582ec5540d6ee8a09caf97a2f298 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sat, 31 Aug 2024 16:21:05 +0200 Subject: [PATCH 14/25] IOS-7738 Add manager --- .../Filecoin/FilecoinWalletAssembly.swift | 15 +++++++++++++-- .../Filecoin/FilecoinWalletManager.swift | 10 +++++++--- .../GetBlock/GetBlockAPIResolver.swift | 2 +- .../NowNodes/NowNodesAPIResolver.swift | 2 ++ BlockchainSdkExample/config | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift index e5a4f4a0e..2f5e44cc8 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift @@ -10,7 +10,18 @@ import Foundation struct FilecoinWalletAssembly: WalletManagerAssembly { func make(with input: WalletManagerAssemblyInput) throws -> WalletManager { - // TODO: [FILECOIN] https://tangem.atlassian.net/browse/IOS-7738 - fatalError("Not implemented") + FilecoinWalletManager( + wallet: input.wallet, + networkService: FilecoinNetworkService( + providers: APIResolver(blockchain: input.blockchain, config: input.blockchainSdkConfig) + .resolveProviders(apiInfos: input.apiInfo) { nodeInfo, _ in + FilecoinNetworkProvider( + node: nodeInfo, + configuration: input.networkConfig + ) + } + ), + transactionBuilder: FilecoinTransactionBuilder(wallet: input.wallet) + ) } } diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 3aa78922c..3d26da950 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -38,9 +38,13 @@ class FilecoinWalletManager: BaseManager, WalletManager { .getAccountInfo(address: wallet.address) .withWeakCaptureOf(self) .sink( - receiveCompletion: { - _ in - + receiveCompletion: { completion in + switch completion { + case .finished: + print("FINISHED") + case .failure(let failure): + print(failure) + } }, receiveValue: { walletManager, accountInfo in if accountInfo.nonce != walletManager.nonce { diff --git a/BlockchainSdk/Common/API/APIResolvers/GetBlock/GetBlockAPIResolver.swift b/BlockchainSdk/Common/API/APIResolvers/GetBlock/GetBlockAPIResolver.swift index 77a9cb10b..9efb25ec4 100644 --- a/BlockchainSdk/Common/API/APIResolvers/GetBlock/GetBlockAPIResolver.swift +++ b/BlockchainSdk/Common/API/APIResolvers/GetBlock/GetBlockAPIResolver.swift @@ -32,7 +32,7 @@ struct GetBlockAPIResolver { switch blockchain { case .cosmos, .tron, .algorand, .aptos: return credentials.credential(for: blockchain, type: .rest) - case .near, .ton, .ethereum, .ethereumClassic, .rsk, .bsc, .polygon, .fantom, .gnosis, .cronos, .zkSync, .moonbeam, .polygonZkEVM, .avalanche, .base, .xrp, .blast: + case .near, .ton, .ethereum, .ethereumClassic, .rsk, .bsc, .polygon, .fantom, .gnosis, .cronos, .zkSync, .moonbeam, .polygonZkEVM, .avalanche, .base, .xrp, .blast, .filecoin: return credentials.credential(for: blockchain, type: .jsonRpc) case .cardano: return credentials.credential(for: blockchain, type: .rosetta) diff --git a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift index a861efd5f..095a603d0 100644 --- a/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift +++ b/BlockchainSdk/Common/API/APIResolvers/NowNodes/NowNodesAPIResolver.swift @@ -68,6 +68,8 @@ struct NowNodesAPIResolver { link = "https://base.nownodes.io/\(apiKey)" case .blast: link = "https://blast.nownodes.io/\(apiKey)" + case .filecoin: + link = "https://fil.nownodes.io/\(apiKey)" default: return nil } diff --git a/BlockchainSdkExample/config b/BlockchainSdkExample/config index b5726a45b..57484a013 160000 --- a/BlockchainSdkExample/config +++ b/BlockchainSdkExample/config @@ -1 +1 @@ -Subproject commit b5726a45bf51b7763c5967afae4d3d687676240b +Subproject commit 57484a0139299d1229872c626b2c9cb34442038c From 38e53c7e2a1f0d1420741795069d88de30ad84c1 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Sat, 31 Aug 2024 18:00:51 +0200 Subject: [PATCH 15/25] IOS-7738 Change naming and data types --- BlockchainSdk.xcodeproj/project.pbxproj | 46 +++++++++---------- .../FilecoinExternalLinkProvider.swift | 6 +-- .../Filecoin/FilecoinFeeParameters.swift | 2 +- .../Filecoin/FilecoinNetworkProvider.swift | 10 ++-- .../Filecoin/FilecoinTransactionBuilder.swift | 6 +-- .../Filecoin/FilecoinWalletManager.swift | 33 +++++++------ .../Network/DTO/FilecoinDTOMapper.swift | 23 ---------- ...actionBody.swift => FilecoinMessage.swift} | 18 ++++---- .../Network/DTO/FilecoinResponse.swift | 13 ++++++ ...Body.swift => FilecoinSignedMessage.swift} | 10 ++-- .../Network/DTO/FilecoinTxGasInfo.swift | 15 ------ .../Filecoin/Network/DTO/FilecoinTxInfo.swift | 16 ------- .../Network/FilecoinNetworkService.swift | 16 +++++-- .../Filecoin/Network/FilecoinTarget.swift | 14 +++--- BlockchainSdk/Extensions/JSONDecoder+.swift | 27 +++++++++++ .../FilecoinTransactionBuilderTests.swift | 18 ++++---- 16 files changed, 130 insertions(+), 143 deletions(-) delete mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift rename BlockchainSdk/Blockchains/Filecoin/Network/DTO/{FilecoinTransactionBody.swift => FilecoinMessage.swift} (56%) rename BlockchainSdk/Blockchains/Filecoin/Network/DTO/{FilecoinSignedTransactionBody.swift => FilecoinSignedMessage.swift} (69%) delete mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift delete mode 100644 BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 16aac378c..65818c84e 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -559,12 +559,9 @@ DAD156592C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */; }; DAD1565C2C7DCFBD00DE52B3 /* FilecoinTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */; }; DAD1565F2C7DD16B00DE52B3 /* FilecoinResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */; }; - DAD156632C7DD21B00DE52B3 /* FilecoinTransactionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */; }; - DAD156652C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */; }; + DAD156632C7DD21B00DE52B3 /* FilecoinMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156622C7DD21B00DE52B3 /* FilecoinMessage.swift */; }; + DAD156652C7DD25800DE52B3 /* FilecoinSignedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156642C7DD25800DE52B3 /* FilecoinSignedMessage.swift */; }; DAD156692C7DD65400DE52B3 /* FilecoinAccountInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */; }; - DAD1566B2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */; }; - DAD1566E2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */; }; - DAD156702C7DE0D000DE52B3 /* FilecoinDTOMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */; }; DAD555292BFB4110000030E5 /* KoinosTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD555282BFB4110000030E5 /* KoinosTransactionBuilder.swift */; }; DAD555382BFB463C000030E5 /* KoinosAccountNonce.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD555372BFB463C000030E5 /* KoinosAccountNonce.swift */; }; DAD5CDF72C0F3A8900DC4909 /* KoinosWalletManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD5CDF62C0F3A8900DC4909 /* KoinosWalletManagerTests.swift */; }; @@ -1502,12 +1499,9 @@ DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FilecoinNetworkProvider.swift; path = ../FilecoinNetworkProvider.swift; sourceTree = ""; }; DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTarget.swift; sourceTree = ""; }; DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinResponse.swift; sourceTree = ""; }; - DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTransactionBody.swift; sourceTree = ""; }; - DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinSignedTransactionBody.swift; sourceTree = ""; }; - DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinAccountInfo.swift; sourceTree = ""; }; - DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTxGasInfo.swift; sourceTree = ""; }; - DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinTxInfo.swift; sourceTree = ""; }; - DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FilecoinDTOMapper.swift; path = DTO/FilecoinDTOMapper.swift; sourceTree = ""; }; + DAD156622C7DD21B00DE52B3 /* FilecoinMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinMessage.swift; sourceTree = ""; }; + DAD156642C7DD25800DE52B3 /* FilecoinSignedMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilecoinSignedMessage.swift; sourceTree = ""; }; + DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FilecoinAccountInfo.swift; path = ../Network/DTO/FilecoinAccountInfo.swift; sourceTree = ""; }; DAD555282BFB4110000030E5 /* KoinosTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosTransactionBuilder.swift; sourceTree = ""; }; DAD555372BFB463C000030E5 /* KoinosAccountNonce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosAccountNonce.swift; sourceTree = ""; }; DAD5CDF62C0F3A8900DC4909 /* KoinosWalletManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KoinosWalletManagerTests.swift; sourceTree = ""; }; @@ -3407,12 +3401,13 @@ DA15D1E82C7782F300FD733B /* Filecoin */ = { isa = PBXGroup; children = ( + DA63E5FE2C836ADF007690B9 /* Model */, DAD1565A2C7DCFAD00DE52B3 /* Network */, DA15D1E92C77830E00FD733B /* FilecoinExternalLinkProvider.swift */, DA20BD692C7BC5E9000F02DF /* FilecoinWalletAssembly.swift */, + DAE864BC2C81D13F00A2D51A /* FilecoinWalletManager.swift */, DA9F15F12C80B3B800EA7FAF /* FilecoinTransactionBuilder.swift */, DAE864BA2C81CF1700A2D51A /* FilecoinFeeParameters.swift */, - DAE864BC2C81D13F00A2D51A /* FilecoinWalletManager.swift */, ); path = Filecoin; sourceTree = ""; @@ -3584,6 +3579,14 @@ path = Address; sourceTree = ""; }; + DA63E5FE2C836ADF007690B9 /* Model */ = { + isa = PBXGroup; + children = ( + DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */, + ); + path = Model; + sourceTree = ""; + }; DA9F76E727EC8AD900F0665C /* Tron */ = { isa = PBXGroup; children = ( @@ -3629,10 +3632,9 @@ isa = PBXGroup; children = ( DAD1565D2C7DD15E00DE52B3 /* DTO */, - DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */, - DAD1566F2C7DE0D000DE52B3 /* FilecoinDTOMapper.swift */, - DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */, DAED18A12C7DF3D900522056 /* FilecoinNetworkService.swift */, + DAD156582C7DCF6600DE52B3 /* FilecoinNetworkProvider.swift */, + DAD1565B2C7DCFBD00DE52B3 /* FilecoinTarget.swift */, ); path = Network; sourceTree = ""; @@ -3641,11 +3643,8 @@ isa = PBXGroup; children = ( DAD1565E2C7DD16B00DE52B3 /* FilecoinResponse.swift */, - DAD156622C7DD21B00DE52B3 /* FilecoinTransactionBody.swift */, - DAD156642C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift */, - DAD156682C7DD65400DE52B3 /* FilecoinAccountInfo.swift */, - DAD1566A2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift */, - DAD1566D2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift */, + DAD156622C7DD21B00DE52B3 /* FilecoinMessage.swift */, + DAD156642C7DD25800DE52B3 /* FilecoinSignedMessage.swift */, ); path = DTO; sourceTree = ""; @@ -4981,7 +4980,7 @@ EF3B194A2AA85E7B0084AA1C /* DashExternalLinkProvider.swift in Sources */, 2DDE5BA229C4F8D200A5B708 /* BinanceWalletAssembly.swift in Sources */, B00DF9912BBEA9DA004397CB /* APIModels.swift in Sources */, - DAD156632C7DD21B00DE52B3 /* FilecoinTransactionBody.swift in Sources */, + DAD156632C7DD21B00DE52B3 /* FilecoinMessage.swift in Sources */, DC5E64F62B1650F400E81AA5 /* OP_LESSTHAN.swift in Sources */, 5DEAFA90244473460032E316 /* Transaction.swift in Sources */, 5D977BB623FAEB4500575BE4 /* DucatusNetworkService.swift in Sources */, @@ -5173,7 +5172,6 @@ EF2D9DA22BC3F6770055C485 /* EthereumAdditionalInfoProvider.swift in Sources */, EF2D9DA12BC3F6770055C485 /* EthereumTransactionDataBuilder.swift in Sources */, B6F89EAD2BB20DB50009A453 /* SubscanAPIResult.Error.swift in Sources */, - DAD156702C7DE0D000DE52B3 /* FilecoinDTOMapper.swift in Sources */, 2DCAEE4F2B147E2800C87E09 /* DecimalPlainAddress.swift in Sources */, DC5E652C2B1650F400E81AA5 /* OP_RETURN.swift in Sources */, EF3B19382AA85D090084AA1C /* PolygonExternalLinkProvider.swift in Sources */, @@ -5260,7 +5258,7 @@ 0A158C052B74E4680004DC23 /* BitcoinCashNowNodesNetworkProvider.swift in Sources */, DC3550F12B57013F00A93DBA /* XDCExternalLinkProvider.swift in Sources */, EFAD40A52A965BA800364D65 /* BlockBookNode.swift in Sources */, - DAD156652C7DD25800DE52B3 /* FilecoinSignedTransactionBody.swift in Sources */, + DAD156652C7DD25800DE52B3 /* FilecoinSignedMessage.swift in Sources */, DA5339A52BFCBE8600BA3D80 /* KoinosProtocol.swift in Sources */, DC5E65012B1650F400E81AA5 /* OP_NEGATE.swift in Sources */, EF3B191E2AA85C150084AA1C /* CardanoExternalLinkProvider.swift in Sources */, @@ -5359,9 +5357,7 @@ DAE657E72BFC732400D7D63A /* token.pb.swift in Sources */, B6417DDC2BA2354D00B9B61D /* PolygonTransactionHistoryProvider.swift in Sources */, DAE657E52BFC732400D7D63A /* protocol.pb.swift in Sources */, - DAD1566B2C7DD67F00DE52B3 /* FilecoinTxGasInfo.swift in Sources */, B6BA93792AEA0F0C00F84E36 /* NEARNetworkResult.GasPrice.swift in Sources */, - DAD1566E2C7DD6AC00DE52B3 /* FilecoinTxInfo.swift in Sources */, B6B2EB6D2B56AAB9005FBE8E /* VeChainNetworkResult.ContractCall.swift in Sources */, EF57BEC82A1E13BE00C2A493 /* DerivationConfig.swift in Sources */, DA0E98D62C04755C00C92985 /* KoinosMethod.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift index 3f6b0987d..500703105 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinExternalLinkProvider.swift @@ -16,11 +16,7 @@ struct FilecoinExternalLinkProvider: ExternalLinkProvider { } func url(transaction hash: String) -> URL? { - /// This method returns `nil` because Filecoin does not use transaction hashes as message identifiers. - /// In other blockchains, a transaction hash can be directly used to generate a URL to explore the transaction details. - /// However, in Filecoin, message IDs (which are used to identify transactions) are not derived from transaction hashes. - /// Therefore, constructing a URL in the format `"\(baseExplorerUrl)/message/\(hash)"` is not applicable. - nil + URL(string: "\(baseExplorerUrl)/message/\(hash)") } func url(address: String, contractAddress: String?) -> URL? { diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift index 876b7de3c..cdb162315 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinFeeParameters.swift @@ -9,7 +9,7 @@ import BigInt struct FilecoinFeeParameters: FeeParameters { - let gasUnitPrice: BigUInt let gasLimit: Int64 + let gasFeeCap: BigUInt let gasPremium: BigUInt } diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift index 9920d18e0..9bb390544 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinNetworkProvider.swift @@ -29,18 +29,18 @@ final class FilecoinNetworkProvider: HostProvider { requestPublisher(for: .getActorInfo(address: address)) } - func getMessageGas(transactionInfo: FilecoinTxInfo) -> AnyPublisher { - requestPublisher(for: .getMessageGas(transactionInfo: transactionInfo)) + func getEstimateMessageGas(message: FilecoinMessage) -> AnyPublisher { + requestPublisher(for: .getEstimateMessageGas(message: message)) } - func submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) -> AnyPublisher { - requestPublisher(for: .submitTransaction(signedTransactionBody: signedTransactionBody)) + func submitTransaction(signedMessage: FilecoinSignedMessage) -> AnyPublisher { + requestPublisher(for: .submitTransaction(signedMessage: signedMessage)) } private func requestPublisher(for target: FilecoinTarget.FilecoinTargetType) -> AnyPublisher { provider.requestPublisher(FilecoinTarget(node: node, target)) .filterSuccessfulStatusAndRedirectCodes() - .map(JSONRPC.Response.self, using: .withSnakeCaseStrategy) + .map(JSONRPC.Response.self) .tryMap { try $0.result.get() } .eraseToAnyPublisher() } diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index 534b9e274..45f1cc458 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -40,7 +40,7 @@ final class FilecoinTransactionBuilder { transaction: Transaction, nonce: UInt64, signatureInfo: SignatureInfo - ) throws -> FilecoinSignedTransactionBody { + ) throws -> FilecoinSignedMessage { guard let feeParameters = transaction.fee.parameters as? FilecoinFeeParameters else { throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } @@ -67,7 +67,7 @@ final class FilecoinTransactionBuilder { throw FilecoinTransactionBuilderError.failedToGetDataFromJSON } - return try JSONDecoder().decode(FilecoinSignedTransactionBody.self, from: jsonData) + return try JSONDecoder().decode(FilecoinSignedMessage.self, from: jsonData) } private func makeSigningInput( @@ -85,8 +85,8 @@ final class FilecoinTransactionBuilder { input.value = value.serialize() - input.gasFeeCap = feeParameters.gasUnitPrice.serialize() input.gasLimit = feeParameters.gasLimit + input.gasFeeCap = feeParameters.gasFeeCap.serialize() input.gasPremium = feeParameters.gasPremium.serialize() input.publicKey = try Secp256k1Key(with: wallet.publicKey.blockchainKey).decompress() diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 3d26da950..24898ab4d 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -65,34 +65,37 @@ class FilecoinWalletManager: BaseManager, WalletManager { } func getFee(amount: Amount, destination: String) -> AnyPublisher<[Fee], any Error> { - let transactionInfo = FilecoinTxInfo( - sourceAddress: wallet.address, - destinationAddress: destination, - amount: amount.value.uint64Value, - nonce: nonce + let message = FilecoinMessage( + from: wallet.address, + to: destination, + value: amount.description, + nonce: nonce, + gasLimit: nil, + gasFeeCap: nil, + gasPremium: nil ) return networkService - .getMessageGas(transactionInfo: transactionInfo) + .getEstimateMessageGas(message: message) .withWeakCaptureOf(self) .tryMap { (walletManager: FilecoinWalletManager, gasInfo) -> [Fee] in - guard let gasLimitDecimal = gasInfo.gasLimit.decimal, - let gasUnitPriceDecimal = gasInfo.gasUnitPrice.decimal - else { + guard let gasFeeCapDecimal = Decimal(stringValue: gasInfo.gasFeeCap) else { throw WalletError.failedToGetFee } + let gasLimitDecimal = Decimal(gasInfo.gasLimit) + return [ Fee( Amount( with: .filecoin, type: .coin, - value: (gasLimitDecimal * gasUnitPriceDecimal) / walletManager.wallet.blockchain.decimalValue + value: gasLimitDecimal * gasFeeCapDecimal / walletManager.wallet.blockchain.decimalValue ), parameters: FilecoinFeeParameters( - gasUnitPrice: gasInfo.gasUnitPrice, - gasLimit: gasLimitDecimal.int64Value, - gasPremium: gasInfo.gasPremium + gasLimit: gasInfo.gasLimit, + gasFeeCap: BigUInt(stringLiteral: gasInfo.gasFeeCap), + gasPremium: BigUInt(stringLiteral: gasInfo.gasPremium) ) ) ] @@ -123,8 +126,8 @@ class FilecoinWalletManager: BaseManager, WalletManager { } } .withWeakCaptureOf(self) - .flatMap { walletManager, body in - walletManager.networkService.submitTransaction(signedTransactionBody: body) + .flatMap { walletManager, message in + walletManager.networkService.submitTransaction(signedMessage: message) } .withWeakCaptureOf(self) .map { walletManager, txId in diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift deleted file mode 100644 index a10f60eaf..000000000 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinDTOMapper.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// FilecoinTransactionBodyConverter.swift -// BlockchainSdk -// -// Created by Aleksei Muraveinik on 27.08.24. -// Copyright © 2024 Tangem AG. All rights reserved. -// - -import Foundation - -enum FilecoinDTOMapper { - static func convertTransactionBody(from transactionInfo: FilecoinTxInfo) -> FilecoinTransactionBody { - FilecoinTransactionBody( - sourceAddress: transactionInfo.sourceAddress, - destinationAddress: transactionInfo.destinationAddress, - amount: "\(transactionInfo.amount)", - nonce: transactionInfo.nonce, - gasUnitPrice: nil, - gasLimit: nil, - gasPremium: nil - ) - } -} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinMessage.swift similarity index 56% rename from BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift rename to BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinMessage.swift index f0127535e..abd5dd66d 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTransactionBody.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinMessage.swift @@ -8,22 +8,22 @@ import Foundation -struct FilecoinTransactionBody: Codable, Equatable { - let sourceAddress: String - let destinationAddress: String - let amount: String +struct FilecoinMessage: Codable, Equatable { + let from: String + let to: String + let value: String let nonce: UInt64 - let gasUnitPrice: String? let gasLimit: UInt64? + let gasFeeCap: String? let gasPremium: String? enum CodingKeys: String, CodingKey { - case sourceAddress = "From" - case destinationAddress = "To" - case amount = "Value" + case from = "From" + case to = "To" + case value = "Value" case nonce = "Nonce" - case gasUnitPrice = "GasFeeCap" case gasLimit = "GasLimit" + case gasFeeCap = "GasFeeCap" case gasPremium = "GasPremium" } } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift index 944d90894..042dad2ba 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift @@ -6,6 +6,7 @@ // Copyright © 2024 Tangem AG. All rights reserved. // +import BigInt import Foundation enum FilecoinResponse { @@ -19,6 +20,18 @@ enum FilecoinResponse { } } + struct GasEstimateMessageGas: Decodable { + let gasLimit: Int64 + let gasFeeCap: String + let gasPremium: String + + enum CodingKeys: String, CodingKey { + case gasLimit = "GasLimit" + case gasFeeCap = "GasFeeCap" + case gasPremium = "GasPremium" + } + } + struct SubmitTransaction: Decodable { let hash: String diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedMessage.swift similarity index 69% rename from BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift rename to BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedMessage.swift index e58d36ddb..3803aef47 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedTransactionBody.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinSignedMessage.swift @@ -8,22 +8,22 @@ import Foundation -struct FilecoinSignedTransactionBody: Codable, Equatable { +struct FilecoinSignedMessage: Codable, Equatable { struct Signature: Codable, Equatable { let type: Int - let signature: String + let data: String enum CodingKeys: String, CodingKey { case type = "Type" - case signature = "Data" + case data = "Data" } } - let transactionBody: FilecoinTransactionBody + let message: FilecoinMessage let signature: Signature enum CodingKeys: String, CodingKey { - case transactionBody = "Message" + case message = "Message" case signature = "Signature" } } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift deleted file mode 100644 index 14ff4737b..000000000 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxGasInfo.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// FilecoinTxGasInfo.swift -// BlockchainSdk -// -// Created by Aleksei Muraveinik on 27.08.24. -// Copyright © 2024 Tangem AG. All rights reserved. -// - -import BigInt - -struct FilecoinTxGasInfo: Decodable { - let gasUnitPrice: BigUInt - let gasLimit: BigUInt - let gasPremium: BigUInt -} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift deleted file mode 100644 index 7b19fcf45..000000000 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinTxInfo.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// FilecoinTxInfo.swift -// BlockchainSdk -// -// Created by Aleksei Muraveinik on 27.08.24. -// Copyright © 2024 Tangem AG. All rights reserved. -// - -import Foundation - -struct FilecoinTxInfo { - let sourceAddress: String - let destinationAddress: String - let amount: UInt64 - let nonce: UInt64 -} diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift index c2dd9e1e5..773c1f9cc 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinNetworkService.swift @@ -16,7 +16,9 @@ class FilecoinNetworkService: MultiNetworkProvider { self.providers = providers } - func getAccountInfo(address: String) -> AnyPublisher { + func getAccountInfo( + address: String + ) -> AnyPublisher { providerPublisher { provider in provider .getActorInfo(address: address) @@ -34,16 +36,20 @@ class FilecoinNetworkService: MultiNetworkProvider { } } - func getMessageGas(transactionInfo: FilecoinTxInfo) -> AnyPublisher { + func getEstimateMessageGas( + message: FilecoinMessage + ) -> AnyPublisher { providerPublisher { provider in - provider.getMessageGas(transactionInfo: transactionInfo) + provider.getEstimateMessageGas(message: message) } } - func submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) -> AnyPublisher { + func submitTransaction( + signedMessage: FilecoinSignedMessage + ) -> AnyPublisher { providerPublisher { provider in provider - .submitTransaction(signedTransactionBody: signedTransactionBody) + .submitTransaction(signedMessage: signedMessage) .map(\.hash) .eraseToAnyPublisher() } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift index 5f2e03fad..adab54fc0 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/FilecoinTarget.swift @@ -12,14 +12,14 @@ import Moya struct FilecoinTarget: TargetType { enum FilecoinTargetType { case getActorInfo(address: String) - case getMessageGas(transactionInfo: FilecoinTxInfo) - case submitTransaction(signedTransactionBody: FilecoinSignedTransactionBody) + case getEstimateMessageGas(message: FilecoinMessage) + case submitTransaction(signedMessage: FilecoinSignedMessage) var method: String { switch self { case .getActorInfo: "Filecoin.StateGetActor" - case .getMessageGas: + case .getEstimateMessageGas: "Filecoin.GasEstimateMessageGas" case .submitTransaction: "Filecoin.MpoolPush" @@ -59,23 +59,23 @@ struct FilecoinTarget: TargetType { ] ) - case .getMessageGas(let transactionInfo): + case .getEstimateMessageGas(let message): .requestJSONRPC( id: Constants.jsonRPCMethodId, method: type.method, params: [ - FilecoinDTOMapper.convertTransactionBody(from: transactionInfo), + message, nil, nil ] ) - case .submitTransaction(let signedTransactionBody): + case .submitTransaction(let signedMessage): .requestJSONRPC( id: Constants.jsonRPCMethodId, method: type.method, params: [ - signedTransactionBody + signedMessage ] ) } diff --git a/BlockchainSdk/Extensions/JSONDecoder+.swift b/BlockchainSdk/Extensions/JSONDecoder+.swift index fc62fb18d..1b5ce56a9 100644 --- a/BlockchainSdk/Extensions/JSONDecoder+.swift +++ b/BlockchainSdk/Extensions/JSONDecoder+.swift @@ -34,3 +34,30 @@ extension JSONDecoder { return encoder } } + +extension JSONDecoder { + static var withUpperCamelToLowerCamelCaseStrategy: JSONDecoder { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .custom { keys in + let lastKey = keys.last!.stringValue + let lowerCamelCaseKey = lastKey.prefix(1).lowercased() + lastKey.dropFirst() + return AnyKey(stringValue: lowerCamelCaseKey)! + } + return decoder + } +} + +private struct AnyKey: CodingKey { + let stringValue: String + let intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + self.intValue = nil + } + + init?(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue + } +} diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift index 9ca0e5564..9eda4c1c7 100644 --- a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -40,8 +40,8 @@ final class FilecoinTransactionBuilderTests: XCTestCase { value: (101225 * 1526328) / Blockchain.filecoin.decimalValue ), parameters: FilecoinFeeParameters( - gasUnitPrice: 101225, gasLimit: 1526328, + gasFeeCap: 101225, gasPremium: 50612 ) ), @@ -60,19 +60,19 @@ final class FilecoinTransactionBuilderTests: XCTestCase { func testBuildForSend() throws { let nonce: UInt64 = 2 - let expected = FilecoinSignedTransactionBody( - transactionBody: FilecoinTransactionBody( - sourceAddress: Constants.sourceAddress, - destinationAddress: Constants.destinationAddress, - amount: "10000000000000000", + let expected = FilecoinSignedMessage( + message: FilecoinMessage( + from: Constants.sourceAddress, + to: Constants.destinationAddress, + value: "10000000000000000", nonce: nonce, - gasUnitPrice: "101225", gasLimit: 1526328, + gasFeeCap: "101225", gasPremium: "50612" ), - signature: FilecoinSignedTransactionBody.Signature( + signature: FilecoinSignedMessage.Signature( type: 1, - signature: "Bogel9o9zvXUT+sC+nVpciGyHfBxWG6V4+xOawP6YrAU1OIbifvEHpRT/Elakv2X6mfUkbQzparvc2HyJBbXRwE=" + data: "Bogel9o9zvXUT+sC+nVpciGyHfBxWG6V4+xOawP6YrAU1OIbifvEHpRT/Elakv2X6mfUkbQzparvc2HyJBbXRwE=" ) ) From c63f4134756cc7a48e2746c492779436016ff37e Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Mon, 2 Sep 2024 19:29:25 +0200 Subject: [PATCH 16/25] IOS-7738 Fix transaction sending --- .../Filecoin/FilecoinTransactionBuilder.swift | 22 +++++++++++++++++-- .../Filecoin/FilecoinWalletManager.swift | 17 +++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index 45f1cc458..6f289bbda 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -6,6 +6,7 @@ // Copyright © 2024 Tangem AG. All rights reserved. // +import BigInt import TangemSdk import WalletCore @@ -45,11 +46,28 @@ final class FilecoinTransactionBuilder { throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } + let decompressed = try Secp256k1Key(with: signatureInfo.publicKey).decompress() + let secp256k1Signature = try Secp256k1Signature(with: signatureInfo.signature) + let unmarshal = try secp256k1Signature.unmarshal(with: decompressed, hash: signatureInfo.hash) + + // As we use the chainID in the transaction according to EIP-155 + // WalletCore will use formula to calculate `V`. + // v = CHAIN_ID * 2 + 35 + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + + // It's strange but we can't use `unmarshal.v` here because WalletCore throw a error. + // And we have to add one zero byte to the signature because + // WalletCore has a validation on the signature count. + // // https://github.com/tangem/wallet-core/blob/996bd5ab37f27e7f6e240a4ec9d0788dfb124e89/src/PublicKey.h#L35 + let v = BigUInt(unmarshal.v) - 27 + let encodedV = v == .zero ? Data([UInt8.zero]) : v.serialize() + let signature = unmarshal.r + unmarshal.s + encodedV + let signatures = DataVector() - signatures.add(data: signatureInfo.signature) + signatures.add(data: signature) let publicKeys = DataVector() - publicKeys.add(data: try Secp256k1Key(with: signatureInfo.publicKey).decompress()) + publicKeys.add(data: decompressed) let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) let txInputData = try input.serializedData() diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 24898ab4d..581a5480d 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -38,12 +38,13 @@ class FilecoinWalletManager: BaseManager, WalletManager { .getAccountInfo(address: wallet.address) .withWeakCaptureOf(self) .sink( - receiveCompletion: { completion in - switch completion { + receiveCompletion: { [weak self] result in + switch result { + case .failure(let error): + self?.wallet.clearAmounts() + completion(.failure(error)) case .finished: - print("FINISHED") - case .failure(let failure): - print(failure) + completion(.success(())) } }, receiveValue: { walletManager, accountInfo in @@ -65,10 +66,14 @@ class FilecoinWalletManager: BaseManager, WalletManager { } func getFee(amount: Amount, destination: String) -> AnyPublisher<[Fee], any Error> { + guard let bigUIntValue = amount.bigUIntValue else { + return .anyFail(error: WalletError.failedToGetFee) + } + let message = FilecoinMessage( from: wallet.address, to: destination, - value: amount.description, + value: bigUIntValue.description, nonce: nonce, gasLimit: nil, gasFeeCap: nil, From e047908a70944679ae78c6a3df24710dc1a5a1d7 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Mon, 2 Sep 2024 19:55:35 +0200 Subject: [PATCH 17/25] IOS-7738 Adjust tests --- .../FilecoinTransactionBuilderTests.swift | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift index 9eda4c1c7..d84020e60 100644 --- a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -31,18 +31,18 @@ final class FilecoinTransactionBuilderTests: XCTestCase { amount: Amount( with: .filecoin, type: .coin, - value: 0.01 + value: 1 ), fee: Fee( Amount( with: .filecoin, type: .coin, - value: (101225 * 1526328) / Blockchain.filecoin.decimalValue + value: (100704 * 1527953) / Blockchain.filecoin.decimalValue ), parameters: FilecoinFeeParameters( - gasLimit: 1526328, - gasFeeCap: 101225, - gasPremium: 50612 + gasLimit: 1527953, + gasFeeCap: 100704, + gasPremium: 99503 ) ), sourceAddress: Constants.sourceAddress, @@ -52,27 +52,27 @@ final class FilecoinTransactionBuilderTests: XCTestCase { } func testBuildForSign() throws { - let expected = Data(hex: "BEB93CCF5C85273B327AC5DCDD58CBF3066F57FC84B87CD20DC67DF69EC2D0A9") - let actual = try transactionBuilder.buildForSign(transaction: transaction, nonce: 2) + let expected = Data(hex: "0beac3427b81d6fa6e93a05a0b64fcc3c7ce4af9d05af31ee343bcc527ae8b18") + let actual = try transactionBuilder.buildForSign(transaction: transaction, nonce: 1) XCTAssertEqual(expected, actual) } func testBuildForSend() throws { - let nonce: UInt64 = 2 + let nonce: UInt64 = 1 let expected = FilecoinSignedMessage( message: FilecoinMessage( from: Constants.sourceAddress, to: Constants.destinationAddress, - value: "10000000000000000", + value: "1000000000000000000", nonce: nonce, - gasLimit: 1526328, - gasFeeCap: "101225", - gasPremium: "50612" + gasLimit: 1527953, + gasFeeCap: "100704", + gasPremium: "99503" ), signature: FilecoinSignedMessage.Signature( type: 1, - data: "Bogel9o9zvXUT+sC+nVpciGyHfBxWG6V4+xOawP6YrAU1OIbifvEHpRT/Elakv2X6mfUkbQzparvc2HyJBbXRwE=" + data: "weMNBBonfukL/wkGAb6z8ZM8c5Op5BuFPMvQAVZvdJkU0/HdRX+DEPV+A4x5sWKmWbZzyIgNyGhxpbD2yO3vkgA=" ) ) @@ -94,10 +94,10 @@ final class FilecoinTransactionBuilderTests: XCTestCase { private extension FilecoinTransactionBuilderTests { enum Constants { - static let publicKey = Data(hex: "0374D0F81F42DDFE34114D533E95E6AE5FE6EA271C96F1FA505199FDC365AE9720") - static let signature = Data(hex: "06881E97DA3DCEF5D44FEB02FA75697221B21DF071586E95E3EC4E6B03FA62B014D4E21B89FBC41E9453FC495A92FD97EA67D491B433A5AAEF7361F22416D74701") + static let publicKey = Data(hex: "02a1f09e4d91756b9f1d4f96c2c71d09178e3850a70703c3d089dad84f3870b3c6") + static let signature = Data(hex: "c1e30d041a277ee90bff090601beb3f1933c7393a9e41b853ccbd001566f749914d3f1dd457f8310f57e038c79b162a659b673c8880dc86871a5b0f6c8edef92") - static let sourceAddress = "f1flbddhx4vwox3y3ux5bwgsgq2frzeiuvvdrjo7i" - static let destinationAddress = "f1rluskhwvv5b3z36skltu4noszbc5stfihevbf2i" + static let sourceAddress = "f1kub5b7ekrwn7vykavn7owjuff7kqcoa4g4fgriq" + static let destinationAddress = "f1ufoxbvz637fkjbrk2d4cktqsgjwsqwm4woa7pda" } } From 9fbe38b6a196a4c6c98380981d325305beecd209 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Mon, 2 Sep 2024 19:57:13 +0200 Subject: [PATCH 18/25] IOS-7738 Remove not used --- BlockchainSdk/Extensions/JSONDecoder+.swift | 27 --------------------- 1 file changed, 27 deletions(-) diff --git a/BlockchainSdk/Extensions/JSONDecoder+.swift b/BlockchainSdk/Extensions/JSONDecoder+.swift index 1b5ce56a9..fc62fb18d 100644 --- a/BlockchainSdk/Extensions/JSONDecoder+.swift +++ b/BlockchainSdk/Extensions/JSONDecoder+.swift @@ -34,30 +34,3 @@ extension JSONDecoder { return encoder } } - -extension JSONDecoder { - static var withUpperCamelToLowerCamelCaseStrategy: JSONDecoder { - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .custom { keys in - let lastKey = keys.last!.stringValue - let lowerCamelCaseKey = lastKey.prefix(1).lowercased() + lastKey.dropFirst() - return AnyKey(stringValue: lowerCamelCaseKey)! - } - return decoder - } -} - -private struct AnyKey: CodingKey { - let stringValue: String - let intValue: Int? - - init?(stringValue: String) { - self.stringValue = stringValue - self.intValue = nil - } - - init?(intValue: Int) { - self.stringValue = "\(intValue)" - self.intValue = intValue - } -} From 9d5a8b866aff8d86fb1fa50aba6bf2e1246135b3 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Mon, 2 Sep 2024 20:06:16 +0200 Subject: [PATCH 19/25] IOS-7738 Pass smallest required entity --- .../Filecoin/FilecoinTransactionBuilder.swift | 8 ++++---- .../Filecoin/FilecoinWalletAssembly.swift | 2 +- .../FilecoinTransactionBuilderTests.swift | 15 +++------------ 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index 6f289bbda..ccc602bb9 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -17,10 +17,10 @@ enum FilecoinTransactionBuilderError: Error { } final class FilecoinTransactionBuilder { - private let wallet: Wallet + private let publicKey: Wallet.PublicKey - init(wallet: Wallet) { - self.wallet = wallet + init(publicKey: Wallet.PublicKey) { + self.publicKey = publicKey } func buildForSign(transaction: Transaction, nonce: UInt64) throws -> Data { @@ -107,7 +107,7 @@ final class FilecoinTransactionBuilder { input.gasFeeCap = feeParameters.gasFeeCap.serialize() input.gasPremium = feeParameters.gasPremium.serialize() - input.publicKey = try Secp256k1Key(with: wallet.publicKey.blockchainKey).decompress() + input.publicKey = try Secp256k1Key(with: publicKey.blockchainKey).decompress() } } } diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift index 2f5e44cc8..63f4ad288 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift @@ -21,7 +21,7 @@ struct FilecoinWalletAssembly: WalletManagerAssembly { ) } ), - transactionBuilder: FilecoinTransactionBuilder(wallet: input.wallet) + transactionBuilder: FilecoinTransactionBuilder(publicKey: input.wallet.publicKey) ) } } diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift index d84020e60..18286d2f9 100644 --- a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -11,18 +11,9 @@ import XCTest final class FilecoinTransactionBuilderTests: XCTestCase { private let transactionBuilder = FilecoinTransactionBuilder( - wallet: Wallet( - blockchain: .filecoin, - addresses: [ - .default: PlainAddress( - value: Constants.sourceAddress, - publicKey: Wallet.PublicKey( - seedKey: Constants.publicKey, - derivationType: nil - ), - type: .default - ) - ] + publicKey: Wallet.PublicKey( + seedKey: Constants.publicKey, + derivationType: nil ) ) From 6f3c65f7404be7f33492280fdb37c42c142ff5cb Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 11:17:45 +0200 Subject: [PATCH 20/25] IOS-7738 Add size test and decompress key in init --- .../Filecoin/FilecoinTransactionBuilder.swift | 15 +++++++-------- .../Filecoin/FilecoinWalletAssembly.swift | 2 +- .../FilecoinTransactionBuilderTests.swift | 6 ++++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index ccc602bb9..1ccbf10bf 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -17,10 +17,10 @@ enum FilecoinTransactionBuilderError: Error { } final class FilecoinTransactionBuilder { - private let publicKey: Wallet.PublicKey + private let decompressedPublicKey: Data - init(publicKey: Wallet.PublicKey) { - self.publicKey = publicKey + init(publicKey: Wallet.PublicKey) throws { + self.decompressedPublicKey = try Secp256k1Key(with: publicKey.blockchainKey).decompress() } func buildForSign(transaction: Transaction, nonce: UInt64) throws -> Data { @@ -46,9 +46,8 @@ final class FilecoinTransactionBuilder { throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } - let decompressed = try Secp256k1Key(with: signatureInfo.publicKey).decompress() let secp256k1Signature = try Secp256k1Signature(with: signatureInfo.signature) - let unmarshal = try secp256k1Signature.unmarshal(with: decompressed, hash: signatureInfo.hash) + let unmarshal = try secp256k1Signature.unmarshal(with: decompressedPublicKey, hash: signatureInfo.hash) // As we use the chainID in the transaction according to EIP-155 // WalletCore will use formula to calculate `V`. @@ -67,7 +66,7 @@ final class FilecoinTransactionBuilder { signatures.add(data: signature) let publicKeys = DataVector() - publicKeys.add(data: decompressed) + publicKeys.add(data: decompressedPublicKey) let input = try makeSigningInput(transaction: transaction, nonce: nonce, feeParameters: feeParameters) let txInputData = try input.serializedData() @@ -97,7 +96,7 @@ final class FilecoinTransactionBuilder { throw FilecoinTransactionBuilderError.failedToConvertAmountToBigUInt } - return try FilecoinSigningInput.with { input in + return FilecoinSigningInput.with { input in input.to = transaction.destinationAddress input.nonce = nonce @@ -107,7 +106,7 @@ final class FilecoinTransactionBuilder { input.gasFeeCap = feeParameters.gasFeeCap.serialize() input.gasPremium = feeParameters.gasPremium.serialize() - input.publicKey = try Secp256k1Key(with: publicKey.blockchainKey).decompress() + input.publicKey = decompressedPublicKey } } } diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift index 63f4ad288..33d2ed2e8 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletAssembly.swift @@ -21,7 +21,7 @@ struct FilecoinWalletAssembly: WalletManagerAssembly { ) } ), - transactionBuilder: FilecoinTransactionBuilder(publicKey: input.wallet.publicKey) + transactionBuilder: try FilecoinTransactionBuilder(publicKey: input.wallet.publicKey) ) } } diff --git a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift index 18286d2f9..3d2fbcbdb 100644 --- a/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift +++ b/BlockchainSdkTests/Filecoin/FilecoinTransactionBuilderTests.swift @@ -10,12 +10,13 @@ import XCTest @testable import BlockchainSdk final class FilecoinTransactionBuilderTests: XCTestCase { - private let transactionBuilder = FilecoinTransactionBuilder( + private let transactionBuilder: FilecoinTransactionBuilder = try! FilecoinTransactionBuilder( publicKey: Wallet.PublicKey( seedKey: Constants.publicKey, derivationType: nil ) ) + private let sizeTester = TransactionSizeTesterUtility() private var transaction: Transaction { Transaction( @@ -45,7 +46,8 @@ final class FilecoinTransactionBuilderTests: XCTestCase { func testBuildForSign() throws { let expected = Data(hex: "0beac3427b81d6fa6e93a05a0b64fcc3c7ce4af9d05af31ee343bcc527ae8b18") let actual = try transactionBuilder.buildForSign(transaction: transaction, nonce: 1) - + + sizeTester.testTxSize(actual) XCTAssertEqual(expected, actual) } From 3be095bcb480f938ef505441adc37c1d44227f8f Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 11:29:54 +0200 Subject: [PATCH 21/25] IOS-7738 Request nonce before sending tx --- .../Filecoin/FilecoinWalletManager.swift | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 581a5480d..eac00f389 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -109,39 +109,45 @@ class FilecoinWalletManager: BaseManager, WalletManager { } func send(_ transaction: Transaction, signer: any TransactionSigner) -> AnyPublisher { - Result { - try transactionBuilder.buildForSign(transaction: transaction, nonce: nonce) - } - .publisher - .withWeakCaptureOf(self) - .flatMap { walletManager, hashToSign in - signer - .sign(hash: hashToSign, walletPublicKey: walletManager.wallet.publicKey) - .withWeakCaptureOf(walletManager) - .tryMap { walletManager, signature in - try walletManager.transactionBuilder.buildForSend( - transaction: transaction, - nonce: walletManager.nonce, - signatureInfo: SignatureInfo( - signature: signature, - publicKey: walletManager.wallet.publicKey.blockchainKey, - hash: hashToSign + networkService + .getAccountInfo(address: wallet.address) + .withWeakCaptureOf(self) + .tryMap { walletManager, accountInfo in + walletManager.nonce = accountInfo.nonce + return try walletManager.transactionBuilder.buildForSign( + transaction: transaction, + nonce: accountInfo.nonce + ) + } + .withWeakCaptureOf(self) + .flatMap { walletManager, hashToSign in + signer + .sign(hash: hashToSign, walletPublicKey: walletManager.wallet.publicKey) + .withWeakCaptureOf(walletManager) + .tryMap { walletManager, signature in + try walletManager.transactionBuilder.buildForSend( + transaction: transaction, + nonce: walletManager.nonce, + signatureInfo: SignatureInfo( + signature: signature, + publicKey: walletManager.wallet.publicKey.blockchainKey, + hash: hashToSign + ) ) - ) - } - } - .withWeakCaptureOf(self) - .flatMap { walletManager, message in - walletManager.networkService.submitTransaction(signedMessage: message) - } - .withWeakCaptureOf(self) - .map { walletManager, txId in - let mapper = PendingTransactionRecordMapper() - let record = mapper.mapToPendingTransactionRecord(transaction: transaction, hash: txId) - walletManager.wallet.addPendingTransaction(record) - return TransactionSendResult(hash: txId) - } - .mapError { SendTxError(error: $0) } - .eraseToAnyPublisher() + } + } + .withWeakCaptureOf(self) + .flatMap { walletManager, message in + walletManager.networkService.submitTransaction(signedMessage: message) + } + .withWeakCaptureOf(self) + .map { walletManager, txId in + let mapper = PendingTransactionRecordMapper() + let record = mapper.mapToPendingTransactionRecord(transaction: transaction, hash: txId) + walletManager.wallet.addPendingTransaction(record) + return TransactionSendResult(hash: txId) + } + .mapError { SendTxError(error: $0) } + .eraseToAnyPublisher() } } From ea7fbddfe0aa536c16f585ed1df320215f7d1c72 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 11:35:32 +0200 Subject: [PATCH 22/25] IOS-7738 Dont save nonce while sending tx --- .../Blockchains/Filecoin/FilecoinWalletManager.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index eac00f389..255d63740 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -111,10 +111,9 @@ class FilecoinWalletManager: BaseManager, WalletManager { func send(_ transaction: Transaction, signer: any TransactionSigner) -> AnyPublisher { networkService .getAccountInfo(address: wallet.address) - .withWeakCaptureOf(self) - .tryMap { walletManager, accountInfo in - walletManager.nonce = accountInfo.nonce - return try walletManager.transactionBuilder.buildForSign( + .withWeakCaptureOf(transactionBuilder) + .tryMap { transactionBuilder, accountInfo in + try transactionBuilder.buildForSign( transaction: transaction, nonce: accountInfo.nonce ) From b1d2d00a70e0aa4ef32179454d84b4c35f9bbe46 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 14:56:22 +0200 Subject: [PATCH 23/25] IOS-7738 CR fixes --- BlockchainSdk.xcodeproj/project.pbxproj | 4 ++ .../Filecoin/FilecoinTransactionBuilder.swift | 24 ++++-------- .../Filecoin/FilecoinWalletManager.swift | 39 +++++++++++-------- .../Network/DTO/FilecoinResponse.swift | 1 - .../VeChain/VeChainTransactionBuilder.swift | 31 ++++----------- .../Common/Utils/SignatureUtils.swift | 38 ++++++++++++++++++ 6 files changed, 79 insertions(+), 58 deletions(-) create mode 100644 BlockchainSdk/Common/Utils/SignatureUtils.swift diff --git a/BlockchainSdk.xcodeproj/project.pbxproj b/BlockchainSdk.xcodeproj/project.pbxproj index 65818c84e..8277068a5 100644 --- a/BlockchainSdk.xcodeproj/project.pbxproj +++ b/BlockchainSdk.xcodeproj/project.pbxproj @@ -589,6 +589,7 @@ DAF0866E27A942D60024312E /* PolkadotWalletManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */; }; DAF0867027A9438C0024312E /* PolkadotNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF0866F27A9438C0024312E /* PolkadotNetworkService.swift */; }; DAF3AD4629E916D300E057FA /* CosmosFeeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF3AD4529E916D300E057FA /* CosmosFeeParameters.swift */; }; + DAF81A762C873CA600B83CB0 /* SignatureUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAF81A752C873CA600B83CB0 /* SignatureUtils.swift */; }; DAFE0D082BB168D8005CBD9C /* MoonriverExternalLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAFE0D072BB168D8005CBD9C /* MoonriverExternalLinkProvider.swift */; }; DAFE0D0A2BB1840E005CBD9C /* MantleExternalLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAFE0D092BB1840E005CBD9C /* MantleExternalLinkProvider.swift */; }; DAFE0D0C2BB1841B005CBD9C /* FlareExternalLinkProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAFE0D0B2BB1841B005CBD9C /* FlareExternalLinkProvider.swift */; }; @@ -1530,6 +1531,7 @@ DAF0866D27A942D60024312E /* PolkadotWalletManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PolkadotWalletManager.swift; sourceTree = ""; }; DAF0866F27A9438C0024312E /* PolkadotNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotNetworkService.swift; sourceTree = ""; }; DAF3AD4529E916D300E057FA /* CosmosFeeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CosmosFeeParameters.swift; sourceTree = ""; }; + DAF81A752C873CA600B83CB0 /* SignatureUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignatureUtils.swift; sourceTree = ""; }; DAFE0D072BB168D8005CBD9C /* MoonriverExternalLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonriverExternalLinkProvider.swift; sourceTree = ""; }; DAFE0D092BB1840E005CBD9C /* MantleExternalLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MantleExternalLinkProvider.swift; sourceTree = ""; }; DAFE0D0B2BB1841B005CBD9C /* FlareExternalLinkProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlareExternalLinkProvider.swift; sourceTree = ""; }; @@ -2908,6 +2910,7 @@ B0A1D39C2625A1150013F0BF /* EthereumUtils.swift */, B64B728B2AEC9C7B005C8C7C /* Lock.swift */, EF74D63F2BA3526D000550F3 /* ObjectDescription.swift */, + DAF81A752C873CA600B83CB0 /* SignatureUtils.swift */, ); path = Utils; sourceTree = ""; @@ -4875,6 +4878,7 @@ 0AEFB5392B7656EC007519F9 /* NodeRequest.swift in Sources */, EF3B19642AA85F280084AA1C /* ChiaExternalLinkProvider.swift in Sources */, EF32FEBF2A306E51002ED43F /* AddressService.swift in Sources */, + DAF81A762C873CA600B83CB0 /* SignatureUtils.swift in Sources */, EF34FCF72A41CA8700E18670 /* CardanoTransactionBuilder.swift in Sources */, 5D7D243625136254001B9A4F /* XRPAccount.swift in Sources */, B6BA93712AEA0E8000F84E36 /* NEARNetworkParams.ViewAccessKey.swift in Sources */, diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift index 1ccbf10bf..5e25aaccd 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinTransactionBuilder.swift @@ -46,24 +46,14 @@ final class FilecoinTransactionBuilder { throw FilecoinTransactionBuilderError.filecoinFeeParametersNotFound } - let secp256k1Signature = try Secp256k1Signature(with: signatureInfo.signature) - let unmarshal = try secp256k1Signature.unmarshal(with: decompressedPublicKey, hash: signatureInfo.hash) - - // As we use the chainID in the transaction according to EIP-155 - // WalletCore will use formula to calculate `V`. - // v = CHAIN_ID * 2 + 35 - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md - - // It's strange but we can't use `unmarshal.v` here because WalletCore throw a error. - // And we have to add one zero byte to the signature because - // WalletCore has a validation on the signature count. - // // https://github.com/tangem/wallet-core/blob/996bd5ab37f27e7f6e240a4ec9d0788dfb124e89/src/PublicKey.h#L35 - let v = BigUInt(unmarshal.v) - 27 - let encodedV = v == .zero ? Data([UInt8.zero]) : v.serialize() - let signature = unmarshal.r + unmarshal.s + encodedV - + let unmarshalledSignature = try SignatureUtils.unmarshalledSignature( + from: signatureInfo.signature, + publicKey: decompressedPublicKey, + hash: signatureInfo.hash + ) + let signatures = DataVector() - signatures.add(data: signature) + signatures.add(data: unmarshalledSignature) let publicKeys = DataVector() publicKeys.add(data: decompressedPublicKey) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 255d63740..165139685 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -70,18 +70,23 @@ class FilecoinWalletManager: BaseManager, WalletManager { return .anyFail(error: WalletError.failedToGetFee) } - let message = FilecoinMessage( - from: wallet.address, - to: destination, - value: bigUIntValue.description, - nonce: nonce, - gasLimit: nil, - gasFeeCap: nil, - gasPremium: nil - ) - return networkService - .getEstimateMessageGas(message: message) + .getAccountInfo(address: wallet.address) + .map { [address = wallet.address] accountInfo in + FilecoinMessage( + from: address, + to: destination, + value: bigUIntValue.description, + nonce: accountInfo.nonce, + gasLimit: nil, + gasFeeCap: nil, + gasPremium: nil + ) + } + .withWeakCaptureOf(networkService) + .flatMap { networkService, message in + networkService.getEstimateMessageGas(message: message) + } .withWeakCaptureOf(self) .tryMap { (walletManager: FilecoinWalletManager, gasInfo) -> [Fee] in guard let gasFeeCapDecimal = Decimal(stringValue: gasInfo.gasFeeCap) else { @@ -113,20 +118,22 @@ class FilecoinWalletManager: BaseManager, WalletManager { .getAccountInfo(address: wallet.address) .withWeakCaptureOf(transactionBuilder) .tryMap { transactionBuilder, accountInfo in - try transactionBuilder.buildForSign( + let hashToSign = try transactionBuilder.buildForSign( transaction: transaction, nonce: accountInfo.nonce ) + return (hashToSign, accountInfo.nonce) } .withWeakCaptureOf(self) - .flatMap { walletManager, hashToSign in - signer + .flatMap { walletManager, args in + let (hashToSign, nonce) = args + return signer .sign(hash: hashToSign, walletPublicKey: walletManager.wallet.publicKey) .withWeakCaptureOf(walletManager) .tryMap { walletManager, signature in try walletManager.transactionBuilder.buildForSend( transaction: transaction, - nonce: walletManager.nonce, + nonce: nonce, signatureInfo: SignatureInfo( signature: signature, publicKey: walletManager.wallet.publicKey.blockchainKey, @@ -146,7 +153,7 @@ class FilecoinWalletManager: BaseManager, WalletManager { walletManager.wallet.addPendingTransaction(record) return TransactionSendResult(hash: txId) } - .mapError { SendTxError(error: $0) } + .eraseSendError() .eraseToAnyPublisher() } } diff --git a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift index 042dad2ba..47794238b 100644 --- a/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift +++ b/BlockchainSdk/Blockchains/Filecoin/Network/DTO/FilecoinResponse.swift @@ -6,7 +6,6 @@ // Copyright © 2024 Tangem AG. All rights reserved. // -import BigInt import Foundation enum FilecoinResponse { diff --git a/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift b/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift index 54e644e75..9b282aa0e 100644 --- a/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift @@ -60,7 +60,13 @@ final class VeChainTransactionBuilder { } let publicKey = try Secp256k1Key(with: transactionParams.publicKey.blockchainKey).decompress() - let unmarshalledSignature = try unmarshalledSignature(from: signature, publicKey: publicKey, hash: hash) + /// VeChain is a fork of `Geth Classic`, so it expects the secp256k1's `recid` to have values in the 0...3 range. + /// Therefore we have to convert value of the standard secp256k1's `recid` to match this expectation. + let unmarshalledSignature = try SignatureUtils.unmarshalledSignature( + from: signature, + publicKey: publicKey, + hash: hash + ) let compiledTransaction = TransactionCompiler.compileWithSignatures( coinType: coinType, @@ -154,25 +160,6 @@ final class VeChainTransactionBuilder { return bigUIntValue } - - /// VeChain is a fork of `Geth Classic`, so it expects the secp256k1's `recid` to have values in the 0...3 range. - /// Therefore we have to convert value of the standard secp256k1's `recid` to match this expectation. - private func unmarshalledSignature(from originalSignature: Data, publicKey: Data, hash: Data) throws -> Data { - let signature = try Secp256k1Signature(with: originalSignature) - let unmarshalledSignature = try signature.unmarshal(with: publicKey, hash: hash) - - guard unmarshalledSignature.v.count == Constants.recoveryIdLength else { - throw WalletError.failedToBuildTx - } - - let recoveryId = unmarshalledSignature.v[0] - Constants.recoveryIdDiff - - guard recoveryId >= Constants.recoveryIdLowerBound, recoveryId <= Constants.recoveryIdUpperBound else { - throw WalletError.failedToBuildTx - } - - return unmarshalledSignature.r + unmarshalledSignature.s + Data(recoveryId) - } } // MARK: - Convenience extensions @@ -189,9 +176,5 @@ private extension VeChainTransactionBuilder { enum Constants { /// `18` is the value used by the official `VeWorld` wallet app, multiplying it by 10 just in case. static let transactionExpiration = 18 * 10 - static let recoveryIdLength = 1 - static let recoveryIdDiff: UInt8 = 27 - static let recoveryIdLowerBound: UInt8 = 0 - static let recoveryIdUpperBound: UInt8 = 3 } } diff --git a/BlockchainSdk/Common/Utils/SignatureUtils.swift b/BlockchainSdk/Common/Utils/SignatureUtils.swift new file mode 100644 index 000000000..41f3b0c51 --- /dev/null +++ b/BlockchainSdk/Common/Utils/SignatureUtils.swift @@ -0,0 +1,38 @@ +// +// SignatureUtils.swift +// BlockchainSdk +// +// Created by Aleksei Muraveinik on 03.09.24. +// Copyright © 2024 Tangem AG. All rights reserved. +// + +import TangemSdk + +enum SignatureUtils { + static func unmarshalledSignature(from originalSignature: Data, publicKey: Data, hash: Data) throws -> Data { + let signature = try Secp256k1Signature(with: originalSignature) + let unmarshalledSignature = try signature.unmarshal(with: publicKey, hash: hash) + + guard unmarshalledSignature.v.count == Constants.recoveryIdLength else { + throw WalletError.failedToBuildTx + } + + let recoveryId = unmarshalledSignature.v[0] - Constants.recoveryIdDiff + + guard recoveryId >= Constants.recoveryIdLowerBound, recoveryId <= Constants.recoveryIdUpperBound else { + throw WalletError.failedToBuildTx + } + + return unmarshalledSignature.r + unmarshalledSignature.s + Data(recoveryId) + } +} + +private extension SignatureUtils { + enum Constants { + static let recoveryIdLength = 1 + static let recoveryIdDiff: UInt8 = 27 + static let recoveryIdLowerBound: UInt8 = 0 + static let recoveryIdUpperBound: UInt8 = 3 + } + +} From 81e9368c10ec52ba3bfacf8d703d4d3624a85b54 Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 18:28:39 +0200 Subject: [PATCH 24/25] IOS-7438 CR Fixes --- .../Filecoin/FilecoinWalletManager.swift | 6 ++++-- .../VeChain/VeChainTransactionBuilder.swift | 2 -- .../Common/Utils/SignatureUtils.swift | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index 165139685..ab579c0eb 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -76,7 +76,7 @@ class FilecoinWalletManager: BaseManager, WalletManager { FilecoinMessage( from: address, to: destination, - value: bigUIntValue.description, + value: String(bigUIntValue, radix: 10), nonce: accountInfo.nonce, gasLimit: nil, gasFeeCap: nil, @@ -144,7 +144,9 @@ class FilecoinWalletManager: BaseManager, WalletManager { } .withWeakCaptureOf(self) .flatMap { walletManager, message in - walletManager.networkService.submitTransaction(signedMessage: message) + walletManager.networkService + .submitTransaction(signedMessage: message) + .mapSendError(tx: try? JSONEncoder().encode(message).hexString.lowercased()) } .withWeakCaptureOf(self) .map { walletManager, txId in diff --git a/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift b/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift index 9b282aa0e..377c2b366 100644 --- a/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift +++ b/BlockchainSdk/Blockchains/VeChain/VeChainTransactionBuilder.swift @@ -60,8 +60,6 @@ final class VeChainTransactionBuilder { } let publicKey = try Secp256k1Key(with: transactionParams.publicKey.blockchainKey).decompress() - /// VeChain is a fork of `Geth Classic`, so it expects the secp256k1's `recid` to have values in the 0...3 range. - /// Therefore we have to convert value of the standard secp256k1's `recid` to match this expectation. let unmarshalledSignature = try SignatureUtils.unmarshalledSignature( from: signature, publicKey: publicKey, diff --git a/BlockchainSdk/Common/Utils/SignatureUtils.swift b/BlockchainSdk/Common/Utils/SignatureUtils.swift index 41f3b0c51..8c98ee75f 100644 --- a/BlockchainSdk/Common/Utils/SignatureUtils.swift +++ b/BlockchainSdk/Common/Utils/SignatureUtils.swift @@ -9,6 +9,24 @@ import TangemSdk enum SignatureUtils { + /// Unmarshals a signature using the provided original signature, public key, and hash. + /// This function is essential for certain blockchains that require signature unmarshalling to correctly + /// reconstruct the signature for verification. + /// + /// - Parameters: + /// - originalSignature: The original `Data` object representing the signature to be unmarshalled. + /// - publicKey: The `Data` object representing the public key associated with the signature. + /// - hash: The `Data` object representing the hash of the message or transaction. + /// - Returns: A `Data` object containing the unmarshalled signature, which includes the `r` and `s` values + /// concatenated with the adjusted recovery ID. + /// - Throws: `WalletError.failedToBuildTx` if the unmarshalling process fails due to an invalid recovery ID. + /// + /// - Important: For certain blockchains, especially those using the Secp256k1 curve, signature unmarshalling + /// is required to correctly reconstruct the signature from the original data. This process involves verifying + /// and adjusting the recovery ID, which is essential for ensuring the signature is valid and can be used for + /// transaction verification. The function checks the length of the recovery ID and adjusts it within valid bounds + /// before concatenating it with the `r` and `s` components of the signature. + static func unmarshalledSignature(from originalSignature: Data, publicKey: Data, hash: Data) throws -> Data { let signature = try Secp256k1Signature(with: originalSignature) let unmarshalledSignature = try signature.unmarshal(with: publicKey, hash: hash) From 5ef0aabf6d35e19b0caa17a2beb26109ee5b768f Mon Sep 17 00:00:00 2001 From: Aleksei Muraveinik Date: Tue, 3 Sep 2024 18:32:05 +0200 Subject: [PATCH 25/25] IOS-7438 Change tx --- BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift index ab579c0eb..beb8744e9 100644 --- a/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift +++ b/BlockchainSdk/Blockchains/Filecoin/FilecoinWalletManager.swift @@ -146,7 +146,7 @@ class FilecoinWalletManager: BaseManager, WalletManager { .flatMap { walletManager, message in walletManager.networkService .submitTransaction(signedMessage: message) - .mapSendError(tx: try? JSONEncoder().encode(message).hexString.lowercased()) + .mapSendError(tx: try? JSONEncoder().encode(message).utf8String) } .withWeakCaptureOf(self) .map { walletManager, txId in