Android: Peer Offer
Peer-to-Peer connections can only be done using the SignalClient
.
Wallets are responsible for creating offers to connect.
Who is this for?
- Android Wallets that want to communicate with other clients
Signaling
import foundation.algorand.auth.connect.SignalClient
val requestID = "UUID-STRING-FROM-QR-CODE" // Scanned from a QR Code or Deep Linkval origin = "https://<ORIGIN-OF-SERVICE-FROM-QR-CODE>" // Origin of the serviceval client = SignalClient(origin, context, httpClient)val dc = client.peer(requestId, "answer" )
Data Channel
Handling the Datachannel can be done with the foundation.algorand.provider
library.
Wallets can implement their own Provider strategy for handling messages
The following is an example of a Provider Implementation:
package com.example.my-wallet
import com.algorand.algosdk.transaction.Transactionimport com.algorand.algosdk.util.Encoderimport foundation.algorand.crypto.EncoderTypeimport foundation.algorand.crypto.avm.KeyPairsimport foundation.algorand.provider.Messageimport foundation.algorand.provider.avm.models.*import java.security.KeyPairimport kotlin.io.encoding.Base64import kotlin.io.encoding.ExperimentalEncodingApi
/** * A provider for the Algorand Virtual Machine (AVM). * Used to test the provider.avm.models package. */class AVMProvider(val providerId: String) { val encoder = foundation.algorand.crypto.avm.Encoder() // A Security KeyPair var keyPair: KeyPair? = null /** * Handle a message from a channel */ fun handleRequestMessage(msg: Message, keyPair: KeyPair): Any { val message = encoder.decode<RequestMessage>(msg.data, msg.encoding) this.keyPair = keyPair
// Handle the message references when (message.reference) { "arc0027:sign_transactions:request" -> { val request = encoder.decode<SignTransactionsParams>( encoder.encode(message.params, EncoderType.NONE), EncoderType.NONE ) return processSignTransactions(request) } else -> { throw IllegalArgumentException("Invalid reference: ${message.reference}") } } } /** * Decode Unsigned Transaction */ @OptIn(ExperimentalEncodingApi::class) private fun decodeUnsignedTransaction(unsignedTxn: String): Transaction? { return Encoder.decodeFromMsgPack(Base64.decode(unsignedTxn), Transaction::class.java) } /** * Process the Sign Transactions Requests */ @OptIn(ExperimentalEncodingApi::class) fun processSignTransactions(params: SignTransactionsParams): SignTransactionsResult { require(params.validate())
val signedTxns = mutableListOf<String>() params.txns.forEach { txn -> val inst = decodeUnsignedTransaction(txn.txn!!) val signature = KeyPairs.rawSignBytes(inst!!.bytesToSign(), this.keyPair!!.private) signedTxns.add(Base64.UrlSafe.encode(signature!!)) } // Create the response payload return SignTransactionsResult(providerId, signedTxns) }}
The following is using a Provider with the SignalClient
import com.fasterxml.uuid.Generatorsimport foundation.algorand.crypto.EncoderTypeimport foundation.algorand.provider.Messageimport foundation.algorand.provider.avm.models.SignMessageParamsimport foundation.algorand.provider.avm.models.SignMessageResultimport foundation.algorand.provider.avm.models.SignTransactionsResultimport kotlin.io.encoding.Base64import kotlin.io.encoding.ExperimentalEncodingApi
val provider = AVMProvider("PROVIDER_UUID")val keyPair = getKeypairFromSecureStore()
client.handleDataChannel(dc, { // Decode the Message val msg = Message(Base64.UrlSafe.decode($it), EncoderType.CBOR) // Create the Result val result = provider.handleRequestMessage(msg, keyPair) // Send to the Response dc.send(Base64.UrlSafe.encode(result.toByteArray(EncoderType.CBOR)))}, { Log.d(TAG, "onStateChange($it)")})