Skip to content

Commit

Permalink
add ability to remove and add wallets to an inbox id
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed Nov 20, 2024
1 parent 6191f59 commit 1d86b31
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,74 @@ class ClientTest {
listOf(fixtures.boClient.inboxId, fixtures.caroClient.inboxId)
)
}
assertEquals(states.first().recoveryAddress.lowercase(), fixtures.bo.walletAddress.lowercase())
assertEquals(states.last().recoveryAddress.lowercase(), fixtures.caro.walletAddress.lowercase())
assertEquals(
states.first().recoveryAddress.lowercase(),
fixtures.bo.walletAddress.lowercase()
)
assertEquals(
states.last().recoveryAddress.lowercase(),
fixtures.caro.walletAddress.lowercase()
)
}

@Test
fun testAddAccounts() {
val fixtures = fixtures()
val alix2Wallet = PrivateKeyBuilder()
val alix3Wallet = PrivateKeyBuilder()
runBlocking { fixtures.alixClient.addAccount(fixtures.alixAccount, alix2Wallet) }
runBlocking { fixtures.alixClient.addAccount(fixtures.alixAccount, alix3Wallet) }

val state = runBlocking { fixtures.alixClient.inboxState(true) }
assertEquals(state.installations.size, 1)
assertEquals(state.addresses.size, 3)
assertEquals(state.recoveryAddress, fixtures.alixClient.address.lowercase())
assertEquals(
state.addresses.sorted(),
listOf(
alix2Wallet.address.lowercase(),
alix3Wallet.address.lowercase(),
fixtures.alixClient.address.lowercase()
).sorted()
)
}

@Test
fun testRemovingAccounts() {
val fixtures = fixtures()
val alix2Wallet = PrivateKeyBuilder()
val alix3Wallet = PrivateKeyBuilder()
runBlocking { fixtures.alixClient.addAccount(fixtures.alixAccount, alix2Wallet) }
runBlocking { fixtures.alixClient.addAccount(fixtures.alixAccount, alix3Wallet) }

var state = runBlocking { fixtures.alixClient.inboxState(true) }
assertEquals(state.addresses.size, 3)
assertEquals(state.recoveryAddress, fixtures.alixClient.address.lowercase())

runBlocking { fixtures.alixClient.removeAccount(fixtures.alixAccount, alix2Wallet.address) }
state = runBlocking { fixtures.alixClient.inboxState(true) }
assertEquals(state.addresses.size, 2)
assertEquals(state.recoveryAddress, fixtures.alixClient.address.lowercase())
assertEquals(
state.addresses.sorted(),
listOf(
alix3Wallet.address.lowercase(),
fixtures.alixClient.address.lowercase()
).sorted()
)
assertEquals(state.installations.size, 1)

// Cannot remove the recovery address
assertThrows(
"Client error: Unknown Signer",
GenericException::class.java
) {
runBlocking {
fixtures.alixClient.removeAccount(
alix3Wallet,
fixtures.alixClient.address
)
}
}
}
}
72 changes: 44 additions & 28 deletions library/src/main/java/org/xmtp/android/library/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.xmtp.android.library.libxmtp.XMTPLogger
import org.xmtp.android.library.messages.rawData
import uniffi.xmtpv3.FfiConversationType
import uniffi.xmtpv3.FfiDeviceSyncKind
import uniffi.xmtpv3.FfiSignatureRequest
import uniffi.xmtpv3.FfiXmtpClient
import uniffi.xmtpv3.createClient
import uniffi.xmtpv3.generateInboxId
Expand Down Expand Up @@ -183,31 +184,54 @@ class Client() {
}
}
ffiClient.signatureRequest()?.let { signatureRequest ->
if (signingKey != null) {
if (signingKey.type == WalletType.SCW) {
val chainId = signingKey.chainId
?: throw XMTPException("ChainId is required for smart contract wallets")
signatureRequest.addScwSignature(
signingKey.signSCW(signatureRequest.signatureText()),
signingKey.address.lowercase(),
chainId.toULong(),
signingKey.blockNumber?.toULong()
)
} else {
signingKey.sign(signatureRequest.signatureText())?.let {
signatureRequest.addEcdsaSignature(it.rawData)
}
}

ffiClient.registerIdentity(signatureRequest)
} else {
throw XMTPException("No signer passed but signer was required.")
}
signingKey?.let { handleSignature(signatureRequest, it) }
?: throw XMTPException("No signer passed but signer was required.")
ffiClient.registerIdentity(signatureRequest)
}

return Pair(ffiClient, dbPath)
}

suspend fun revokeAllOtherInstallations(signingKey: SigningKey) {
val signatureRequest = ffiClient.revokeAllOtherInstallations()
handleSignature(signatureRequest, signingKey)
ffiClient.applySignatureRequest(signatureRequest)
}

suspend fun addAccount(recoverAccount: SigningKey, newAccount: SigningKey) {
val signatureRequest =
ffiClient.addWallet(address.lowercase(), newAccount.address.lowercase())
handleSignature(signatureRequest, recoverAccount)
handleSignature(signatureRequest, newAccount)
ffiClient.applySignatureRequest(signatureRequest)
}

suspend fun removeAccount(recoverAccount: SigningKey, addressToRemove: String) {
val signatureRequest = ffiClient.revokeWallet(addressToRemove.lowercase())
handleSignature(signatureRequest, recoverAccount)
ffiClient.applySignatureRequest(signatureRequest)
}

private suspend fun handleSignature(
signatureRequest: FfiSignatureRequest,
signingKey: SigningKey,
) {
if (signingKey.type == WalletType.SCW) {
val chainId = signingKey.chainId
?: throw XMTPException("ChainId is required for smart contract wallets")
signatureRequest.addScwSignature(
signingKey.signSCW(signatureRequest.signatureText()),
signingKey.address.lowercase(),
chainId.toULong(),
signingKey.blockNumber?.toULong()
)
} else {
signingKey.sign(signatureRequest.signatureText())?.let {
signatureRequest.addEcdsaSignature(it.rawData)
}
}
}

fun signWithInstallationKey(message: String): ByteArray {
return ffiClient.signWithInstallationKey(message)
}
Expand Down Expand Up @@ -303,14 +327,6 @@ class Client() {
ffiClient.sendSyncRequest(FfiDeviceSyncKind.CONSENT)
}

suspend fun revokeAllOtherInstallations(signingKey: SigningKey) {
val signatureRequest = ffiClient.revokeAllOtherInstallations()
signingKey.sign(signatureRequest.signatureText())?.let {
signatureRequest.addEcdsaSignature(it.rawData)
ffiClient.applySignatureRequest(signatureRequest)
}
}

suspend fun inboxStatesForInboxIds(
refreshFromNetwork: Boolean,
inboxIds: List<String>,
Expand Down

0 comments on commit 1d86b31

Please sign in to comment.