Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/xrpl/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
### Fixed
* Update ripple-binary-codec to 2.5.1 to address serialization/deserialization issues in `Issue` serialized type for `MPTIssue`.
* Better faucet error handling
* Mark the `AssetsAvailable`, `AssetsTotal`, and `LossUnrealized` fields of the Vault object as optional.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Mark the `AssetsAvailable`, `AssetsTotal`, and `LossUnrealized` fields of the Vault object as optional.
* Mark the `AssetsAvailable`, `AssetsTotal`, and `LossUnrealized` fields of the Vault object as Default.

Copy link
Collaborator Author

@kuan121 kuan121 Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to make this change. In rippled, soeDEFAULT is an internal serialization style. In xrpl.js/Typescript, fields are either required or optional (marked with ?). There is no concept of "Default" fields in TypeScript.


## 4.4.3 (2025-11-07)

Expand Down
6 changes: 3 additions & 3 deletions packages/xrpl/src/models/ledger/Vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ export default interface Vault extends BaseLedgerEntry, HasPreviousTxnID {
/**
* The total value of the vault.
*/
AssetsTotal: string
AssetsTotal?: string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: These fields have been marked as "Default", not "Optional". Hence, we need to introduce a Default value for these fields. I'm not sure if there is a precedent in the xrpl.js library, we'll need to look into it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those fields of the Vault ledger entry were updated from soeREQUIRED to soeDEFAULT, and, by definition, soeDEFAULT is optional, if present, must not have default value. The correct TypeScript representation is simply making the field optional with ?, which is what we've done in this library, e.g., AccountRoot.AccountTxnID?, AccountRoot.AMMID?, AccountRoot.BurnedNFTokens?, AccountRoot.BurnedNFTokens?


/**
* The asset amount that is available in the vault.
*/
AssetsAvailable: string
AssetsAvailable?: string

/**
* The potential loss amount that is not yet realized expressed as the vaults asset.
*/
LossUnrealized: string
LossUnrealized?: string

/**
* The identifier of the share MPTokenIssuance object.
Expand Down
4 changes: 2 additions & 2 deletions packages/xrpl/src/models/methods/vaultInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ export interface VaultInfoResponse extends BaseResponse {
/**
* Amount of assets currently available for withdrawal.
*/
AssetsAvailable: string
AssetsAvailable?: string
Copy link
Collaborator

@Patel-Raj11 Patel-Raj11 Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a breaking change is introduced in rippled that makes these properties optional that were once required. If someone if accessing them directly as we did in integration tests, it would break their code.

Not to block this, but should we confirm this in cpp-informal or xrpl-lending-protocol-core slack channel?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for bringing this up. I asked in #cpp-informal. The conclusion is this is fine since SAV is not even up for voting yet and breaking changes are allowed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw the note from Mayukha, since we are releasing library even before the amendment goes live on Mainnet, we should allow such breaking changes as bug fixes OR keep releasing, the features as release candidates and only release a stable version once the amendment is live on mainnet (to follow Semver). Some thoughts...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you said makes sense. Feel free to champion this, and we should adopt it if it brings benefits to the team and the community.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are releasing library even before the amendment goes live on Mainnet, we should allow such breaking changes as bug fixes

Where can people use the client library features for Single-Asset-Vault? Apart from standalone nodes on their local nodes, is it available for use on public networks? (The XRPLF developers have the right to introduce breaking changes into the devnet, because features are experimental, by definition on the devnet.)


/**
* Total amount of assets in the vault.
*/
AssetsTotal: string
AssetsTotal?: string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these fields marked as Optional in the vaultInfo RPC method? As per my understanding, the vaultInfo RPC response prints the Default values for these fields, even if the genesis VaultCreate transaction did not explicitly specify these fields.

In your experiments, did you observe that vaultInfo does not print these fields?

Copy link
Collaborator Author

@kuan121 kuan121 Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your experiments, did you observe that vaultInfo does not print these fields?

Correct. The existing integration tests are failing because vaultInfo RPC doesn't include those fields in the response when they have default values. This match the definition of an soeDEFAULT field, which is optional, if present, must not have default value. In other words, If they have the default values, they won't be present in rippled, and thus Vault related RPC responses.


/**
* Ledger entry type, always "Vault".
Expand Down
4 changes: 2 additions & 2 deletions packages/xrpl/test/integration/requests/vaultInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ describe('Single Asset Vault', function () {
VaultWithdrawalPolicy.vaultStrategyFirstComeFirstServe,
)
assert.equal(
vault.AssetsTotal,
vault.AssetsTotal ?? '0',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the test file supplying a default value for these fields? The default value of 0 must have been provided by rippled automatically.

It is preferable to remove the ?? operator because it will inform readers about the choices for default values.

Suggested change
vault.AssetsTotal ?? '0',
vault.AssetsTotal,

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value of 0 must have been provided by rippled automatically.

This is no longer true, and why those tests are failing. Without the change, we are performing assert.equal(vault.AssetsTotal=undefined, '0', 'New Vault should have zero total assets')

'0',
'New Vault should have zero total assets',
)
assert.equal(
vault.AssetsAvailable,
vault.AssetsAvailable ?? '0',
'0',
'New Vault should have zero available assets',
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ describe('Single Asset Vault', function () {

// Should have new balance after deposit (this assumes AssetsTotal tracks deposits)
assert.equal(
afterDepositVault.AssetsTotal,
afterDepositVault.AssetsTotal ?? '0',
depositAmount,
'Vault should reflect deposited assets',
)
Expand Down Expand Up @@ -224,9 +224,9 @@ describe('Single Asset Vault', function () {

// Should have reduced balance after withdrawal (should be 0 if all withdrawn)
assert.equal(
afterWithdrawVault.AssetsTotal,
afterWithdrawVault.AssetsTotal ?? '0',
(
BigInt(afterDepositVault.AssetsTotal) - BigInt(withdrawAmount)
BigInt(afterDepositVault.AssetsTotal ?? '0') - BigInt(withdrawAmount)
).toString(),
'Vault should reflect withdrawn assets',
)
Expand Down Expand Up @@ -255,13 +255,14 @@ describe('Single Asset Vault', function () {
account: vaultOwnerWallet.classicAddress,
type: 'vault',
})

const afterClawbackVault = afterClawbackResult.result
.account_objects[0] as Vault

assert.equal(
afterClawbackVault.AssetsTotal,
afterClawbackVault.AssetsTotal ?? '0',
(
BigInt(afterWithdrawVault.AssetsTotal) - BigInt(clawbackAmount)
BigInt(afterWithdrawVault.AssetsTotal ?? '0') - BigInt(clawbackAmount)
).toString(),
'Vault should reflect assets after clawback',
)
Expand Down Expand Up @@ -470,9 +471,9 @@ describe('Single Asset Vault', function () {

// Should have reduced balance after withdrawal (should be 0 if all withdrawn)
assert.equal(
afterWithdrawVault.AssetsTotal,
afterWithdrawVault.AssetsTotal ?? '0',
(
BigInt(afterDepositVault.AssetsTotal) - BigInt(withdrawAmount)
BigInt(afterDepositVault.AssetsTotal ?? '0') - BigInt(withdrawAmount)
).toString(),
'Vault should reflect withdrawn assets',
)
Expand Down Expand Up @@ -504,9 +505,9 @@ describe('Single Asset Vault', function () {
.account_objects[0] as Vault

assert.equal(
afterClawbackVault.AssetsTotal,
afterClawbackVault.AssetsTotal ?? '0',
(
BigInt(afterWithdrawVault.AssetsTotal) - BigInt(clawbackAmount)
BigInt(afterWithdrawVault.AssetsTotal ?? '0') - BigInt(clawbackAmount)
).toString(),
'Vault should reflect assets after clawback',
)
Expand Down
Loading