-
Notifications
You must be signed in to change notification settings - Fork 116
Single Asset Vault XLS-65d #814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f0a0f58
e4e9ec5
5d015a3
6ea3965
f06f909
2858df2
3e86842
ea1ef24
6966ae7
24b4df0
3646909
307c515
e97a4b7
1617cad
671690a
b09b37a
537cc2f
6c4f801
2765937
18bfd1c
f967f23
eb78553
4cb1d02
f4830a0
0abade7
a1073b3
dd20aa8
4e7343b
edd5400
d7a903f
c90479c
5a3b29c
12b7819
f00a4c5
afbd4e5
27ff509
b2c2de7
9488ae9
ebb70ec
2dc7e25
a2619de
56a19e8
de2131e
4b2084d
eb0260e
4e9a805
9c11f46
e6f591f
3661d9a
260b69f
217cace
4e728b5
6a1be36
dfc19ff
34cee18
16bbc80
25e204e
9144d2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| from tests.integration.integration_test_case import IntegrationTestCase | ||
| from tests.integration.it_utils import ( | ||
| fund_wallet_async, | ||
| sign_and_reliable_submission_async, | ||
| test_async_and_sync, | ||
| ) | ||
| from xrpl.models.currencies import XRP | ||
| from xrpl.models.requests import AccountObjects, VaultInfo | ||
| from xrpl.models.response import ResponseStatus | ||
| from xrpl.models.transactions import VaultCreate | ||
| from xrpl.models.transactions.vault_create import VaultCreateFlag | ||
| from xrpl.wallet import Wallet | ||
|
|
||
|
|
||
| class TestVaultInfo(IntegrationTestCase): | ||
| @test_async_and_sync(globals()) | ||
| async def test_basic_functionality(self, client): | ||
|
|
||
| VAULT_OWNER = Wallet.create() | ||
| await fund_wallet_async(VAULT_OWNER) | ||
|
|
||
| # Create a vault | ||
| # Additionally validate the usage of flags in the VaultCreate transaction | ||
| tx = VaultCreate( | ||
| account=VAULT_OWNER.address, | ||
| asset=XRP(), | ||
| withdrawal_policy=1, | ||
| flags=VaultCreateFlag.TF_VAULT_PRIVATE | ||
| | VaultCreateFlag.TF_VAULT_SHARE_NON_TRANSFERABLE, | ||
| ) | ||
| response = await sign_and_reliable_submission_async(tx, VAULT_OWNER, client) | ||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||
|
|
||
| # Note: Due to the setup of the integration testing framework, it is difficult | ||
| # to obtain the next-sequence number of an account (in sync Client tests). | ||
| # Hence, AccountObjects request is used to fetch the `index` of the vault | ||
| # ledger-object. | ||
| vault_object = await client.request( | ||
| AccountObjects( | ||
| account=VAULT_OWNER.address, | ||
| type="vault", | ||
| ) | ||
| ) | ||
| self.assertEqual(len(vault_object.result["account_objects"]), 1) | ||
| self.assertEqual( | ||
| vault_object.result["account_objects"][0]["LedgerEntryType"], "Vault" | ||
| ) | ||
| vault_object_hash = vault_object.result["account_objects"][0]["index"] | ||
|
|
||
| # Fetch information about the vault using VaultInfo request | ||
| response = await client.request( | ||
| VaultInfo( | ||
| vault_id=vault_object_hash, | ||
| ) | ||
| ) | ||
| self.assertTrue(response.is_successful()) | ||
| self.assertEqual(response.result["vault"]["Owner"], VAULT_OWNER.address) | ||
| self.assertEqual(response.result["vault"]["index"], vault_object_hash) |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,167 @@ | ||||||||||
| from tests.integration.integration_test_case import IntegrationTestCase | ||||||||||
| from tests.integration.it_utils import ( | ||||||||||
| fund_wallet_async, | ||||||||||
| sign_and_reliable_submission_async, | ||||||||||
| test_async_and_sync, | ||||||||||
| ) | ||||||||||
| from tests.integration.reusable_values import WALLET | ||||||||||
| from xrpl.models import ( | ||||||||||
| AccountSet, | ||||||||||
| AccountSetAsfFlag, | ||||||||||
| Payment, | ||||||||||
| TrustSet, | ||||||||||
| VaultClawback, | ||||||||||
| VaultCreate, | ||||||||||
| VaultDelete, | ||||||||||
| VaultDeposit, | ||||||||||
| VaultSet, | ||||||||||
| VaultWithdraw, | ||||||||||
| ) | ||||||||||
| from xrpl.models.amounts.issued_currency_amount import IssuedCurrencyAmount | ||||||||||
| from xrpl.models.currencies import IssuedCurrency | ||||||||||
| from xrpl.models.requests import AccountObjects, LedgerEntry | ||||||||||
| from xrpl.models.requests.account_objects import AccountObjectType | ||||||||||
| from xrpl.models.response import ResponseStatus | ||||||||||
| from xrpl.models.transactions.vault_create import WithdrawalPolicy | ||||||||||
| from xrpl.utils import str_to_hex | ||||||||||
| from xrpl.wallet import Wallet | ||||||||||
|
|
||||||||||
|
|
||||||||||
| class TestSingleAssetVault(IntegrationTestCase): | ||||||||||
| @test_async_and_sync(globals()) | ||||||||||
| async def test_sav_lifecycle(self, client): | ||||||||||
|
|
||||||||||
| vault_owner = Wallet.create() | ||||||||||
| await fund_wallet_async(vault_owner) | ||||||||||
|
|
||||||||||
| issuer_wallet = Wallet.create() | ||||||||||
| await fund_wallet_async(issuer_wallet) | ||||||||||
|
|
||||||||||
| # Set up the relevant flags on the issuer_wallet account -- This is | ||||||||||
| # a pre-requisite for a Vault to hold the Issued Currency Asset | ||||||||||
| # This test uses an IOU to demonstrate the VaultClawback functionality. | ||||||||||
| # Clawback is not possible with the native XRP asset. | ||||||||||
| response = await sign_and_reliable_submission_async( | ||||||||||
| AccountSet( | ||||||||||
| account=issuer_wallet.classic_address, | ||||||||||
| set_flag=AccountSetAsfFlag.ASF_DEFAULT_RIPPLE, | ||||||||||
| ), | ||||||||||
| issuer_wallet, | ||||||||||
| ) | ||||||||||
| self.assertTrue(response.is_successful()) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| response = await sign_and_reliable_submission_async( | ||||||||||
| AccountSet( | ||||||||||
| account=issuer_wallet.classic_address, | ||||||||||
| set_flag=AccountSetAsfFlag.ASF_ALLOW_TRUSTLINE_CLAWBACK, | ||||||||||
| ), | ||||||||||
| issuer_wallet, | ||||||||||
| ) | ||||||||||
| self.assertTrue(response.is_successful()) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-0.a: Prerequisites: Set up the IOU trust line | ||||||||||
| tx = TrustSet( | ||||||||||
| account=WALLET.address, | ||||||||||
| limit_amount=IssuedCurrencyAmount( | ||||||||||
| currency="USD", issuer=issuer_wallet.address, value="1000" | ||||||||||
| ), | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, WALLET, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-0.b: Send the payment of IOUs from issuer_wallet to WALLET | ||||||||||
| tx = Payment( | ||||||||||
| account=issuer_wallet.address, | ||||||||||
| amount=IssuedCurrencyAmount( | ||||||||||
| currency="USD", issuer=issuer_wallet.address, value="1000" | ||||||||||
| ), | ||||||||||
| destination=WALLET.address, | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, issuer_wallet, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-1.a: Create a vault | ||||||||||
| tx = VaultCreate( | ||||||||||
| account=vault_owner.address, | ||||||||||
| asset=IssuedCurrency(currency="USD", issuer=issuer_wallet.address), | ||||||||||
| assets_maximum="1000", | ||||||||||
| withdrawal_policy=WithdrawalPolicy.VAULT_STRATEGY_FIRST_COME_FIRST_SERVE, | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, vault_owner, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-1.b: Verify the existence of the vault with account_objects RPC call | ||||||||||
| account_objects_response = await client.request( | ||||||||||
| AccountObjects(account=vault_owner.address, type=AccountObjectType.VAULT) | ||||||||||
| ) | ||||||||||
| self.assertEqual(len(account_objects_response.result["account_objects"]), 1) | ||||||||||
|
|
||||||||||
| VAULT_ID = account_objects_response.result["account_objects"][0]["index"] | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add validation for vault existence before extracting VAULT_ID. The code assumes that the vault exists in the account objects without validation. -VAULT_ID = account_objects_response.result["account_objects"][0]["index"]
+account_objects = account_objects_response.result.get("account_objects", [])
+self.assertGreater(len(account_objects), 0, "No vault found in account objects")
+VAULT_ID = account_objects[0]["index"]📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The existence is guaranteed due to a successful There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ckeshava You're absolutely right! I apologize for overlooking the existing validation. The assertion The existing validation is indeed sufficient for this test case, and my original suggestion was unnecessary. Thank you for the clarification! 🧠 Learnings used |
||||||||||
|
|
||||||||||
| # Step-1.c: Verify the existence of the vault with ledger_entry RPC call | ||||||||||
| ledger_entry_response = await client.request(LedgerEntry(index=VAULT_ID)) | ||||||||||
| self.assertEqual(ledger_entry_response.status, ResponseStatus.SUCCESS) | ||||||||||
|
|
||||||||||
| # Step-2: Update the characteristics of the vault with VaultSet transaction | ||||||||||
| # print(await client.request(AccountInfo(account=vault_owner.address))) | ||||||||||
| tx = VaultSet( | ||||||||||
| account=vault_owner.address, | ||||||||||
| vault_id=VAULT_ID, | ||||||||||
| data=str_to_hex("auxilliary data pertaining to the vault"), | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, vault_owner, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-3: Execute a VaultDeposit transaction | ||||||||||
| tx = VaultDeposit( | ||||||||||
| account=WALLET.address, | ||||||||||
| vault_id=VAULT_ID, | ||||||||||
| amount=IssuedCurrencyAmount( | ||||||||||
| currency="USD", issuer=issuer_wallet.address, value="10" | ||||||||||
| ), | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, WALLET, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-4: Execute a VaultWithdraw transaction | ||||||||||
| tx = VaultWithdraw( | ||||||||||
| account=WALLET.address, | ||||||||||
| vault_id=VAULT_ID, | ||||||||||
| amount=IssuedCurrencyAmount( | ||||||||||
| currency="USD", issuer=issuer_wallet.address, value="9" | ||||||||||
| ), | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, WALLET, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-5: Execute a VaultClawback transaction from issuer_wallet | ||||||||||
| tx = VaultClawback( | ||||||||||
| holder=WALLET.address, | ||||||||||
| account=issuer_wallet.address, | ||||||||||
| vault_id=VAULT_ID, | ||||||||||
| # Note: Although the amount is specified as 9, 1 unit of the IOU will be | ||||||||||
| # clawed back, because that is the remaining balance in the vault | ||||||||||
| amount=IssuedCurrencyAmount( | ||||||||||
| currency="USD", issuer=issuer_wallet.address, value="9" | ||||||||||
| ), | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, issuer_wallet, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
|
|
||||||||||
| # Step-6: Delete the Vault with VaultDelete transaction | ||||||||||
| tx = VaultDelete( | ||||||||||
| account=vault_owner.address, | ||||||||||
| vault_id=VAULT_ID, | ||||||||||
| ) | ||||||||||
| response = await sign_and_reliable_submission_async(tx, vault_owner, client) | ||||||||||
| self.assertEqual(response.status, ResponseStatus.SUCCESS) | ||||||||||
| self.assertEqual(response.result["engine_result"], "tesSUCCESS") | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import unittest | ||
|
|
||
| from xrpl.core.binarycodec.types.number import Number | ||
|
|
||
|
|
||
| class TestNumber(unittest.TestCase): | ||
| def test_serialization_and_deserialization(self): | ||
| serialized_number = Number.from_value("124") | ||
| self.assertEqual(serialized_number.to_json(), "124") | ||
|
|
||
| serialized_number = Number.from_value("1000") | ||
| self.assertEqual(serialized_number.to_json(), "1000") | ||
|
|
||
| serialized_number = Number.from_value("0") | ||
| self.assertEqual(serialized_number.to_json(), "0") | ||
|
|
||
| serialized_number = Number.from_value("-1") | ||
| self.assertEqual(serialized_number.to_json(), "-1") | ||
|
|
||
| serialized_number = Number.from_value("-10") | ||
| self.assertEqual(serialized_number.to_json(), "-10") | ||
|
|
||
| serialized_number = Number.from_value("123.456") | ||
| self.assertEqual(serialized_number.to_json(), "123.456") | ||
|
|
||
| serialized_number = Number.from_value("1.456e-45") | ||
| self.assertEqual(serialized_number.to_json(), "1456000000000000e-60") | ||
|
|
||
| serialized_number = Number.from_value("0.456e34") | ||
| self.assertEqual(serialized_number.to_json(), "4560000000000000e18") | ||
|
|
||
| serialized_number = Number.from_value("4e34") | ||
| self.assertEqual(serialized_number.to_json(), "4000000000000000e19") | ||
|
|
||
ckeshava marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| def test_extreme_limits(self): | ||
| lowest_mantissa = "-9223372036854776" | ||
| serialized_number = Number.from_value(lowest_mantissa + "e3") | ||
| self.assertEqual( | ||
| serialized_number.display_serialized_hex(), "FFDF3B645A1CAC0800000003" | ||
| ) | ||
|
|
||
| highest_mantissa = "9223372036854776" | ||
| serialized_number = Number.from_value(highest_mantissa + "e3") | ||
| self.assertEqual( | ||
| serialized_number.display_serialized_hex(), "0020C49BA5E353F800000003" | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from unittest import TestCase | ||
|
|
||
| from xrpl.models.requests import VaultInfo | ||
|
|
||
| VAULT_ID = "CE47F59928D43773A8A9CB7F525BE031977EFB72A23FF094C1C326E687D2B567" | ||
|
|
||
|
|
||
| class TestVaultInfo(TestCase): | ||
| def test_valid_vault_info(self): | ||
| request = VaultInfo( | ||
| vault_id=VAULT_ID, | ||
| ) | ||
| self.assertTrue(request.is_valid()) | ||
|
|
||
| def test_vault_info_requires_parameters(self): | ||
| with self.assertRaises(ValueError): | ||
| VaultInfo() | ||
|
|
||
| def test_vault_info_rejects_conflicting_parameters(self): | ||
| with self.assertRaises(ValueError): | ||
| VaultInfo( | ||
| vault_id=VAULT_ID, | ||
| owner="rN6zcSynkRnf8zcgTVrRL8K7r4ovE7J4Zj", | ||
| seq=1234567890, | ||
| ) | ||
|
|
||
| def test_valid_vault_info_with_owner_and_seq(self): | ||
| request = VaultInfo( | ||
| owner="rN6zcSynkRnf8zcgTVrRL8K7r4ovE7J4Zj", | ||
| seq=1234567890, | ||
| ) | ||
| self.assertTrue(request.is_valid()) |
Uh oh!
There was an error while loading. Please reload this page.