Send to and receive payments from Contract Accounts
Payments between Contract Accounts (C addresses) and Classic Accounts (G addresses) are supported on a protocol level, but there are differences in the implementations that are required to support them. This guide will cover implementations for applications that use classic G accounts and want to support transacting with Contract Accounts.
Receiving payments from Contract Accounts (C to G)
If a sender is using a Contract Account, and sending an SAC token (such as XLM, USDC, etc.), the transaction will be received by the G account normally since it is supported on a protocol level.
Receiving payments from Contract Accounts requiring a memo
Entities such as exchanges and asset issuers usually use omnibus accounts, using a shared receiving address and a unique identifier memo like:
- Account:
GBLVHX33XGOBDOXK7ERDL34NVH6WW7VTT2OBAHPJ7G3D423HBG5NOMY7 - Memo ID:
123456789
Transactions involving Contract Accounts make use of contract invocations to execute a 'transfer' function on the asset contract. This kind of transaction doesn't allow for the 'memo' field to be used, so instead, the sending app will encode it in the address, generating a unique muxed address that includes the receiving account (GBLVHX…) and provided id in the muxed id field (123456789).
To enable support for deposits coming from Contract Accounts, nothing needs to change in the information displayed to customers or the deposit accounts used by the exchange. Wallets will still use the G account and memo provided to send a payment to the exchange's G account including the memo with the unique ID.
That's the main difference between receiving from customers using G or Contract Accounts: instead of looking at the memo field to identify the individual account, you'll look at the muxed ID. Everything else stays the same.
Example using Horizon
Receiving from a G address
Using Horizon's accounts/{acc_id}/transactions endpoint (example)
The memo field will be present in the response.
Example response from a G address:
{
"memo": "123456789",
"memo_bytes": "MTIzNDU2Nzg5",
"source_account": "GCNG5JXJY3LNRMXCX23RIGKTURQACTSV5LL6NKL535BYRGOGWUX6J45Y",
"memo_type": "text"
}
Receiving from a Contract Account
Using Horizon's accounts/{acc_id}/payments endpoint (example)
After the transaction is processed, this payment detail will be present in the '/payments' endpoint, under a section called 'asset_balance_changes', which will present the encoded ID and the underlying G-address separately.
It is important to note the 'asset_balance_changes' section only supports Stellar assets and transactions that make use of the transfer function in the Stellar Asset Contract (SAC).
Example response from a Contract Account:
{
"asset_balance_changes": [
{
"asset_type": "native",
"type": "transfer",
"from": "CBP4GFAK4GDKCMVLNIHRZPEAPT7CFYTBKICOXCVMP2FEN3QFKCRZ27KS",
"to": "GBLVHX33XGOBDOXK7ERDL34NVH6WW7VTT2OBAHPJ7G3D423HBG5NOMY7",
"amount": "1.0000000",
"destination_muxed_id": "123456789"
}
]
}
For a detailed code example, see the section 'Monitoring Payments -> Using the Horizon API' of this repository's examples.
Example using RPC
Since the release of the Unified Asset Events (CAP-67) on Protocol 23, a number of transactions involving Stellar assets now emit standardized events that can be ingested by both the Horizon API and the Stellar RPC. If funds are sent through a 'payment' operation or by invoking the 'transfer' function of the asset contract, the same kind of event is emitted for both cases.
To monitor these payments, the method 'getEvents' of the Stellar RPC is used to stream events emitted by the Stellar Asset Contract. A filter can be used to specify the target asset (SAC contract ID) and accounts.
From a G address
When the receiver is a normal G address, the value portion of the event is just the amount received.
{
"inSuccessfulContractCall": true,
"topicJson": [
{
"symbol": "transfer"
},
{
"address": "GD6MYLASTCZ3H4UFLH2YSIASHJNBFUCKC5YHGU44VCH2BGHN3WJQX6LG"
},
{
"address": "GA4PDUF3BLBSK47UTNY44AIZAP5EPHW2UIJRKB5HN76HHC55IWKSIHFD"
},
{
"string": "native"
}
],
"valueJson": {
"i128": "10000000"
}
}
From a Contract Account
When the transaction is sent using a muxed account, the value portion of the event is broken down into an object containing the amount and the unique ID encoded in the address.
{
"inSuccessfulContractCall": true,
"topicJson": [
{
"symbol": "transfer"
},
{
"address": "GD6MYLASTCZ3H4UFLH2YSIASHJNBFUCKC5YHGU44VCH2BGHN3WJQX6LG"
},
{
"address": "GA4PDUF3BLBSK47UTNY44AIZAP5EPHW2UIJRKB5HN76HHC55IWKSIHFD"
},
{
"string": "native"
}
],
"valueJson": {
"map": [
{
"key": {
"symbol": "amount"
},
"val": {
"i128": "10000000"
}
},
{
"key": {
"symbol": "to_muxed_id"
},
"val": {
"u64": "123456789"
}
}
]
}
}
For a detailed code example, see the section ‘Monitoring Payments -> Using the Stellar RPC’ of this repository's examples.
Sending payments from Contract Accounts to a recipient that requires a memo
If a sender is using a Contract Account, and sending an SAC token (such as XLM, USDC, etc.) to a recipient that requires a memo, (an exchange, for example) it should create a muxed address that includes the receiving account (GBLVHX…) and provided memo id in the muxed id field (123456789). In the user inteface, the resulting memo address doesn't need to be surfaced to the user, it should be used directly in the transaction.
If the receiving party already provides an M address, it should be used directly, without requiring a memo field. Since this is the value provided by the user, it should be used in the transaction and displayed to the user.
Sending payments to Contract Accounts (G to C)
Sending a ‘transfer’ via Stellar RPC
This approach is simpler but requires the use of an RPC and involves a slightly different transaction workflow than a traditional native operation. For a detailed code example, see the section ‘Sending Payments through the SAC -> Using the Stellar RPC’ of this repository's examples.
Assembling the operation and transaction
To perform a ‘transfer’ through an SAC, it is necessary to assemble a ‘InvokeHostFunctionOp’ operation with similar arguments as a ‘payment’ operation along with the contract identifier and target function name(‘transfer’).
This can be seen in detail in the ‘assembleTransferOperation’ function of the demo. While the example demonstrates this process in greater detail, it is possible to use the js-stellar-sdk and its Contract client in a simpler manner.
The transaction is then built by adding this operation and configuring the additional parameters as any other ‘payment’ transaction.
Simulating the transaction
After building the transaction, the RPC method for ‘simulateTransaction’ is used to simulate an execution of this transaction against the current state of the network, identify if it is expected to succeed and, also provide a number of additional parameters about this execution.
This process is fully handled by the SDK in a very simple step by using the ‘prepareTransaction’ function of the RPC server client. It automatically simulates and provides an updated transaction object. See this process in detail in the demo.
Signing
When the same account is used as the ‘sender’ of the funds and also the ‘source’ of the transaction, the signing step will be exactly the same. Once the updated transaction object is returned from the previous step, you just sign it with the source/sender account and it will be ready.
When the ‘source’ account of the transaction differs from the ‘sender’ account, an additional signed entry will be necessary to authorize the ‘transfer’ invocation explicitly. Refer to the Soroban Authorization Framework documentation for further details.
Sending the Transaction for processing
When a transaction is submitted for processing through the Stellar RPC, differently from the Horizon API, it will resolve immediately confirming its submission but not the processing. It is necessary to poll the transaction status for the next moment until you get a confirmation that it was successfully processed or a status update on a potential failure.
Sending a ‘transfer’ via Horizon API
When sending a ‘transfer’ via the Horizon API, this approach introduces a few extra steps when compared to the use of an RPC. For a detailed code example, see the section ‘Sending Payments through the SAC -> Using the Horizon API’ of this repository's examples.
Assembling the operation and transaction
This process is mostly the same as described in the previous section ‘Sending a ‘transfer’ via Stellar RPC’ with some slight modifications. Since the Horizon API does not provide an endpoint to simulate a transaction execution, this means that when the transaction is assembled we need to ensure it also contains:
- The Soroban authorization entries that fulfill the smart contracts authorization requirements.
- The Soroban data object, detailing the footprint, resources, and resource fee expected for this contract invocation.
These are normally populated automatically based on the output of the simulation and by simply signing and adding the authorization entries generated by the RPC. Here, we need to include these manually.
The auth entries can be easily predicted and assembled based on the configuration. Assuming the ‘sender’ account is the same as the ‘source’ account of the transaction, a source-account credential needs to be added to the operation, indicating this invocation will be used the same envelope signature to authorize the ‘transfer’. See this process in detail in the ‘assembleSourceAuthEntry’ function of the demo.
Once the auth entries are assembled and signed(when not a ‘source-account’ entry), they need to be included in the operation, in the ‘auth’ parameter.
For the Soroban Data on the other hand, the process can be a bit harder to execute manually. Considering all SAC contracts use the same native implementation, we can expect all ‘transfer’ invocations to be very similar.
The amount of resources consumed shouldn't vary much with the exception of some edge cases such as the transaction involving archived entries or a custom authorization for a smart wallet as the sender. See this process of manually assembling the Soroban Data in the function ’getSorobanData’ of the demo.
Once the Soroban Data is assembled, it is included in the Transaction Builder.
Signing
After building the transaction, assuming the ‘auth entries’ from the previous step were configured correctly, the transaction can be signed normally by the source account.
Sending the Transaction for processing
This step remains the same as any transaction submitted through the Horizon API.
Guías en esta categoría:
📄️ Crear una cuenta
Aprende sobre cómo crear cuentas Stellar, pares de llaves, financiamiento y conceptos básicos de las cuentas.
📄️ Send to and receive payments from Contract Accounts
Learn to send payments to and receive payments from Contract Accounts on the Stellar network.
📄️ Enviar y recibir pagos
Aprende a enviar pagos y estar atento a los pagos recibidos en la red Stellar.
📄️ Cuentas canalizadas
Crea cuentas canalizadas para enviar transacciones a la red a una alta velocidad.
📄️ Saldos reclamables
Divide un pago en dos partes creando un saldo reclamable.
📄️ Recuperaciones
Usa las recuperaciones para quemar una cantidad específica de un activo habilitado para recuperación desde una trustline o un saldo reclamable.
📄️ Transacciones de suplemento de tarifa
Usa transacciones fee-bump para pagar las comisiones de transacción en nombre de otra cuenta sin volver a firmar la transacción.
📄️ Reservas patrocinadas
Utiliza las reservas patrocinadas para pagar las reservas base en nombre de otra cuenta.
📄️ Pagos con rutas
Enviar un pago donde el activo recibido sea diferente del activo enviado.
📄️ Cuentas agrupadas: cuentas muxed y memos
Usa cuentas muxed para diferenciar entre cuentas individuales dentro de una cuenta agrupada.
📄️ Instalar y desplegar un contrato inteligente con código
Instalar y desplegar un contrato inteligente con código.
📄️ Invocar una función de contrato en una transacción usando SDKs
Usa el Stellar SDK para crear, simular y ensamblar una transacción.
📄️ guía del método RPC simulateTransaction
Guía de ejemplos y tutoriales de simulateTransaction.
📄️ Enviar una transacción a Stellar RPC utilizando el SDK de JavaScript
Utiliza un mecanismo de repetición para enviar una transacción al RPC.
📄️ Subir código byte de WebAssembly (Wasm) usando código
Sube el Wasm del contrato usando js-stellar-sdk.