Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import com.circle.modularwallets.core.utils.NonceManagerSource
import com.circle.modularwallets.core.utils.abi.encodeCallData
import com.circle.modularwallets.core.utils.signature.hashMessage
import com.circle.modularwallets.core.utils.signature.hashTypedData
import com.circle.modularwallets.core.utils.smartAccount.getMinimumVerificationGasLimit
import com.circle.modularwallets.core.utils.smartAccount.getDefaultVerificationGasLimit
import com.circle.modularwallets.core.utils.userOperation.getUserOperationHash
import com.circle.modularwallets.core.utils.userOperation.parseFactoryAddressAndData
import org.web3j.utils.Numeric
Expand Down Expand Up @@ -167,8 +167,7 @@ class CircleSmartAccount(
*/
override var userOperation: UserOperationConfiguration? =
UserOperationConfiguration { userOperation ->
val minimumVerificationGasLimit =
getMinimumVerificationGasLimit(isDeployed(), client.chain.chainId)
val minimumVerificationGasLimit = getDefaultVerificationGasLimit(isDeployed(), client.transport)
EstimateUserOperationGasResult(
verificationGasLimit = minimumVerificationGasLimit
.max(userOperation.verificationGasLimit ?: BigInteger.ZERO)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import com.circle.modularwallets.core.utils.webauthn.getSavedCredentials
* Throws: BaseError if userName is null for WebAuthnMode.Register.
*
*/

@ExcludeFromGeneratedCCReport
@Throws(Exception::class)
@JvmOverloads
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
package com.circle.modularwallets.core.apis.modular

import com.circle.modularwallets.core.models.AddressMappingOwner
import com.circle.modularwallets.core.models.CreateAddressMappingResult
import com.circle.modularwallets.core.models.AddressMappingResult
import com.circle.modularwallets.core.models.GetUserOperationGasPriceResult
import com.circle.modularwallets.core.transports.Transport

internal interface ModularApi {
Expand All @@ -28,6 +29,20 @@ internal interface ModularApi {
transport: Transport,
walletAddress: String,
owners: Array<AddressMappingOwner>
): Array<CreateAddressMappingResult>
): Array<AddressMappingResult>

suspend fun getAddressMapping(
transport: Transport,
owner: AddressMappingOwner
): Array<AddressMappingResult>

/**
* Gets the gas price options for a user operation.
*
* @param transport The transport to use for the request.
* @return The gas price options with low, medium, high tiers and optional verificationGasLimit.
*/
suspend fun getUserOperationGasPrice(
transport: Transport
): GetUserOperationGasPriceResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ package com.circle.modularwallets.core.apis.modular

import com.circle.modularwallets.core.errors.BaseError
import com.circle.modularwallets.core.models.AddressMappingOwner
import com.circle.modularwallets.core.models.CreateAddressMappingResult
import com.circle.modularwallets.core.models.AddressMappingResult
import com.circle.modularwallets.core.models.EoaAddressMappingOwner
import com.circle.modularwallets.core.models.GetUserOperationGasPriceResult
import com.circle.modularwallets.core.models.WebAuthnAddressMappingOwner
import com.circle.modularwallets.core.transports.RpcRequest
import com.circle.modularwallets.core.transports.Transport
Expand All @@ -43,7 +44,7 @@ internal object ModularApiImpl : ModularApi {
transport: Transport,
walletAddress: String,
owners: Array<AddressMappingOwner>
): Array<CreateAddressMappingResult> {
): Array<AddressMappingResult> {
if (!isAddress(walletAddress)) {
throw BaseError("walletAddress is invalid")
}
Expand Down Expand Up @@ -75,10 +76,50 @@ internal object ModularApiImpl : ModularApi {
listOf(CreateAddressMappingReq(walletAddress, owners))
)
val rawList = performJsonRpcRequest(transport, req) as ArrayList<*>
val result: Array<CreateAddressMappingResult> = rawList.mapNotNull { item ->
resultToTypeAndJson(item, CreateAddressMappingResult::class.java).first
}.toTypedArray()
val result: Array<AddressMappingResult> = processAddressMappingResponse(rawList)
return result
}

override suspend fun getAddressMapping(
transport: Transport,
owner: AddressMappingOwner
): Array<AddressMappingResult> {
val req = RpcRequest(
"circle_getAddressMapping",
listOf(GetAddressMappingReq(owner))
)
val rawList = performJsonRpcRequest(transport, req) as ArrayList<*>
val result: Array<AddressMappingResult> = processAddressMappingResponse(rawList)
return result
}

private fun processAddressMappingResponse(rawList: ArrayList<*>):
Array<AddressMappingResult> {
return rawList.mapNotNull { item ->
resultToTypeAndJson(item, AddressMappingResult::class.java).first
}.toTypedArray()
}
/**
* Gets the gas price options for a user operation.
*
* @param transport The transport to use for the request.
* @return The gas price options with low, medium, high tiers and optional verificationGasLimit.
*/
override suspend fun getUserOperationGasPrice(
transport: Transport,
): GetUserOperationGasPriceResult {

val req = RpcRequest(
"circle_getUserOperationGasPrice"
)

val result = performJsonRpcRequest(
transport,
req,
GetUserOperationGasPriceResult::class.java
)

return result.first
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,8 @@ internal data class CreateAddressMappingReq(
@Json(name = "walletAddress") val walletAddress: String,
@Json(name = "owners") val owners: Array<AddressMappingOwner>,
)

@JsonClass(generateAdapter = true)
internal data class GetAddressMappingReq(
@Json(name = "owner") val owner: AddressMappingOwner,
)
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ internal interface UtilApi {
account: String,
ownerToCheck: String,
): Boolean

suspend fun isOwnerOf(
transport: Transport,
account: String,
ownerXToCheck: String,
ownerYToCheck: String,
): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.web3j.abi.datatypes.Address
import org.web3j.abi.datatypes.Bool
import org.web3j.abi.datatypes.DynamicBytes
import org.web3j.abi.datatypes.Function
import org.web3j.abi.datatypes.StaticStruct
import org.web3j.abi.datatypes.Type
import org.web3j.abi.datatypes.generated.Bytes32
import org.web3j.abi.datatypes.generated.Bytes4
Expand Down Expand Up @@ -187,6 +188,48 @@ internal object UtilApiImpl : UtilApi {
}
return decoded[0].value as Boolean
}
@ExcludeFromGeneratedCCReport
override suspend fun isOwnerOf(
transport: Transport,
account: String,
xOfOwnerToCheck: String,
yOfOwnerToCheck: String,
): Boolean {
val publicKeys = StaticStruct(
Uint256(BigInteger(xOfOwnerToCheck)),
Uint256(BigInteger(yOfOwnerToCheck))
)
val function = Function(
"isOwnerOf",
listOf<Type<*>>(
Address(account),
publicKeys
),
listOf<TypeReference<*>>(
object : TypeReference<Bool>() {})
)
val data = FunctionEncoder.encode(function)
Logger.d(
msg = """
isOwnerOf > call
Account: $account
xOfOwnerToCheck: $xOfOwnerToCheck
yOfOwnerToCheck: $yOfOwnerToCheck
""".trimIndent()
)
val resp = call(
transport,
from = account,
to = CIRCLE_WEIGHTED_WEB_AUTHN_MULTISIG_PLUGIN.address,
data
)
val decoded = FunctionReturnDecoder.decode(resp, function.outputParameters)
if (decoded.isEmpty()) {
Logger.w(msg = "Empty response from isOwner call")
return false
}
return decoded[0].value as Boolean
}

override suspend fun getReplaySafeMessageHash(
transport: Transport,
Expand Down
Loading