@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,176 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from kotlin/authon/src/main/kotlin/dev/authon/sdk/wallet/Eip712.kt. Do not edit: change the source and run the script.
|
|
2
|
+
package dev.authon.sdk.wallet
|
|
3
|
+
|
|
4
|
+
import kotlinx.serialization.json.JsonArray
|
|
5
|
+
import kotlinx.serialization.json.JsonElement
|
|
6
|
+
import kotlinx.serialization.json.JsonObject
|
|
7
|
+
import kotlinx.serialization.json.JsonPrimitive
|
|
8
|
+
import kotlinx.serialization.json.booleanOrNull
|
|
9
|
+
import kotlinx.serialization.json.contentOrNull
|
|
10
|
+
import org.web3j.crypto.Hash
|
|
11
|
+
import org.web3j.crypto.Keys
|
|
12
|
+
import java.math.BigInteger
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* EIP-712 v4 hashing with viem's rules (hashTypedData): the EIP712Domain type is derived from the
|
|
16
|
+
* domain fields present unless the request supplies one, dependencies are sorted, arrays hash the
|
|
17
|
+
* concatenated element encodings, and signed integers are 256-bit two's complement. Keccak comes
|
|
18
|
+
* from web3j; only the encoding is assembled here.
|
|
19
|
+
*/
|
|
20
|
+
internal object Eip712 {
|
|
21
|
+
data class Field(val name: String, val type: String)
|
|
22
|
+
|
|
23
|
+
private val INT_TYPE = Regex("^(u?)int([0-9]*)$")
|
|
24
|
+
private val BYTES_N = Regex("^bytes([0-9]+)$")
|
|
25
|
+
private val ADDRESS = Regex("^0x[0-9a-fA-F]{40}$")
|
|
26
|
+
private val TWO_256: BigInteger = BigInteger.ONE.shiftLeft(256)
|
|
27
|
+
|
|
28
|
+
fun hashTypedData(typedData: JsonObject): ByteArray {
|
|
29
|
+
val domain = typedData["domain"] as? JsonObject ?: JsonObject(emptyMap())
|
|
30
|
+
val primaryType = (typedData["primaryType"] as? JsonPrimitive)?.contentOrNull
|
|
31
|
+
?: throw invalid("primaryType missing")
|
|
32
|
+
val provided = parseTypes(typedData["types"] as? JsonObject ?: throw invalid("types missing"))
|
|
33
|
+
val types = LinkedHashMap<String, List<Field>>()
|
|
34
|
+
types["EIP712Domain"] = domainFields(domain)
|
|
35
|
+
types.putAll(provided)
|
|
36
|
+
val parts = mutableListOf(byteArrayOf(0x19, 0x01), hashStruct("EIP712Domain", domain, types))
|
|
37
|
+
if (primaryType != "EIP712Domain") {
|
|
38
|
+
val message = typedData["message"] as? JsonObject ?: throw invalid("message missing")
|
|
39
|
+
parts += hashStruct(primaryType, message, types)
|
|
40
|
+
}
|
|
41
|
+
return Hash.sha3(Bytes.concat(*parts.toTypedArray()))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fun parseTypes(obj: JsonObject): Map<String, List<Field>> = obj.mapValues { (name, fields) ->
|
|
45
|
+
(fields as? JsonArray ?: throw invalid("type $name must be an array")).map { f ->
|
|
46
|
+
val o = f as? JsonObject ?: throw invalid("field of $name must be an object")
|
|
47
|
+
Field(
|
|
48
|
+
(o["name"] as? JsonPrimitive)?.contentOrNull ?: throw invalid("field name missing in $name"),
|
|
49
|
+
(o["type"] as? JsonPrimitive)?.contentOrNull ?: throw invalid("field type missing in $name"),
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** viem getTypesForEIP712Domain. */
|
|
55
|
+
private fun domainFields(domain: JsonObject): List<Field> = buildList {
|
|
56
|
+
val name = domain["name"] as? JsonPrimitive
|
|
57
|
+
if (name != null && name.isString) add(Field("name", "string"))
|
|
58
|
+
val version = domain["version"] as? JsonPrimitive
|
|
59
|
+
if (version != null && truthy(version)) add(Field("version", "string"))
|
|
60
|
+
val chainId = domain["chainId"] as? JsonPrimitive
|
|
61
|
+
if (chainId != null && !chainId.isString && chainId.booleanOrNull == null && chainId.contentOrNull != null) {
|
|
62
|
+
add(Field("chainId", "uint256"))
|
|
63
|
+
}
|
|
64
|
+
val vc = domain["verifyingContract"] as? JsonPrimitive
|
|
65
|
+
if (vc != null && truthy(vc)) add(Field("verifyingContract", "address"))
|
|
66
|
+
val salt = domain["salt"] as? JsonPrimitive
|
|
67
|
+
if (salt != null && truthy(salt)) add(Field("salt", "bytes32"))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private fun truthy(p: JsonPrimitive): Boolean {
|
|
71
|
+
val c = p.contentOrNull ?: return false
|
|
72
|
+
if (p.isString) return c.isNotEmpty()
|
|
73
|
+
p.booleanOrNull?.let { return it }
|
|
74
|
+
return c.toBigDecimalOrNull()?.signum() != 0
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fun encodeType(primaryType: String, types: Map<String, List<Field>>): String {
|
|
78
|
+
val deps = LinkedHashSet<String>()
|
|
79
|
+
findDependencies(primaryType, types, deps)
|
|
80
|
+
val ordered = listOf(primaryType) + deps.filter { it != primaryType }.sorted()
|
|
81
|
+
return ordered.joinToString("") { t ->
|
|
82
|
+
"$t(" + types.getValue(t).joinToString(",") { "${it.type} ${it.name}" } + ")"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private fun findDependencies(type: String, types: Map<String, List<Field>>, out: MutableSet<String>) {
|
|
87
|
+
val base = Regex("^\\w*").find(type)?.value ?: ""
|
|
88
|
+
if (base in out || types[base] == null) return
|
|
89
|
+
out += base
|
|
90
|
+
for (f in types.getValue(base)) findDependencies(f.type, types, out)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fun hashStruct(type: String, data: JsonObject, types: Map<String, List<Field>>): ByteArray {
|
|
94
|
+
val fields = types[type] ?: throw invalid("unknown type $type")
|
|
95
|
+
val parts = ArrayList<ByteArray>(fields.size + 1)
|
|
96
|
+
parts += Hash.sha3(Bytes.utf8(encodeType(type, types)))
|
|
97
|
+
for (f in fields) parts += encodeField(f.type, data[f.name], types)
|
|
98
|
+
return Hash.sha3(Bytes.concat(*parts.toTypedArray()))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private fun encodeField(type: String, value: JsonElement?, types: Map<String, List<Field>>): ByteArray {
|
|
102
|
+
if (types[type] != null) {
|
|
103
|
+
val obj = value as? JsonObject ?: throw invalid("$type value must be an object")
|
|
104
|
+
return hashStruct(type, obj, types)
|
|
105
|
+
}
|
|
106
|
+
if (type.endsWith("]")) {
|
|
107
|
+
val open = type.lastIndexOf('[')
|
|
108
|
+
val inner = type.substring(0, open)
|
|
109
|
+
val len = type.substring(open + 1, type.length - 1)
|
|
110
|
+
val arr = value as? JsonArray ?: throw invalid("$type value must be an array")
|
|
111
|
+
if (len.isNotEmpty() && len.toIntOrNull() != arr.size) throw invalid("$type expects $len elements")
|
|
112
|
+
return Hash.sha3(Bytes.concat(*arr.map { encodeField(inner, it, types) }.toTypedArray()))
|
|
113
|
+
}
|
|
114
|
+
val p = value as? JsonPrimitive ?: throw invalid("missing value for $type")
|
|
115
|
+
return when {
|
|
116
|
+
type == "string" -> {
|
|
117
|
+
if (!p.isString) throw invalid("string value expected")
|
|
118
|
+
Hash.sha3(Bytes.utf8(p.content))
|
|
119
|
+
}
|
|
120
|
+
type == "bytes" -> {
|
|
121
|
+
if (!p.isString) throw invalid("hex value expected")
|
|
122
|
+
Hash.sha3(Bytes.fromHexOrNull(p.content)?.takeIf { p.content.startsWith("0x") } ?: throw invalid("bytes must be 0x hex"))
|
|
123
|
+
}
|
|
124
|
+
type == "bool" -> {
|
|
125
|
+
val b = if (p.isString) null else p.booleanOrNull
|
|
126
|
+
word(if (b ?: throw invalid("boolean value expected")) BigInteger.ONE else BigInteger.ZERO)
|
|
127
|
+
}
|
|
128
|
+
type == "address" -> {
|
|
129
|
+
val a = p.contentOrNull?.takeIf { p.isString } ?: throw invalid("address expected")
|
|
130
|
+
word(BigInteger(1, Bytes.fromHex(checkAddress(a))))
|
|
131
|
+
}
|
|
132
|
+
INT_TYPE.matches(type) -> {
|
|
133
|
+
val m = INT_TYPE.find(type)!!
|
|
134
|
+
val signed = m.groupValues[1].isEmpty()
|
|
135
|
+
val bits = m.groupValues[2].ifEmpty { "256" }.toInt()
|
|
136
|
+
if (bits < 8 || bits > 256 || bits % 8 != 0) throw invalid("invalid integer type $type")
|
|
137
|
+
val v = JsValues.toBigIntOrNull(p) ?: throw invalid("integer value expected for $type")
|
|
138
|
+
val (min, max) = if (signed) {
|
|
139
|
+
BigInteger.ONE.shiftLeft(bits - 1).negate() to BigInteger.ONE.shiftLeft(bits - 1).subtract(BigInteger.ONE)
|
|
140
|
+
} else {
|
|
141
|
+
BigInteger.ZERO to BigInteger.ONE.shiftLeft(bits).subtract(BigInteger.ONE)
|
|
142
|
+
}
|
|
143
|
+
if (v < min || v > max) throw invalid("$type value out of range")
|
|
144
|
+
word(if (v.signum() < 0) v.add(TWO_256) else v)
|
|
145
|
+
}
|
|
146
|
+
BYTES_N.matches(type) -> {
|
|
147
|
+
val n = BYTES_N.find(type)!!.groupValues[1].toInt()
|
|
148
|
+
if (n < 1 || n > 32) throw invalid("invalid type $type")
|
|
149
|
+
val bytes = p.contentOrNull?.takeIf { p.isString && it.startsWith("0x") }?.let { Bytes.fromHexOrNull(it) }
|
|
150
|
+
?: throw invalid("$type must be 0x hex")
|
|
151
|
+
if (bytes.size != n) throw invalid("$type expects $n bytes")
|
|
152
|
+
bytes.copyOf(32)
|
|
153
|
+
}
|
|
154
|
+
else -> throw invalid("unsupported type $type")
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** viem isAddress (strict): mixed-case addresses must carry a valid EIP-55 checksum. */
|
|
159
|
+
fun checkAddress(address: String): String {
|
|
160
|
+
if (!ADDRESS.matches(address)) throw invalid("invalid address $address")
|
|
161
|
+
val body = address.substring(2)
|
|
162
|
+
val mixed = body.any { it.isUpperCase() } && body.any { it.isLowerCase() }
|
|
163
|
+
if (mixed && Keys.toChecksumAddress(address) != address) throw invalid("address checksum mismatch $address")
|
|
164
|
+
return address
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private fun word(v: BigInteger): ByteArray {
|
|
168
|
+
val raw = v.toByteArray()
|
|
169
|
+
val out = ByteArray(32)
|
|
170
|
+
val src = if (raw.size > 32) raw.copyOfRange(raw.size - 32, raw.size) else raw
|
|
171
|
+
src.copyInto(out, 32 - src.size)
|
|
172
|
+
return out
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private fun invalid(message: String) = walletError(WalletErrorCode.INVALID_REQUEST, message)
|
|
176
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from kotlin/authon/src/main/kotlin/dev/authon/sdk/wallet/Encodings.kt. Do not edit: change the source and run the script.
|
|
2
|
+
package dev.authon.sdk.wallet
|
|
3
|
+
|
|
4
|
+
import java.math.BigInteger
|
|
5
|
+
|
|
6
|
+
/** Base58 (Bitcoin and XRP alphabets) and Base58Check with a double-SHA-256 checksum. */
|
|
7
|
+
internal object Base58 {
|
|
8
|
+
const val BITCOIN = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
9
|
+
const val XRP = "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
|
|
10
|
+
private val FIFTY_EIGHT = BigInteger.valueOf(58)
|
|
11
|
+
|
|
12
|
+
fun encode(data: ByteArray, alphabet: String = BITCOIN): String {
|
|
13
|
+
var n = BigInteger(1, data)
|
|
14
|
+
val out = StringBuilder()
|
|
15
|
+
while (n.signum() > 0) {
|
|
16
|
+
val (q, r) = n.divideAndRemainder(FIFTY_EIGHT)
|
|
17
|
+
out.append(alphabet[r.toInt()])
|
|
18
|
+
n = q
|
|
19
|
+
}
|
|
20
|
+
for (b in data) {
|
|
21
|
+
if (b.toInt() != 0) break
|
|
22
|
+
out.append(alphabet[0])
|
|
23
|
+
}
|
|
24
|
+
return out.reverse().toString()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun decode(text: String, alphabet: String = BITCOIN): ByteArray {
|
|
28
|
+
var n = BigInteger.ZERO
|
|
29
|
+
for (c in text) {
|
|
30
|
+
val digit = alphabet.indexOf(c)
|
|
31
|
+
if (digit < 0) throw walletError(WalletErrorCode.INVALID_REQUEST, "invalid base58")
|
|
32
|
+
n = n.multiply(FIFTY_EIGHT).add(BigInteger.valueOf(digit.toLong()))
|
|
33
|
+
}
|
|
34
|
+
val body = n.toByteArray().let { if (it.size > 1 && it[0].toInt() == 0) it.copyOfRange(1, it.size) else it }
|
|
35
|
+
val zeros = text.takeWhile { it == alphabet[0] }.length
|
|
36
|
+
return ByteArray(zeros) + if (n.signum() == 0) ByteArray(0) else body
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun encodeCheck(payload: ByteArray, alphabet: String = BITCOIN): String {
|
|
40
|
+
val checksum = Bytes.sha256(Bytes.sha256(payload)).copyOf(4)
|
|
41
|
+
return encode(payload + checksum, alphabet)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Bech32 (BIP173) and Bech32m (BIP350) for segwit addresses. */
|
|
46
|
+
internal object Bech32 {
|
|
47
|
+
private const val BECH32M_CONST = 0x2bc830a3
|
|
48
|
+
private const val CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|
49
|
+
private val GEN = intArrayOf(0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3)
|
|
50
|
+
|
|
51
|
+
private fun polymod(values: IntArray): Int {
|
|
52
|
+
var chk = 1
|
|
53
|
+
for (v in values) {
|
|
54
|
+
val top = chk ushr 25
|
|
55
|
+
chk = ((chk and 0x1ffffff) shl 5) xor v
|
|
56
|
+
for (i in 0 until 5) if ((top ushr i) and 1 == 1) chk = chk xor GEN[i]
|
|
57
|
+
}
|
|
58
|
+
return chk
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun hrpExpand(hrp: String): IntArray =
|
|
62
|
+
IntArray(hrp.length) { hrp[it].code ushr 5 } + intArrayOf(0) + IntArray(hrp.length) { hrp[it].code and 31 }
|
|
63
|
+
|
|
64
|
+
fun encode(hrp: String, data: IntArray, bech32m: Boolean = false): String {
|
|
65
|
+
val values = hrpExpand(hrp) + data + IntArray(6)
|
|
66
|
+
val mod = polymod(values) xor (if (bech32m) BECH32M_CONST else 1)
|
|
67
|
+
val checksum = IntArray(6) { (mod ushr (5 * (5 - it))) and 31 }
|
|
68
|
+
return hrp + "1" + (data + checksum).joinToString("") { CHARSET[it].toString() }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** True when [address] is a valid Bech32 string (checksum and charset); case must not be mixed. */
|
|
72
|
+
fun verify(address: String): Boolean {
|
|
73
|
+
if (address.lowercase() != address && address.uppercase() != address) return false
|
|
74
|
+
val s = address.lowercase()
|
|
75
|
+
val pos = s.lastIndexOf('1')
|
|
76
|
+
if (pos < 1 || pos + 7 > s.length || s.length > 90) return false
|
|
77
|
+
val data = s.substring(pos + 1).map { CHARSET.indexOf(it) }.toIntArray()
|
|
78
|
+
if (data.any { it < 0 }) return false
|
|
79
|
+
return polymod(hrpExpand(s.substring(0, pos)) + data) == 1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** 8-bit bytes to 5-bit groups with padding (BIP173 convertbits). */
|
|
83
|
+
fun toWords(bytes: ByteArray): IntArray {
|
|
84
|
+
val out = ArrayList<Int>()
|
|
85
|
+
var acc = 0
|
|
86
|
+
var bits = 0
|
|
87
|
+
for (b in bytes) {
|
|
88
|
+
acc = (acc shl 8) or (b.toInt() and 0xff)
|
|
89
|
+
bits += 8
|
|
90
|
+
while (bits >= 5) {
|
|
91
|
+
bits -= 5
|
|
92
|
+
out += (acc ushr bits) and 31
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (bits > 0) out += (acc shl (5 - bits)) and 31
|
|
96
|
+
return out.toIntArray()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fun segwitV0(hrp: String, program: ByteArray): String = encode(hrp, intArrayOf(0) + toWords(program))
|
|
100
|
+
|
|
101
|
+
/** Segwit address for witness [version] (v0 bech32, v1+ bech32m). */
|
|
102
|
+
fun segwit(hrp: String, version: Int, program: ByteArray): String = encode(hrp, intArrayOf(version) + toWords(program), version > 0)
|
|
103
|
+
|
|
104
|
+
/** Decodes a segwit address of [hrp] to (version, program); null when it is not one. */
|
|
105
|
+
fun decodeSegwit(hrp: String, address: String): Pair<Int, ByteArray>? {
|
|
106
|
+
if (address.lowercase() != address && address.uppercase() != address) return null
|
|
107
|
+
val s = address.lowercase()
|
|
108
|
+
val pos = s.lastIndexOf('1')
|
|
109
|
+
if (pos < 1 || pos + 7 > s.length || s.length > 90 || s.substring(0, pos) != hrp) return null
|
|
110
|
+
val data = s.substring(pos + 1).map { CHARSET.indexOf(it) }.toIntArray()
|
|
111
|
+
if (data.any { it < 0 }) return null
|
|
112
|
+
val check = polymod(hrpExpand(hrp) + data)
|
|
113
|
+
val words = data.copyOfRange(0, data.size - 6)
|
|
114
|
+
if (words.isEmpty()) return null
|
|
115
|
+
val version = words[0]
|
|
116
|
+
if (version > 16 || check != (if (version == 0) 1 else BECH32M_CONST)) return null
|
|
117
|
+
var acc = 0
|
|
118
|
+
var bits = 0
|
|
119
|
+
val out = ArrayList<Byte>()
|
|
120
|
+
for (w in words.drop(1)) {
|
|
121
|
+
acc = (acc shl 5) or w
|
|
122
|
+
bits += 5
|
|
123
|
+
if (bits >= 8) {
|
|
124
|
+
bits -= 8
|
|
125
|
+
out += ((acc ushr bits) and 0xff).toByte()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (bits >= 5 || (acc and ((1 shl bits) - 1)) != 0) return null
|
|
129
|
+
val program = out.toByteArray()
|
|
130
|
+
if (program.size < 2 || program.size > 40 || (version == 0 && program.size != 20 && program.size != 32)) return null
|
|
131
|
+
return version to program
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from kotlin/authon/src/main/kotlin/dev/authon/sdk/wallet/EvmAccount.kt. Do not edit: change the source and run the script.
|
|
2
|
+
package dev.authon.sdk.wallet
|
|
3
|
+
|
|
4
|
+
import kotlinx.serialization.json.JsonObject
|
|
5
|
+
import org.web3j.crypto.ECKeyPair
|
|
6
|
+
import org.web3j.crypto.Hash
|
|
7
|
+
import org.web3j.crypto.Keys
|
|
8
|
+
import org.web3j.crypto.Sign
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* secp256k1 account backed by web3j (RFC 6979 deterministic, low-s), producing the same bytes as
|
|
12
|
+
* viem's privateKeyToAccount: signatures are r||s||v with v = 27/28.
|
|
13
|
+
* web3j keeps the key as a BigInteger, which cannot be wiped; the object is short-lived.
|
|
14
|
+
*/
|
|
15
|
+
internal class EvmAccount(privateKey: ByteArray) {
|
|
16
|
+
private val keyPair: ECKeyPair = ECKeyPair.create(privateKey)
|
|
17
|
+
|
|
18
|
+
val address: String = Keys.toChecksumAddress(Keys.getAddress(keyPair.publicKey))
|
|
19
|
+
|
|
20
|
+
class Signature(val r: ByteArray, val s: ByteArray, val yParity: Int) {
|
|
21
|
+
fun toHex(): String = "0x" + Bytes.toHex(Bytes.concat(r, s, byteArrayOf((27 + yParity).toByte())))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fun signDigest(digest: ByteArray): Signature {
|
|
25
|
+
require(digest.size == 32) { "digest must be 32 bytes" }
|
|
26
|
+
val sig = Sign.signMessage(digest, keyPair, false)
|
|
27
|
+
val v = sig.v[0].toInt() and 0xff
|
|
28
|
+
return Signature(sig.r, sig.s, v - 27)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** personal_sign (EIP-191 version 0x45) over raw bytes. */
|
|
32
|
+
fun signMessage(message: ByteArray): String = signDigest(personalMessageHash(message)).toHex()
|
|
33
|
+
|
|
34
|
+
fun signTypedData(typedData: JsonObject): String = signDigest(Eip712.hashTypedData(typedData)).toHex()
|
|
35
|
+
|
|
36
|
+
fun signTransaction(tx: EvmTransaction): String {
|
|
37
|
+
val sig = signDigest(Hash.sha3(tx.serialize(null)))
|
|
38
|
+
return "0x" + Bytes.toHex(tx.serialize(sig))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
companion object {
|
|
42
|
+
fun personalMessageHash(message: ByteArray): ByteArray =
|
|
43
|
+
Hash.sha3(Bytes.concat(Bytes.utf8("\u0019Ethereum Signed Message:\n${message.size}"), message))
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from kotlin/authon/src/main/kotlin/dev/authon/sdk/wallet/EvmTransaction.kt. Do not edit: change the source and run the script.
|
|
2
|
+
package dev.authon.sdk.wallet
|
|
3
|
+
|
|
4
|
+
import kotlinx.serialization.json.JsonArray
|
|
5
|
+
import kotlinx.serialization.json.JsonElement
|
|
6
|
+
import kotlinx.serialization.json.JsonNull
|
|
7
|
+
import kotlinx.serialization.json.JsonObject
|
|
8
|
+
import kotlinx.serialization.json.JsonPrimitive
|
|
9
|
+
import kotlinx.serialization.json.contentOrNull
|
|
10
|
+
import org.web3j.rlp.RlpEncoder
|
|
11
|
+
import org.web3j.rlp.RlpList
|
|
12
|
+
import org.web3j.rlp.RlpString
|
|
13
|
+
import org.web3j.rlp.RlpType
|
|
14
|
+
import java.math.BigInteger
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* EVM transaction in the frame's input shape (parseTransaction + viem), serialized exactly like
|
|
18
|
+
* viem's serializeTransaction for legacy (EIP-155), EIP-2930 and EIP-1559, including contract
|
|
19
|
+
* creation. RLP comes from web3j.
|
|
20
|
+
*/
|
|
21
|
+
internal class EvmTransaction(
|
|
22
|
+
val type: Type,
|
|
23
|
+
val chainId: Long,
|
|
24
|
+
val nonce: Long?,
|
|
25
|
+
val gas: BigInteger?,
|
|
26
|
+
val gasPrice: BigInteger?,
|
|
27
|
+
val maxFeePerGas: BigInteger?,
|
|
28
|
+
val maxPriorityFeePerGas: BigInteger?,
|
|
29
|
+
/** Null for a contract creation. */
|
|
30
|
+
val to: String?,
|
|
31
|
+
val value: BigInteger?,
|
|
32
|
+
val data: ByteArray,
|
|
33
|
+
val accessList: List<AccessListEntry>,
|
|
34
|
+
/** The parsed request as the approval summary sees it. */
|
|
35
|
+
val fields: JsonObject,
|
|
36
|
+
) {
|
|
37
|
+
enum class Type { LEGACY, EIP2930, EIP1559 }
|
|
38
|
+
|
|
39
|
+
class AccessListEntry(val address: String, val storageKeys: List<ByteArray>)
|
|
40
|
+
|
|
41
|
+
fun serialize(signature: EvmAccount.Signature?): ByteArray {
|
|
42
|
+
val items = ArrayList<RlpType>()
|
|
43
|
+
fun num(v: BigInteger?) = RlpString.create(v ?: BigInteger.ZERO)
|
|
44
|
+
fun numL(v: Long?) = RlpString.create(BigInteger.valueOf(v ?: 0L))
|
|
45
|
+
val toItem = RlpString.create(to?.let { Bytes.fromHex(it) } ?: ByteArray(0))
|
|
46
|
+
val accessItems: RlpType = RlpList(
|
|
47
|
+
accessList.map { e ->
|
|
48
|
+
RlpList(RlpString.create(Bytes.fromHex(e.address)), RlpList(e.storageKeys.map { RlpString.create(it) }))
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
when (type) {
|
|
52
|
+
Type.LEGACY -> {
|
|
53
|
+
items += listOf(numL(nonce), num(gasPrice), num(gas), toItem, num(value), RlpString.create(data))
|
|
54
|
+
if (signature != null) {
|
|
55
|
+
val v = if (chainId > 0) {
|
|
56
|
+
BigInteger.valueOf(chainId).multiply(BigInteger.TWO).add(BigInteger.valueOf(35L + signature.yParity))
|
|
57
|
+
} else {
|
|
58
|
+
BigInteger.valueOf(27L + signature.yParity)
|
|
59
|
+
}
|
|
60
|
+
items += listOf(RlpString.create(v), sigInt(signature.r), sigInt(signature.s))
|
|
61
|
+
} else if (chainId > 0) {
|
|
62
|
+
items += listOf(numL(chainId), RlpString.create(ByteArray(0)), RlpString.create(ByteArray(0)))
|
|
63
|
+
}
|
|
64
|
+
return RlpEncoder.encode(RlpList(items))
|
|
65
|
+
}
|
|
66
|
+
Type.EIP2930 -> {
|
|
67
|
+
items += listOf(numL(chainId), numL(nonce), num(gasPrice), num(gas), toItem, num(value), RlpString.create(data), accessItems)
|
|
68
|
+
}
|
|
69
|
+
Type.EIP1559 -> {
|
|
70
|
+
items += listOf(
|
|
71
|
+
numL(chainId), numL(nonce), num(maxPriorityFeePerGas), num(maxFeePerGas), num(gas), toItem, num(value),
|
|
72
|
+
RlpString.create(data), accessItems,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (signature != null) {
|
|
77
|
+
items += listOf(RlpString.create(BigInteger.valueOf(signature.yParity.toLong())), sigInt(signature.r), sigInt(signature.s))
|
|
78
|
+
}
|
|
79
|
+
val prefix: Byte = if (type == Type.EIP2930) 0x01 else 0x02
|
|
80
|
+
return byteArrayOf(prefix) + RlpEncoder.encode(RlpList(items))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private fun sigInt(bytes: ByteArray) = RlpString.create(BigInteger(1, bytes))
|
|
84
|
+
|
|
85
|
+
companion object {
|
|
86
|
+
private val BIGINT_FIELDS = listOf("value", "gas", "gasPrice", "maxFeePerGas", "maxPriorityFeePerGas", "maxFeePerBlobGas")
|
|
87
|
+
private val NUMBER_FIELDS = listOf("nonce", "chainId")
|
|
88
|
+
private val MAX_UINT256: BigInteger = BigInteger.ONE.shiftLeft(256).subtract(BigInteger.ONE)
|
|
89
|
+
|
|
90
|
+
/** The frame's parseTransaction followed by viem's type inference and assertions. */
|
|
91
|
+
fun parse(input: JsonObject): EvmTransaction {
|
|
92
|
+
val tx = LinkedHashMap<String, JsonElement>(input)
|
|
93
|
+
val big = HashMap<String, BigInteger>()
|
|
94
|
+
for (f in BIGINT_FIELDS + NUMBER_FIELDS) {
|
|
95
|
+
val raw = tx[f] ?: continue
|
|
96
|
+
if (raw is JsonNull) continue
|
|
97
|
+
val v = JsValues.toBigIntOrNull(raw) ?: throw invalid("transaction numeric field invalid")
|
|
98
|
+
big[f] = v
|
|
99
|
+
tx[f] = JsonPrimitive(v)
|
|
100
|
+
}
|
|
101
|
+
val chainIdBig = big["chainId"] ?: throw invalid("chainId required")
|
|
102
|
+
val chainId = chainIdBig.toLong()
|
|
103
|
+
val nonce = big["nonce"]?.toLong()
|
|
104
|
+
|
|
105
|
+
val explicit = (tx["type"] as? JsonPrimitive)?.contentOrNull
|
|
106
|
+
val type = when (explicit) {
|
|
107
|
+
null -> when {
|
|
108
|
+
big["maxFeePerBlobGas"] != null || tx["blobs"].present() || tx["blobVersionedHashes"].present() ->
|
|
109
|
+
throw walletError(WalletErrorCode.UNSUPPORTED_TYPE, "blob transactions are not supported")
|
|
110
|
+
tx["authorizationList"].present() ->
|
|
111
|
+
throw walletError(WalletErrorCode.UNSUPPORTED_TYPE, "EIP-7702 transactions are not supported")
|
|
112
|
+
big["maxFeePerGas"] != null || big["maxPriorityFeePerGas"] != null -> Type.EIP1559
|
|
113
|
+
big["gasPrice"] != null -> if (tx["accessList"].present()) Type.EIP2930 else Type.LEGACY
|
|
114
|
+
else -> throw invalid("cannot infer the transaction type")
|
|
115
|
+
}
|
|
116
|
+
"legacy", "0x0" -> Type.LEGACY
|
|
117
|
+
"eip2930", "0x1" -> Type.EIP2930
|
|
118
|
+
"eip1559", "0x2" -> Type.EIP1559
|
|
119
|
+
else -> throw walletError(WalletErrorCode.UNSUPPORTED_TYPE, "transaction type $explicit is not supported")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
val toRaw = tx["to"]
|
|
123
|
+
val to = when {
|
|
124
|
+
toRaw == null || toRaw is JsonNull -> null
|
|
125
|
+
toRaw is JsonPrimitive && toRaw.isString && toRaw.content.isEmpty() -> null
|
|
126
|
+
toRaw is JsonPrimitive && toRaw.isString -> Eip712.checkAddress(toRaw.content)
|
|
127
|
+
else -> throw invalid("to must be an address")
|
|
128
|
+
}
|
|
129
|
+
val dataRaw = tx["data"]
|
|
130
|
+
val data = when {
|
|
131
|
+
dataRaw == null || dataRaw is JsonNull -> ByteArray(0)
|
|
132
|
+
dataRaw is JsonPrimitive && dataRaw.isString && dataRaw.content.startsWith("0x") ->
|
|
133
|
+
Bytes.fromHexOrNull(dataRaw.content) ?: throw invalid("data must be hex")
|
|
134
|
+
else -> throw invalid("data must be 0x hex")
|
|
135
|
+
}
|
|
136
|
+
val accessList = parseAccessList(tx["accessList"])
|
|
137
|
+
|
|
138
|
+
val gasPrice = big["gasPrice"]
|
|
139
|
+
val maxFee = big["maxFeePerGas"]
|
|
140
|
+
val maxTip = big["maxPriorityFeePerGas"]
|
|
141
|
+
if (chainId <= 0 && type != Type.LEGACY) throw invalid("invalid chainId")
|
|
142
|
+
if (type == Type.LEGACY && tx["chainId"] != null && chainId <= 0) throw invalid("invalid chainId")
|
|
143
|
+
when (type) {
|
|
144
|
+
Type.LEGACY, Type.EIP2930 -> {
|
|
145
|
+
if (maxFee != null || maxTip != null) throw invalid("maxFeePerGas/maxPriorityFeePerGas are not valid for this type")
|
|
146
|
+
if (gasPrice != null && gasPrice > MAX_UINT256) throw invalid("gasPrice too high")
|
|
147
|
+
}
|
|
148
|
+
Type.EIP1559 -> {
|
|
149
|
+
if (maxFee != null && maxFee > MAX_UINT256) throw invalid("maxFeePerGas too high")
|
|
150
|
+
if (maxTip != null && maxFee != null && maxTip > maxFee) throw invalid("maxPriorityFeePerGas above maxFeePerGas")
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for ((k, v) in big) if (v.signum() < 0) throw invalid("$k must not be negative")
|
|
154
|
+
if (type == Type.LEGACY && accessList.isNotEmpty()) throw invalid("accessList is not valid for legacy transactions")
|
|
155
|
+
|
|
156
|
+
return EvmTransaction(
|
|
157
|
+
type, chainId, nonce, big["gas"], gasPrice, maxFee, maxTip, to, big["value"], data, accessList, JsonObject(tx),
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private fun parseAccessList(raw: JsonElement?): List<AccessListEntry> {
|
|
162
|
+
if (raw == null || raw is JsonNull) return emptyList()
|
|
163
|
+
val arr = raw as? JsonArray ?: throw invalid("accessList must be an array")
|
|
164
|
+
return arr.map { item ->
|
|
165
|
+
val o = item as? JsonObject ?: throw invalid("accessList entry must be an object")
|
|
166
|
+
val address = (o["address"] as? JsonPrimitive)?.contentOrNull ?: throw invalid("accessList address missing")
|
|
167
|
+
val keys = (o["storageKeys"] as? JsonArray ?: JsonArray(emptyList())).map { k ->
|
|
168
|
+
val hex = (k as? JsonPrimitive)?.contentOrNull ?: throw invalid("storage key must be hex")
|
|
169
|
+
if (hex.length != 66) throw invalid("storage key must be 32 bytes")
|
|
170
|
+
Bytes.fromHexOrNull(hex) ?: throw invalid("storage key must be hex")
|
|
171
|
+
}
|
|
172
|
+
AccessListEntry(Eip712.checkAddress(address), keys)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun JsonElement?.present(): Boolean = this != null && this !is JsonNull
|
|
177
|
+
|
|
178
|
+
private fun invalid(message: String) = walletError(WalletErrorCode.INVALID_REQUEST, message)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// GENERATED by scripts/sync-native-wallet.mjs from kotlin/authon/src/main/kotlin/dev/authon/sdk/wallet/GfTables.kt. Do not edit: change the source and run the script.
|
|
2
|
+
package dev.authon.sdk.wallet
|
|
3
|
+
|
|
4
|
+
// GF(2^8) tables of the shamir-secret-sharing JS library (polynomial x^8+x^4+x^3+x+1, generator 0xe5),
|
|
5
|
+
// copied verbatim so combine/split/deriveShare produce the same bytes as the web frame.
|
|
6
|
+
internal object GfTables {
|
|
7
|
+
val LOG: IntArray = intArrayOf(
|
|
8
|
+
0x00, 0xff, 0xc8, 0x08, 0x91, 0x10, 0xd0, 0x36, 0x5a, 0x3e, 0xd8, 0x43, 0x99, 0x77, 0xfe, 0x18,
|
|
9
|
+
0x23, 0x20, 0x07, 0x70, 0xa1, 0x6c, 0x0c, 0x7f, 0x62, 0x8b, 0x40, 0x46, 0xc7, 0x4b, 0xe0, 0x0e,
|
|
10
|
+
0xeb, 0x16, 0xe8, 0xad, 0xcf, 0xcd, 0x39, 0x53, 0x6a, 0x27, 0x35, 0x93, 0xd4, 0x4e, 0x48, 0xc3,
|
|
11
|
+
0x2b, 0x79, 0x54, 0x28, 0x09, 0x78, 0x0f, 0x21, 0x90, 0x87, 0x14, 0x2a, 0xa9, 0x9c, 0xd6, 0x74,
|
|
12
|
+
0xb4, 0x7c, 0xde, 0xed, 0xb1, 0x86, 0x76, 0xa4, 0x98, 0xe2, 0x96, 0x8f, 0x02, 0x32, 0x1c, 0xc1,
|
|
13
|
+
0x33, 0xee, 0xef, 0x81, 0xfd, 0x30, 0x5c, 0x13, 0x9d, 0x29, 0x17, 0xc4, 0x11, 0x44, 0x8c, 0x80,
|
|
14
|
+
0xf3, 0x73, 0x42, 0x1e, 0x1d, 0xb5, 0xf0, 0x12, 0xd1, 0x5b, 0x41, 0xa2, 0xd7, 0x2c, 0xe9, 0xd5,
|
|
15
|
+
0x59, 0xcb, 0x50, 0xa8, 0xdc, 0xfc, 0xf2, 0x56, 0x72, 0xa6, 0x65, 0x2f, 0x9f, 0x9b, 0x3d, 0xba,
|
|
16
|
+
0x7d, 0xc2, 0x45, 0x82, 0xa7, 0x57, 0xb6, 0xa3, 0x7a, 0x75, 0x4f, 0xae, 0x3f, 0x37, 0x6d, 0x47,
|
|
17
|
+
0x61, 0xbe, 0xab, 0xd3, 0x5f, 0xb0, 0x58, 0xaf, 0xca, 0x5e, 0xfa, 0x85, 0xe4, 0x4d, 0x8a, 0x05,
|
|
18
|
+
0xfb, 0x60, 0xb7, 0x7b, 0xb8, 0x26, 0x4a, 0x67, 0xc6, 0x1a, 0xf8, 0x69, 0x25, 0xb3, 0xdb, 0xbd,
|
|
19
|
+
0x66, 0xdd, 0xf1, 0xd2, 0xdf, 0x03, 0x8d, 0x34, 0xd9, 0x92, 0x0d, 0x63, 0x55, 0xaa, 0x49, 0xec,
|
|
20
|
+
0xbc, 0x95, 0x3c, 0x84, 0x0b, 0xf5, 0xe6, 0xe7, 0xe5, 0xac, 0x7e, 0x6e, 0xb9, 0xf9, 0xda, 0x8e,
|
|
21
|
+
0x9a, 0xc9, 0x24, 0xe1, 0x0a, 0x15, 0x6b, 0x3a, 0xa0, 0x51, 0xf4, 0xea, 0xb2, 0x97, 0x9e, 0x5d,
|
|
22
|
+
0x22, 0x88, 0x94, 0xce, 0x19, 0x01, 0x71, 0x4c, 0xa5, 0xe3, 0xc5, 0x31, 0xbb, 0xcc, 0x1f, 0x2d,
|
|
23
|
+
0x3b, 0x52, 0x6f, 0xf6, 0x2e, 0x89, 0xf7, 0xc0, 0x68, 0x1b, 0x64, 0x04, 0x06, 0xbf, 0x83, 0x38,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
val EXP: IntArray = intArrayOf(
|
|
27
|
+
0x01, 0xe5, 0x4c, 0xb5, 0xfb, 0x9f, 0xfc, 0x12, 0x03, 0x34, 0xd4, 0xc4, 0x16, 0xba, 0x1f, 0x36,
|
|
28
|
+
0x05, 0x5c, 0x67, 0x57, 0x3a, 0xd5, 0x21, 0x5a, 0x0f, 0xe4, 0xa9, 0xf9, 0x4e, 0x64, 0x63, 0xee,
|
|
29
|
+
0x11, 0x37, 0xe0, 0x10, 0xd2, 0xac, 0xa5, 0x29, 0x33, 0x59, 0x3b, 0x30, 0x6d, 0xef, 0xf4, 0x7b,
|
|
30
|
+
0x55, 0xeb, 0x4d, 0x50, 0xb7, 0x2a, 0x07, 0x8d, 0xff, 0x26, 0xd7, 0xf0, 0xc2, 0x7e, 0x09, 0x8c,
|
|
31
|
+
0x1a, 0x6a, 0x62, 0x0b, 0x5d, 0x82, 0x1b, 0x8f, 0x2e, 0xbe, 0xa6, 0x1d, 0xe7, 0x9d, 0x2d, 0x8a,
|
|
32
|
+
0x72, 0xd9, 0xf1, 0x27, 0x32, 0xbc, 0x77, 0x85, 0x96, 0x70, 0x08, 0x69, 0x56, 0xdf, 0x99, 0x94,
|
|
33
|
+
0xa1, 0x90, 0x18, 0xbb, 0xfa, 0x7a, 0xb0, 0xa7, 0xf8, 0xab, 0x28, 0xd6, 0x15, 0x8e, 0xcb, 0xf2,
|
|
34
|
+
0x13, 0xe6, 0x78, 0x61, 0x3f, 0x89, 0x46, 0x0d, 0x35, 0x31, 0x88, 0xa3, 0x41, 0x80, 0xca, 0x17,
|
|
35
|
+
0x5f, 0x53, 0x83, 0xfe, 0xc3, 0x9b, 0x45, 0x39, 0xe1, 0xf5, 0x9e, 0x19, 0x5e, 0xb6, 0xcf, 0x4b,
|
|
36
|
+
0x38, 0x04, 0xb9, 0x2b, 0xe2, 0xc1, 0x4a, 0xdd, 0x48, 0x0c, 0xd0, 0x7d, 0x3d, 0x58, 0xde, 0x7c,
|
|
37
|
+
0xd8, 0x14, 0x6b, 0x87, 0x47, 0xe8, 0x79, 0x84, 0x73, 0x3c, 0xbd, 0x92, 0xc9, 0x23, 0x8b, 0x97,
|
|
38
|
+
0x95, 0x44, 0xdc, 0xad, 0x40, 0x65, 0x86, 0xa2, 0xa4, 0xcc, 0x7f, 0xec, 0xc0, 0xaf, 0x91, 0xfd,
|
|
39
|
+
0xf7, 0x4f, 0x81, 0x2f, 0x5b, 0xea, 0xa8, 0x1c, 0x02, 0xd1, 0x98, 0x71, 0xed, 0x25, 0xe3, 0x24,
|
|
40
|
+
0x06, 0x68, 0xb3, 0x93, 0x2c, 0x6f, 0x3e, 0x6c, 0x0a, 0xb8, 0xce, 0xae, 0x74, 0xb1, 0x42, 0xb4,
|
|
41
|
+
0x1e, 0xd3, 0x49, 0xe9, 0x9c, 0xc8, 0xc6, 0xc7, 0x22, 0x6e, 0xdb, 0x20, 0xbf, 0x43, 0x51, 0x52,
|
|
42
|
+
0x66, 0xb2, 0x76, 0x60, 0xda, 0xc5, 0xf3, 0xf6, 0xaa, 0xcd, 0x9a, 0xa0, 0x75, 0x54, 0x0e, 0x01,
|
|
43
|
+
)
|
|
44
|
+
}
|