From 0d19c04d6f0d74ef009ff2ab32412f040e518313 Mon Sep 17 00:00:00 2001 From: Christian Rogobete Date: Sat, 27 Jun 2020 01:17:37 +0200 Subject: [PATCH] add allow trust example --- README.md | 2 +- documentation/README.md | 1 + documentation/sdk_examples/README.md | 1 + documentation/sdk_examples/allow_trust.md | 170 ++++++++++++++++++ test/examples_test.dart | 202 ++++++++++++++++++++++ 5 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 documentation/sdk_examples/allow_trust.md diff --git a/README.md b/README.md index c3ddf1a..bca7a45 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ if (response.success) { | [Manage sell offer](documentation/sdk_examples/manage_buy_offer.md) | Creates, updates, or deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook. | [Manage sell offer](https://www.stellar.org/developers/guides/concepts/list-of-operations.html#manage-sell-offer) | | [Create passive sell offer](documentation/sdk_examples/create_passive_sell_offer.md) | Creates, updates and deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook, _without taking a reverse offer of equal price_. | [Create passive sell offer](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#create-passive-sell-offer) | | [Change trust](documentation/sdk_examples/change_trust.md) | Creates, updates, and deletes a trustline. | [Change trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#change-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | - +| [Allow trust](documentation/sdk_examples/allow_trust.md) | Updates the authorized flag of an existing trustline. | [Allow trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#allow-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | Additional examples can be found in the [tests](https://github.com/Soneso/stellar_flutter_sdk/blob/master/test/). diff --git a/documentation/README.md b/documentation/README.md index 56c38c0..cee3b8d 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -28,6 +28,7 @@ The Soneso open source Stellar SDK for Flutter is build with Dart and provides A | [Manage sell offer](sdk_examples/manage_buy_offer.md) | Creates, updates, or deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook. | [Manage sell offer](https://www.stellar.org/developers/guides/concepts/list-of-operations.html#manage-sell-offer) | | [Create passive sell offer](sdk_examples/create_passive_sell_offer.md) | Creates, updates and deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook, _without taking a reverse offer of equal price_. | [Create passive sell offer](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#create-passive-sell-offer) | | [Change trust](sdk_examples/change_trust.md) | Creates, updates, and deletes a trustline. | [Change trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#change-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | +| [Allow trust](sdk_examples/allow_trust.md) | Updates the authorized flag of an existing trustline. | [Allow trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#allow-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | More examples and use cases can be found in the [test classes](../test). diff --git a/documentation/sdk_examples/README.md b/documentation/sdk_examples/README.md index e4cbd68..ad87d2a 100644 --- a/documentation/sdk_examples/README.md +++ b/documentation/sdk_examples/README.md @@ -19,4 +19,5 @@ The [Soneso open source Stellar SDK for Flutter](https://github.com/Soneso/stell | [Manage sell offer](manage_buy_offer.md) | Creates, updates, or deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook. | [Manage sell offer](https://www.stellar.org/developers/guides/concepts/list-of-operations.html#manage-sell-offer) | | [Create passive sell offer](create_passive_sell_offer.md) | Creates, updates and deletes an offer to sell one asset for another, otherwise known as a "ask" order or “offer” on a traditional orderbook, _without taking a reverse offer of equal price_. | [Create passive sell offer](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#create-passive-sell-offer) | | [Change trust](change_trust.md) | Creates, updates, and deletes a trustline. | [Change trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#change-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | +| [Allow trust](allow_trust.md) | Updates the authorized flag of an existing trustline. | [Allow trust](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#allow-trust) and [Assets documentation](https://www.stellar.org/developers/learn/concepts/assets.html) | diff --git a/documentation/sdk_examples/allow_trust.md b/documentation/sdk_examples/allow_trust.md new file mode 100644 index 0000000..c1723f9 --- /dev/null +++ b/documentation/sdk_examples/allow_trust.md @@ -0,0 +1,170 @@ + +### Allow trust + +In this example we will update the ```authorized``` flag of an existing trustline. This can only be called by the issuer of a trustline’s asset, and only when ```AUTHORIZATION REQUIRED``` (at the minimum) has been set on the issuer’s account. + +The issuer can only clear the ```authorized``` flag if the issuer has the ```AUTH_REVOCABLE_FLAG``` set. Otherwise, the issuer can only set the authorized flag. + +If the issuer clears the ```authorized``` flag, all offers owned by the trustor that are either selling type or buying type will be deleted. + +```dart +// Create two random key pairs, we will need them later for signing. +KeyPair issuerKeipair = KeyPair.random(); +KeyPair trustorKeipair = KeyPair.random(); + +// Account Ids. +String issuerAccountId = issuerKeipair.accountId; +String trustorAccountId = trustorKeipair.accountId; + +// Create trustor account. +await FriendBot.fundTestAccount(trustorAccountId); + +// Load trustor account, we will need it later to create the trustline. +AccountResponse trustorAccount = await sdk.accounts.account(trustorAccountId); + +// Create the issuer account. +CreateAccountOperation cao = CreateAccountOperationBuilder(issuerAccountId, "10").build(); +Transaction transaction = TransactionBuilder(trustorAccount, Network.TESTNET).addOperation(cao).build(); +transaction.sign(trustorKeipair); +SubmitTransactionResponse response = await sdk.submitTransaction(transaction); + +// Load the issuer account. +AccountResponse issuerAccount = await sdk.accounts.account(issuerAccountId); +// Set up the flags on the isser account. +SetOptionsOperationBuilder sopb = SetOptionsOperationBuilder(); +sopb.setSetFlags(3); // Auth required, auth revocable +// Build the transaction. +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(sopb.build()).build(); +// Sign. +transaction.sign(issuerKeipair); +// Submit. +response = await sdk.submitTransaction(transaction); + +// Reload the issuer account to check the flags. +issuerAccount = await sdk.accounts.account(issuerAccountId); +if(issuerAccount.flags.authRequired + && issuerAccount.flags.authRevocable + && !issuerAccount.flags.authImmutable) { + + print("issuer account flags correctly set"); +} + +// Define our custom asset. +String assetCode = "ASTRO"; +Asset astroDollar = AssetTypeCreditAlphaNum12(assetCode, issuerAccountId); + +// Build the trustline. +String limit = "10000"; +ChangeTrustOperation cto = ChangeTrustOperationBuilder(astroDollar, limit).build(); +transaction = TransactionBuilder(trustorAccount, Network.TESTNET) + .addOperation(cto) + .build(); +transaction.sign(trustorKeipair); +response = await sdk.submitTransaction(transaction); + +// Reload the trustor account to see if the trustline has been created. +trustorAccount = await sdk.accounts.account(trustorAccountId); +for (Balance balance in trustorAccount.balances) { + if (balance.assetCode == assetCode) { + print("trustline awailable"); + break; + } +} + +// Now lets try to send some custom asset funds to the trustor account. +// This should not work, because the issuer must authorize the trustline first. +PaymentOperation po = PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); +transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(po) + .build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); +if(!response.success) { // not authorized. + print("trustline is not authorized"); +} + +// Now let's authorize the trustline. +// Build the allow trust operation. Set the authorized flag to 1. +AllowTrustOperation aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 1).build(); // authorize +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(aop).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); + +// Try again to send the payment. Should work now. +po = PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(po).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); +if(response.success) { // authorized. + print("sccess - trustline is now authorized."); +} + +// Now create an offer, to see if it will be deleted after we will remove the authorized flag. +String amountSelling = "100"; +String price = "0.5"; +CreatePassiveSellOfferOperation cpso = CreatePassiveSellOfferOperationBuilder(astroDollar, Asset.NATIVE, amountSelling, price).build(); +transaction = TransactionBuilder(trustorAccount, Network.TESTNET).addOperation(cpso).build(); +transaction.sign(trustorKeipair); +response = await sdk.submitTransaction(transaction); + +// Check if the offer has been added. +List offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; +OfferResponse offer = offers.first; +if(offer.buying == Asset.NATIVE && offer.selling == astroDollar) { + print("offer found"); +} + +// Now lets remove the authorization. To do so, we set the authorized flag to 0. +// This should also delete the offer. +aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 0).build(); // not authorized +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(aop).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); + +// Check if the offer has been deleted. +offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; +if(offers.length == 0) { + print("success, offer has been deleted"); +} + +// Now, let's authorize the trustline again and then authorize it only to maintain liabilities. +aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 1).build(); // authorize +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(aop).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); + +// Create the offer again. +cpso = CreatePassiveSellOfferOperationBuilder(astroDollar, Asset.NATIVE, amountSelling, price).build(); +transaction = TransactionBuilder(trustorAccount, Network.TESTNET).addOperation(cpso).build(); +transaction.sign(trustorKeipair); +response = await sdk.submitTransaction(transaction); + +// Check that the offer has been created. +offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; +if(offers.length == 1) { + print("offer has been created"); +} + +// Now let's deautorize the trustline but allow the trustor to maintain his offer. +// For this, we set the authorized flag to 2. +aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 2).build(); // authorized to maintain liabilities. +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(aop).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); + +// Load the offers to see if our offer is still there. +offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; +if(offers.length == 1) { + print("success, offer exists"); +} + +// Next, let's try to send some ASTRO to the trustor account. +// This should not work, since the trustline has been deauthorized before. +po = PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); +transaction = TransactionBuilder(issuerAccount, Network.TESTNET).addOperation(po).build(); +transaction.sign(issuerKeipair); +response = await sdk.submitTransaction(transaction); +if(!response.success); {// is not authorized for new funds + print("payment correctly blocked."); +} +``` diff --git a/test/examples_test.dart b/test/examples_test.dart index 9c3d131..33873dc 100644 --- a/test/examples_test.dart +++ b/test/examples_test.dart @@ -1155,4 +1155,206 @@ void main() { print("success, trustline deleted"); } }); + + test('allow trust', () async { + // Create two random key pairs, we will need them later for signing. + KeyPair issuerKeipair = KeyPair.random(); + KeyPair trustorKeipair = KeyPair.random(); + + // Account Ids. + String issuerAccountId = issuerKeipair.accountId; + String trustorAccountId = trustorKeipair.accountId; + + // Create trustor account. + await FriendBot.fundTestAccount(trustorAccountId); + + // Load trustor account, we will need it later to create the trustline. + AccountResponse trustorAccount = + await sdk.accounts.account(trustorAccountId); + + // Create the issuer account. + CreateAccountOperation cao = + CreateAccountOperationBuilder(issuerAccountId, "10").build(); + Transaction transaction = + TransactionBuilder(trustorAccount, Network.TESTNET) + .addOperation(cao) + .build(); + transaction.sign(trustorKeipair); + SubmitTransactionResponse response = + await sdk.submitTransaction(transaction); + + // Load the issuer account. + AccountResponse issuerAccount = await sdk.accounts.account(issuerAccountId); + // Set up the flags on the isser account. + SetOptionsOperationBuilder sopb = SetOptionsOperationBuilder(); + sopb.setSetFlags(3); // Auth required, auth revocable + // Build the transaction. + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(sopb.build()) + .build(); + // Sign. + transaction.sign(issuerKeipair); + // Submit. + response = await sdk.submitTransaction(transaction); + + // Reload the issuer account to check the flags. + issuerAccount = await sdk.accounts.account(issuerAccountId); + if (issuerAccount.flags.authRequired && + issuerAccount.flags.authRevocable && + !issuerAccount.flags.authImmutable) { + print("issuer account flags correctly set"); + } + + // Define our custom asset. + String assetCode = "ASTRO"; + Asset astroDollar = AssetTypeCreditAlphaNum12(assetCode, issuerAccountId); + + // Build the trustline. + String limit = "10000"; + ChangeTrustOperation cto = + ChangeTrustOperationBuilder(astroDollar, limit).build(); + transaction = TransactionBuilder(trustorAccount, Network.TESTNET) + .addOperation(cto) + .build(); + transaction.sign(trustorKeipair); + response = await sdk.submitTransaction(transaction); + + // Reload the trustor account to see if the trustline has been created. + trustorAccount = await sdk.accounts.account(trustorAccountId); + for (Balance balance in trustorAccount.balances) { + if (balance.assetCode == assetCode) { + print("trustline awailable"); + break; + } + } + + // Now lets try to send some custom asset funds to the trustor account. + // This should not work, because the issuer must authorize the trustline first. + PaymentOperation po = + PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(po) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + if (!response.success) { + // not authorized. + print("trustline is not authorized"); + } + + // Now let's authorize the trustline. + // Build the allow trust operation. Set the authorized flag to 1. + AllowTrustOperation aop = + AllowTrustOperationBuilder(trustorAccountId, assetCode, 1) + .build(); // authorize + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(aop) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + + // Try again to send the payment. Should work now. + po = PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(po) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + if (response.success) { + // authorized. + print("sccess - trustline is now authorized."); + } + + // Now create an offer, to see if it will be deleted after we will remove the authorized flag. + String amountSelling = "100"; + String price = "0.5"; + CreatePassiveSellOfferOperation cpso = + CreatePassiveSellOfferOperationBuilder( + astroDollar, Asset.NATIVE, amountSelling, price) + .build(); + transaction = TransactionBuilder(trustorAccount, Network.TESTNET) + .addOperation(cpso) + .build(); + transaction.sign(trustorKeipair); + response = await sdk.submitTransaction(transaction); + + // Check if the offer has been added. + List offers = + (await sdk.offers.forAccount(trustorAccountId).execute()).records; + OfferResponse offer = offers.first; + if (offer.buying == Asset.NATIVE && offer.selling == astroDollar) { + print("offer found"); + } + + // Now lets remove the authorization. To do so, we set the authorized flag to 0. + // This should also delete the offer. + aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 0) + .build(); // not authorized + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(aop) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + + // Check if the offer has been deleted. + offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; + if (offers.length == 0) { + print("success, offer has been deleted"); + } + + // Now, let's authorize the trustline again and then authorize it only to maintain liabilities. + aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 1) + .build(); // authorize + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(aop) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + + // Create the offer again. + cpso = CreatePassiveSellOfferOperationBuilder( + astroDollar, Asset.NATIVE, amountSelling, price) + .build(); + transaction = TransactionBuilder(trustorAccount, Network.TESTNET) + .addOperation(cpso) + .build(); + transaction.sign(trustorKeipair); + response = await sdk.submitTransaction(transaction); + + // Check that the offer has been created. + offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; + if (offers.length == 1) { + print("offer has been created"); + } + + // Now let's deautorize the trustline but allow the trustor to maintain his offer. + // For this, we set the authorized flag to 2. + aop = AllowTrustOperationBuilder(trustorAccountId, assetCode, 2) + .build(); // authorized to maintain liabilities. + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(aop) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + + // Load the offers to see if our offer is still there. + offers = (await sdk.offers.forAccount(trustorAccountId).execute()).records; + if (offers.length == 1) { + print("success, offer exists"); + } + + // Next, let's try to send some ASTRO to the trustor account. + // This should not work, since the trustline has been deauthorized before. + po = PaymentOperationBuilder(trustorAccountId, astroDollar, "100").build(); + transaction = TransactionBuilder(issuerAccount, Network.TESTNET) + .addOperation(po) + .build(); + transaction.sign(issuerKeipair); + response = await sdk.submitTransaction(transaction); + if (!response.success) ; + { + // is not authorized for new funds + print("payment correctly blocked."); + } + }); }