@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.
- package/CHANGELOG.md +20 -0
- package/README.md +251 -2
- package/android/build.gradle +40 -0
- package/android/consumer-rules.pro +10 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/dev/authon/reactnative/wallet/AuthonWalletModule.kt +235 -0
- package/android/src/vendor/GENERATED.md +4 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/AndroidCapabilityProbe.kt +86 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/AuthonWallet.kt +218 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Bitcoin.kt +296 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Bytes.kt +74 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Chains.kt +157 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/CredentialManagerPasskeys.kt +192 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Der.kt +17 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/DeviceStore.kt +170 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/DialogWalletApprover.kt +141 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Eip712.kt +176 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Encodings.kt +133 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/EvmAccount.kt +45 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/EvmTransaction.kt +180 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/GfTables.kt +44 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/HdWallet.kt +130 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Http.kt +86 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/JsValues.kt +83 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/KeystoreDeviceStore.kt +236 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Prf.kt +111 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Proof.kt +134 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Shamir.kt +106 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/SignSummary.kt +335 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Solana.kt +195 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Tron.kt +184 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletApi.kt +361 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletCapabilities.kt +91 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletError.kt +74 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletOps.kt +551 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/WalletTypes.kt +78 -0
- package/android/src/vendor/kotlin/dev/authon/sdk/wallet/Xrp.kt +193 -0
- package/build/authonContext.d.ts +19 -0
- package/build/authonContext.d.ts.map +1 -0
- package/build/authonContext.js +20 -0
- package/build/authonContext.js.map +1 -0
- package/build/client.d.ts +92 -0
- package/build/client.d.ts.map +1 -0
- package/build/client.js +431 -0
- package/build/client.js.map +1 -0
- package/build/errors.d.ts +25 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +15 -0
- package/build/errors.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/native.d.ts +43 -0
- package/build/native.d.ts.map +1 -0
- package/build/native.js +12 -0
- package/build/native.js.map +1 -0
- package/build/types.d.ts +167 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +3 -0
- package/build/types.js.map +1 -0
- package/build/useAuthonWallet.d.ts +25 -0
- package/build/useAuthonWallet.d.ts.map +1 -0
- package/build/useAuthonWallet.js +77 -0
- package/build/useAuthonWallet.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/AuthonReactNativeWallet.podspec +41 -0
- package/ios/AuthonWalletModule.swift +233 -0
- package/ios/vendor/AuthonWallet/AuthonWallet.swift +232 -0
- package/ios/vendor/AuthonWallet/Capabilities.swift +149 -0
- package/ios/vendor/AuthonWallet/Chains/Bitcoin.swift +296 -0
- package/ios/vendor/AuthonWallet/Chains/Solana.swift +207 -0
- package/ios/vendor/AuthonWallet/Chains/Tron.swift +181 -0
- package/ios/vendor/AuthonWallet/Chains/XRP.swift +191 -0
- package/ios/vendor/AuthonWallet/Crypto/BIP39Wordlist.swift +262 -0
- package/ios/vendor/AuthonWallet/Crypto/Chains.swift +278 -0
- package/ios/vendor/AuthonWallet/Crypto/HDKey.swift +108 -0
- package/ios/vendor/AuthonWallet/Crypto/Secp256k1.swift +128 -0
- package/ios/vendor/AuthonWallet/Crypto/Shamir.swift +123 -0
- package/ios/vendor/AuthonWallet/EVM/Address.swift +57 -0
- package/ios/vendor/AuthonWallet/EVM/EvmAccount.swift +48 -0
- package/ios/vendor/AuthonWallet/EVM/Transaction.swift +165 -0
- package/ios/vendor/AuthonWallet/EVM/TypedData.swift +193 -0
- package/ios/vendor/AuthonWallet/Support/BigInteger.swift +220 -0
- package/ios/vendor/AuthonWallet/Support/Bytes.swift +89 -0
- package/ios/vendor/AuthonWallet/Support/JSONValue.swift +341 -0
- package/ios/vendor/AuthonWallet/UI/WalletApprover.swift +250 -0
- package/ios/vendor/AuthonWallet/Wallet/Backup.swift +69 -0
- package/ios/vendor/AuthonWallet/Wallet/DeviceStore.swift +351 -0
- package/ios/vendor/AuthonWallet/Wallet/Passkeys.swift +190 -0
- package/ios/vendor/AuthonWallet/Wallet/Proof.swift +143 -0
- package/ios/vendor/AuthonWallet/Wallet/Shares.swift +116 -0
- package/ios/vendor/AuthonWallet/Wallet/Summary.swift +342 -0
- package/ios/vendor/AuthonWallet/Wallet/WalletAPI.swift +361 -0
- package/ios/vendor/AuthonWallet/Wallet/WalletOps.swift +654 -0
- package/ios/vendor/AuthonWallet/WalletError.swift +84 -0
- package/ios/vendor/CKeccak/LICENSE +22 -0
- package/ios/vendor/CKeccak/README.md +30 -0
- package/ios/vendor/CKeccak/byte_order.h +59 -0
- package/ios/vendor/CKeccak/include/ckeccak.h +13 -0
- package/ios/vendor/CKeccak/memzero.c +75 -0
- package/ios/vendor/CKeccak/memzero.h +8 -0
- package/ios/vendor/CKeccak/options.h +99 -0
- package/ios/vendor/CKeccak/ripemd160.c +343 -0
- package/ios/vendor/CKeccak/ripemd160.h +22 -0
- package/ios/vendor/CKeccak/sha3.c +413 -0
- package/ios/vendor/CKeccak/sha3.h +89 -0
- package/ios/vendor/CMonocypher/LICENCE.md +173 -0
- package/ios/vendor/CMonocypher/README.md +27 -0
- package/ios/vendor/CMonocypher/include/monocypher-ed25519.h +140 -0
- package/ios/vendor/CMonocypher/include/monocypher.h +321 -0
- package/ios/vendor/CMonocypher/monocypher-ed25519.c +500 -0
- package/ios/vendor/CMonocypher/monocypher.c +2956 -0
- package/ios/vendor/CSecp256k1/COPYING +19 -0
- package/ios/vendor/CSecp256k1/README.md +35 -0
- package/ios/vendor/CSecp256k1/build/precomputed_ecmult.c +3 -0
- package/ios/vendor/CSecp256k1/build/precomputed_ecmult_gen.c +3 -0
- package/ios/vendor/CSecp256k1/build/secp256k1.c +3 -0
- package/ios/vendor/CSecp256k1/include/secp256k1.h +899 -0
- package/ios/vendor/CSecp256k1/include/secp256k1_preallocated.h +134 -0
- package/ios/vendor/CSecp256k1/include/secp256k1_recovery.h +113 -0
- package/ios/vendor/CSecp256k1/src/assumptions.h +87 -0
- package/ios/vendor/CSecp256k1/src/checkmem.h +102 -0
- package/ios/vendor/CSecp256k1/src/ecdsa.h +21 -0
- package/ios/vendor/CSecp256k1/src/ecdsa_impl.h +304 -0
- package/ios/vendor/CSecp256k1/src/eckey.h +25 -0
- package/ios/vendor/CSecp256k1/src/eckey_impl.h +92 -0
- package/ios/vendor/CSecp256k1/src/ecmult.h +61 -0
- package/ios/vendor/CSecp256k1/src/ecmult_const.h +38 -0
- package/ios/vendor/CSecp256k1/src/ecmult_const_impl.h +399 -0
- package/ios/vendor/CSecp256k1/src/ecmult_gen.h +143 -0
- package/ios/vendor/CSecp256k1/src/ecmult_gen_impl.h +341 -0
- package/ios/vendor/CSecp256k1/src/ecmult_impl.h +853 -0
- package/ios/vendor/CSecp256k1/src/field.h +350 -0
- package/ios/vendor/CSecp256k1/src/field_10x26.h +57 -0
- package/ios/vendor/CSecp256k1/src/field_10x26_impl.h +1232 -0
- package/ios/vendor/CSecp256k1/src/field_5x52.h +62 -0
- package/ios/vendor/CSecp256k1/src/field_5x52_impl.h +522 -0
- package/ios/vendor/CSecp256k1/src/field_5x52_int128_impl.h +274 -0
- package/ios/vendor/CSecp256k1/src/field_impl.h +457 -0
- package/ios/vendor/CSecp256k1/src/group.h +212 -0
- package/ios/vendor/CSecp256k1/src/group_impl.h +974 -0
- package/ios/vendor/CSecp256k1/src/hash.h +44 -0
- package/ios/vendor/CSecp256k1/src/hash_impl.h +299 -0
- package/ios/vendor/CSecp256k1/src/hsort.h +33 -0
- package/ios/vendor/CSecp256k1/src/hsort_impl.h +125 -0
- package/ios/vendor/CSecp256k1/src/int128.h +90 -0
- package/ios/vendor/CSecp256k1/src/int128_impl.h +18 -0
- package/ios/vendor/CSecp256k1/src/int128_native.h +19 -0
- package/ios/vendor/CSecp256k1/src/int128_native_impl.h +94 -0
- package/ios/vendor/CSecp256k1/src/int128_struct.h +14 -0
- package/ios/vendor/CSecp256k1/src/int128_struct_impl.h +205 -0
- package/ios/vendor/CSecp256k1/src/modinv32.h +43 -0
- package/ios/vendor/CSecp256k1/src/modinv32_impl.h +725 -0
- package/ios/vendor/CSecp256k1/src/modinv64.h +47 -0
- package/ios/vendor/CSecp256k1/src/modinv64_impl.h +780 -0
- package/ios/vendor/CSecp256k1/src/modules/recovery/main_impl.h +159 -0
- package/ios/vendor/CSecp256k1/src/precomputed_ecmult.c +16456 -0
- package/ios/vendor/CSecp256k1/src/precomputed_ecmult.h +38 -0
- package/ios/vendor/CSecp256k1/src/precomputed_ecmult_gen.c +1779 -0
- package/ios/vendor/CSecp256k1/src/precomputed_ecmult_gen.h +26 -0
- package/ios/vendor/CSecp256k1/src/scalar.h +105 -0
- package/ios/vendor/CSecp256k1/src/scalar_4x64.h +19 -0
- package/ios/vendor/CSecp256k1/src/scalar_4x64_impl.h +1000 -0
- package/ios/vendor/CSecp256k1/src/scalar_8x32.h +19 -0
- package/ios/vendor/CSecp256k1/src/scalar_8x32_impl.h +816 -0
- package/ios/vendor/CSecp256k1/src/scalar_impl.h +321 -0
- package/ios/vendor/CSecp256k1/src/scalar_low.h +24 -0
- package/ios/vendor/CSecp256k1/src/scalar_low_impl.h +206 -0
- package/ios/vendor/CSecp256k1/src/scratch.h +44 -0
- package/ios/vendor/CSecp256k1/src/scratch_impl.h +99 -0
- package/ios/vendor/CSecp256k1/src/secp256k1.c +831 -0
- package/ios/vendor/CSecp256k1/src/selftest.h +32 -0
- package/ios/vendor/CSecp256k1/src/util.h +451 -0
- package/ios/vendor/GENERATED.md +4 -0
- package/package.json +66 -3
- package/src/authonContext.ts +30 -0
- package/src/client.ts +459 -0
- package/src/errors.ts +58 -0
- package/src/index.ts +26 -0
- package/src/native.ts +52 -0
- package/src/types.ts +171 -0
- package/src/useAuthonWallet.ts +103 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/EVM/TypedData.swift. Do not edit: change the source and run the script.
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
/// EIP-712 v4 hashing with viem's rules (hashTypedData + validateTypedData).
|
|
5
|
+
struct TypedData {
|
|
6
|
+
struct Field {
|
|
7
|
+
var name: String
|
|
8
|
+
var type: String
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
var domain: JSONObject
|
|
12
|
+
var types: [String: [Field]]
|
|
13
|
+
var primaryType: String
|
|
14
|
+
var message: JSONValue
|
|
15
|
+
|
|
16
|
+
private static func bad(_ m: String) -> WalletError { WalletError(.invalidRequest, m) }
|
|
17
|
+
|
|
18
|
+
init(_ value: JSONValue) throws {
|
|
19
|
+
guard let obj = value.objectValue else { throw TypedData.bad("typedData must be an object") }
|
|
20
|
+
let domainValue = obj["domain"] ?? .null
|
|
21
|
+
if domainValue == .null {
|
|
22
|
+
domain = JSONObject()
|
|
23
|
+
} else {
|
|
24
|
+
guard let d = domainValue.objectValue else { throw TypedData.bad("domain must be an object") }
|
|
25
|
+
domain = d
|
|
26
|
+
}
|
|
27
|
+
guard case .string(let primary) = obj["primaryType"] ?? .null else { throw TypedData.bad("primaryType must be a string") }
|
|
28
|
+
primaryType = primary
|
|
29
|
+
message = obj["message"] ?? .null
|
|
30
|
+
guard let rawTypes = obj["types"]?.objectValue else { throw TypedData.bad("types must be an object") }
|
|
31
|
+
var parsed = [String: [Field]]()
|
|
32
|
+
parsed["EIP712Domain"] = TypedData.domainFields(domain)
|
|
33
|
+
for (name, list) in rawTypes.entries {
|
|
34
|
+
guard let arr = list.arrayValue else { throw TypedData.bad("types.\(name) must be an array") }
|
|
35
|
+
parsed[name] = try arr.map { f in
|
|
36
|
+
guard case .string(let n) = f["name"] ?? .null, case .string(let t) = f["type"] ?? .null else {
|
|
37
|
+
throw TypedData.bad("invalid field in \(name)")
|
|
38
|
+
}
|
|
39
|
+
return Field(name: n, type: t)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
types = parsed
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// getTypesForEIP712Domain: chainId only when it is a number, the others when truthy.
|
|
46
|
+
private static func domainFields(_ d: JSONObject) -> [Field] {
|
|
47
|
+
var out = [Field]()
|
|
48
|
+
if case .string = d["name"] ?? .null { out.append(Field(name: "name", type: "string")) }
|
|
49
|
+
if d["version"]?.isTruthy == true { out.append(Field(name: "version", type: "string")) }
|
|
50
|
+
if case .number = d["chainId"] ?? .null { out.append(Field(name: "chainId", type: "uint256")) }
|
|
51
|
+
if d["verifyingContract"]?.isTruthy == true { out.append(Field(name: "verifyingContract", type: "address")) }
|
|
52
|
+
if d["salt"]?.isTruthy == true { out.append(Field(name: "salt", type: "bytes32")) }
|
|
53
|
+
return out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func digest() throws -> [UInt8] {
|
|
57
|
+
try validate()
|
|
58
|
+
var parts: [UInt8] = [0x19, 0x01]
|
|
59
|
+
parts += try hashStruct("EIP712Domain", .object(domain))
|
|
60
|
+
if primaryType != "EIP712Domain" { parts += try hashStruct(primaryType, message) }
|
|
61
|
+
return Keccak.hash256(parts)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MARK: - Validation (validateTypedData)
|
|
65
|
+
|
|
66
|
+
private func validate() throws {
|
|
67
|
+
func validateData(_ fields: [Field], _ data: JSONValue) throws {
|
|
68
|
+
for f in fields {
|
|
69
|
+
let value = data[f.name]
|
|
70
|
+
let base = f.type.replacingOccurrences(of: #"(\[[0-9]*\])+$"#, with: "", options: .regularExpression)
|
|
71
|
+
if base == "int" || base == "uint" { throw TypedData.bad("invalid type \(f.type)") }
|
|
72
|
+
if let (signed, bits) = TypedData.integerType(f.type), let v = value, case .number = v {
|
|
73
|
+
guard let n = v.jsBigInt, n.fits(bits: bits, signed: signed) else { throw TypedData.bad("\(f.name) out of range") }
|
|
74
|
+
}
|
|
75
|
+
if f.type == "address", case .string(let s) = value ?? .null, !EvmAddress.isAddress(s) {
|
|
76
|
+
throw TypedData.bad("invalid address \(s)")
|
|
77
|
+
}
|
|
78
|
+
if let size = TypedData.fixedBytesSize(f.type), size > 0 {
|
|
79
|
+
guard case .string(let s) = value ?? .null, let b = Bytes.fromHex(s), Bytes.isHex(s), b.count == size else {
|
|
80
|
+
throw TypedData.bad("\(f.name) must be \(size) bytes")
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if let nested = types[f.type] {
|
|
84
|
+
guard let v = value else { throw TypedData.bad("missing \(f.name)") }
|
|
85
|
+
try validateData(nested, v)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if let d = types["EIP712Domain"] { try validateData(d, .object(domain)) }
|
|
90
|
+
if primaryType != "EIP712Domain" {
|
|
91
|
+
guard let fields = types[primaryType] else { throw TypedData.bad("unknown primaryType \(primaryType)") }
|
|
92
|
+
try validateData(fields, message)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// uint8..uint256 / int8..int256 in steps of 8.
|
|
97
|
+
static func integerType(_ type: String) -> (Bool, Int)? {
|
|
98
|
+
let signed = type.hasPrefix("int")
|
|
99
|
+
guard signed || type.hasPrefix("uint") else { return nil }
|
|
100
|
+
let digits = type.dropFirst(signed ? 3 : 4)
|
|
101
|
+
guard let bits = Int(digits), String(bits) == digits, bits >= 8, bits <= 256, bits % 8 == 0 else { return nil }
|
|
102
|
+
return (signed, bits)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// bytes1..bytes32 (0 for dynamic `bytes`, nil otherwise).
|
|
106
|
+
static func fixedBytesSize(_ type: String) -> Int? {
|
|
107
|
+
guard type.hasPrefix("bytes") else { return nil }
|
|
108
|
+
let digits = type.dropFirst(5)
|
|
109
|
+
if digits.isEmpty { return 0 }
|
|
110
|
+
guard let n = Int(digits), String(n) == digits, n >= 1, n <= 32 else { return nil }
|
|
111
|
+
return n
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// MARK: - Encoding
|
|
115
|
+
|
|
116
|
+
func encodeType(_ primary: String) -> String {
|
|
117
|
+
var deps = Set<String>()
|
|
118
|
+
findDependencies(primary, &deps)
|
|
119
|
+
deps.remove(primary)
|
|
120
|
+
let sorted = deps.sorted { $0.utf16.lexicographicallyPrecedes($1.utf16) }
|
|
121
|
+
return ([primary] + sorted).map { t in
|
|
122
|
+
"\(t)(" + (types[t] ?? []).map { "\($0.type) \($0.name)" }.joined(separator: ",") + ")"
|
|
123
|
+
}.joined()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private func findDependencies(_ type: String, _ results: inout Set<String>) {
|
|
127
|
+
let base = String(type.prefix { $0.isLetter || $0.isNumber || $0 == "_" })
|
|
128
|
+
guard !results.contains(base), let fields = types[base] else { return }
|
|
129
|
+
results.insert(base)
|
|
130
|
+
for f in fields { findDependencies(f.type, &results) }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func hashStruct(_ type: String, _ data: JSONValue) throws -> [UInt8] {
|
|
134
|
+
Keccak.hash256(try encodeData(type, data))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private func encodeData(_ type: String, _ data: JSONValue) throws -> [UInt8] {
|
|
138
|
+
guard let fields = types[type] else { throw TypedData.bad("unknown type \(type)") }
|
|
139
|
+
guard case .object = data else { throw TypedData.bad("\(type) value must be an object") }
|
|
140
|
+
var out = Keccak.hash256(Array(encodeType(type).utf8))
|
|
141
|
+
for f in fields { out += try encodeField(f.type, data[f.name]) }
|
|
142
|
+
return out
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// One 32-byte word per field.
|
|
146
|
+
private func encodeField(_ type: String, _ value: JSONValue?) throws -> [UInt8] {
|
|
147
|
+
if types[type] != nil {
|
|
148
|
+
guard let v = value else { throw TypedData.bad("missing \(type) value") }
|
|
149
|
+
return Keccak.hash256(try encodeData(type, v))
|
|
150
|
+
}
|
|
151
|
+
if type == "bytes" {
|
|
152
|
+
guard case .string(let s) = value ?? .null, Bytes.isHex(s), let b = Bytes.fromHex(s) else { throw TypedData.bad("bytes must be hex") }
|
|
153
|
+
return Keccak.hash256(b)
|
|
154
|
+
}
|
|
155
|
+
if type == "string" {
|
|
156
|
+
guard case .string(let s) = value ?? .null else { throw TypedData.bad("string expected") }
|
|
157
|
+
return Keccak.hash256(Array(s.utf8))
|
|
158
|
+
}
|
|
159
|
+
if type.hasSuffix("]"), let open = type.range(of: "[", options: .backwards) {
|
|
160
|
+
let inner = String(type[..<open.lowerBound])
|
|
161
|
+
guard let items = value?.arrayValue else { throw TypedData.bad("array expected for \(type)") }
|
|
162
|
+
var concat = [UInt8]()
|
|
163
|
+
for item in items { concat += try encodeField(inner, item) }
|
|
164
|
+
return Keccak.hash256(concat)
|
|
165
|
+
}
|
|
166
|
+
return try encodeAtomic(type, value)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private func encodeAtomic(_ type: String, _ value: JSONValue?) throws -> [UInt8] {
|
|
170
|
+
let v = value ?? .null
|
|
171
|
+
if type == "address" {
|
|
172
|
+
guard case .string(let s) = v, EvmAddress.isAddress(s), let b = EvmAddress.bytes(s) else { throw TypedData.bad("invalid address") }
|
|
173
|
+
return [UInt8](repeating: 0, count: 12) + b
|
|
174
|
+
}
|
|
175
|
+
if type == "bool" {
|
|
176
|
+
guard case .bool(let b) = v else { throw TypedData.bad("bool expected") }
|
|
177
|
+
return [UInt8](repeating: 0, count: 31) + [b ? 1 : 0]
|
|
178
|
+
}
|
|
179
|
+
if let (signed, bits) = TypedData.integerType(type) {
|
|
180
|
+
guard let n = v.jsBigInt, n.fits(bits: bits, signed: signed), let word = n.word() else {
|
|
181
|
+
throw TypedData.bad("\(type) value out of range")
|
|
182
|
+
}
|
|
183
|
+
return word
|
|
184
|
+
}
|
|
185
|
+
if let size = TypedData.fixedBytesSize(type), size > 0 {
|
|
186
|
+
guard case .string(let s) = v, Bytes.isHex(s), let b = Bytes.fromHex(s), b.count == size else {
|
|
187
|
+
throw TypedData.bad("\(type) size mismatch")
|
|
188
|
+
}
|
|
189
|
+
return b + [UInt8](repeating: 0, count: 32 - size)
|
|
190
|
+
}
|
|
191
|
+
throw TypedData.bad("unsupported type \(type)")
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/Support/BigInteger.swift. Do not edit: change the source and run the script.
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
/// Unsigned arbitrary-precision integer for amounts, gas and EIP-712 integers. Only the
|
|
5
|
+
/// operations the wallet needs (parsing, printing, encoding, add/sub/mul, compare).
|
|
6
|
+
struct BigUInt: Comparable, Hashable, CustomStringConvertible {
|
|
7
|
+
/// Little-endian 32-bit limbs without trailing zero limbs.
|
|
8
|
+
private(set) var limbs: [UInt32]
|
|
9
|
+
|
|
10
|
+
init(_ value: UInt64 = 0) {
|
|
11
|
+
limbs = [UInt32(truncatingIfNeeded: value), UInt32(truncatingIfNeeded: value >> 32)]
|
|
12
|
+
normalize()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
init(limbs: [UInt32]) {
|
|
16
|
+
self.limbs = limbs
|
|
17
|
+
normalize()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// Big-endian bytes.
|
|
21
|
+
init(bytes: [UInt8]) {
|
|
22
|
+
var out = [UInt32]()
|
|
23
|
+
var i = bytes.count
|
|
24
|
+
while i > 0 {
|
|
25
|
+
var limb: UInt32 = 0
|
|
26
|
+
let start = Swift.max(0, i - 4)
|
|
27
|
+
for b in bytes[start..<i] { limb = limb << 8 | UInt32(b) }
|
|
28
|
+
out.append(limb)
|
|
29
|
+
i = start
|
|
30
|
+
}
|
|
31
|
+
self.init(limbs: out)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
init?(decimal text: String) {
|
|
35
|
+
guard !text.isEmpty, text.utf8.allSatisfy({ $0 >= 0x30 && $0 <= 0x39 }) else { return nil }
|
|
36
|
+
var v = BigUInt()
|
|
37
|
+
for c in text.utf8 { v = v.multiplied(by: 10).adding(UInt32(c - 0x30)) }
|
|
38
|
+
self = v
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
init?(hexDigits text: String) {
|
|
42
|
+
guard !text.isEmpty, !text.contains("x"), !text.contains("X"), let bytes = Bytes.fromHex(text) else { return nil }
|
|
43
|
+
self.init(bytes: bytes)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private mutating func normalize() {
|
|
47
|
+
while let last = limbs.last, last == 0 { limbs.removeLast() }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
var isZero: Bool { limbs.isEmpty }
|
|
51
|
+
|
|
52
|
+
var bitWidth: Int {
|
|
53
|
+
guard let last = limbs.last else { return 0 }
|
|
54
|
+
return (limbs.count - 1) * 32 + (32 - last.leadingZeroBitCount)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Minimal big-endian bytes; zero is empty.
|
|
58
|
+
var bytes: [UInt8] {
|
|
59
|
+
var out = [UInt8]()
|
|
60
|
+
for limb in limbs.reversed() {
|
|
61
|
+
out += [UInt8(limb >> 24), UInt8(truncatingIfNeeded: limb >> 16), UInt8(truncatingIfNeeded: limb >> 8), UInt8(truncatingIfNeeded: limb)]
|
|
62
|
+
}
|
|
63
|
+
if let first = out.firstIndex(where: { $0 != 0 }) { return Array(out[first...]) }
|
|
64
|
+
return []
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// Big-endian, left-padded to `size` bytes; nil when it does not fit.
|
|
68
|
+
func padded(to size: Int) -> [UInt8]? {
|
|
69
|
+
let b = bytes
|
|
70
|
+
guard b.count <= size else { return nil }
|
|
71
|
+
return [UInt8](repeating: 0, count: size - b.count) + b
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var uint64: UInt64? {
|
|
75
|
+
guard limbs.count <= 2 else { return nil }
|
|
76
|
+
return limbs.enumerated().reduce(UInt64(0)) { $0 | UInt64($1.element) << (32 * UInt64($1.offset)) }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static func power2(_ n: Int) -> BigUInt {
|
|
80
|
+
var l = [UInt32](repeating: 0, count: n / 32 + 1)
|
|
81
|
+
l[n / 32] = 1 << UInt32(n % 32)
|
|
82
|
+
return BigUInt(limbs: l)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func adding(_ small: UInt32) -> BigUInt { self + BigUInt(UInt64(small)) }
|
|
86
|
+
|
|
87
|
+
func multiplied(by small: UInt32) -> BigUInt { self * BigUInt(UInt64(small)) }
|
|
88
|
+
|
|
89
|
+
static func + (a: BigUInt, b: BigUInt) -> BigUInt {
|
|
90
|
+
var out = [UInt32]()
|
|
91
|
+
var carry: UInt64 = 0
|
|
92
|
+
for i in 0..<Swift.max(a.limbs.count, b.limbs.count) {
|
|
93
|
+
let s = UInt64(i < a.limbs.count ? a.limbs[i] : 0) + UInt64(i < b.limbs.count ? b.limbs[i] : 0) + carry
|
|
94
|
+
out.append(UInt32(truncatingIfNeeded: s))
|
|
95
|
+
carry = s >> 32
|
|
96
|
+
}
|
|
97
|
+
if carry > 0 { out.append(UInt32(carry)) }
|
|
98
|
+
return BigUInt(limbs: out)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/// a - b for a >= b.
|
|
102
|
+
static func - (a: BigUInt, b: BigUInt) -> BigUInt {
|
|
103
|
+
precondition(a >= b)
|
|
104
|
+
var out = [UInt32]()
|
|
105
|
+
var borrow: Int64 = 0
|
|
106
|
+
for i in 0..<a.limbs.count {
|
|
107
|
+
var d = Int64(a.limbs[i]) - Int64(i < b.limbs.count ? b.limbs[i] : 0) - borrow
|
|
108
|
+
borrow = 0
|
|
109
|
+
if d < 0 { d += 1 << 32; borrow = 1 }
|
|
110
|
+
out.append(UInt32(d))
|
|
111
|
+
}
|
|
112
|
+
return BigUInt(limbs: out)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static func * (a: BigUInt, b: BigUInt) -> BigUInt {
|
|
116
|
+
if a.isZero || b.isZero { return BigUInt() }
|
|
117
|
+
var out = [UInt32](repeating: 0, count: a.limbs.count + b.limbs.count)
|
|
118
|
+
for i in 0..<a.limbs.count {
|
|
119
|
+
var carry: UInt64 = 0
|
|
120
|
+
for j in 0..<b.limbs.count {
|
|
121
|
+
let t = UInt64(a.limbs[i]) * UInt64(b.limbs[j]) + UInt64(out[i + j]) + carry
|
|
122
|
+
out[i + j] = UInt32(truncatingIfNeeded: t)
|
|
123
|
+
carry = t >> 32
|
|
124
|
+
}
|
|
125
|
+
out[i + b.limbs.count] = UInt32(carry)
|
|
126
|
+
}
|
|
127
|
+
return BigUInt(limbs: out)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
func quotientAndRemainder(dividingBy d: UInt32) -> (BigUInt, UInt32) {
|
|
131
|
+
var q = [UInt32](repeating: 0, count: limbs.count)
|
|
132
|
+
var rem: UInt64 = 0
|
|
133
|
+
for i in stride(from: limbs.count - 1, through: 0, by: -1) {
|
|
134
|
+
let cur = rem << 32 | UInt64(limbs[i])
|
|
135
|
+
q[i] = UInt32(cur / UInt64(d))
|
|
136
|
+
rem = cur % UInt64(d)
|
|
137
|
+
}
|
|
138
|
+
return (BigUInt(limbs: q), UInt32(rem))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
var description: String {
|
|
142
|
+
if isZero { return "0" }
|
|
143
|
+
var parts = [String]()
|
|
144
|
+
var v = self
|
|
145
|
+
while !v.isZero {
|
|
146
|
+
let (q, r) = v.quotientAndRemainder(dividingBy: 1_000_000_000)
|
|
147
|
+
parts.append(String(r))
|
|
148
|
+
v = q
|
|
149
|
+
}
|
|
150
|
+
var out = parts.removeLast()
|
|
151
|
+
for p in parts.reversed() { out += String(repeating: "0", count: 9 - p.count) + p }
|
|
152
|
+
return out
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static func < (a: BigUInt, b: BigUInt) -> Bool {
|
|
156
|
+
if a.limbs.count != b.limbs.count { return a.limbs.count < b.limbs.count }
|
|
157
|
+
for i in stride(from: a.limbs.count - 1, through: 0, by: -1) where a.limbs[i] != b.limbs[i] {
|
|
158
|
+
return a.limbs[i] < b.limbs[i]
|
|
159
|
+
}
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// Signed integer with JavaScript `BigInt()` parsing semantics.
|
|
165
|
+
struct BigInteger: Equatable, CustomStringConvertible {
|
|
166
|
+
var negative: Bool
|
|
167
|
+
var magnitude: BigUInt
|
|
168
|
+
|
|
169
|
+
init(_ magnitude: BigUInt, negative: Bool = false) {
|
|
170
|
+
self.magnitude = magnitude
|
|
171
|
+
self.negative = negative && !magnitude.isZero
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// `BigInt(string)`: surrounding whitespace ignored, empty is 0, 0x/0o/0b prefixes, optional sign for decimals.
|
|
175
|
+
init?(jsString raw: String) {
|
|
176
|
+
let s = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
177
|
+
if s.isEmpty { self.init(BigUInt()); return }
|
|
178
|
+
let lower = s.lowercased()
|
|
179
|
+
if lower.hasPrefix("0x") {
|
|
180
|
+
guard let v = BigUInt(hexDigits: String(s.dropFirst(2))) else { return nil }
|
|
181
|
+
self.init(v)
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
if lower.hasPrefix("0o") || lower.hasPrefix("0b") {
|
|
185
|
+
let radix: UInt32 = lower.hasPrefix("0o") ? 8 : 2
|
|
186
|
+
let digits = s.dropFirst(2)
|
|
187
|
+
guard !digits.isEmpty else { return nil }
|
|
188
|
+
var v = BigUInt()
|
|
189
|
+
for c in digits.utf8 {
|
|
190
|
+
let d = UInt32(c) &- 0x30
|
|
191
|
+
guard d < radix else { return nil }
|
|
192
|
+
v = v.multiplied(by: radix).adding(d)
|
|
193
|
+
}
|
|
194
|
+
self.init(v)
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
var body = Substring(s)
|
|
198
|
+
var neg = false
|
|
199
|
+
if body.hasPrefix("-") { neg = true; body = body.dropFirst() } else if body.hasPrefix("+") { body = body.dropFirst() }
|
|
200
|
+
guard let v = BigUInt(decimal: String(body)) else { return nil }
|
|
201
|
+
self.init(v, negative: neg)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
var description: String { (negative ? "-" : "") + magnitude.description }
|
|
205
|
+
|
|
206
|
+
/// 32-byte two's complement.
|
|
207
|
+
func word() -> [UInt8]? {
|
|
208
|
+
if !negative { return magnitude.padded(to: 32) }
|
|
209
|
+
let mod = BigUInt.power2(256)
|
|
210
|
+
guard magnitude <= BigUInt.power2(255) else { return nil }
|
|
211
|
+
return (mod - magnitude).padded(to: 32)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/// Range check for uintN / intN.
|
|
215
|
+
func fits(bits: Int, signed: Bool) -> Bool {
|
|
216
|
+
if !signed { return !negative && magnitude.bitWidth <= bits }
|
|
217
|
+
if negative { return magnitude <= BigUInt.power2(bits - 1) }
|
|
218
|
+
return magnitude < BigUInt.power2(bits - 1)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from swift/Sources/AuthonWallet/Support/Bytes.swift. Do not edit: change the source and run the script.
|
|
2
|
+
import CryptoKit
|
|
3
|
+
import Foundation
|
|
4
|
+
import Security
|
|
5
|
+
|
|
6
|
+
enum Bytes {
|
|
7
|
+
static func random(_ count: Int) throws -> [UInt8] {
|
|
8
|
+
var out = [UInt8](repeating: 0, count: count)
|
|
9
|
+
let status = out.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, count, $0.baseAddress!) }
|
|
10
|
+
guard status == errSecSuccess else { throw WalletError(.internal, "random source unavailable") }
|
|
11
|
+
return out
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static func sha256(_ data: [UInt8]) -> [UInt8] { Array(SHA256.hash(data: data)) }
|
|
15
|
+
|
|
16
|
+
static func wipe(_ buffers: inout [UInt8]) {
|
|
17
|
+
buffers.withUnsafeMutableBytes { raw in
|
|
18
|
+
if let base = raw.baseAddress { memset_s(base, raw.count, 0, raw.count) }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// MARK: - Hex
|
|
23
|
+
|
|
24
|
+
static func hex(_ bytes: [UInt8], prefix: Bool = false) -> String {
|
|
25
|
+
let digits = Array("0123456789abcdef".utf8)
|
|
26
|
+
var out = [UInt8]()
|
|
27
|
+
out.reserveCapacity(bytes.count * 2 + 2)
|
|
28
|
+
if prefix { out += [0x30, 0x78] }
|
|
29
|
+
for b in bytes {
|
|
30
|
+
out.append(digits[Int(b >> 4)])
|
|
31
|
+
out.append(digits[Int(b & 0x0f)])
|
|
32
|
+
}
|
|
33
|
+
return String(decoding: out, as: UTF8.self)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// Strict hex decoding with an optional 0x prefix. An odd digit count is left-padded with 0 like viem.
|
|
37
|
+
static func fromHex(_ value: String, requirePrefix: Bool = false) -> [UInt8]? {
|
|
38
|
+
var body = Substring(value)
|
|
39
|
+
if body.hasPrefix("0x") || body.hasPrefix("0X") { body = body.dropFirst(2) } else if requirePrefix { return nil }
|
|
40
|
+
var chars = Array(body.utf8)
|
|
41
|
+
if chars.count % 2 == 1 { chars.insert(0x30, at: 0) }
|
|
42
|
+
var out = [UInt8]()
|
|
43
|
+
out.reserveCapacity(chars.count / 2)
|
|
44
|
+
var i = 0
|
|
45
|
+
while i < chars.count {
|
|
46
|
+
guard let hi = nibble(chars[i]), let lo = nibble(chars[i + 1]) else { return nil }
|
|
47
|
+
out.append(hi << 4 | lo)
|
|
48
|
+
i += 2
|
|
49
|
+
}
|
|
50
|
+
return out
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static func isHex(_ value: String) -> Bool {
|
|
54
|
+
guard value.hasPrefix("0x") else { return false }
|
|
55
|
+
return value.utf8.dropFirst(2).allSatisfy { nibble($0) != nil }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private static func nibble(_ c: UInt8) -> UInt8? {
|
|
59
|
+
switch c {
|
|
60
|
+
case 0x30...0x39: return c - 0x30
|
|
61
|
+
case 0x61...0x66: return c - 0x61 + 10
|
|
62
|
+
case 0x41...0x46: return c - 0x41 + 10
|
|
63
|
+
default: return nil
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// MARK: - Base64
|
|
68
|
+
|
|
69
|
+
static func base64(_ bytes: [UInt8]) -> String { Data(bytes).base64EncodedString() }
|
|
70
|
+
|
|
71
|
+
static func base64url(_ bytes: [UInt8]) -> String {
|
|
72
|
+
base64(bytes).replacingOccurrences(of: "+", with: "-").replacingOccurrences(of: "/", with: "_")
|
|
73
|
+
.replacingOccurrences(of: "=", with: "")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Accepts standard and URL-safe alphabets, with or without padding (like the frame's fromBase64).
|
|
77
|
+
static func fromBase64(_ value: String) -> [UInt8]? {
|
|
78
|
+
var s = value.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
|
|
79
|
+
let rem = s.count % 4
|
|
80
|
+
if rem == 1 { return nil }
|
|
81
|
+
if rem > 0 { s += String(repeating: "=", count: 4 - rem) }
|
|
82
|
+
guard let data = Data(base64Encoded: s) else { return nil }
|
|
83
|
+
return Array(data)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
extension Array where Element == UInt8 {
|
|
88
|
+
mutating func wipe() { Bytes.wipe(&self) }
|
|
89
|
+
}
|