@authon/react-native-wallet 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +251 -2
  3. package/android/build.gradle +40 -0
  4. package/android/consumer-rules.pro +10 -0
  5. package/android/src/main/AndroidManifest.xml +8 -0
  6. package/android/src/main/java/dev/authon/reactnative/wallet/AuthonWalletModule.kt +235 -0
  7. package/android/src/vendor/GENERATED.md +4 -0
  8. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/AndroidCapabilityProbe.kt +86 -0
  9. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/AuthonWallet.kt +218 -0
  10. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Bitcoin.kt +296 -0
  11. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Bytes.kt +74 -0
  12. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Chains.kt +157 -0
  13. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/CredentialManagerPasskeys.kt +192 -0
  14. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Der.kt +17 -0
  15. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/DeviceStore.kt +170 -0
  16. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/DialogWalletApprover.kt +141 -0
  17. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Eip712.kt +176 -0
  18. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Encodings.kt +133 -0
  19. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/EvmAccount.kt +45 -0
  20. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/EvmTransaction.kt +180 -0
  21. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/GfTables.kt +44 -0
  22. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/HdWallet.kt +130 -0
  23. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Http.kt +86 -0
  24. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/JsValues.kt +83 -0
  25. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/KeystoreDeviceStore.kt +236 -0
  26. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Prf.kt +111 -0
  27. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Proof.kt +134 -0
  28. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Shamir.kt +106 -0
  29. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/SignSummary.kt +335 -0
  30. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Solana.kt +195 -0
  31. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Tron.kt +184 -0
  32. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletApi.kt +361 -0
  33. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletCapabilities.kt +91 -0
  34. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletError.kt +74 -0
  35. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletOps.kt +551 -0
  36. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletTypes.kt +78 -0
  37. package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Xrp.kt +193 -0
  38. package/build/authonContext.d.ts +19 -0
  39. package/build/authonContext.d.ts.map +1 -0
  40. package/build/authonContext.js +20 -0
  41. package/build/authonContext.js.map +1 -0
  42. package/build/client.d.ts +92 -0
  43. package/build/client.d.ts.map +1 -0
  44. package/build/client.js +431 -0
  45. package/build/client.js.map +1 -0
  46. package/build/errors.d.ts +25 -0
  47. package/build/errors.d.ts.map +1 -0
  48. package/build/errors.js +15 -0
  49. package/build/errors.js.map +1 -0
  50. package/build/index.d.ts +7 -0
  51. package/build/index.d.ts.map +1 -0
  52. package/build/index.js +4 -0
  53. package/build/index.js.map +1 -0
  54. package/build/native.d.ts +43 -0
  55. package/build/native.d.ts.map +1 -0
  56. package/build/native.js +12 -0
  57. package/build/native.js.map +1 -0
  58. package/build/types.d.ts +167 -0
  59. package/build/types.d.ts.map +1 -0
  60. package/build/types.js +3 -0
  61. package/build/types.js.map +1 -0
  62. package/build/useAuthonWallet.d.ts +25 -0
  63. package/build/useAuthonWallet.d.ts.map +1 -0
  64. package/build/useAuthonWallet.js +77 -0
  65. package/build/useAuthonWallet.js.map +1 -0
  66. package/expo-module.config.json +9 -0
  67. package/ios/AuthonReactNativeWallet.podspec +41 -0
  68. package/ios/AuthonWalletModule.swift +233 -0
  69. package/ios/vendor/AuthonWallet/AuthonWallet.swift +232 -0
  70. package/ios/vendor/AuthonWallet/Capabilities.swift +149 -0
  71. package/ios/vendor/AuthonWallet/Chains/Bitcoin.swift +296 -0
  72. package/ios/vendor/AuthonWallet/Chains/Solana.swift +207 -0
  73. package/ios/vendor/AuthonWallet/Chains/Tron.swift +181 -0
  74. package/ios/vendor/AuthonWallet/Chains/XRP.swift +191 -0
  75. package/ios/vendor/AuthonWallet/Crypto/BIP39Wordlist.swift +262 -0
  76. package/ios/vendor/AuthonWallet/Crypto/Chains.swift +278 -0
  77. package/ios/vendor/AuthonWallet/Crypto/HDKey.swift +108 -0
  78. package/ios/vendor/AuthonWallet/Crypto/Secp256k1.swift +128 -0
  79. package/ios/vendor/AuthonWallet/Crypto/Shamir.swift +123 -0
  80. package/ios/vendor/AuthonWallet/EVM/Address.swift +57 -0
  81. package/ios/vendor/AuthonWallet/EVM/EvmAccount.swift +48 -0
  82. package/ios/vendor/AuthonWallet/EVM/Transaction.swift +165 -0
  83. package/ios/vendor/AuthonWallet/EVM/TypedData.swift +193 -0
  84. package/ios/vendor/AuthonWallet/Support/BigInteger.swift +220 -0
  85. package/ios/vendor/AuthonWallet/Support/Bytes.swift +89 -0
  86. package/ios/vendor/AuthonWallet/Support/JSONValue.swift +341 -0
  87. package/ios/vendor/AuthonWallet/UI/WalletApprover.swift +250 -0
  88. package/ios/vendor/AuthonWallet/Wallet/Backup.swift +69 -0
  89. package/ios/vendor/AuthonWallet/Wallet/DeviceStore.swift +351 -0
  90. package/ios/vendor/AuthonWallet/Wallet/Passkeys.swift +190 -0
  91. package/ios/vendor/AuthonWallet/Wallet/Proof.swift +143 -0
  92. package/ios/vendor/AuthonWallet/Wallet/Shares.swift +116 -0
  93. package/ios/vendor/AuthonWallet/Wallet/Summary.swift +342 -0
  94. package/ios/vendor/AuthonWallet/Wallet/WalletAPI.swift +361 -0
  95. package/ios/vendor/AuthonWallet/Wallet/WalletOps.swift +654 -0
  96. package/ios/vendor/AuthonWallet/WalletError.swift +84 -0
  97. package/ios/vendor/CKeccak/LICENSE +22 -0
  98. package/ios/vendor/CKeccak/README.md +30 -0
  99. package/ios/vendor/CKeccak/byte_order.h +59 -0
  100. package/ios/vendor/CKeccak/include/ckeccak.h +13 -0
  101. package/ios/vendor/CKeccak/memzero.c +75 -0
  102. package/ios/vendor/CKeccak/memzero.h +8 -0
  103. package/ios/vendor/CKeccak/options.h +99 -0
  104. package/ios/vendor/CKeccak/ripemd160.c +343 -0
  105. package/ios/vendor/CKeccak/ripemd160.h +22 -0
  106. package/ios/vendor/CKeccak/sha3.c +413 -0
  107. package/ios/vendor/CKeccak/sha3.h +89 -0
  108. package/ios/vendor/CMonocypher/LICENCE.md +173 -0
  109. package/ios/vendor/CMonocypher/README.md +27 -0
  110. package/ios/vendor/CMonocypher/include/monocypher-ed25519.h +140 -0
  111. package/ios/vendor/CMonocypher/include/monocypher.h +321 -0
  112. package/ios/vendor/CMonocypher/monocypher-ed25519.c +500 -0
  113. package/ios/vendor/CMonocypher/monocypher.c +2956 -0
  114. package/ios/vendor/CSecp256k1/COPYING +19 -0
  115. package/ios/vendor/CSecp256k1/README.md +35 -0
  116. package/ios/vendor/CSecp256k1/build/precomputed_ecmult.c +3 -0
  117. package/ios/vendor/CSecp256k1/build/precomputed_ecmult_gen.c +3 -0
  118. package/ios/vendor/CSecp256k1/build/secp256k1.c +3 -0
  119. package/ios/vendor/CSecp256k1/include/secp256k1.h +899 -0
  120. package/ios/vendor/CSecp256k1/include/secp256k1_preallocated.h +134 -0
  121. package/ios/vendor/CSecp256k1/include/secp256k1_recovery.h +113 -0
  122. package/ios/vendor/CSecp256k1/src/assumptions.h +87 -0
  123. package/ios/vendor/CSecp256k1/src/checkmem.h +102 -0
  124. package/ios/vendor/CSecp256k1/src/ecdsa.h +21 -0
  125. package/ios/vendor/CSecp256k1/src/ecdsa_impl.h +304 -0
  126. package/ios/vendor/CSecp256k1/src/eckey.h +25 -0
  127. package/ios/vendor/CSecp256k1/src/eckey_impl.h +92 -0
  128. package/ios/vendor/CSecp256k1/src/ecmult.h +61 -0
  129. package/ios/vendor/CSecp256k1/src/ecmult_const.h +38 -0
  130. package/ios/vendor/CSecp256k1/src/ecmult_const_impl.h +399 -0
  131. package/ios/vendor/CSecp256k1/src/ecmult_gen.h +143 -0
  132. package/ios/vendor/CSecp256k1/src/ecmult_gen_impl.h +341 -0
  133. package/ios/vendor/CSecp256k1/src/ecmult_impl.h +853 -0
  134. package/ios/vendor/CSecp256k1/src/field.h +350 -0
  135. package/ios/vendor/CSecp256k1/src/field_10x26.h +57 -0
  136. package/ios/vendor/CSecp256k1/src/field_10x26_impl.h +1232 -0
  137. package/ios/vendor/CSecp256k1/src/field_5x52.h +62 -0
  138. package/ios/vendor/CSecp256k1/src/field_5x52_impl.h +522 -0
  139. package/ios/vendor/CSecp256k1/src/field_5x52_int128_impl.h +274 -0
  140. package/ios/vendor/CSecp256k1/src/field_impl.h +457 -0
  141. package/ios/vendor/CSecp256k1/src/group.h +212 -0
  142. package/ios/vendor/CSecp256k1/src/group_impl.h +974 -0
  143. package/ios/vendor/CSecp256k1/src/hash.h +44 -0
  144. package/ios/vendor/CSecp256k1/src/hash_impl.h +299 -0
  145. package/ios/vendor/CSecp256k1/src/hsort.h +33 -0
  146. package/ios/vendor/CSecp256k1/src/hsort_impl.h +125 -0
  147. package/ios/vendor/CSecp256k1/src/int128.h +90 -0
  148. package/ios/vendor/CSecp256k1/src/int128_impl.h +18 -0
  149. package/ios/vendor/CSecp256k1/src/int128_native.h +19 -0
  150. package/ios/vendor/CSecp256k1/src/int128_native_impl.h +94 -0
  151. package/ios/vendor/CSecp256k1/src/int128_struct.h +14 -0
  152. package/ios/vendor/CSecp256k1/src/int128_struct_impl.h +205 -0
  153. package/ios/vendor/CSecp256k1/src/modinv32.h +43 -0
  154. package/ios/vendor/CSecp256k1/src/modinv32_impl.h +725 -0
  155. package/ios/vendor/CSecp256k1/src/modinv64.h +47 -0
  156. package/ios/vendor/CSecp256k1/src/modinv64_impl.h +780 -0
  157. package/ios/vendor/CSecp256k1/src/modules/recovery/main_impl.h +159 -0
  158. package/ios/vendor/CSecp256k1/src/precomputed_ecmult.c +16456 -0
  159. package/ios/vendor/CSecp256k1/src/precomputed_ecmult.h +38 -0
  160. package/ios/vendor/CSecp256k1/src/precomputed_ecmult_gen.c +1779 -0
  161. package/ios/vendor/CSecp256k1/src/precomputed_ecmult_gen.h +26 -0
  162. package/ios/vendor/CSecp256k1/src/scalar.h +105 -0
  163. package/ios/vendor/CSecp256k1/src/scalar_4x64.h +19 -0
  164. package/ios/vendor/CSecp256k1/src/scalar_4x64_impl.h +1000 -0
  165. package/ios/vendor/CSecp256k1/src/scalar_8x32.h +19 -0
  166. package/ios/vendor/CSecp256k1/src/scalar_8x32_impl.h +816 -0
  167. package/ios/vendor/CSecp256k1/src/scalar_impl.h +321 -0
  168. package/ios/vendor/CSecp256k1/src/scalar_low.h +24 -0
  169. package/ios/vendor/CSecp256k1/src/scalar_low_impl.h +206 -0
  170. package/ios/vendor/CSecp256k1/src/scratch.h +44 -0
  171. package/ios/vendor/CSecp256k1/src/scratch_impl.h +99 -0
  172. package/ios/vendor/CSecp256k1/src/secp256k1.c +831 -0
  173. package/ios/vendor/CSecp256k1/src/selftest.h +32 -0
  174. package/ios/vendor/CSecp256k1/src/util.h +451 -0
  175. package/ios/vendor/GENERATED.md +4 -0
  176. package/package.json +66 -3
  177. package/src/authonContext.ts +30 -0
  178. package/src/client.ts +459 -0
  179. package/src/errors.ts +58 -0
  180. package/src/index.ts +26 -0
  181. package/src/native.ts +52 -0
  182. package/src/types.ts +171 -0
  183. package/src/useAuthonWallet.ts +103 -0
@@ -0,0 +1,207 @@
1
+ // GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/Chains/Solana.swift. Do not edit: change the source and run the script.
2
+ #if canImport(CMonocypher)
3
+ import CMonocypher
4
+ #endif
5
+ import Foundation
6
+
7
+ /// Solana transaction signing (docs/wallet/NATIVE.md section 12, `apps/wallet/src/solana.ts`).
8
+ /// The app builds the serialized Message; the wallet parses it only to describe it and signs
9
+ /// the exact bytes.
10
+ enum Solana {
11
+ static let maxMessage = 1232
12
+
13
+ static let system = "11111111111111111111111111111111"
14
+ static let token = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
15
+ static let token2022 = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
16
+ static let associatedToken = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
17
+ static let computeBudget = "ComputeBudget111111111111111111111111111111"
18
+ static let memo = "MemoSq4gqABAXKb96qnH8TyNoJ6CDrADxwaj4uuQ"
19
+
20
+ struct Instruction {
21
+ var programId: String
22
+ /// nil for an account that comes from an address lookup table.
23
+ var accounts: [String?]
24
+ var data: [UInt8]
25
+ }
26
+
27
+ struct Message {
28
+ var isV0: Bool
29
+ var numRequiredSignatures: Int
30
+ var accountKeys: [String]
31
+ var recentBlockhash: String
32
+ var instructions: [Instruction]
33
+ /// Accounts loaded from address lookup tables (v0 only).
34
+ var lookupAccounts: Int
35
+ }
36
+
37
+ private static func invalid() -> WalletError { WalletError(.invalidRequest, "not a valid Solana message") }
38
+
39
+ private struct Reader {
40
+ let bytes: [UInt8]
41
+ var pos = 0
42
+ var done: Bool { pos == bytes.count }
43
+
44
+ mutating func u8() throws -> Int {
45
+ guard pos < bytes.count else { throw invalid() }
46
+ pos += 1
47
+ return Int(bytes[pos - 1])
48
+ }
49
+
50
+ mutating func take(_ n: Int) throws -> [UInt8] {
51
+ guard n >= 0, pos + n <= bytes.count else { throw invalid() }
52
+ pos += n
53
+ return Array(bytes[(pos - n)..<pos])
54
+ }
55
+
56
+ /// compact-u16 (shortvec)
57
+ mutating func len() throws -> Int {
58
+ var value = 0
59
+ for i in 0..<3 {
60
+ let b = try u8()
61
+ value |= (b & 0x7f) << (7 * i)
62
+ if b & 0x80 == 0 { return value }
63
+ }
64
+ throw invalid()
65
+ }
66
+ }
67
+
68
+ static func parse(_ bytes: [UInt8]) throws -> Message {
69
+ guard !bytes.isEmpty, bytes.count <= maxMessage else { throw invalid() }
70
+ var r = Reader(bytes: bytes)
71
+ var isV0 = false
72
+ var first = try r.u8()
73
+ if first & 0x80 != 0 {
74
+ guard first & 0x7f == 0 else { throw WalletError(.invalidRequest, "unsupported Solana message version") }
75
+ isV0 = true
76
+ first = try r.u8()
77
+ }
78
+ let required = first
79
+ _ = try r.u8() // readonly signed
80
+ _ = try r.u8() // readonly unsigned
81
+ let keyCount = try r.len()
82
+ var keys = [String]()
83
+ for _ in 0..<keyCount { keys.append(Base58.encode(try r.take(32), alphabet: Base58.bitcoin)) }
84
+ let blockhash = Base58.encode(try r.take(32), alphabet: Base58.bitcoin)
85
+ var raw = [(program: Int, accounts: [Int], data: [UInt8])]()
86
+ for _ in 0..<(try r.len()) {
87
+ let program = try r.u8()
88
+ var accounts = [Int]()
89
+ for _ in 0..<(try r.len()) { accounts.append(try r.u8()) }
90
+ let data = try r.take(try r.len())
91
+ raw.append((program, accounts, data))
92
+ }
93
+ var lookups = 0
94
+ if isV0 {
95
+ for _ in 0..<(try r.len()) {
96
+ _ = try r.take(32)
97
+ lookups += try r.take(try r.len()).count
98
+ lookups += try r.take(try r.len()).count
99
+ }
100
+ }
101
+ guard r.done, required >= 1, required <= keyCount else { throw invalid() }
102
+ let total = keyCount + lookups
103
+ func key(_ i: Int) throws -> String? {
104
+ guard i < total else { throw invalid() }
105
+ return i < keyCount ? keys[i] : nil
106
+ }
107
+ let instructions = try raw.map { ix -> Instruction in
108
+ // Programs must be static keys.
109
+ guard let program = try key(ix.program) else { throw invalid() }
110
+ return Instruction(programId: program, accounts: try ix.accounts.map(key), data: ix.data)
111
+ }
112
+ return Message(isV0: isV0, numRequiredSignatures: required, accountKeys: keys, recentBlockhash: blockhash, instructions: instructions, lookupAccounts: lookups)
113
+ }
114
+
115
+ private static func u64(_ d: [UInt8], _ at: Int) throws -> UInt64 {
116
+ guard d.count >= at + 8 else { throw invalid() }
117
+ return (0..<8).reduce(UInt64(0)) { $0 | UInt64(d[at + $1]) << (8 * UInt64($1)) }
118
+ }
119
+
120
+ private static func u32(_ d: [UInt8], _ at: Int) throws -> UInt32 {
121
+ guard d.count >= at + 4 else { throw invalid() }
122
+ return (0..<4).reduce(UInt32(0)) { $0 | UInt32(d[at + $1]) << (8 * UInt32($1)) }
123
+ }
124
+
125
+ /// Integer amount with `decimals` places, trailing zeros removed.
126
+ static func units(_ amount: UInt64, _ decimals: Int) -> String {
127
+ if decimals == 0 { return String(amount) }
128
+ var digits = String(amount)
129
+ if digits.count <= decimals { digits = String(repeating: "0", count: decimals - digits.count + 1) + digits }
130
+ let whole = String(digits.dropLast(decimals))
131
+ var frac = String(digits.suffix(decimals))
132
+ while frac.hasSuffix("0") { frac.removeLast() }
133
+ return whole + (frac.isEmpty ? "" : "." + frac)
134
+ }
135
+
136
+ private static func addr(_ a: String??) -> String { (a ?? nil) ?? "(address from a lookup table)" }
137
+
138
+ /// The approval summary. The signer must pay the fee (account 0).
139
+ static func summarize(_ msg: Message, signer: String, network: String) throws -> SignSummary {
140
+ guard msg.accountKeys.first == signer else {
141
+ throw WalletError(.addressMismatch, "the fee payer is not the signing account")
142
+ }
143
+ var rows: [SignSummary.Row] = [.init(label: "Network", value: network), .init(label: "Account", value: signer, mono: true)]
144
+ var warnings = [String]()
145
+ if msg.numRequiredSignatures > 1 {
146
+ warnings.append("This transaction needs \(msg.numRequiredSignatures) signatures; you sign as the fee payer.")
147
+ }
148
+ if msg.lookupAccounts > 0 { warnings.append("Some accounts come from address lookup tables and cannot be shown.") }
149
+ for ix in msg.instructions {
150
+ let d = ix.data
151
+ func account(_ i: Int) -> String?? { i < ix.accounts.count ? ix.accounts[i] : .some(nil) }
152
+ let isToken = ix.programId == token || ix.programId == token2022
153
+ if ix.programId == system, d.count >= 12, try u32(d, 0) == 2 {
154
+ rows += [.init(label: "Send", value: units(try u64(d, 4), 9) + " SOL"), .init(label: "To", value: addr(account(1)), mono: true)]
155
+ if (ix.accounts.first ?? nil) != signer { warnings.append("SOL is sent from an account other than yours.") }
156
+ } else if isToken, d.first == 12, d.count >= 10 {
157
+ rows += [
158
+ .init(label: "Send token", value: units(try u64(d, 1), Int(d[9]))),
159
+ .init(label: "Token", value: addr(account(1)), mono: true),
160
+ .init(label: "To token account", value: addr(account(2)), mono: true),
161
+ ]
162
+ } else if isToken, d.first == 3, d.count >= 9 {
163
+ rows += [
164
+ .init(label: "Send token (raw units)", value: String(try u64(d, 1))),
165
+ .init(label: "To token account", value: addr(account(1)), mono: true),
166
+ ]
167
+ warnings.append("Token amount is shown in raw units (no decimals in this instruction).")
168
+ } else if ix.programId == associatedToken, d.isEmpty || d[0] == 0 || d[0] == 1 {
169
+ rows.append(.init(label: "Create token account", value: addr(account(1)), mono: true))
170
+ } else if ix.programId == computeBudget, d.first == 2, d.count >= 5 {
171
+ rows.append(.init(label: "Compute limit", value: String(try u32(d, 1))))
172
+ } else if ix.programId == computeBudget, d.first == 3, d.count >= 9 {
173
+ rows.append(.init(label: "Priority fee", value: "\(try u64(d, 1)) micro-lamports per unit"))
174
+ } else if ix.programId == memo {
175
+ rows.append(.init(label: "Memo", value: String(decoding: d, as: UTF8.self)))
176
+ } else {
177
+ rows.append(.init(label: "Program call", value: ix.programId, mono: true))
178
+ warnings.append("Calls a program this wallet cannot describe (\(ix.programId)). Approve only if you trust the app.")
179
+ }
180
+ }
181
+ rows.append(.init(label: "Recent blockhash", value: msg.recentBlockhash, mono: true))
182
+ return SignSummary(kind: .transaction, title: "Solana transaction", rows: rows, body: nil, warnings: warnings, risk: .high)
183
+ }
184
+
185
+ /// The SLIP-0010 key of Solana account `index`. Callers wipe it.
186
+ static func privateKey(_ secret: [UInt8], index: Int) throws -> [UInt8] {
187
+ guard WalletShares.isAccountIndex(index) else { throw WalletError(.invalidRequest, "invalid account index") }
188
+ guard WalletShares.isHdSecret(secret) else { throw WalletError(.accountUnavailable, "this wallet has only EVM account 0") }
189
+ var seed = try BIP39.seed(mnemonic: try BIP39.mnemonic(entropy: secret))
190
+ defer { seed.wipe() }
191
+ return try ChainAddresses.ed25519Key(seed: seed, path: WalletChain.solana.path(index))
192
+ }
193
+
194
+ /// Deterministic RFC 8032 Ed25519 (Monocypher) over the exact message bytes.
195
+ /// Returns (address, base58 signature).
196
+ static func sign(_ message: [UInt8], privateKey: [UInt8]) -> (address: String, signature: String) {
197
+ var seed = privateKey // crypto_ed25519_key_pair wipes its seed argument
198
+ var secretKey = [UInt8](repeating: 0, count: 64)
199
+ var publicKey = [UInt8](repeating: 0, count: 32)
200
+ var signature = [UInt8](repeating: 0, count: 64)
201
+ crypto_ed25519_key_pair(&secretKey, &publicKey, &seed)
202
+ message.withUnsafeBufferPointer { m in crypto_ed25519_sign(&signature, secretKey, m.baseAddress, m.count) }
203
+ secretKey.wipe()
204
+ seed.wipe()
205
+ return (Base58.encode(publicKey, alphabet: Base58.bitcoin), Base58.encode(signature, alphabet: Base58.bitcoin))
206
+ }
207
+ }
@@ -0,0 +1,181 @@
1
+ // GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/Chains/Tron.swift. Do not edit: change the source and run the script.
2
+ import Foundation
3
+
4
+ /// TRON transaction signing (docs/wallet/NATIVE.md section 12, `apps/wallet/src/tron.ts`). The app
5
+ /// builds raw_data; the wallet decodes it only to describe it and signs SHA-256(raw_data) like
6
+ /// TronWeb (r || s || v with v = recovery + 27).
7
+ enum Tron {
8
+ static let maxRawData = 4096
9
+
10
+ struct Contract {
11
+ var type: UInt64
12
+ /// Decoded fields of TransferContract (1) / TriggerSmartContract (31).
13
+ var owner: String?
14
+ var to: String?
15
+ var amount: UInt64?
16
+ var contractAddress: String?
17
+ var callValue: UInt64?
18
+ var data: [UInt8]?
19
+ }
20
+
21
+ struct RawData {
22
+ var expiration: UInt64?
23
+ var timestamp: UInt64?
24
+ var feeLimit: UInt64?
25
+ var memo: [UInt8]?
26
+ var contracts: [Contract]
27
+ }
28
+
29
+ private static func invalid() -> WalletError { WalletError(.invalidRequest, "not a valid TRON raw_data") }
30
+
31
+ struct Field {
32
+ var no: UInt64
33
+ var varint: UInt64?
34
+ var bytes: [UInt8]?
35
+ }
36
+
37
+ /// Minimal protobuf reader: varint (0), 64-bit (1), length-delimited (2), 32-bit (5).
38
+ static func fields(_ buf: [UInt8]) throws -> [Field] {
39
+ var out = [Field]()
40
+ var pos = 0
41
+ func varint() throws -> UInt64 {
42
+ var v: UInt64 = 0
43
+ var shift: UInt64 = 0
44
+ while shift < 64 {
45
+ guard pos < buf.count else { throw invalid() }
46
+ let b = buf[pos]
47
+ pos += 1
48
+ if shift == 63 && b > 1 { throw invalid() }
49
+ v |= UInt64(b & 0x7f) << shift
50
+ if b & 0x80 == 0 { return v }
51
+ shift += 7
52
+ }
53
+ throw invalid()
54
+ }
55
+ while pos < buf.count {
56
+ let key = try varint()
57
+ let no = key >> 3
58
+ let wire = key & 7
59
+ guard no != 0 else { throw invalid() }
60
+ switch wire {
61
+ case 0:
62
+ out.append(Field(no: no, varint: try varint()))
63
+ case 2:
64
+ let len = try varint()
65
+ guard len <= UInt64(buf.count - pos) else { throw invalid() }
66
+ out.append(Field(no: no, bytes: Array(buf[pos..<(pos + Int(len))])))
67
+ pos += Int(len)
68
+ case 1, 5:
69
+ let len = wire == 1 ? 8 : 4
70
+ guard pos + len <= buf.count else { throw invalid() }
71
+ pos += len
72
+ out.append(Field(no: no))
73
+ default:
74
+ throw invalid()
75
+ }
76
+ }
77
+ return out
78
+ }
79
+
80
+ private static func one(_ fs: [Field], _ no: UInt64) -> Field? { fs.first { $0.no == no } }
81
+
82
+ static func address(_ raw: [UInt8]) throws -> String {
83
+ guard raw.count == 21, raw[0] == 0x41 else { throw invalid() }
84
+ return Base58.encode(raw + ChainAddresses.checksum4(raw), alphabet: Base58.bitcoin)
85
+ }
86
+
87
+ static func parse(_ raw: [UInt8]) throws -> RawData {
88
+ guard !raw.isEmpty, raw.count <= maxRawData else { throw invalid() }
89
+ let top = try fields(raw)
90
+ let contracts = try top.filter { $0.no == 11 && $0.bytes != nil }.map { f -> Contract in
91
+ let c = try fields(f.bytes!)
92
+ let type = one(c, 1)?.varint ?? 0
93
+ var contract = Contract(type: type)
94
+ let any = one(c, 2)?.bytes
95
+ let value = try any.flatMap { one(try fields($0), 2)?.bytes }
96
+ if let value, type == 1 || type == 31 {
97
+ let v = try fields(value)
98
+ func addr(_ no: UInt64) throws -> String? { try one(v, no)?.bytes.map(address) }
99
+ contract.owner = try addr(1)
100
+ if type == 1 {
101
+ contract.to = try addr(2)
102
+ contract.amount = one(v, 3)?.varint ?? 0
103
+ } else {
104
+ contract.contractAddress = try addr(2)
105
+ contract.callValue = one(v, 3)?.varint ?? 0
106
+ contract.data = one(v, 4)?.bytes ?? []
107
+ }
108
+ }
109
+ return contract
110
+ }
111
+ guard !contracts.isEmpty else { throw invalid() }
112
+ return RawData(
113
+ expiration: one(top, 8)?.varint,
114
+ timestamp: one(top, 14)?.varint,
115
+ feeLimit: one(top, 18)?.varint,
116
+ memo: one(top, 10)?.bytes,
117
+ contracts: contracts
118
+ )
119
+ }
120
+
121
+ static func trx(_ sun: UInt64) -> String { Solana.units(sun, 6) + " TRX" }
122
+
123
+ private static func word(_ data: [UInt8], _ i: Int) -> [UInt8] { Array(data[(4 + 32 * i)..<(4 + 32 * (i + 1))]) }
124
+
125
+ /// `new Date(ms).toISOString()`
126
+ static func isoDate(_ ms: UInt64) throws -> String {
127
+ guard ms <= 8_640_000_000_000_000 else { throw invalid() }
128
+ let f = ISO8601DateFormatter()
129
+ f.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
130
+ f.timeZone = TimeZone(identifier: "UTC")
131
+ return f.string(from: Date(timeIntervalSince1970: Double(ms) / 1000))
132
+ }
133
+
134
+ static func summarize(_ tx: RawData, signer: String) throws -> SignSummary {
135
+ var rows: [SignSummary.Row] = [.init(label: "Network", value: "TRON"), .init(label: "Account", value: signer, mono: true)]
136
+ var warnings = [String]()
137
+ if tx.contracts.count != 1 { warnings.append("This transaction has \(tx.contracts.count) contracts.") }
138
+ for c in tx.contracts {
139
+ if let owner = c.owner, owner != signer {
140
+ throw WalletError(.addressMismatch, "the transaction owner is not the signing account")
141
+ }
142
+ if c.type == 1, let to = c.to, !to.isEmpty {
143
+ rows += [.init(label: "Send", value: trx(c.amount ?? 0)), .init(label: "To", value: to, mono: true)]
144
+ } else if c.type == 31, let data = c.data {
145
+ rows.append(.init(label: "Contract", value: c.contractAddress ?? "?", mono: true))
146
+ if let v = c.callValue, v > 0 { rows.append(.init(label: "Send", value: trx(v))) }
147
+ let selector = Bytes.hex(Array(data.prefix(4)))
148
+ if selector == "a9059cbb" && data.count == 68 {
149
+ rows += [
150
+ .init(label: "Token transfer to", value: try address([0x41] + word(data, 0)[12...]), mono: true),
151
+ .init(label: "Token amount (raw units)", value: BigUInt(bytes: word(data, 1)).description),
152
+ ]
153
+ } else if selector == "095ea7b3" && data.count == 68 {
154
+ let amount = BigUInt(bytes: word(data, 1))
155
+ rows += [
156
+ .init(label: "Allow spender", value: try address([0x41] + word(data, 0)[12...]), mono: true),
157
+ .init(label: "Allowance (raw units)", value: amount == BigUInt.power2(256) - BigUInt(1) ? "Unlimited" : amount.description),
158
+ ]
159
+ warnings.append("This lets another address spend your tokens.")
160
+ } else {
161
+ rows.append(.init(label: "Call data", value: Bytes.hex(data, prefix: true), mono: true))
162
+ warnings.append("Calls a contract function this wallet cannot describe. Approve only if you trust the app.")
163
+ }
164
+ } else {
165
+ rows.append(.init(label: "Contract type", value: String(c.type)))
166
+ warnings.append("TRON contract type \(c.type) cannot be described. Approve only if you trust the app.")
167
+ }
168
+ }
169
+ if let fee = tx.feeLimit { rows.append(.init(label: "Fee limit", value: trx(fee))) }
170
+ if let memo = tx.memo, !memo.isEmpty { rows.append(.init(label: "Memo", value: String(decoding: memo, as: UTF8.self))) }
171
+ if let exp = tx.expiration { rows.append(.init(label: "Expires", value: try isoDate(exp))) }
172
+ return SignSummary(kind: .transaction, title: "TRON transaction", rows: rows, body: nil, warnings: warnings, risk: .high)
173
+ }
174
+
175
+ /// txID = SHA-256(raw_data); signature r || s || (recovery + 27) in lowercase hex.
176
+ static func sign(_ raw: [UInt8], privateKey: [UInt8]) throws -> [String: String] {
177
+ let txID = Bytes.sha256(raw)
178
+ let sig = try Secp256k1.sign(hash: txID, key: privateKey)
179
+ return ["txID": Bytes.hex(txID), "signature": Bytes.hex(sig.r + sig.s + [UInt8(27 + sig.recoveryId)])]
180
+ }
181
+ }
@@ -0,0 +1,191 @@
1
+ // GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/Chains/XRP.swift. Do not edit: change the source and run the script.
2
+ import CryptoKit
3
+ import Foundation
4
+
5
+ /// XRP Ledger signing (docs/wallet/NATIVE.md section 12, `apps/wallet/src/xrp.ts`). The app sends
6
+ /// the output of ripple-binary-codec encodeForSigning (prefix STX\0); the wallet decodes it only
7
+ /// to describe it and signs SHA-512Half(blob) with secp256k1, DER, low S.
8
+ enum XRP {
9
+ static let maxBlob = 4096
10
+ static let signingPrefix: [UInt8] = [0x53, 0x54, 0x58, 0x00]
11
+
12
+ struct Tx {
13
+ var transactionType: Int?
14
+ var account: String?
15
+ var destination: String?
16
+ /// Drops for XRP amounts; `.some(nil)` for issued-token amounts.
17
+ var amount: UInt64??
18
+ var fee: UInt64??
19
+ var sequence: Int?
20
+ var destinationTag: Int?
21
+ var lastLedgerSequence: Int?
22
+ var signingPubKey: [UInt8]?
23
+ var memos: [String] = []
24
+ }
25
+
26
+ private static func invalid(_ why: String = "not a valid XRP signing blob") -> WalletError { WalletError(.invalidRequest, why) }
27
+
28
+ static func address(accountId: [UInt8]) throws -> String {
29
+ guard accountId.count == 20 else { throw invalid() }
30
+ let payload = [0x00] + accountId
31
+ return Base58.encode(payload + ChainAddresses.checksum4(payload), alphabet: Base58.xrp)
32
+ }
33
+
34
+ static func address(publicKey compressed: [UInt8]) throws -> String {
35
+ try address(accountId: ChainAddresses.hash160(compressed))
36
+ }
37
+
38
+ private struct Reader {
39
+ let b: [UInt8]
40
+ var pos = 0
41
+ var done: Bool { pos >= b.count }
42
+
43
+ mutating func u8() throws -> Int {
44
+ guard pos < b.count else { throw invalid() }
45
+ pos += 1
46
+ return Int(b[pos - 1])
47
+ }
48
+
49
+ mutating func take(_ n: Int) throws -> [UInt8] {
50
+ guard pos + n <= b.count else { throw invalid() }
51
+ pos += n
52
+ return Array(b[(pos - n)..<pos])
53
+ }
54
+
55
+ mutating func uint(_ n: Int) throws -> Int { try take(n).reduce(0) { $0 * 256 + Int($1) } }
56
+
57
+ /// XRPL variable-length prefix.
58
+ mutating func vl() throws -> [UInt8] {
59
+ let b1 = try u8()
60
+ if b1 <= 192 { return try take(b1) }
61
+ if b1 <= 240 { return try take(193 + (b1 - 193) * 256 + (try u8())) }
62
+ if b1 <= 254 { return try take(12481 + (b1 - 241) * 65536 + (try u8()) * 256 + (try u8())) }
63
+ throw invalid()
64
+ }
65
+
66
+ mutating func field() throws -> (type: Int, code: Int) {
67
+ let h = try u8()
68
+ var type = h >> 4
69
+ var code = h & 0x0f
70
+ if type == 0 { type = try u8() }
71
+ if code == 0 { code = try u8() }
72
+ return (type, code)
73
+ }
74
+
75
+ mutating func amount() throws -> UInt64? {
76
+ guard pos < b.count else { throw invalid() }
77
+ if b[pos] & 0x80 != 0 {
78
+ _ = try take(48) // issued token: 8 value + 20 currency + 20 issuer
79
+ return nil
80
+ }
81
+ let v = try take(8).reduce(UInt64(0)) { $0 << 8 | UInt64($1) }
82
+ return v & 0x3fff_ffff_ffff_ffff
83
+ }
84
+ }
85
+
86
+ /// Reads one STObject until its end marker (or the end of the blob at the top level).
87
+ /// `memos` collects MemoData inside the top-level Memos array.
88
+ private static func readObject(_ r: inout Reader, _ tx: inout Tx?, depth: Int, memos: inout [String]?) throws {
89
+ guard depth <= 4 else { throw invalid() }
90
+ while !r.done {
91
+ let (type, code) = try r.field()
92
+ if type == 14 && code == 1 { return } // ObjectEndMarker
93
+ if type == 15 && code == 1 { return } // ArrayEndMarker
94
+ switch type {
95
+ case 1:
96
+ let v = try r.uint(2)
97
+ if code == 2 { tx?.transactionType = v }
98
+ case 2:
99
+ let v = try r.uint(4)
100
+ if code == 4 { tx?.sequence = v } else if code == 14 { tx?.destinationTag = v } else if code == 27 { tx?.lastLedgerSequence = v }
101
+ case 3: _ = try r.take(8)
102
+ case 4: _ = try r.take(16)
103
+ case 5: _ = try r.take(32)
104
+ case 16: _ = try r.take(1)
105
+ case 17: _ = try r.take(20)
106
+ case 6:
107
+ let v = try r.amount()
108
+ if code == 1 { tx?.amount = .some(v) } else if code == 8 { tx?.fee = .some(v) }
109
+ case 7:
110
+ let v = try r.vl()
111
+ if tx != nil, code == 3 {
112
+ tx?.signingPubKey = v
113
+ } else if tx == nil, code == 13 {
114
+ memos?.append(String(decoding: v, as: UTF8.self))
115
+ }
116
+ case 8:
117
+ let v = try r.vl()
118
+ if tx != nil, code == 1 { tx?.account = try address(accountId: v) } else if tx != nil, code == 3 { tx?.destination = try address(accountId: v) }
119
+ case 14:
120
+ var none: Tx? = nil
121
+ try readObject(&r, &none, depth: depth + 1, memos: &memos)
122
+ case 15:
123
+ var none: Tx? = nil
124
+ if tx != nil && code == 9 {
125
+ var collected: [String]? = []
126
+ try readObject(&r, &none, depth: depth + 1, memos: &collected)
127
+ tx?.memos += collected ?? []
128
+ } else {
129
+ try readObject(&r, &none, depth: depth + 1, memos: &memos)
130
+ }
131
+ default:
132
+ throw invalid("XRP field type \(type) is not supported")
133
+ }
134
+ }
135
+ }
136
+
137
+ static func parse(_ blob: [UInt8]) throws -> Tx {
138
+ guard blob.count >= 5, blob.count <= maxBlob, Array(blob.prefix(4)) == signingPrefix else { throw invalid() }
139
+ var r = Reader(b: Array(blob.dropFirst(4)))
140
+ var tx: Tx? = Tx()
141
+ var memos: [String]? = nil
142
+ try readObject(&r, &tx, depth: 0, memos: &memos)
143
+ guard let parsed = tx, parsed.transactionType != nil, parsed.account != nil, parsed.signingPubKey != nil else { throw invalid() }
144
+ return parsed
145
+ }
146
+
147
+ static func xrp(_ drops: UInt64) -> String { Solana.units(drops, 6) + " XRP" }
148
+
149
+ private static let types: [Int: String] = [0: "Payment", 3: "AccountSet", 7: "OfferCreate", 8: "OfferCancel", 12: "SetRegularKey", 20: "TrustSet"]
150
+
151
+ static func summarize(_ tx: Tx, signer: String, signerPublicKey: [UInt8]) throws -> SignSummary {
152
+ guard tx.account == signer else { throw WalletError(.addressMismatch, "the transaction account is not the signing account") }
153
+ guard tx.signingPubKey == signerPublicKey else {
154
+ throw WalletError(.invalidRequest, "SigningPubKey must be the signing account public key")
155
+ }
156
+ let type = tx.transactionType ?? 0
157
+ var rows: [SignSummary.Row] = [
158
+ .init(label: "Network", value: "XRP Ledger"),
159
+ .init(label: "Account", value: signer, mono: true),
160
+ .init(label: "Type", value: types[type] ?? "Type \(type)"),
161
+ ]
162
+ var warnings = [String]()
163
+ if type == 0 {
164
+ switch tx.amount {
165
+ case .some(.none):
166
+ rows.append(.init(label: "Send", value: "Issued token amount"))
167
+ warnings.append("Issued-token payments cannot be described in detail.")
168
+ case .some(.some(let drops)):
169
+ rows.append(.init(label: "Send", value: xrp(drops)))
170
+ case .none:
171
+ break
172
+ }
173
+ if let d = tx.destination, !d.isEmpty { rows.append(.init(label: "To", value: d, mono: true)) }
174
+ if let tag = tx.destinationTag { rows.append(.init(label: "Destination tag", value: String(tag))) }
175
+ } else {
176
+ warnings.append("\(types[type] ?? "This") transaction cannot be described in detail. Approve only if you trust the app.")
177
+ }
178
+ for m in tx.memos { rows.append(.init(label: "Memo", value: m)) }
179
+ if case .some(.some(let fee)) = tx.fee { rows.append(.init(label: "Network fee", value: xrp(fee))) }
180
+ if let s = tx.sequence { rows.append(.init(label: "Sequence", value: String(s))) }
181
+ if let l = tx.lastLedgerSequence { rows.append(.init(label: "Valid until ledger", value: String(l))) }
182
+ return SignSummary(kind: .transaction, title: "XRP Ledger transaction", rows: rows, body: nil, warnings: warnings, risk: .high)
183
+ }
184
+
185
+ static func sha512Half(_ data: [UInt8]) -> [UInt8] { Array(Array(SHA512.hash(data: data))[0..<32]) }
186
+
187
+ /// DER (low S) over SHA-512Half of the signing blob, uppercase hex like ripple-keypairs.
188
+ static func sign(_ blob: [UInt8], privateKey: [UInt8]) throws -> [String: String] {
189
+ ["signature": Bytes.hex(try Secp256k1.signDER(hash: sha512Half(blob), key: privateKey)).uppercased()]
190
+ }
191
+ }