Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Syn-McJ committed Nov 1, 2024
2 parents a498989 + b777cde commit 54002b4
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 70 deletions.
8 changes: 2 additions & 6 deletions alchemy/src/main/java/org/aakotlin/alchemy/Chains.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ package org.aakotlin.alchemy
import org.aakotlin.core.Chain

val SupportedChains = mapOf(
Chain.PolygonMumbai.id to Chain.PolygonMumbai,
Chain.Polygon.id to Chain.Polygon,
Chain.MainNet.id to Chain.MainNet,
Chain.Sepolia.id to Chain.Sepolia,
Chain.Goerli.id to Chain.Goerli,
Chain.ArbitrumGoerli.id to Chain.ArbitrumGoerli,
Chain.ArbitrumGoerli.id to Chain.ArbitrumSepolia,
Chain.Arbitrum.id to Chain.Arbitrum,
Expand All @@ -27,32 +25,30 @@ val SupportedChains = mapOf(

val Chain.alchemyRpcHttpUrl: String?
get() = when (this) {
Chain.PolygonMumbai -> "https://polygon-mumbai.g.alchemy.com/v2"
Chain.Polygon -> "https://polygon-mainnet.g.alchemy.com/v2"
Chain.MainNet -> "https://eth-mainnet.g.alchemy.com/v2"
Chain.Sepolia -> "https://eth-sepolia.g.alchemy.com/v2"
Chain.Goerli -> "https://eth-goerli.g.alchemy.com/v2"
Chain.ArbitrumGoerli -> "https://arb-goerli.g.alchemy.com/v2"
Chain.Arbitrum -> "https://arb-mainnet.g.alchemy.com/v2"
Chain.Optimism -> "https://opt-mainnet.g.alchemy.com/v2"
Chain.OptimismGoerli -> "https://opt-goerli.g.alchemy.com/v2"
Chain.Base -> "https://base-mainnet.g.alchemy.com/v2"
Chain.BaseGoerli -> "https://base-goerli.g.alchemy.com/v2"
Chain.BaseSepolia -> "https://base-sepolia.g.alchemy.com/v2/"
else -> null
}

val Chain.alchemyRpcWebSocketUrl: String?
get() = when(this) {
Chain.PolygonMumbai -> "wss://polygon-mumbai.g.alchemy.com/v2"
Chain.Polygon -> "wss://polygon-mainnet.g.alchemy.com/v2"
Chain.MainNet -> "wss://eth-mainnet.g.alchemy.com/v2"
Chain.Sepolia -> "wss://eth-sepolia.g.alchemy.com/v2"
Chain.Goerli -> "wss://eth-goerli.g.alchemy.com/v2"
Chain.ArbitrumGoerli -> "wss://arb-goerli.g.alchemy.com/v2"
Chain.Arbitrum -> "wss://arb-mainnet.g.alchemy.com/v2"
Chain.Optimism -> "wss://opt-mainnet.g.alchemy.com/v2"
Chain.OptimismGoerli -> "wss://opt-goerli.g.alchemy.com/v2"
Chain.Base -> "wss://base-mainnet.g.alchemy.com/v2"
Chain.BaseGoerli -> "wss://base-goerli.g.alchemy.com/v2"
Chain.BaseSepolia -> "wss://base-sepolia.g.alchemy.com/v2"
else -> null
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ class LightSmartContractAccount(
factoryAddress,
signer,
chain,
accountAddress,
) {
override suspend fun getAccountInitCode(): String {
accountAddress
) {
override suspend fun getAccountInitCode(forAddress: String): String {
return concatHex(
listOf(
factoryAddress.address,
FunctionEncoder.encode(
Function(
"createAccount",
listOf(
org.web3j.abi.datatypes.Address(signer.getAddress()),
org.web3j.abi.datatypes.Address(forAddress),
// light account does not support sub-accounts
Uint256(0),
Uint256(0)
),
listOf(
TypeReference.create(org.web3j.abi.datatypes.Address::class.java),
),
),
),
),
)
)
)
)
)
}
}
29 changes: 25 additions & 4 deletions alchemy/src/main/java/org/aakotlin/alchemy/account/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,40 @@ package org.aakotlin.alchemy.account
import org.aakotlin.core.Address
import org.aakotlin.core.Chain

fun Chain.defaultLightAccountFactoryAddress(): Address {
sealed class LightAccountVersion(val version: String, val factoryAddress: Address, val implAddress: Address) {
@Deprecated("This version does not support 1271 signature validation", ReplaceWith("LightAccountVersion.V1_1_0"))
data object V1_0_1 : LightAccountVersion(
version = "v1.0.1",
factoryAddress = Address("0x000000893A26168158fbeaDD9335Be5bC96592E2"),
implAddress = Address("0xc1b2fc4197c9187853243e6e4eb5a4af8879a1c0")
)

@Deprecated("This version has a known issue with 1271 validation", ReplaceWith("LightAccountVersion.V1_1_0"))
data object V1_0_2 : LightAccountVersion(
version = "v1.0.2",
factoryAddress = Address("0x00000055C0b4fA41dde26A74435ff03692292FBD"),
implAddress = Address("0x5467b1947F47d0646704EB801E075e72aeAe8113")
)

data object V1_1_0 : LightAccountVersion(
version = "v1.1.0",
factoryAddress = Address("0x00004EC70002a32400f8ae005A26081065620D20"),
implAddress = Address("0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba")
)
}

fun Chain.defaultLightAccountFactoryAddress(version: LightAccountVersion = LightAccountVersion.V1_1_0): Address {
return when (id) {
Chain.MainNet.id,
Chain.Sepolia.id,
Chain.Goerli.id,
Chain.Polygon.id,
Chain.PolygonMumbai.id,
Chain.Optimism.id,
Chain.OptimismGoerli.id,
Chain.Arbitrum.id,
Chain.ArbitrumGoerli.id,
Chain.Base.id,
Chain.BaseGoerli.id -> Address("0x000000893A26168158fbeaDD9335Be5bC96592E2")
Chain.BaseGoerli.id,
Chain.BaseSepolia.id -> version.factoryAddress

else -> throw Error("no default light account factory contract exists for $name")
}
Expand Down
14 changes: 0 additions & 14 deletions core/src/main/java/org/aakotlin/core/Chain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,13 @@ sealed class Chain(
Currency("Sepolia Ether", "SEP", 18)
)

data object Goerli: Chain(
5,
"goerli",
"Goerli",
Currency("Goerli Ether", "ETH", 18)
)

data object Polygon: Chain(
137,
"matic",
"Polygon",
Currency("MATIC", "MATIC", 18)
)

data object PolygonMumbai: Chain(
80_001,
"maticmum",
"Polygon Mumbai",
Currency("MATIC", "MATIC", 18)
)

data object Optimism: Chain(
10,
"optimism",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract class BaseSmartContractAccount(
) : ISmartContractAccount {
protected var deploymentState = DeploymentState.UNDEFINED

abstract suspend fun getAccountInitCode(): String
abstract suspend fun getAccountInitCode(forAddress: String): String

override suspend fun getInitCode(): String {
if (this.deploymentState == DeploymentState.DEPLOYED) {
Expand All @@ -58,7 +58,7 @@ abstract class BaseSmartContractAccount(
this.deploymentState = DeploymentState.NOT_DEPLOYED
}

return getAccountInitCode()
return getAccountInitCode(signer.getAddress())
}

override suspend fun getNonce(): BigInteger {
Expand Down Expand Up @@ -95,23 +95,27 @@ abstract class BaseSmartContractAccount(
return it
}

val initCode = getAccountInitCode()
val address = getAddressForSigner(signer.getAddress())
this.accountAddress = address

return address
}

override suspend fun getAddressForSigner(signerAddress: String): Address {
val initCode = getAccountInitCode(signerAddress)
val encodedCall = encodeGetSenderAddress(initCode)

try {
rpcClient.ethCall(
Transaction.createEthCallTransaction(
signer.getAddress(),
signerAddress,
getEntryPointAddress().address,
encodedCall,
),
DefaultBlockParameterName.LATEST,
).await()
} catch (ex: JsonRpcError) {
val address = Address("0x${(ex.data as String).trim('"', ' ').takeLast(40)}")
this.accountAddress = address

return address
return Address("0x${(ex.data as String).trim('"', ' ').takeLast(40)}")
}

throw CounterfactualAddressException("Failed to get smart contract account address")
Expand All @@ -128,10 +132,10 @@ abstract class BaseSmartContractAccount(
listOf(
DynamicBytes(
Numeric.hexStringToByteArray(initCode),
),
)
),
listOf(),
),
listOf()
)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ interface ISmartContractAccount {
*/
suspend fun getAddress(): Address

/**
* @returns the address of the smart contract account for the specified signer
*/
suspend fun getAddressForSigner(signerAddress: String): Address

/**
* @returns the smart contract account owner instance if it exists.
* It is optional for a smart contract account to have an owner account.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,11 @@ open class SimpleSmartContractAccount(
chain,
accountAddress
) {
override suspend fun getAccountInitCode(): String {
val address = signer.getAddress()
override suspend fun getAccountInitCode(forAddress: String): String {
val function = Function(
"createAccount",
listOf(
org.web3j.abi.datatypes.Address(address),
org.web3j.abi.datatypes.Address(forAddress),
Uint256(index ?: 0)
),
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ interface ISmartAccountProvider {
*/
suspend fun getAddress(): Address

/**
* @returns the address of the smart contract account for the specified signer
*/
suspend fun getAddressForSigner(signerAddress: String): Address

/**
* Sends a user operation using the connected account.
* Before executing, sendUserOperation will run the user operation through the middleware pipeline.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,20 @@ open class SmartAccountProvider(
val chain: Chain,
private val opts: SmartAccountProviderOpts? = null,
) : ISmartAccountProvider {
val rpcClient: Erc4337Client
val rpcClient: Erc4337Client = client ?: rpcUrl?.let {
createPublicErc4337Client(it)
} ?: throw IllegalArgumentException("No rpcUrl or client provided")

private var account: ISmartContractAccount? = null
private var gasEstimator: ClientMiddlewareFn = ::defaultGasEstimator
private set
private var feeDataGetter: ClientMiddlewareFn = ::defaultFeeDataGetter
private set
private var paymasterDataMiddleware: ClientMiddlewareFn = ::defaultPaymasterDataMiddleware
private set
private var overridePaymasterDataMiddleware: ClientMiddlewareFn = ::defaultOverridePaymasterDataMiddleware
private set
private var dummyPaymasterDataMiddleware: ClientMiddlewareFn = ::defaultDummyPaymasterDataMiddleware
private set

override val isConnected: Boolean
get() = this.account != null

init {
this.rpcClient = client ?: rpcUrl?.let {
createPublicErc4337Client(it)
} ?: throw IllegalArgumentException("No rpcUrl or client provided")
}

fun connect(account: ISmartContractAccount) {
this.account = account
// TODO: this method isn't very useful atm
Expand All @@ -70,6 +61,11 @@ open class SmartAccountProvider(
return account.getAddress()
}

override suspend fun getAddressForSigner(signerAddress: String): Address {
val account = this.account ?: throw IllegalStateException("Account not connected")
return account.getAddressForSigner(signerAddress)
}

override suspend fun sendUserOperation(
data: UserOperationCallData,
overrides: UserOperationOverrides?
Expand Down
10 changes: 4 additions & 6 deletions core/src/main/java/org/aakotlin/core/util/Defaults.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ object Defaults {
return when (chain.id) {
Chain.MainNet.id,
Chain.Sepolia.id,
Chain.Goerli.id,
Chain.Polygon.id,
Chain.PolygonMumbai.id,
Chain.Optimism.id,
Chain.OptimismGoerli.id,
Chain.Arbitrum.id,
Chain.ArbitrumGoerli.id,
Chain.Base.id,
Chain.BaseGoerli.id -> Address("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")
Chain.BaseGoerli.id,
Chain.BaseSepolia.id -> Address("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")

else -> throw Error("no default entry point contract exists for ${chain.name}")
}
Expand All @@ -49,11 +48,10 @@ object Defaults {
Chain.Optimism.id,
Chain.Arbitrum.id,
Chain.Base.id,
Chain.BaseGoerli.id -> Address("0x15Ba39375ee2Ab563E8873C8390be6f2E2F50232")
Chain.BaseGoerli.id,
Chain.BaseSepolia.id -> Address("0x15Ba39375ee2Ab563E8873C8390be6f2E2F50232")

Chain.Sepolia.id,
Chain.Goerli.id,
Chain.PolygonMumbai.id,
Chain.OptimismGoerli.id,
Chain.ArbitrumGoerli.id -> Address("0x9406Cc6185a346906296840746125a0E44976454")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ class BaseSmartContractAccountTest {
entryPointAddress = null,
factoryAddress = Address("0x000000893A26168158fbeaDD9335Be5bC96592E2"),
signer = signer,
chain = Chain.PolygonMumbai,
chain = Chain.BaseSepolia,
accountAddress = null
)

val initCode = scAccount.getAccountInitCode()
val initCode = scAccount.getAccountInitCode(signer.getAddress())
val encoded = scAccount.encodeGetSenderAddress(initCode)
Assert.assertEquals(
encoded,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SimpleSmartContractAccountTest {

@Test
fun `getAccountInitCode should return correct hex`() = runTest {
val initCode = scAccount.getAccountInitCode()
val initCode = scAccount.getAccountInitCode(signer.getAddress())
assertEquals(initCode, "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d27895fbfb9cf00000000000000000000000029df43f75149d0552475a6f9b2ac96e28796ed0b0000000000000000000000000000000000000000000000000000000000000000")
}

Expand Down
2 changes: 1 addition & 1 deletion example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")

implementation("com.github.Web3Auth:web3auth-android-sdk:5.0.2")
implementation("com.github.Web3Auth:web3auth-android-sdk:7.1.0")
implementation("org.web3j:core:4.10.3")
implementation("org.web3j:contracts:4.10.3")

Expand Down
4 changes: 3 additions & 1 deletion example/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:icon="@mipmap/ic_launcher"
Expand All @@ -8,6 +9,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.AAKotlin"
android:allowBackup="false"
tools:replace="android:allowBackup"
android:dataExtractionRules="@xml/data_extraction_rules">

<activity
Expand Down

0 comments on commit 54002b4

Please sign in to comment.