From fabf5d53a28295557171f950c5961fe36ac25def Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 29 May 2026 09:54:11 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'lib/'=20wi?= =?UTF-8?q?th=20remote=20'lib/'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/consumer-rules.pro | 64 +++++++++++++++++++ .../circle/modularwallets/core/chains/Arc.kt | 24 +++++++ .../core/constants/AbiConstants.kt | 3 +- .../core/models/EIP712TypedData.kt | 15 ++++- .../modularwallets/core/models/Token.kt | 1 + 5 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 lib/consumer-rules.pro create mode 100644 lib/src/main/java/com/circle/modularwallets/core/chains/Arc.kt diff --git a/lib/consumer-rules.pro b/lib/consumer-rules.pro new file mode 100644 index 0000000..de749f0 --- /dev/null +++ b/lib/consumer-rules.pro @@ -0,0 +1,64 @@ +# Consumer ProGuard rules — applied by R8 in the consumer app's build. +# +# These rules ship with the AAR (via consumerProguardFiles in lib/build.gradle.kts) +# and run in addition to whatever rules the consumer app supplies. +# +# Keep narrow targets only. Each block must have a comment explaining why it +# is load-bearing — without that, future maintainers can't tell whether the +# rule is still needed. + +# Preserve the JVM Signature attribute. Jackson reads it at runtime to recover +# generic type information for collection-typed properties — notably +# EIP712Message.types : MutableMap>. Without it, +# Jackson sees the setter as raw `Map`/`List`, deserializes the nested type +# entries as LinkedHashMap, and downstream code (StructuredDataEncoder) then +# ClassCastExceptions when iterating them as Entry. InnerClasses and +# EnclosingMethod are paired per R8's own recommendation — Signature can +# reference inner classes, and stripping the other two leaves dangling refs. +# The default proguard-android(-optimize).txt usually keeps these, but +# consumer R8 configurations vary, so we set them explicitly. +-keepattributes Signature, InnerClasses, EnclosingMethod + +# EIP-712 typed-data DTOs are deserialized by Jackson via reflection +# (see StructuredDataEncoder.parseJSONMessage). Jackson is brought in +# transitively via web3j; jackson-module-kotlin is NOT registered, so +# Jackson falls back to JavaBean-style binding and needs each property's +# public setter to remain reachable. Without these rules, R8 in consumer +# apps strips the setters as unused (Jackson's reflective access is +# invisible to R8) and verifyingContract / chainId / etc. fail to bind +# with `UnrecognizedPropertyException`. +# +# Scope: constructors + getters + setters only. Data-class extras +# (componentN / copy / equals / hashCode / toString) are not on Jackson's +# binding path and can be shrunk/obfuscated freely. +-keepclassmembers class com.circle.modularwallets.core.models.EIP712Domain { + (...); + public *** get*(); + public void set*(***); +} +-keepclassmembers class com.circle.modularwallets.core.models.EIP712Message { + (...); + public *** get*(); + public void set*(***); +} +-keepclassmembers class com.circle.modularwallets.core.models.Entry { + (...); + public *** get*(); + public void set*(***); +} + +# web3j (transitive dependency, used internally by StructuredDataEncoder for +# EIP-712 typed-data hashing). web3j resolves ABI type classes by reflection +# (`Class.forName("org.web3j.abi.datatypes." + name)` in AbiTypes/TypeEncoder), +# so consumer R8 must not rename or strip those datatype classes. Without this +# rule, `hashTypedData(json)` fails at runtime with +# `BaseError: Received an invalid argument for which no constructor exists for the ABI Class …` +# in any minified consumer app. The crypto and utils packages are not reflective +# — SDK code directly imports the entry points (Hash, Sign, Numeric, …) so R8's +# tracer keeps everything reachable through them. No broad `crypto.**` keep +# needed. +-keep class org.web3j.abi.datatypes.** { *; } +-dontwarn org.web3j.** +# web3j drags in SLF4J as a logging facade. Consumer apps that don't ship a +# concrete SLF4J binding would otherwise R8-error on the missing impl class. +-dontwarn org.slf4j.** diff --git a/lib/src/main/java/com/circle/modularwallets/core/chains/Arc.kt b/lib/src/main/java/com/circle/modularwallets/core/chains/Arc.kt new file mode 100644 index 0000000..2280bc8 --- /dev/null +++ b/lib/src/main/java/com/circle/modularwallets/core/chains/Arc.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2025 Circle Internet Group, Inc. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at. + * + * Http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.circle.modularwallets.core.chains + +object Arc : Chain() { + override val chainId: Long + get() = 5042L +} diff --git a/lib/src/main/java/com/circle/modularwallets/core/constants/AbiConstants.kt b/lib/src/main/java/com/circle/modularwallets/core/constants/AbiConstants.kt index e048147..a260704 100644 --- a/lib/src/main/java/com/circle/modularwallets/core/constants/AbiConstants.kt +++ b/lib/src/main/java/com/circle/modularwallets/core/constants/AbiConstants.kt @@ -28,6 +28,7 @@ internal val CONTRACT_ADDRESS: Map = mapOf( Token.Arbitrum_ARB.name to "0x912CE59144191C1204E64559FE8253a0e49E6548", Token.ArbitrumSepolia_USDC.name to "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", Token.ArcTestnet_USDC.name to "0x3600000000000000000000000000000000000000", + Token.Arc_USDC.name to "0x3600000000000000000000000000000000000000", Token.Avalanche_USDC.name to "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", Token.AvalancheFuji_USDC.name to "0x5425890298aed601595a70AB815c96711a31Bc65", Token.Base_USDC.name to "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", @@ -1852,4 +1853,4 @@ val CIRCLE_MSCA_6900_V1_EP07_ABI = """ "type": "receive" } ] -""".trimIndent() \ No newline at end of file +""".trimIndent() diff --git a/lib/src/main/java/com/circle/modularwallets/core/models/EIP712TypedData.kt b/lib/src/main/java/com/circle/modularwallets/core/models/EIP712TypedData.kt index 470b628..e9abdfc 100644 --- a/lib/src/main/java/com/circle/modularwallets/core/models/EIP712TypedData.kt +++ b/lib/src/main/java/com/circle/modularwallets/core/models/EIP712TypedData.kt @@ -22,6 +22,13 @@ import com.circle.modularwallets.core.constants.REPLAY_SAFE_HASH_V1 import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +// The Moshi @JsonClass / @Json annotations stay because the generated +// EIP712*JsonAdapter classes are published public API surface — consumer apps +// that use Moshi (without KotlinJsonAdapterFactory) can depend on them. +// However, the SDK's own typed-data parser uses Jackson +// (StructuredDataEncoder.parseJSONMessage), and that path needs consumer-side +// R8 keep rules in lib/consumer-rules.pro. + @JsonClass(generateAdapter = true) data class EIP712Message @JvmOverloads constructor( @Json(name = "types") var types: MutableMap>? = null, @@ -36,12 +43,18 @@ data class Entry @JvmOverloads constructor( @Json(name = "type") var type: String? = null, ) +// All five canonical EIP712Domain fields must remain `var` — the SDK's +// Jackson-based typed-data parser binds via JavaBean setters (no +// jackson-module-kotlin on the classpath), so a `val` property has no setter +// and Jackson throws UnrecognizedPropertyException for that field in any +// minified consumer app. The structural invariant is asserted by +// EIP712DomainParseTest.canonicalDomainFieldsExposePublicSetters. @JsonClass(generateAdapter = true) data class EIP712Domain @JvmOverloads constructor( @Json(name = "name") var name: String? = null, @Json(name = "version") var version: String? = null, @Json(name = "chainId") var chainId: Long? = null, - @Json(name = "verifyingContract") val verifyingContract: String? = null, + @Json(name = "verifyingContract") var verifyingContract: String? = null, @Json(name = "salt") var salt: String? = null, ) diff --git a/lib/src/main/java/com/circle/modularwallets/core/models/Token.kt b/lib/src/main/java/com/circle/modularwallets/core/models/Token.kt index 61c5d63..01e9841 100644 --- a/lib/src/main/java/com/circle/modularwallets/core/models/Token.kt +++ b/lib/src/main/java/com/circle/modularwallets/core/models/Token.kt @@ -28,6 +28,7 @@ enum class Token { Arbitrum_ARB, ArbitrumSepolia_USDC, ArcTestnet_USDC, + Arc_USDC, Avalanche_USDC, AvalancheFuji_USDC, Base_USDC, From e20057677ba1d4aa5ae65b224c4c04b4b2447017 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 29 May 2026 09:54:11 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'README.md'?= =?UTF-8?q?=20with=20remote=20'README.md'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc838d5..edc2d53 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ Add the maven setting values in `local.properties` file: ```properties mwsdk.maven.url=https://maven.pkg.github.com/circlefin/modularwallets-android-sdk mwsdk.maven.username= -# Fine-grained personal access tokens or classic with package write permission. +# Classic personal access token with `read:packages` scope — GitHub Packages Gradle registry authenticates classic PATs only (fine-grained PATs are not supported here). +# For SSO-enforced orgs, also authorize the PAT for that org — see GitHub Packages auth docs. mwsdk.maven.password= ``` @@ -33,4 +34,4 @@ Add the dependency: dependencies { implementation 'circle.modularwallets:core:version' } -``` \ No newline at end of file +``` From 2201ffc5031c93f404de24d6c65ea22f9aaab9b8 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 29 May 2026 09:54:11 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=94=84=20synced=20local=20'lib/build.?= =?UTF-8?q?gradle.kts'=20with=20remote=20'lib/build.gradle.kts.public'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 53e926c..de34e89 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -118,6 +118,7 @@ android { testInstrumentationRunnerArguments += mapOf( "notPackage" to "com.circle.modularwallets.core.manual" ) + consumerProguardFiles("consumer-rules.pro") } buildTypes {