diff --git a/content/docs/glossary/claimable-balance.mdx b/content/docs/glossary/claimable-balance.mdx
index c8ea26c1f..357772866 100644
--- a/content/docs/glossary/claimable-balance.mdx
+++ b/content/docs/glossary/claimable-balance.mdx
@@ -124,31 +124,43 @@ func main() {
-At this point, the claimable balance exists in the ledger. We can now claim it
-by its Balance ID. This can be acquired in two ways:
- 1. the submitter of the entry (Account A in this case) parses the XDR of the transaction result's operations, **or**
- 2. someone queries the list of claimable balances (filtering accordingly, if necessary)
+At this point, the `ClaimableBalanceEntry` exists in the ledger, but we'll need its Balance ID to claim it. This can be acquired in a number of ways:
+
+ 1. the submitter of the entry (Account A in this case) can retrieve the balance ID *prior* to submitting the transaction;
+ 2. the submitter parses the XDR of the transaction result's operations; **or**
+ 3. someone queries the list of claimable balances (filtered accordingly, if necessary).
+
+Either party could also check the `/effects` of the transaction, query `/claimable_balances` with different filters, etc. Note that while (1) may be unavailable in some SDKs as its just a helper, the other methods are universal.
```go
-// Suppose `txResp` comes from the transaction submission above.
+// Method 1: Suppose `tx` comes from the transaction built above.
+// Notice that this can be done *before* submission.
+balanceId, err := tx.ClaimableBalanceID(0)
+check(err)
+
+// Method 2: Suppose `txResp` comes from the transaction submission above.
var txResult xdr.TransactionResult
err = xdr.SafeUnmarshalBase64(txResp.ResultXdr, &txResult)
check(err)
if results, ok := txResult.OperationResults(); ok {
+ // We look at the first result since our first (and only) operation in the
+ // transaction was the CreateClaimableBalanceOp.
operationResult := results[0].MustTr().CreateClaimableBalanceResult
balanceId, err := xdr.MarshalHex(operationResult.BalanceId)
+ check(err)
fmt.Println("Balance ID:", balanceId)
}
-// Alternatively, Account B would do something like:
+// Method 3: Account B could alternatively do something like:
balances, err := client.ClaimableBalances(sdk.ClaimableBalanceRequest{Claimant: B})
check(err)
balanceId := balances.Embedded.Records[0].BalanceID
-// Now Account B can actually claim the balance, provided too much time hasn't elapsed!
+// Now Account B can actually claim the balance, provided too much time
+// hasn't elapsed, or Account A can "reclaim" it otherwise.
claimBalance := txnbuild.ClaimClaimableBalance{BalanceID: balanceId}
tx, err = txnbuild.NewTransaction(
txnbuild.TransactionParams{
@@ -162,7 +174,7 @@ tx, err = txnbuild.NewTransaction(
check(err)
tx, err = tx.Sign(network.TestNetworkPassphrase, aKeys)
check(err)
-err = client.SubmitTransaction(tx)
+txResp, err = client.SubmitTransaction(tx)
check(err)
```
diff --git a/content/docs/glossary/sponsored-reserves.mdx b/content/docs/glossary/sponsored-reserves.mdx
index a785ea7d7..e661af197 100644
--- a/content/docs/glossary/sponsored-reserves.mdx
+++ b/content/docs/glossary/sponsored-reserves.mdx
@@ -58,6 +58,8 @@ See [Revoke Sponsorship](../start/list-of-operations.mdx#revoke-sponsorship) for
The logic above does not detail any of the error cases, which are specified [here](../start/list-of-operations.mdx#revoke-sponsorship).
+
+
## Examples
Each example builds on itself, referencing variables from previous snippets. We'll demonstrate a few different things you can do with sponsoring:
- Sponsor creation of a trustline for another account.
@@ -67,6 +69,7 @@ Each example builds on itself, referencing variables from previous snippets. We'
(For brevity, we'll assume the existence of a `SignAndSend(...)` method (defined [below](#footnote)) which will creates and submits a transaction with the proper parameters and error-checking.
+
### Preamble
We'll start by including the boilerplate of account and asset creation.
@@ -121,7 +124,7 @@ func main() {
-### Sponsoring a Trustline
+### Sponsoring Trustlines
Now, let's sponsor trustlines for Account A. Notice how the `CHANGE_TRUST` operation is sandwiched between the begin and end sponsoring operations and that all relevant accounts need to sign the transaction.
@@ -136,9 +139,8 @@ Now, let's sponsor trustlines for Account A. Notice how the `CHANGE_TRUST` opera
SponsoredID: addressA,
},
&txnbuild.ChangeTrust{
- SourceAccount: &aAccount,
- Line: &assets[0],
- Limit: txnbuild.MaxTrustlineLimit,
+ Line: &assets[0],
+ Limit: txnbuild.MaxTrustlineLimit,
},
&txnbuild.EndSponsoringFutureReserves{},
}
@@ -181,7 +183,9 @@ Now, let's sponsor trustlines for Account A. Notice how the `CHANGE_TRUST` opera
### Transferring Sponsorship
-Suppose that now Signer 1 wants to transfer responsibility of sponsoring reserves for the trustline to Sponsor 2. This is accomplished by sandwiching the transfer between the `BEGIN/END_SPONSORING_FUTURE_RESERVES` operations. Both of the participants must sign the transaction, though either can submit it.
+Suppose that now Signer 1 wants to transfer responsibility of sponsoring reserves for the trustline to Sponsor 2. This is accomplished by sandwiching the transfer between the `BEGIN`/`END_SPONSORING_FUTURE_RESERVES` operations. Both of the participants must sign the transaction, though either can submit it.
+
+An intuitive way to think of a sponsorship transfer is that the very act of sponsorship is being sponsored by a new account. That is, the new sponsor takes over the responsibilities of the old sponsor by sponsoring a revocation.
@@ -195,7 +199,6 @@ Suppose that now Signer 1 wants to transfer responsibility of sponsoring reserve
SponsoredID: S1.Address(),
},
&txnbuild.RevokeSponsorship{
- SourceAccount: &s1Account,
SponsorshipType: txnbuild.RevokeSponsorshipTypeTrustLine,
Account: &addressA,
TrustLine: &txnbuild.TrustLineID{
@@ -206,8 +209,8 @@ Suppose that now Signer 1 wants to transfer responsibility of sponsoring reserve
&txnbuild.EndSponsoringFutureReserves{},
}
- // Notice that while the old sponsor *sends* the transaction, both sponsors
- // must *approve* the transfer.
+ // Notice that while the old sponsor *sends* the transaction (in this case),
+ // both sponsors must *approve* the transfer.
SignAndSend(client, &s1Account, []*keypair.Full{S1, S2}, transferOps...)
fmt.Println("Transferred sponsorship for", A.Address())
```
@@ -216,6 +219,7 @@ Suppose that now Signer 1 wants to transfer responsibility of sponsoring reserve
At this point, Signer 1 is only sponsoring the first asset (arbitrarily coded as `ABCD`), while Signer 2 is sponsoring the other two assets.
+
### Sponsorship Revocation
Finally, we can demonstrate complete revocation of sponsorships. Below, Signer 2 removes themselves from all responsibility over the two asset trustlines. Notice that Account A is not involved at all, since revocation should be performable purely at the sponsor's discretion.
@@ -252,6 +256,40 @@ Finally, we can demonstrate complete revocation of sponsorships. Below, Signer 2
+### Sponsorship Source Accounts
+When it comes to the `SourceAccount` fields of the sponsorship sandwich, it's important to refer to the wisdom of [CAP-33](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0033.md#abstract):
+
+> This relation is initiated by `BeginSponsoringFutureReservesOp`, where the **sponsoring** account is the source account, and is terminated by `EndSponsoringFutureReserveOp`, where the **sponsored** account is the source account.
+
+Since the source account defaults to the transaction submitter when omitted, this field needs always needs to be set for either the `Begin` or the `End`.
+
+For example, the following is an identical expression of the [earlier example](#sponsoring-trustlines) on sponsoring a trustline, just submitted by the **sponsor** (Sponsor 1) rather than the **sponsored** account (Account A). Notice the differences in where `SourceAccount` is set:
+
+
+
+```go
+ sponsorTrustline := []txnbuild.Operation{
+ &txnbuild.BeginSponsoringFutureReserves{
+ SponsoredID: addressA,
+ },
+ &txnbuild.ChangeTrust{
+ SourceAccount: &aAccount,
+ Line: &assets[0],
+ Limit: txnbuild.MaxTrustlineLimit,
+ },
+ &txnbuild.EndSponsoringFutureReserves{
+ SourceAccount: &aAccount,
+ },
+ }
+
+ // Again, both participants must still sign the transaction: the sponsored
+ // account must consent to the sponsorship.
+ SignAndSend(client, &s1Account, []*keypair.Full{S1, A}, sponsorTrustline...)
+```
+
+
+
+
### Other Examples
If you'd like other examples, or want to view a more-generic pseudocode breakdown of these sponsorship scenarios, you can refer to [CAP-0033](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0033.md#example-revoke-sponsorship) directly.