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.