SDK for interacting with the ethOS system wallet using Account Abstraction (ERC-4337). Supports batched transactions, automatic gas estimation via a bundler, message signing, chain switching, and address utilities.
Minimum Android SDK: 27
Add JitPack to settings.gradle in both pluginManagement and dependencyResolutionManagement:
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}Add dependencies in your app/module build.gradle:
// Required by WalletSDK (library declares web3j as compileOnly)
implementation 'org.web3j:core:4.9.4'
// WalletSDK
implementation 'com.github.EthereumPhone:WalletSDK:0.2.0'WalletSDK requires a bundler RPC URL. Best compatibility is reached with a pimlico URL, which you can just put here for ERC-4337 operations. Example using local.properties → BuildConfig:
# local.properties (do not commit secrets)
BUNDLER_RPC_URL=https://your-bundler.example// app/build.gradle
android {
defaultConfig {
Properties props = new Properties()
props.load(project.rootProject.file('local.properties').newDataInputStream())
buildConfigField 'String', 'BUNDLER_RPC_URL', '"' + props.getProperty('BUNDLER_RPC_URL') + '"'
}
}val wallet = WalletSDK(
context = context,
bundlerRPCUrl = BuildConfig.BUNDLER_RPC_URL,
// optional: override default web3 provider used for reads (eth_call, code, etc.)
web3jInstance = Web3j.build(HttpService("https://base.llamarpc.com"))
)CoroutineScope(Dispatchers.IO).launch {
val address = wallet.getAddress()
}CoroutineScope(Dispatchers.IO).launch {
val signature = wallet.signMessage(
message = "Message to sign",
chainId = 1, // required
// type = "personal_sign" // optional (default)
)
}CoroutineScope(Dispatchers.IO).launch {
val userOpHashOrError = wallet.sendTransaction(
to = "0x3a4e6ed8b0f02bfbfaa3c6506af2db939ea5798c",
value = "1000000000000000000", // wei
data = "0",
callGas = null, // null → auto-estimate via bundler
chainId = 1,
rpcEndpoint = "https://rpc.ankr.com/eth"
)
}CoroutineScope(Dispatchers.IO).launch {
val txs = listOf(
WalletSDK.TxParams(
to = "0x...",
value = "0",
data = "0x..."
),
WalletSDK.TxParams(
to = "0x...",
value = "12345",
data = "0"
)
)
val userOpHash = wallet.sendTransaction(
txParamsList = txs,
callGas = null,
chainId = 1,
rpcEndpoint = "https://rpc.ankr.com/eth"
)
}CoroutineScope(Dispatchers.IO).launch {
val current = wallet.getChainId()
val result = wallet.changeChain(
chainId = 8453,
rpcEndpoint = "https://base.llamarpc.com",
mBundlerRPCUrl = "https://your-bundler.for-base"
)
}isWalletConnected(): BooleanswitchAccount(index: Int): StringgetNonce(senderAddress: String, rpcEndpoint: String?): BigIntegergetPrecomputedAddress(pubKeyX: BigInteger, pubKeyY: BigInteger, salt: BigInteger = BigInteger.ZERO): String
Notes
- Works on ethOS devices with the system wallet service available. Construction will throw
NoSysWalletExceptionif the system service is unavailable. sendTransactionreturns a user operation hash on success, or the stringdeclineif the user rejected the request.