From 27659c02962f08ee97d7a1d8c5aeda7110531fc8 Mon Sep 17 00:00:00 2001
From: Aleksandr <44946855+Platonenkov@users.noreply.github.com>
Date: Fri, 10 May 2024 13:19:03 +0300
Subject: [PATCH] NegativeUNL, AMMInfo (#68)
---
.ci-config/rippled.cfg | 121 +++++------
.github/workflows/dotnet.test.yml | 11 +-
.../Binary/BinarySerializer.cs | 1 +
Base/Xrpl.BinaryCodec/Binary/BytesList.cs | 9 +
.../{Types => Enums}/EngineResult.cs | 27 ++-
Base/Xrpl.BinaryCodec/Enums/Field.cs | 29 ++-
Base/Xrpl.BinaryCodec/Enums/FieldType.cs | 5 +-
Base/Xrpl.BinaryCodec/Enums/FromJson.cs | 1 +
Base/Xrpl.BinaryCodec/Enums/FromParser.cs | 1 +
Base/Xrpl.BinaryCodec/Enums/IssueField.cs | 12 ++
.../{Types => Enums}/LedgerEntryType.cs | 2 +-
.../Enums/SerializedEnumItem.cs | 1 +
.../{Types => Enums}/TransactionType.cs | 9 +-
Base/Xrpl.BinaryCodec/Exceptions.cs | 21 ++
Base/Xrpl.BinaryCodec/ISerializedType.cs | 36 ----
Base/Xrpl.BinaryCodec/ShaMapTree/ShaMap.cs | 1 +
Base/Xrpl.BinaryCodec/Types/Currency.cs | 19 --
.../Xrpl.BinaryCodec/Types/ISerializedType.cs | 124 +++++++++++
.../Types/InvalidJsonException.cs | 25 ---
Base/Xrpl.BinaryCodec/Types/Issue.cs | 106 +++++++++
Base/Xrpl.BinaryCodec/Types/UnissuedAmount.cs | 28 ---
Tests/Xrpl.Tests/Models/TestAMMBid.cs | 165 ++++++++++++++
Tests/Xrpl.Tests/Models/TestAMMCreate.cs | 92 ++++++++
Tests/Xrpl.Tests/Models/TestAMMDeposit.cs | 156 ++++++++++++++
Tests/Xrpl.Tests/Models/TestAMMVote.cs | 79 +++++++
Tests/Xrpl.Tests/Models/TestAMMWithdraw.cs | 167 ++++++++++++++
Tests/Xrpl.Tests/Models/TestAccountSet.cs | 3 +-
Xrpl/Models/Common/Common.cs | 60 ------
Xrpl/Models/Common/{Currency.cs => Index.cs} | 137 +++++++++++-
Xrpl/Models/Common/LedgerIndex.cs | 31 ---
Xrpl/Models/Enums.cs | 31 ++-
Xrpl/Models/Ledger/LOAccountRoot.cs | 1 +
Xrpl/Models/Ledger/LOAmm.cs | 132 ++++++++++++
Xrpl/Models/Ledger/LONegativeUNL.cs | 40 ++++
Xrpl/Models/Methods/AMMInfo.cs | 112 ++++++++++
Xrpl/Models/Transactions/AMMBid.cs | 149 +++++++++++++
Xrpl/Models/Transactions/AMMCreate.cs | 105 +++++++++
Xrpl/Models/Transactions/AMMDelete.cs | 88 ++++++++
Xrpl/Models/Transactions/AMMDeposit.cs | 183 ++++++++++++++++
Xrpl/Models/Transactions/AMMVote.cs | 80 +++++++
Xrpl/Models/Transactions/AMMWithdraw.cs | 203 ++++++++++++++++++
Xrpl/Models/Transactions/Common.cs | 18 ++
Xrpl/Models/Transactions/TxFormat.cs | 54 ++---
Xrpl/Models/Transactions/Validation.cs | 27 ++-
Xrpl/Models/Utils/Flags.cs | 14 ++
45 files changed, 2403 insertions(+), 313 deletions(-)
rename Base/Xrpl.BinaryCodec/{Types => Enums}/EngineResult.cs (86%)
create mode 100644 Base/Xrpl.BinaryCodec/Enums/IssueField.cs
rename Base/Xrpl.BinaryCodec/{Types => Enums}/LedgerEntryType.cs (98%)
rename Base/Xrpl.BinaryCodec/{Types => Enums}/TransactionType.cs (93%)
delete mode 100644 Base/Xrpl.BinaryCodec/ISerializedType.cs
create mode 100644 Base/Xrpl.BinaryCodec/Types/ISerializedType.cs
delete mode 100644 Base/Xrpl.BinaryCodec/Types/InvalidJsonException.cs
create mode 100644 Base/Xrpl.BinaryCodec/Types/Issue.cs
delete mode 100644 Base/Xrpl.BinaryCodec/Types/UnissuedAmount.cs
create mode 100644 Tests/Xrpl.Tests/Models/TestAMMBid.cs
create mode 100644 Tests/Xrpl.Tests/Models/TestAMMCreate.cs
create mode 100644 Tests/Xrpl.Tests/Models/TestAMMDeposit.cs
create mode 100644 Tests/Xrpl.Tests/Models/TestAMMVote.cs
create mode 100644 Tests/Xrpl.Tests/Models/TestAMMWithdraw.cs
delete mode 100644 Xrpl/Models/Common/Common.cs
rename Xrpl/Models/Common/{Currency.cs => Index.cs} (52%)
delete mode 100644 Xrpl/Models/Common/LedgerIndex.cs
create mode 100644 Xrpl/Models/Ledger/LOAmm.cs
create mode 100644 Xrpl/Models/Ledger/LONegativeUNL.cs
create mode 100644 Xrpl/Models/Methods/AMMInfo.cs
create mode 100644 Xrpl/Models/Transactions/AMMBid.cs
create mode 100644 Xrpl/Models/Transactions/AMMCreate.cs
create mode 100644 Xrpl/Models/Transactions/AMMDelete.cs
create mode 100644 Xrpl/Models/Transactions/AMMDeposit.cs
create mode 100644 Xrpl/Models/Transactions/AMMVote.cs
create mode 100644 Xrpl/Models/Transactions/AMMWithdraw.cs
diff --git a/.ci-config/rippled.cfg b/.ci-config/rippled.cfg
index 5c219c65..09bbe09f 100644
--- a/.ci-config/rippled.cfg
+++ b/.ci-config/rippled.cfg
@@ -105,67 +105,68 @@ validators.txt
# Note: The version of rippled you use this config with must have an implementation for the amendments you attempt to enable or it will crash.
# If you need the version of rippled to be more up to date, you may need to make a comment on this repo: https://github.com/WietseWind/docker-rippled
-[amendments]
+[features]
# Devnet amendments as of June 28th, 2023
-B4E4F5D2D6FB84DF7399960A732309C9FD530EAE5941838160042833625A6076 NegativeUNL
-DF8B4536989BDACE3F934F29423848B9F1D76D09BE6A1FCFE7E7F06AA26ABEAD fixRemoveNFTokenAutoTrustLine
-3C43D9A973AA4443EF3FC38E42DD306160FBFFDAB901CD8BAA15D09F2597EB87 NonFungibleTokensV1
-98DECF327BF79997AEC178323AD51A830E457BFC6D454DAF3E46E5EC42DC619F CheckCashMakesTrustLine
-B6B3EEDC0267AB50491FDC450A398AF30DBCD977CECED8BEF2499CAB5DAC19E2 fixRmSmallIncreasedQOffers
-452F5906C46D46F407883344BFDD90E672B672C5E9943DB4891E3A34FEEEB9DB fixSTAmountCanonicalize
-AF8DF7465C338AE64B1E937D6C8DA138C0D63AD5134A68792BBBE1F63356C422 FlowSortStrands
-955DF3FA5891195A9DAEFA1DDC6BB244B545DDE1BAA84CBB25D5F12A8DA68A0C TicketBatch
-B4D44CC3111ADD964E846FC57760C8B50FFCD5A82C86A72756F6B058DDDF96AD fix1201
-89308AF3B8B10B7192C4E613E1D2E4D9BA64B2EE2D5232402AE82A6A7220D953 fixQualityUpperBound
-3012E8230864E95A58C60FD61430D7E1B4D3353195F2981DC12B0C7C0950FFAC FlowCross
-DC9CA96AEA1DCF83E527D1AFC916EFAF5D27388ECA4060A88817C1238CAEE0BF EnforceInvariants
-B9E739B8296B4A1BB29BE990B17D66E21B62A300A909F25AC55C22D6C72E1F9D fix1523
-1F4AFA8FA1BC8827AD4C0F682C03A8B671DCDF6B5C4DE36D44243A684103EF88 HardenedValidations
-3CBC5C4E630A1B82380295CDA84B32B49DD066602E74E39B85EF64137FA65194 DepositPreauth
-586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF1FC07EFE41D MultiSignReserve
-58BE9B5968C4DA7C59BA900961828B113E5490699B21877DEF9A31E9D0FE5D5F fix1623
-42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE FeeEscalation
-08DE7D96082187F6E6578530258C77FAABABE4C20474BDB82F04B021F1A68647 PayChan
-67A34F2CF55BFC0F93AACD5B281413176FEE195269FA6D95219A2DF738671172 fix1513
-00C1FC4A53E60AB02C864641002B3172F38677E29C26C5406685179B37E1EDAC RequireFullyCanonicalSig
-CA7C02118BA27599528543DFE77BA6838D1B0F43B447D4D7F53523CE6A0E9AC2 fix1543
-532651B4FD58DF8922A49BA101AB3E996E5BFBF95A913B3E392504863E63B164 TickSize
-25BA44241B3BD880770BFA4DA21C7180576831855368CBEC6A3154FDE4A7676E fix1781
-8F81B066ED20DAECA20DF57187767685EEF3980B228E0667A650BAF24426D3B4 fixCheckThreading
-5D08145F0A4983F23AFFFF514E83FAD355C5ABFBB6CAB76FB5BC8519FF5F33BE fix1515
-1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146 CryptoConditions
-1D3463A5891F9E589C5AE839FFAC4A917CE96197098A1EF22304E1BC5B98A454 fix1528
-621A0B264970359869E3C0363A899909AAB7A887C8B73519E4ECF952D33258A8 fixPayChanRecipientOwnerDir
-CC5ABAE4F3EC92E94A59B1908C2BE82D2228B6485C00AFF8F22DF930D89C194E SortedDirectories
-FBD513F1B893AC765B78F250E6FFA6A11B573209D1842ADC787C850696741288 fix1578
-7117E2EC2DBF119CA55181D69819F1999ECEE1A0225A7FD2B9ED47940968479C fix1571
-4F46DF03559967AC60F2EB272FEFE3928A7594A45FF774B87A7E540DB0F8F068 fixAmendmentMajorityCalc
-2CD5286D8D687E98B41102BDD797198E81EA41DF7BD104E6561FEB104EFF2561 fixTakerDryOfferRemoval
-C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD37 fixMasterKeyAsRegularKey
-740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11 Flow
-07D43DCE529B15A10827E5E04943B496762F9A88E3268269D69C44BE49E21104 Escrow
-6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC TrustSetAuth
-30CD365592B8EE40489BA01AE2F7555CAC9C983145871DC82A42A31CF5BAE7D9 DeletableAccounts
-F64E1EABBE79D55B3BB82020516CEC2C582A98A6BFE20FBE9BB6A0D233418064 DepositAuth
-E2E6F2866106419B88C50045ACE96368558C345566AC8F2BDF5A5B5587F0E6FA fix1368
-6C92211186613F9647A89DFFBAB8F94C99D4C7E956D495270789128569177DA1 fix1512
-42EEA5E28A97824821D4EF97081FE36A54E9593C6E4F20CBAE098C69D2E072DC fix1373
-4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373 MultiSign
-157D2D480E006395B76F948E3E07A45A05FE10230D88A7993C71F97AE4B1F2D1 Checks
-32A122F1352A4C7B3A6D790362CC34749C5E57FCE896377BFDC6CCD14F6CD627 NonFungibleTokensV1_1
+NegativeUNL
+fixRemoveNFTokenAutoTrustLine
+NonFungibleTokensV1
+CheckCashMakesTrustLine
+fixRmSmallIncreasedQOffers
+fixSTAmountCanonicalize
+FlowSortStrands
+TicketBatch
+fix1201
+fixQualityUpperBound
+FlowCross
+EnforceInvariants
+fix1523
+HardenedValidations
+DepositPreauth
+MultiSignReserve
+fix1623
+FeeEscalation
+PayChan
+fix1513
+RequireFullyCanonicalSig
+fix1543
+TickSize
+fix1781
+fixCheckThreading
+fix1515
+CryptoConditions
+fix1528
+fixPayChanRecipientOwnerDir
+SortedDirectories
+fix1578
+fix1571
+fixAmendmentMajorityCalc
+fixTakerDryOfferRemoval
+fixMasterKeyAsRegularKey
+Flow
+Escrow
+TrustSetAuth
+DeletableAccounts
+DepositAuth
+fix1368
+fix1512
+fix1373
+MultiSign
+Checks
+NonFungibleTokensV1_1
# 1.10.0 Amendments
-47C3002ABA31628447E8E9A8B315FAA935CE30183F9A9B86845E469CA2CDC3DF DisallowIncoming
-73761231F7F3D94EC3D8C63D91BDD0D89045C6F71B917D1925C01253515A6669 fixNonFungibleTokensV1_2
-F1ED6B4A411D8B872E65B9DCB4C8B100375B0DD3D62D07192E011D6D7F339013 fixTrustLinesToSelf
-2E2FB9CF8A44EB80F4694D38AADAE9B8B7ADAFD2F092E10068E61C98C4F092B0 fixUniversalNumber
-75A7E01C505DD5A179DFE3E000A9B6F1EDDEB55A12F95579A23E15B15DC8BE5A ImmediateOfferKilled
-93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515A7 XRPFees
+DisallowIncoming
+fixNonFungibleTokensV1_2
+fixTrustLinesToSelf
+fixUniversalNumber
+ImmediateOfferKilled
+XRPFees
# 1.11.0 Amendments
-B2A4DB846F0891BF2C76AB2F2ACC8F5B4EC64437135C6E56F3F859DE5FFD5856 ExpandedSignerList
-# 1.12.0-b1 Amendments
-56B241D7A43D40354D02A9DC4C8DF5C7A1F930D92A9035C4E12291B3CA3E1C2B featureClawback
-27CD95EE8E1E5A537FF2F89B6CEB7C622E78E9374EBD7DCBEDFAE21CD6F16E0A fixReducedOffersV1
+ExpandedSignerList
# 1.12.0 Amendments
-8CC0774A3BF66D1D22E76BBDA8E8A232E6B6313834301B3B23E8601196AE6455 AMM
-# Added August 9th, 2023
-AE35ABDEFBDE520372B31C957020B34A7A4A9DC3115A69803A44016477C84D6E fixNFTokenRemint
\ No newline at end of file
+AMM
+Clawback
+fixReducedOffersV1
+fixNFTokenRemint
+# 2.0.0 Amendments
+XChainBridge
+DID
\ No newline at end of file
diff --git a/.github/workflows/dotnet.test.yml b/.github/workflows/dotnet.test.yml
index 529466a3..f08eae98 100644
--- a/.github/workflows/dotnet.test.yml
+++ b/.github/workflows/dotnet.test.yml
@@ -3,6 +3,9 @@
name: .NET CI
+env:
+ RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4
+
on:
push:
branches: [ main ]
@@ -49,8 +52,8 @@ jobs:
- uses: actions/checkout@v3
- name: Run docker in background
- run: |
- docker run --detach --rm --name rippled-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/config/" --health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env "ENV_ARGS=-a --start" --env GITHUB_ACTIONS=true --env CI=true xrpllabsofficial/xrpld:1.12.0
+ run: |
+ docker run --detach --rm --name rippled-service -p 6006:6006 --volume "${{ github.workspace }}/.ci-config/":"/opt/ripple/etc/" --health-cmd="wget localhost:6006 || exit 1" --health-interval=5s --health-retries=10 --health-timeout=2s --env GITHUB_ACTIONS=true --env CI=true ${{ env.RIPPLED_DOCKER_IMAGE }} /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg
- name: Use .NET "${{ matrix.dotnet }}"
uses: actions/setup-dotnet@v3
@@ -67,5 +70,5 @@ jobs:
PORT: ${{ job.services.rippled.ports['6006'] }}
- name: Stop docker container
- if: always()
- run: docker stop rippled-service
\ No newline at end of file
+ if: always()
+ run: docker stop rippled-service
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/Binary/BinarySerializer.cs b/Base/Xrpl.BinaryCodec/Binary/BinarySerializer.cs
index 625bf1b8..2ccec0be 100644
--- a/Base/Xrpl.BinaryCodec/Binary/BinarySerializer.cs
+++ b/Base/Xrpl.BinaryCodec/Binary/BinarySerializer.cs
@@ -1,5 +1,6 @@
using System;
using Xrpl.BinaryCodec.Enums;
+using Xrpl.BinaryCodec.Types;
//https://github.com/XRPLF/xrpl.js/blob/8a9a9bcc28ace65cde46eed5010eb8927374a736/packages/ripple-binary-codec/src/serdes/binary-serializer.ts#L52
diff --git a/Base/Xrpl.BinaryCodec/Binary/BytesList.cs b/Base/Xrpl.BinaryCodec/Binary/BytesList.cs
index 037903e4..5e5c3109 100644
--- a/Base/Xrpl.BinaryCodec/Binary/BytesList.cs
+++ b/Base/Xrpl.BinaryCodec/Binary/BytesList.cs
@@ -49,6 +49,15 @@ public byte[] Bytes()
AddBytes(bytes, 0);
return bytes;
}
+ /// Get all bytes
+ /// Bytes
+ public byte[] ToBytes()
+ {
+ var n = BytesLength();
+ var bytes = new byte[n];
+ AddBytes(bytes, 0);
+ return bytes;
+ }
/// Hex Lookup
public static string[] HexLookup = new string[256];
static BytesList()
diff --git a/Base/Xrpl.BinaryCodec/Types/EngineResult.cs b/Base/Xrpl.BinaryCodec/Enums/EngineResult.cs
similarity index 86%
rename from Base/Xrpl.BinaryCodec/Types/EngineResult.cs
rename to Base/Xrpl.BinaryCodec/Enums/EngineResult.cs
index 37b9e7eb..8a3dde12 100644
--- a/Base/Xrpl.BinaryCodec/Types/EngineResult.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/EngineResult.cs
@@ -2,7 +2,7 @@
//todo not found doc
-namespace Xrpl.BinaryCodec.Types
+namespace Xrpl.BinaryCodec.Enums
{
public class EngineResult : SerializedEnumItem
{
@@ -58,6 +58,11 @@ private static EngineResult Add(string name, int ordinal, string description)
public static readonly EngineResult temUNCERTAIN = Add(nameof(temUNCERTAIN), -272, "In process of determining result. Never returned.");
public static readonly EngineResult temUNKNOWN = Add(nameof(temUNKNOWN), -271, "The transactions requires logic not implemented yet.");
+ public static readonly EngineResult temSEQ_AND_TICKET = Add(nameof(temSEQ_AND_TICKET), -263, "");
+ public static readonly EngineResult temBAD_NFTOKEN_TRANSFER_FEE = Add(nameof(temBAD_NFTOKEN_TRANSFER_FEE), -262, "");
+ public static readonly EngineResult temBAD_AMM_OPTIONS = Add(nameof(temBAD_AMM_OPTIONS), -261, "");
+ public static readonly EngineResult temBAD_AMM_TOKENS = Add(nameof(temBAD_AMM_TOKENS), -260, "");
+
public static readonly EngineResult tefFAILURE = Add(nameof(tefFAILURE), -199, "Failed to apply.");
public static readonly EngineResult tefALREADY = Add(nameof(tefALREADY), -198, "The exact transaction was already in this ledger.");
public static readonly EngineResult tefBAD_ADD_AUTH = Add(nameof(tefBAD_ADD_AUTH), -197, "Not authorized to add account.");
@@ -83,6 +88,9 @@ private static EngineResult Add(string name, int ordinal, string description)
public static readonly EngineResult terPRE_SEQ = Add(nameof(terPRE_SEQ), -92, "Missing/inapplicable prior transaction.");
public static readonly EngineResult terLAST = Add(nameof(terLAST), -91, "Process last.");
public static readonly EngineResult terNO_RIPPLE = Add(nameof(terNO_RIPPLE), -90, "Process last.");
+ public static readonly EngineResult terQUEUED = Add(nameof(terQUEUED), -89, "");
+ public static readonly EngineResult terPRE_TICKET = Add(nameof(terPRE_TICKET), -88, "");
+ public static readonly EngineResult terNO_AMM = Add(nameof(terNO_AMM), -87, "");
public static readonly EngineResult tesSUCCESS = Add(nameof(tesSUCCESS), 0, "The transaction was applied.");
public static readonly EngineResult tecCLAIM = Add(nameof(tecCLAIM), 100, "Fee claimed. Sequence used. No action.");
@@ -116,7 +124,22 @@ private static EngineResult Add(string name, int ordinal, string description)
public static readonly EngineResult tecDST_TAG_NEEDED = Add(nameof(tecDST_TAG_NEEDED), 143, "A destination tag is required.");
public static readonly EngineResult tecINTERNAL = Add(nameof(tecINTERNAL), 144, "An internal error has occurred during processing.");
public static readonly EngineResult tecOVERSIZE = Add(nameof(tecOVERSIZE), 145, "Object exceeded serialization limits.");
-
+
+ public static readonly EngineResult tecCANT_ACCEPT_OWN_NFTOKEN_OFFER = Add(nameof(tecCANT_ACCEPT_OWN_NFTOKEN_OFFER), 158, "");
+ public static readonly EngineResult tecINSUFFICIENT_FUNDS = Add(nameof(tecINSUFFICIENT_FUNDS), 159, "");
+ public static readonly EngineResult tecOBJECT_NOT_FOUND = Add(nameof(tecOBJECT_NOT_FOUND), 160, "");
+ public static readonly EngineResult tecINSUFFICIENT_PAYMENT = Add(nameof(tecINSUFFICIENT_PAYMENT), 161, "");
+ public static readonly EngineResult tecUNFUNDED_AMM = Add(nameof(tecUNFUNDED_AMM), 162, "");
+ public static readonly EngineResult tecAMM_BALANCE = Add(nameof(tecAMM_BALANCE), 163, "");
+ public static readonly EngineResult tecAMM_FAILED_DEPOSIT = Add(nameof(tecAMM_FAILED_DEPOSIT), 164, "");
+ public static readonly EngineResult tecAMM_FAILED_WITHDRAW = Add(nameof(tecAMM_FAILED_WITHDRAW), 165, "");
+ public static readonly EngineResult tecAMM_INVALID_TOKENS = Add(nameof(tecAMM_INVALID_TOKENS), 166, "");
+ public static readonly EngineResult tecAMM_EXISTS = Add(nameof(tecAMM_EXISTS), 167, "");
+ public static readonly EngineResult tecAMM_FAILED_BID = Add(nameof(tecAMM_FAILED_BID), 168, "");
+ public static readonly EngineResult tecAMM_FAILED_VOTE = Add(nameof(tecAMM_FAILED_VOTE), 169, "");
+
+
+
// ReSharper restore InconsistentNaming
public bool ShouldClaimFee()
{
diff --git a/Base/Xrpl.BinaryCodec/Enums/Field.cs b/Base/Xrpl.BinaryCodec/Enums/Field.cs
index 27fc6d48..e17fe111 100644
--- a/Base/Xrpl.BinaryCodec/Enums/Field.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/Field.cs
@@ -1,4 +1,5 @@
using System;
+using Xrpl.BinaryCodec.Types;
namespace Xrpl.BinaryCodec.Enums
{
@@ -85,6 +86,7 @@ private bool IsVlEncodedType()
public static readonly TransactionTypeField TransactionType = new TransactionTypeField(nameof(TransactionType), 2);
public static readonly Uint16Field SignerWeight = new Uint16Field(nameof(SignerWeight), 3);
public static readonly Uint16Field TransferFee = new Uint16Field(nameof(TransferFee), 4);
+ public static readonly Uint16Field TradingFee = new Uint16Field(nameof(TradingFee), 4);
public static readonly Uint16Field Version = new Uint16Field(nameof(Version), 16);
public static readonly Uint16Field HookStateChangeCount = new Uint16Field(nameof(HookStateChangeCount), 17);
public static readonly Uint16Field HookStateEmitCount = new Uint16Field(nameof(HookStateEmitCount), 18);
@@ -139,7 +141,9 @@ private bool IsVlEncodedType()
public static readonly Uint32Field BurnedTokens = new Uint32Field(nameof(BurnedTokens), 44);
public static readonly Uint32Field HookStateCount = new Uint32Field(nameof(HookStateCount), 45);
public static readonly Uint32Field EmitGeneration = new Uint32Field(nameof(EmitGeneration), 46);
-
+ public static readonly Uint32Field VoteWeight = new Uint32Field(nameof(VoteWeight), 47);
+ public static readonly Uint32Field DiscountedFee = new Uint32Field(nameof(DiscountedFee), 48);
+
public static readonly Uint64Field IndexNext = new Uint64Field(nameof(IndexNext), 1);
public static readonly Uint64Field IndexPrevious = new Uint64Field(nameof(IndexPrevious), 2);
public static readonly Uint64Field BookNode = new Uint64Field(nameof(BookNode), 3);
@@ -178,6 +182,7 @@ private bool IsVlEncodedType()
public static readonly Hash256Field EmitParentTxnID = new Hash256Field(nameof(EmitParentTxnID), 11);
public static readonly Hash256Field EmitNonce = new Hash256Field(nameof(EmitNonce), 12);
public static readonly Hash256Field EmitHookHash = new Hash256Field(nameof(EmitHookHash), 13);
+ public static readonly Hash256Field AMMID = new Hash256Field(nameof(AMMID), 14);
public static readonly Hash256Field BookDirectory = new Hash256Field(nameof(BookDirectory), 16);
public static readonly Hash256Field InvoiceID = new Hash256Field(nameof(InvoiceID), 17);
public static readonly Hash256Field Nickname = new Hash256Field(nameof(Nickname), 18);
@@ -207,11 +212,19 @@ private bool IsVlEncodedType()
public static readonly AmountField Fee = new AmountField(nameof(Fee), 8);
public static readonly AmountField SendMax = new AmountField(nameof(SendMax), 9);
public static readonly AmountField DeliverMin = new AmountField(nameof(DeliverMin), 10);
+ public static readonly AmountField Amount2 = new AmountField(nameof(Amount2), 11);
+ public static readonly AmountField BidMin = new AmountField(nameof(BidMin), 12);
+ public static readonly AmountField BidMax = new AmountField(nameof(BidMax), 13);
public static readonly AmountField MinimumOffer = new AmountField(nameof(MinimumOffer), 16);
public static readonly AmountField RippleEscrow = new AmountField(nameof(RippleEscrow), 17);
public static readonly AmountField DeliveredAmount = new AmountField(nameof(DeliveredAmount), 18);
public static readonly AmountField NFTokenBrokerFee = new AmountField(nameof(NFTokenBrokerFee), 19);
- public static readonly AmountField HookCallbackFee = new AmountField(nameof(HookCallbackFee), 20);
+ //public static readonly AmountField HookCallbackFee = new AmountField(nameof(HookCallbackFee), 20);
+ public static readonly AmountField LPTokenOut = new AmountField(nameof(LPTokenOut), 20);
+ public static readonly AmountField LPTokenIn = new AmountField(nameof(LPTokenIn), 21);
+ public static readonly AmountField EPrice = new AmountField(nameof(EPrice), 22);
+ public static readonly AmountField Price = new AmountField(nameof(Price), 23);
+ public static readonly AmountField LPTokenBalance = new AmountField(nameof(LPTokenBalance), 24);
public static readonly BlobField PublicKey = new BlobField(nameof(PublicKey), 1);
public static readonly BlobField MessageKey = new BlobField(nameof(MessageKey), 2);
@@ -247,6 +260,7 @@ private bool IsVlEncodedType()
public static readonly AccountIdField RegularKey = new AccountIdField(nameof(RegularKey), 8);
public static readonly AccountIdField NFTokenMinter = new AccountIdField(nameof(NFTokenMinter), 9);
public static readonly AccountIdField EmitCallback = new AccountIdField(nameof(EmitCallback), 10);
+ public static readonly AccountIdField AMMAccount = new AccountIdField(nameof(AMMAccount), 11);
public static readonly AccountIdField HookAccount = new AccountIdField(nameof(HookAccount), 16);
public static readonly Vector256Field Indexes = new Vector256Field(nameof(Indexes), 1);
@@ -257,6 +271,9 @@ private bool IsVlEncodedType()
public static readonly PathSetField Paths = new PathSetField(nameof(Paths), 1);
+ public static readonly IssueField Asset = new IssueField(nameof(Asset), 3);
+ public static readonly IssueField Asset2 = new IssueField(nameof(Asset2), 4);
+
public static readonly StObjectField TransactionMetaData = new StObjectField(nameof(TransactionMetaData), 2);
public static readonly StObjectField CreatedNode = new StObjectField(nameof(CreatedNode), 3);
public static readonly StObjectField DeletedNode = new StObjectField(nameof(DeletedNode), 4);
@@ -278,8 +295,10 @@ private bool IsVlEncodedType()
public static readonly StObjectField HookDefinition = new StObjectField(nameof(HookDefinition), 22);
public static readonly StObjectField HookParameter = new StObjectField(nameof(HookParameter), 23);
public static readonly StObjectField HookGrant = new StObjectField(nameof(HookGrant), 24);
-
- public static readonly StArrayField Signers = new StArrayField(nameof(Signers), 3, isSigningField: false);
+ public static readonly StObjectField VoteEntry = new StObjectField(nameof(VoteEntry), 25);
+ public static readonly StObjectField AuctionSlot = new StObjectField(nameof(AuctionSlot), 27);
+ public static readonly StObjectField AuthAccount = new StObjectField(nameof(AuthAccount), 28);
+ public static readonly StArrayField Signers = new StArrayField(nameof(Signers), 3, isSigningField:false);
public static readonly StArrayField SignerEntries = new StArrayField(nameof(SignerEntries), 4);
public static readonly StArrayField Template = new StArrayField(nameof(Template), 5);
public static readonly StArrayField Necessary = new StArrayField(nameof(Necessary), 6);
@@ -288,11 +307,13 @@ private bool IsVlEncodedType()
public static readonly StArrayField Memos = new StArrayField(nameof(Memos), 9);
public static readonly StArrayField NFTokens = new StArrayField(nameof(NFTokens), 10);
public static readonly StArrayField Hooks = new StArrayField(nameof(Hooks), 11);
+ public static readonly StArrayField VoteSlots = new StArrayField(nameof(VoteSlots), 14);
public static readonly StArrayField Majorities = new StArrayField(nameof(Majorities), 16);
public static readonly StArrayField DisabledValidators = new StArrayField(nameof(DisabledValidators), 17);
public static readonly StArrayField HookExecutions = new StArrayField(nameof(HookExecutions), 18);
public static readonly StArrayField HookParameters = new StArrayField(nameof(HookParameters), 19);
public static readonly StArrayField HookGrants = new StArrayField(nameof(HookGrants), 19);
+ public static readonly StArrayField AuthAccounts = new StArrayField(nameof(AuthAccounts), 26);
public static readonly Field Generic = new Field(nameof(Generic), 0, FieldType.Unknown, isSigningField: false);
public static readonly Field Invalid = new Field(nameof(Invalid), -1, FieldType.Unknown, isSigningField: false);
diff --git a/Base/Xrpl.BinaryCodec/Enums/FieldType.cs b/Base/Xrpl.BinaryCodec/Enums/FieldType.cs
index 491f9e22..7c459284 100644
--- a/Base/Xrpl.BinaryCodec/Enums/FieldType.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/FieldType.cs
@@ -1,4 +1,6 @@
-namespace Xrpl.BinaryCodec.Enums
+using Xrpl.BinaryCodec.Types;
+
+namespace Xrpl.BinaryCodec.Enums
{
public class FieldType : EnumItem
{
@@ -24,6 +26,7 @@ public FieldType(string name, int ordinal) : base(name, ordinal)
public static readonly FieldType Hash160 = new FieldType(nameof(Hash160), 17);
public static readonly FieldType PathSet = new FieldType(nameof(PathSet), 18);
public static readonly FieldType Vector256 = new FieldType(nameof(Vector256), 19);
+ public static readonly FieldType Issue = new FieldType(nameof(Issue), 24);
public static readonly FieldType Transaction = new FieldType(nameof(Transaction), 10001);
public static readonly FieldType LedgerEntry = new FieldType(nameof(LedgerEntry), 10002);
public static readonly FieldType Validation = new FieldType(nameof(Validation), 10003);
diff --git a/Base/Xrpl.BinaryCodec/Enums/FromJson.cs b/Base/Xrpl.BinaryCodec/Enums/FromJson.cs
index e62eb3cb..9b0cecbb 100644
--- a/Base/Xrpl.BinaryCodec/Enums/FromJson.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/FromJson.cs
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
+using Xrpl.BinaryCodec.Types;
namespace Xrpl.BinaryCodec.Enums
{
diff --git a/Base/Xrpl.BinaryCodec/Enums/FromParser.cs b/Base/Xrpl.BinaryCodec/Enums/FromParser.cs
index 2fab4299..b5ddaaa0 100644
--- a/Base/Xrpl.BinaryCodec/Enums/FromParser.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/FromParser.cs
@@ -1,4 +1,5 @@
using Xrpl.BinaryCodec.Binary;
+using Xrpl.BinaryCodec.Types;
namespace Xrpl.BinaryCodec.Enums
{
diff --git a/Base/Xrpl.BinaryCodec/Enums/IssueField.cs b/Base/Xrpl.BinaryCodec/Enums/IssueField.cs
new file mode 100644
index 00000000..6c0f98f1
--- /dev/null
+++ b/Base/Xrpl.BinaryCodec/Enums/IssueField.cs
@@ -0,0 +1,12 @@
+//https://xrpl.org/serialization.html#uint-fields
+namespace Xrpl.BinaryCodec.Enums
+{
+ public class IssueField : Field
+ {
+ public IssueField(string name, int nthOfType,
+ bool isSigningField = true, bool isSerialised = true) :
+ base(name, nthOfType, FieldType.Uint8,
+ isSigningField, isSerialised)
+ { }
+ }
+}
diff --git a/Base/Xrpl.BinaryCodec/Types/LedgerEntryType.cs b/Base/Xrpl.BinaryCodec/Enums/LedgerEntryType.cs
similarity index 98%
rename from Base/Xrpl.BinaryCodec/Types/LedgerEntryType.cs
rename to Base/Xrpl.BinaryCodec/Enums/LedgerEntryType.cs
index 5ae599f3..834d80c9 100644
--- a/Base/Xrpl.BinaryCodec/Types/LedgerEntryType.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/LedgerEntryType.cs
@@ -3,7 +3,7 @@
//todo not found doc
-namespace Xrpl.BinaryCodec.Types
+namespace Xrpl.BinaryCodec.Enums
{
public class LedgerEntryType : SerializedEnumItem
{
diff --git a/Base/Xrpl.BinaryCodec/Enums/SerializedEnumItem.cs b/Base/Xrpl.BinaryCodec/Enums/SerializedEnumItem.cs
index e2c5f0d0..f3c30b92 100644
--- a/Base/Xrpl.BinaryCodec/Enums/SerializedEnumItem.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/SerializedEnumItem.cs
@@ -2,6 +2,7 @@
using System.Runtime.InteropServices;
using Newtonsoft.Json.Linq;
using Xrpl.BinaryCodec.Binary;
+using Xrpl.BinaryCodec.Types;
using Xrpl.BinaryCodec.Util;
namespace Xrpl.BinaryCodec.Enums
diff --git a/Base/Xrpl.BinaryCodec/Types/TransactionType.cs b/Base/Xrpl.BinaryCodec/Enums/TransactionType.cs
similarity index 93%
rename from Base/Xrpl.BinaryCodec/Types/TransactionType.cs
rename to Base/Xrpl.BinaryCodec/Enums/TransactionType.cs
index f9d1c6c1..25428afd 100644
--- a/Base/Xrpl.BinaryCodec/Types/TransactionType.cs
+++ b/Base/Xrpl.BinaryCodec/Enums/TransactionType.cs
@@ -1,6 +1,6 @@
using Xrpl.BinaryCodec.Enums;
-namespace Xrpl.BinaryCodec.Types
+namespace Xrpl.BinaryCodec.Enums
{
public class TransactionType : SerializedEnumItem
{
@@ -80,6 +80,13 @@ private static TransactionType Add(string name, int ordinal)
public static readonly TransactionType NFTokenCancelOffer = Add(nameof(NFTokenCancelOffer), 28);
/// This transaction accepts an existing offer to buy or sell an existing NFT.
public static readonly TransactionType NFTokenAcceptOffer = Add(nameof(NFTokenAcceptOffer), 29);
+
+ public static readonly TransactionType AMMCreate = Add(nameof(AMMCreate), 35);
+ public static readonly TransactionType AMMDeposit = Add(nameof(AMMDeposit), 36);
+ public static readonly TransactionType AMMWithdraw = Add(nameof(AMMWithdraw), 37);
+ public static readonly TransactionType AMMVote = Add(nameof(AMMVote), 38);
+ public static readonly TransactionType AMMBid = Add(nameof(AMMBid), 39);
+
// ...
///
/// This system-generated transaction type is used to update the status of the various amendments.
diff --git a/Base/Xrpl.BinaryCodec/Exceptions.cs b/Base/Xrpl.BinaryCodec/Exceptions.cs
index 8f56aa03..f3c60c04 100644
--- a/Base/Xrpl.BinaryCodec/Exceptions.cs
+++ b/Base/Xrpl.BinaryCodec/Exceptions.cs
@@ -8,4 +8,25 @@ public BinaryCodecException() { }
public BinaryCodecException(string message) : base(message){ }
}
+
+ ///
+ /// Thrown when JSON is not valid.
+ ///
+ public class InvalidJsonException : Exception
+ {
+ ///
+ public InvalidJsonException()
+ {
+ }
+
+ ///
+ public InvalidJsonException(string message) : base(message)
+ {
+ }
+
+ ///
+ public InvalidJsonException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
}
diff --git a/Base/Xrpl.BinaryCodec/ISerializedType.cs b/Base/Xrpl.BinaryCodec/ISerializedType.cs
deleted file mode 100644
index 1a3c0140..00000000
--- a/Base/Xrpl.BinaryCodec/ISerializedType.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Linq;
-using Newtonsoft.Json.Linq;
-using Xrpl.BinaryCodec.Binary;
-using Xrpl.BinaryCodec.Util;
-
-namespace Xrpl.BinaryCodec
-{
-
- public interface ISerializedType
- {
- /// to bytes Sink
- /// bytes Sink container
- void ToBytes(IBytesSink sink);
- /// Get the JSON representation of this type
- JToken ToJson();
- }
- /// extension for ISerializedType
- public static class StExtensions
- {
- /// object to hex string
- /// Serialized type
- ///
- public static string ToHex(this ISerializedType st)
- {
- BytesList list = new BytesList();
- st.ToBytes(list);
- return list.BytesHex();
- }
- public static string ToDebuggedHex(this ISerializedType st)
- {
- BytesList list = new BytesList();
- st.ToBytes(list);
- return list.RawList().Aggregate("", (a, b) => a + ',' + B16.Encode(b));
- }
- }
-}
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/ShaMapTree/ShaMap.cs b/Base/Xrpl.BinaryCodec/ShaMapTree/ShaMap.cs
index b00b93b9..c57e461e 100644
--- a/Base/Xrpl.BinaryCodec/ShaMapTree/ShaMap.cs
+++ b/Base/Xrpl.BinaryCodec/ShaMapTree/ShaMap.cs
@@ -1,5 +1,6 @@
using System.Linq;
using Newtonsoft.Json.Linq;
+using Xrpl.BinaryCodec.Enums;
using Xrpl.BinaryCodec.Types;
namespace Xrpl.BinaryCodec.ShaMapTree
diff --git a/Base/Xrpl.BinaryCodec/Types/Currency.cs b/Base/Xrpl.BinaryCodec/Types/Currency.cs
index dcf42064..45dc1926 100644
--- a/Base/Xrpl.BinaryCodec/Types/Currency.cs
+++ b/Base/Xrpl.BinaryCodec/Types/Currency.cs
@@ -163,24 +163,5 @@ public override string ToString()
{
return new Currency(parser.Read(20));
}
-
- //public static UnissuedAmount operator /(decimal v, Currency c)
- //{
- // if (c == Xrp)
- // {
- // v *= 1e6m;
- // }
- // return new UnissuedAmount(v, c);
- //}
-
- public static Issue operator /(Currency c, AccountId ac)
- {
- return new Issue(); //todo ?
- }
- }
-
- public class Issue
- {
- //todo ?
}
}
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/Types/ISerializedType.cs b/Base/Xrpl.BinaryCodec/Types/ISerializedType.cs
new file mode 100644
index 00000000..6b542db3
--- /dev/null
+++ b/Base/Xrpl.BinaryCodec/Types/ISerializedType.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Linq;
+using Newtonsoft.Json.Linq;
+using Xrpl.BinaryCodec.Binary;
+using Xrpl.BinaryCodec.Util;
+
+namespace Xrpl.BinaryCodec.Types
+{
+ public class SerializedType
+ {
+ protected byte[] Buffer;
+
+ //public SerializedType(byte[] buffer)
+ //{
+ // this.Buffer = buffer ?? new byte[0];
+ //}
+
+ //public static SerializedType FromParser(BinaryParser parser, int? hint = null)
+ //{
+ // throw new Exception("fromParser not implemented");
+ // //return FromParser(parser, hint);
+ //}
+
+ //public static SerializedType From(SerializedType value)
+ //{
+ // throw new Exception("from not implemented");
+ // //return From(value);
+ //}
+
+ public void ToBytesSink(BytesList list)
+ {
+ list.Put(Buffer);
+ }
+
+ public string ToHex()
+ {
+ return ToBytes().ToHex();
+ }
+
+ public byte[] ToBytes()
+ {
+ if (Buffer != null)
+ {
+ return Buffer;
+ }
+ var bl = new BytesList();
+ ToBytesSink(bl);
+ return bl.ToBytes();
+ }
+
+ public object ToJson()
+ {
+ return ToHex();
+ }
+
+ public override string ToString()
+ {
+ return ToHex();
+ }
+ }
+
+ public class Comparable : SerializedType
+ {
+ //public Comparable(byte[] bytes) : base(bytes) {}
+
+ public bool Lt(Comparable other)
+ {
+ return CompareTo(other) < 0;
+ }
+
+ public bool Eq(Comparable other)
+ {
+ return CompareTo(other) == 0;
+ }
+
+ public bool Gt(Comparable other)
+ {
+ return CompareTo(other) > 0;
+ }
+
+ public bool Gte(Comparable other)
+ {
+ return CompareTo(other) > -1;
+ }
+
+ public bool Lte(Comparable other)
+ {
+ return CompareTo(other) < 1;
+ }
+
+ public int CompareTo(Comparable other)
+ {
+ throw new Exception($"cannot compare {ToString()} and {other.ToString()}");
+ }
+ }
+
+ public interface ISerializedType
+ {
+ /// to bytes Sink
+ /// bytes Sink container
+ void ToBytes(IBytesSink sink);
+ /// Get the JSON representation of this type
+ JToken ToJson();
+ }
+ /// extension for ISerializedType
+ public static class StExtensions
+ {
+ /// object to hex string
+ /// Serialized type
+ ///
+ public static string ToHex(this ISerializedType st)
+ {
+ BytesList list = new BytesList();
+ st.ToBytes(list);
+ return list.BytesHex();
+ }
+ public static string ToDebuggedHex(this ISerializedType st)
+ {
+ BytesList list = new BytesList();
+ st.ToBytes(list);
+ return list.RawList().Aggregate("", (a, b) => a + ',' + B16.Encode(b));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/Types/InvalidJsonException.cs b/Base/Xrpl.BinaryCodec/Types/InvalidJsonException.cs
deleted file mode 100644
index f6cedf64..00000000
--- a/Base/Xrpl.BinaryCodec/Types/InvalidJsonException.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-
-namespace Xrpl.BinaryCodec.Types
-{
- ///
- /// Thrown when JSON is not valid.
- ///
- public class InvalidJsonException : Exception
- {
- ///
- public InvalidJsonException()
- {
- }
-
- ///
- public InvalidJsonException(string message) : base(message)
- {
- }
-
- ///
- public InvalidJsonException(string message, Exception innerException) : base(message, innerException)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/Types/Issue.cs b/Base/Xrpl.BinaryCodec/Types/Issue.cs
new file mode 100644
index 00000000..fe0d47b9
--- /dev/null
+++ b/Base/Xrpl.BinaryCodec/Types/Issue.cs
@@ -0,0 +1,106 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text.Json.Nodes;
+using Xrpl.BinaryCodec.Binary;
+using Xrpl.BinaryCodec.Util;
+
+// https://github.com/XRPLF/xrpl.js/blob/amm/packages/ripple-binary-codec/src/types/issue.ts
+
+namespace Xrpl.BinaryCodec.Types
+{
+ ///
+ /// Hash with a width of 160 bits
+ ///
+ public class Issue: ISerializedType
+ {
+ public readonly byte[] _Bytes;
+
+ public class IssueObject
+ {
+ public string Currency { get; set; }
+ public string Issuer { get; set; }
+ }
+
+ ///
+ /// Type guard for AmountObject
+ ///
+ public static bool IsIssueObject(JObject arg)
+ {
+ var keys = arg.Properties().Select(p => p.Name).ToList();
+ keys.Sort();
+ if (keys.Count == 1)
+ {
+ return keys[0] == "currency";
+ }
+ return keys.Count == 2 && keys[0] == "currency" && keys[1] == "issuer";
+ }
+
+ public static readonly Issue ZERO_ISSUED_CURRENCY = new Issue(new byte[20]);
+
+ private Issue(byte[] buffer)
+ {
+ this._Bytes = buffer;
+ }
+
+ public static implicit operator Issue(byte[] buffer)
+ {
+ Contract.Assert(buffer.Length == 20, "buffer should be 20 bytes");
+ return new Issue(buffer ?? ZERO_ISSUED_CURRENCY._Bytes);
+ }
+
+ ///
+ /// Read an amount from a BinaryParser
+ ///
+ /// BinaryParser to read the Amount from
+ /// An Amount object
+ public static Issue FromParser(BinaryParser parser)
+ {
+ var currency = parser.Read(20);
+ if (new Currency(currency).ToString() == "XRP")
+ {
+ return new Issue(currency);
+ }
+ var currencyAndIssuer = new byte[40];
+ Buffer.BlockCopy(currency, 0, currencyAndIssuer, 0, 20);
+ Buffer.BlockCopy(parser.Read(20), 0, currencyAndIssuer, 20, 20);
+ return new Issue(currencyAndIssuer);
+ }
+
+ ///
+ /// Get the JSON representation of this Amount
+ ///
+ /// the JSON interpretation of this.bytes
+ public IssueObject ToJson()
+ {
+ var parser = new BufferParser(this.ToString());
+ var currency = Currency.FromParser(parser) as Currency;
+
+ if (currency.ToString() == "XRP")
+ {
+ return new IssueObject { Currency = currency.ToString() };
+ }
+
+ var issuer = AccountId.FromParser(parser) as AccountId;
+
+ return new IssueObject
+ {
+ Currency = currency.ToString(),
+ Issuer = issuer.ToString()
+ };
+ }
+
+ public void ToBytes(IBytesSink sink)
+ {
+ throw new NotImplementedException();
+ }
+
+ JToken ISerializedType.ToJson()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Base/Xrpl.BinaryCodec/Types/UnissuedAmount.cs b/Base/Xrpl.BinaryCodec/Types/UnissuedAmount.cs
deleted file mode 100644
index cc907dd0..00000000
--- a/Base/Xrpl.BinaryCodec/Types/UnissuedAmount.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-//todo not found doc
-
-//namespace Xrpl.BinaryCodecLib.Types
-//{
-// public class UnissuedAmount
-// {
-// private readonly Currency _currency;
-// private readonly decimal _value;
-
-// public UnissuedAmount(decimal value, Currency currency)
-// {
-// _value = value;
-// _currency = currency;
-// }
-
-// public static Amount operator / (UnissuedAmount ui, AccountId issuer)
-// {
-// return new Amount(ui._value, ui._currency, issuer);
-// }
-
-// public static implicit operator Amount(UnissuedAmount a)
-// {
-// return new Amount(a._value, a._currency);
-// }
-// }
-//}
\ No newline at end of file
diff --git a/Tests/Xrpl.Tests/Models/TestAMMBid.cs b/Tests/Xrpl.Tests/Models/TestAMMBid.cs
new file mode 100644
index 00000000..1f3e8f3f
--- /dev/null
+++ b/Tests/Xrpl.Tests/Models/TestAMMBid.cs
@@ -0,0 +1,165 @@
+
+
+// https://github.com/XRPLF/xrpl.js/blob/amm-beta/packages/xrpl/test/models/AMMBid.ts
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Transactions;
+
+namespace XrplTests.Xrpl.Models
+{
+ [TestClass]
+ public class TestUAMMBid
+ {
+ public static Dictionary bid;
+
+ [ClassInitialize]
+ public static void MyClassInitialize(TestContext testContext)
+ {
+ bid = new Dictionary
+ {
+ {"TransactionType", "AMMBid"},
+ {"Account", "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"},
+ {"Asset", new Dictionary(){{"currency","XRP"}}},
+ {"Asset2", new Dictionary(){{"currency","ETH"},{"issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } }},
+ {"BidMin", "5"},
+ {"BidMax", "10"},
+ {"AuthAccounts", new List>() {
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rNZdsTBP5tH1M6GHC6bTreHAp6ouP8iZSh" }
+ }}
+ },
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rfpFv97Dwu89FTyUwPjtpZBbuZxTqqgTmH" }
+ }}
+ },
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rzzYHPGb8Pa64oqxCzmuffm122bitq3Vb" }
+ }}
+ },
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rhwxHxaHok86fe4LykBom1jSJ3RYQJs1h4" }
+ }}
+ }, }
+ },
+ {"Sequence", 1337u},
+ };
+ }
+
+ [TestMethod]
+ public async Task TestVerifyValid()
+ {
+ //verifies valid AMMBid
+ await Validation.Validate(bid);
+
+ //throws w/ missing field Asset
+ bid.Remove("Asset");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: missing field Asset");
+ bid["Asset"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ bid["Asset"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: Asset must be an Issue");
+ bid["Asset"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ missing field Asset2
+ bid.Remove("Asset2");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: missing field Asset2");
+ bid["Asset2"] = new Dictionary() { { "currency", "ETH" }, { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } };
+ //throws w/ Asset2 must be an Issue
+ bid["Asset2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: Asset2 must be an Issue");
+ bid["Asset2"] = new Dictionary() { { "currency", "ETH" }, { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } };
+
+ //throws w/ BidMin must be an Amount
+ bid["BidMin"] = 5;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: BidMin must be an Amount");
+ bid["BidMin"] = "5";
+
+ //throws w/ BidMax must be an Amount
+ bid["BidMax"] = 10;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: BidMax must be an Amount");
+ bid["BidMax"] = "10";
+
+ //throws w/ AuthAccounts length must not be greater than 4
+ bid["AuthAccounts"] = new List>()
+ {
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rNZdsTBP5tH1M6GHC6bTreHAp6ouP8iZSh" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rfpFv97Dwu89FTyUwPjtpZBbuZxTqqgTmH" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rzzYHPGb8Pa64oqxCzmuffm122bitq3Vb" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rhwxHxaHok86fe4LykBom1jSJ3RYQJs1h4" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "r3X6noRsvaLapAKCG78zAtWcbhB3sggS1s" }
+ }}
+ },
+ };
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(bid), "AMMBid: invalid ClearFlag - no ERROR");
+ bid["AuthAccounts"] = new List>()
+ {
+ new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rNZdsTBP5tH1M6GHC6bTreHAp6ouP8iZSh" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rfpFv97Dwu89FTyUwPjtpZBbuZxTqqgTmH" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rzzYHPGb8Pa64oqxCzmuffm122bitq3Vb" }
+ }}
+ }, new Dictionary()
+ {
+ {"AuthAccount",new Dictionary()
+ {
+ { "Account", "rhwxHxaHok86fe4LykBom1jSJ3RYQJs1h4" }
+ }}
+ }
+ };
+ }
+ }
+}
+
diff --git a/Tests/Xrpl.Tests/Models/TestAMMCreate.cs b/Tests/Xrpl.Tests/Models/TestAMMCreate.cs
new file mode 100644
index 00000000..74105987
--- /dev/null
+++ b/Tests/Xrpl.Tests/Models/TestAMMCreate.cs
@@ -0,0 +1,92 @@
+// https://github.com/XRPLF/xrpl.js/blob/amm-beta/packages/xrpl/test/models/AMMCreate.ts
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Transactions;
+
+namespace XrplTests.Xrpl.Models
+{
+ [TestClass]
+ public class TestUAMMCreate
+ {
+ public static Dictionary ammCreate;
+
+ [ClassInitialize]
+ public static void MyClassInitialize(TestContext testContext)
+ {
+ ammCreate = new Dictionary
+ {
+ {"TransactionType", "AMMCreate"},
+ {"Account", "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"},
+ {"Amount", "1000"},
+ {"Amount2", new Dictionary()
+ {
+ {"currency","USD"},
+ {"issuer","rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ {"value","1000"},
+ }},
+ {"TradingFee", 12u},
+ {"Sequence", 1337u},
+ };
+ }
+
+ [TestMethod]
+ public async Task TestVerifyValid()
+ {
+ //verifies valid AMMCreate
+ await Validation.Validate(ammCreate);
+
+ //throws w/ missing Amount
+ ammCreate.Remove("Amount");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: missing field Amount");
+ ammCreate["Amount"] = "1000";
+ //throws w/ Amount must be an Amount
+ ammCreate["Amount"] = 1000;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: Amount must be an Amount");
+ ammCreate["Amount"] = "1000";
+
+ //throws w/ missing Amount2
+ ammCreate.Remove("Amount2");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: missing field Amount2");
+ ammCreate["Amount2"] = new Dictionary()
+ {
+ {"currency","USD"},
+ {"issuer","rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ {"value","1000"},
+ };
+ //throws w/ Amount must be an Amount2
+ ammCreate["Amount2"] = 1000;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: Amount2 must be an Amount");
+ ammCreate["Amount"] = new Dictionary()
+ {
+ {"currency","USD"},
+ {"issuer","rPyfep3gcLzkosKC9XiE77Y8DZWG6iWDT9"},
+ {"value","1000"},
+ };
+ //throws w/ missing TradingFee
+ ammCreate.Remove("TradingFee");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: missing field TradingFee");
+ ammCreate["TradingFee"] = 12u;
+ //throws w/ TradingFee must be a number
+ ammCreate["TradingFee"] = "12";
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: TradingFee must be a number");
+ ammCreate["TradingFee"] = 12u;
+
+ //throws when TradingFee is greater than 1000
+ ammCreate["TradingFee"] = 1001u;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: TradingFee must be between 0 and 1000");
+ ammCreate["TradingFee"] = 12u;
+ //throws when TradingFee is greater than 1000
+ ammCreate["TradingFee"] = -1;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(ammCreate), "AMMCreate: TradingFee must be between 0 and 1000");
+ ammCreate["TradingFee"] = 12u;
+
+ }
+ }
+}
+
+
diff --git a/Tests/Xrpl.Tests/Models/TestAMMDeposit.cs b/Tests/Xrpl.Tests/Models/TestAMMDeposit.cs
new file mode 100644
index 00000000..56a0dfe0
--- /dev/null
+++ b/Tests/Xrpl.Tests/Models/TestAMMDeposit.cs
@@ -0,0 +1,156 @@
+// https://github.com/XRPLF/xrpl.js/blob/amm/packages/xrpl/test/models/AMMDeposit.ts
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Transactions;
+
+namespace XrplTests.Xrpl.Models
+{
+ [TestClass]
+ public class TestUAMMDeposit
+ {
+ public static Dictionary LPTokenOut;
+ public static Dictionary deposit;
+
+ [ClassInitialize]
+ public static void MyClassInitialize(TestContext testContext)
+ {
+ LPTokenOut = new Dictionary()
+ {
+ { "currency", "B3813FCAB4EE68B3D0D735D6849465A9113EE048" },
+ { "issuer", "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg" },
+ { "value", "1000" },
+ };
+ deposit = new Dictionary
+ {
+ {"TransactionType", "AMMDeposit"},
+ {"Account", "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"},
+ {"Asset", new Dictionary(){{"currency","XRP"}}},
+ {"Asset2", new Dictionary(){{"currency","ETH"},{"issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } }},
+ {"Sequence", 1337u},
+ {"Flags", 0u},
+ };
+ }
+
+ [TestMethod]
+ public async Task TestVerifyValid()
+ {
+ //verifies valid AMMDeposit with LPTokenOut
+ deposit["LPTokenOut"] = LPTokenOut;
+ deposit["Flags"] = AMMDepositFlags.tfLPToken;
+ await Validation.Validate(deposit);
+ deposit.Remove("LPTokenOut");
+ deposit["Flags"] = 0u;
+
+
+ //verifies valid AMMDeposit with Amount
+ deposit["Amount"] = "1000";
+ deposit["Flags"] = AMMDepositFlags.tfSingleAsset;
+ await Validation.Validate(deposit);
+ deposit.Remove("Amount");
+ deposit["Flags"] = 0u;
+
+ //verifies valid AMMDeposit with Amount and Amount2
+ deposit["Amount"] = "1000";
+ deposit["Amount2"] = new Dictionary()
+ {
+ {"currency","ETH"},
+ {"issuer","rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"},
+ {"value","2.5"},
+ };
+ deposit["Flags"] = AMMDepositFlags.tfTwoAsset;
+ await Validation.Validate(deposit);
+ deposit.Remove("Amount");
+ deposit.Remove("Amount2");
+ deposit["Flags"] = 0u;
+
+
+ //verifies valid AMMDeposit with Amount and LPTokenOut
+ deposit["Amount"] = "1000";
+ deposit["LPTokenOut"] = LPTokenOut;
+ deposit["Flags"] = AMMDepositFlags.tfOneAssetLPToken;
+ await Validation.Validate(deposit);
+ deposit.Remove("Amount");
+ deposit.Remove("LPTokenOut");
+ deposit["Flags"] = 0u;
+
+ //verifies valid AMMDeposit with Amount and EPrice
+ deposit["Amount"] = "1000";
+ deposit["EPrice"] = "25";
+ deposit["Flags"] = AMMDepositFlags.tfLimitLPToken;
+ await Validation.Validate(deposit);
+ deposit.Remove("Amount");
+ deposit.Remove("EPrice");
+ deposit["Flags"] = 0u;
+
+ //throws w/ missing field Asset
+ deposit.Remove("Asset");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: missing field Asset");
+ deposit["Asset"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ deposit["Asset"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: Asset must be an Issue");
+ deposit["Asset"] = new Dictionary() { { "currency", "XRP" } };
+
+ //throws w/ missing field Asset
+ deposit.Remove("Asset2");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: missing field Asset2");
+ deposit["Asset2"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ deposit["Asset2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: Asset2 must be an Issue");
+ deposit["Asset2"] = new Dictionary() { { "currency", "ETH" }, { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } };
+
+ //throws w/ must set at least LPTokenOut or Amount
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: must set at least LPTokenOut or Amount");
+
+ //throws w/ must set Amount with Amount2
+ deposit["Amount2"] = new Dictionary()
+ {
+ { "currency", "ETH" },
+ { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" },
+ { "value", "2.5" },
+ };
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: must set Amount with Amount2");
+ deposit.Remove("Amount2");
+
+ //throws w/ must set Amount with EPrice
+ deposit["EPrice"] = "25";
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: must set Amount with EPrice");
+ deposit.Remove("EPrice");
+
+ //throws w/ LPTokenOut must be an IssuedCurrencyAmount
+ deposit["LPTokenOut"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount");
+ deposit.Remove("LPTokenOut");
+
+ //throws w/ Amount must be an Amount
+ deposit["Amount"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: Amount must be an Amount");
+ deposit.Remove("Amount");
+
+ //throws w/ Amount2 must be an Amount
+ deposit["Amount"] = "1000";
+ deposit["Amount2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: Amount2 must be an Amount");
+ deposit.Remove("Amount");
+ deposit.Remove("Amount2");
+
+ //throws w/ EPrice must be an Amount
+ deposit["Amount"] = "1000";
+ deposit["EPrice"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(deposit), "AMMDeposit: EPrice must be an Amount");
+ deposit.Remove("Amount");
+ deposit.Remove("EPrice");
+
+
+ }
+ }
+}
+
+
+
diff --git a/Tests/Xrpl.Tests/Models/TestAMMVote.cs b/Tests/Xrpl.Tests/Models/TestAMMVote.cs
new file mode 100644
index 00000000..044afbc0
--- /dev/null
+++ b/Tests/Xrpl.Tests/Models/TestAMMVote.cs
@@ -0,0 +1,79 @@
+// https://github.com/XRPLF/xrpl.js/blob/amm-beta/packages/xrpl/test/models/AMMVote.ts
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Transactions;
+
+namespace XrplTests.Xrpl.Models
+{
+ [TestClass]
+ public class TestUAMMVote
+ {
+ public static Dictionary vote;
+
+ [ClassInitialize]
+ public static void MyClassInitialize(TestContext testContext)
+ {
+ vote = new Dictionary
+ {
+ {"TransactionType", "AMMVote"},
+ {"Account", "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"},
+ {"Asset", new Dictionary(){{"currency","XRP"}}},
+ {"Asset2", new Dictionary(){{"currency","ETH"},{"issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } }},
+ {"TradingFee", 12u},
+ {"Sequence", 1337u},
+ };
+ }
+
+ [TestMethod]
+ public async Task TestVerifyValid()
+ {
+ //verifies valid AMMVote
+ await Validation.Validate(vote);
+
+ //throws w/ missing field Asset
+ vote.Remove("Asset");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: missing field Asset");
+ vote["Asset"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ vote["Asset"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: Asset must be an Issue");
+ vote["Asset"] = new Dictionary() { { "currency", "XRP" } };
+
+ //throws w/ missing field Asset
+ vote.Remove("Asset2");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: missing field Asset2");
+ vote["Asset2"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ vote["Asset2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: Asset2 must be an Issue");
+ vote["Asset2"] = new Dictionary() { { "currency", "ETH" }, { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } };
+
+ //throws w/ missing TradingFee
+ vote.Remove("TradingFee");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: missing field TradingFee");
+ vote["TradingFee"] = 12u;
+ //throws w/ TradingFee must be a number
+ vote["TradingFee"] = "12";
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: TradingFee must be a number");
+ vote["TradingFee"] = 12u;
+
+ //throws when TradingFee is greater than 1000
+ vote["TradingFee"] = 1001u;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: TradingFee must be between 0 and 1000");
+ vote["TradingFee"] = 12u;
+ //throws when TradingFee is greater than 1000
+ vote["TradingFee"] = -1;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(vote), "AMMVote: TradingFee must be between 0 and 1000");
+ vote["TradingFee"] = 12u;
+
+ }
+ }
+}
+
+
+
diff --git a/Tests/Xrpl.Tests/Models/TestAMMWithdraw.cs b/Tests/Xrpl.Tests/Models/TestAMMWithdraw.cs
new file mode 100644
index 00000000..cae73161
--- /dev/null
+++ b/Tests/Xrpl.Tests/Models/TestAMMWithdraw.cs
@@ -0,0 +1,167 @@
+// https://github.com/XRPLF/xrpl.js/blob/amm-beta/packages/xrpl/test/models/AMMWithdraw.ts
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Transactions;
+
+namespace XrplTests.Xrpl.Models
+{
+ [TestClass]
+ public class TestUAMMWithdraw
+ {
+ public static Dictionary LPTokenIn;
+ public static Dictionary withdraw;
+
+ [ClassInitialize]
+ public static void MyClassInitialize(TestContext testContext)
+ {
+ LPTokenIn = new Dictionary()
+ {
+ { "currency", "B3813FCAB4EE68B3D0D735D6849465A9113EE048" },
+ { "issuer", "rH438jEAzTs5PYtV6CHZqpDpwCKQmPW9Cg" },
+ { "value", "1000" },
+ };
+ withdraw = new Dictionary
+ {
+ {"TransactionType", "AMMWithdraw"},
+ {"Account", "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"},
+ {"Asset", new Dictionary(){{"currency","XRP"}}},
+ {"Asset2", new Dictionary(){{"currency","ETH"},{"issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } }},
+ {"Sequence", 1337u},
+ {"Flags", 0u},
+ };
+ }
+
+ [TestMethod]
+ public async Task TestVerifyValid()
+ {
+ //verifies valid AMMWithdraw with LPTokenIn
+ withdraw["LPTokenIn"] = LPTokenIn;
+ withdraw["Flags"] = AMMWithdrawFlags.tfLPToken;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("LPTokenIn");
+ withdraw["Flags"] = 0u;
+
+
+ //verifies valid AMMWithdraw with Amount
+ withdraw["Amount"] = "1000";
+ withdraw["Flags"] = AMMWithdrawFlags.tfSingleAsset;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("Amount");
+ withdraw["Flags"] = 0u;
+
+ //verifies valid AMMWithdraw with Amount and Amount2
+ withdraw["Amount"] = "1000";
+ withdraw["Amount2"] = new Dictionary()
+ {
+ {"currency","ETH"},
+ {"issuer","rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"},
+ {"value","2.5"},
+ };
+ withdraw["Flags"] = AMMWithdrawFlags.tfTwoAsset;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("Amount");
+ withdraw.Remove("Amount2");
+ withdraw["Flags"] = 0u;
+
+
+ //verifies valid AMMWithdraw with Amount and LPTokenIn
+ withdraw["Amount"] = "1000";
+ withdraw["LPTokenIn"] = LPTokenIn;
+ withdraw["Flags"] = AMMWithdrawFlags.tfOneAssetLPToken;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("Amount");
+ withdraw.Remove("LPTokenIn");
+ withdraw["Flags"] = 0u;
+
+ //verifies valid AMMWithdraw with Amount and EPrice
+ withdraw["Amount"] = "1000";
+ withdraw["EPrice"] = "25";
+ withdraw["Flags"] = AMMWithdrawFlags.tfLimitLPToken;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("Amount");
+ withdraw.Remove("EPrice");
+ withdraw["Flags"] = 0u;
+
+ //verifies valid AMMWithdraw one asset withdraw all
+ withdraw["Amount"] = "1000";
+ withdraw["Flags"] = AMMWithdrawFlags.tfOneAssetWithdrawAll;
+ await Validation.Validate(withdraw);
+ withdraw.Remove("Amount");
+ withdraw["Flags"] = 0u;
+
+ //verifies valid AMMWithdraw withdraw all
+ withdraw["Flags"] = AMMWithdrawFlags.tfWithdrawAll;
+ await Validation.Validate(withdraw);
+ withdraw["Flags"] = 0u;
+
+
+ //throws w/ missing field Asset
+ withdraw.Remove("Asset");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: missing field Asset");
+ withdraw["Asset"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ withdraw["Asset"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: Asset must be an Issue");
+ withdraw["Asset"] = new Dictionary() { { "currency", "XRP" } };
+
+ //throws w/ missing field Asset2
+ withdraw.Remove("Asset2");
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: missing field Asset2");
+ withdraw["Asset2"] = new Dictionary() { { "currency", "XRP" } };
+ //throws w/ Asset must be an Issue
+ withdraw["Asset2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: Asset2 must be an Issue");
+ withdraw["Asset2"] = new Dictionary() { { "currency", "ETH" }, { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" } };
+
+ //throws w/ must set Amount with Amount2
+ withdraw["Amount2"] = new Dictionary()
+ {
+ { "currency", "ETH" },
+ { "issuer", "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd" },
+ { "value", "2.5" },
+ };
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: must set Amount with Amount2");
+ withdraw.Remove("Amount2");
+
+ //throws w/ must set Amount with EPrice
+ withdraw["EPrice"] = "25";
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: must set Amount with EPrice");
+ withdraw.Remove("EPrice");
+
+ //throws w/ LPTokenIn must be an IssuedCurrencyAmount
+ withdraw["LPTokenIn"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount");
+ withdraw.Remove("LPTokenIn");
+
+ //throws w/ Amount must be an Amount
+ withdraw["Amount"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: Amount must be an Amount");
+ withdraw.Remove("Amount");
+
+ //throws w/ Amount2 must be an Amount
+ withdraw["Amount"] = "1000";
+ withdraw["Amount2"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: Amount2 must be an Amount");
+ withdraw.Remove("Amount");
+ withdraw.Remove("Amount2");
+
+ //throws w/ EPrice must be an Amount
+ withdraw["Amount"] = "1000";
+ withdraw["EPrice"] = 1234;
+ await Assert.ThrowsExceptionAsync(() => Validation.Validate(withdraw), "AMMWithdraw: EPrice must be an Amount");
+ withdraw.Remove("Amount");
+ withdraw.Remove("EPrice");
+
+
+ }
+ }
+}
+
+
+
+
diff --git a/Tests/Xrpl.Tests/Models/TestAccountSet.cs b/Tests/Xrpl.Tests/Models/TestAccountSet.cs
index 46eb78ee..71ffeb41 100644
--- a/Tests/Xrpl.Tests/Models/TestAccountSet.cs
+++ b/Tests/Xrpl.Tests/Models/TestAccountSet.cs
@@ -3,10 +3,11 @@
// https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/test/models/accountSet.ts
using Microsoft.VisualStudio.TestTools.UnitTesting;
+
using System.Collections.Generic;
using System.Threading.Tasks;
+
using Xrpl.Client.Exceptions;
-using Xrpl.Models.Transaction;
using Xrpl.Models.Transactions;
namespace XrplTests.Xrpl.Models
diff --git a/Xrpl/Models/Common/Common.cs b/Xrpl/Models/Common/Common.cs
deleted file mode 100644
index 6a783b8c..00000000
--- a/Xrpl/Models/Common/Common.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using Newtonsoft.Json;
-
-// https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/common/index.ts
-
-namespace Xrpl.Models.Common
-{
- /////
- ///// Order book currency
- /////
- //public class Currency
- //{
- // ///
- // /// Currency code
- // ///
- // [JsonProperty("currency")]
- // public string Currency { get; set; }
- // ///
- // /// Currency Issuer
- // ///
- // [JsonProperty("issuer")]
- // public string Issuer { get; set; }
- //}
-
- /// common class
- public class Common
- {
- /// is XRP currency
- public class XRP
- {
- /// XRP currency code
- [JsonProperty("currency")]
- public string Currency = "XRP";
- }
-
- /// currency with issuer
- public class IssuedCurrency
- {
- ///
- /// currency code
- ///
- [JsonProperty("currency")]
- public string Currency { get; set; }
-
- ///
- /// currency issuer
- ///
- [JsonProperty("issuer")]
- public string Issuer { get; set; }
- }
-
- /// currency with amount and issuer
- public class IssuedCurrencyAmount : IssuedCurrency
- {
- /// currency value
- [JsonProperty("value")]
- public string Value { get; set; }
- }
- }
-}
-
diff --git a/Xrpl/Models/Common/Currency.cs b/Xrpl/Models/Common/Index.cs
similarity index 52%
rename from Xrpl/Models/Common/Currency.cs
rename to Xrpl/Models/Common/Index.cs
index 11c2e053..b5a3e74a 100644
--- a/Xrpl/Models/Common/Currency.cs
+++ b/Xrpl/Models/Common/Index.cs
@@ -1,10 +1,13 @@
-using Newtonsoft.Json;
-
+using System.Collections.Generic;
using System.Globalization;
+using Newtonsoft.Json;
+using Xrpl.BinaryCodec.Types;
+using Xrpl.Models.Ledger;
using Xrpl.Client.Extensions;
+//https://xrpl.org/ledger-header.html#ledger-index
//https://xrpl.org/currency-formats.html#currency-formats
-//https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/common/index.ts
+// https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/common/index.ts
namespace Xrpl.Models.Common
{
@@ -100,5 +103,133 @@ public decimal? ValueAsXrp
}
}
}
+ #region Overrides of Object
+
+ public override string ToString() => CurrencyValidName == "XRP" ? $"XRP: {ValueAsXrp:0.######}" : $"{CurrencyValidName}: {ValueAsNumber:0.###############}";
+ public override bool Equals(object o) => o is Currency model && model.Issuer == Issuer && model.CurrencyCode == CurrencyCode;
+
+ public static bool operator ==(Currency c1, Currency c2) => c1.Equals(c2);
+
+ public static bool operator !=(Currency c1, Currency c2) => !c1.Equals(c2);
+
+ #endregion
+
+ }
+
+ public class LedgerIndex
+ {
+ public LedgerIndex(uint index)
+ {
+ Index = index;
+ }
+
+ public LedgerIndex(LedgerIndexType ledgerIndexType)
+ {
+ LedgerIndexType = ledgerIndexType;
+ }
+
+ public uint? Index { get; set; }
+ ///
+ /// Index type
+ /// validated
+ /// closed
+ /// current
+ ///
+ public LedgerIndexType LedgerIndexType { get; set; }
+ }
+
+ /// common class
+ public class Common
+ {
+ public enum LedgerIndex
+ {
+ Validated,
+ Closed,
+ Current
+ }
+
+ public enum AccountObjectType
+ {
+ Check,
+ DepositPreauth,
+ Escrow,
+ NftOffer,
+ Offer,
+ PaymentChannel,
+ SignerList,
+ Ticket,
+ State
+ }
+
+ public class MemoEntry
+ {
+ public string MemoData { get; set; }
+ public string MemoType { get; set; }
+ public string MemoFormat { get; set; }
+ }
+
+ public class ISigner
+ {
+ public SignerEntry Signer { get; set; }
+ }
+
+ public class IssuedCurrencyAmount
+ {
+ [JsonProperty("currency")]
+ public string Currency { get; set; }
+
+ [JsonProperty("value")]
+ public string Value { get; set; }
+
+ [JsonProperty("issuer")]
+ public string Issuer { get; set; }
+ }
+
+ public class IMemo
+ {
+ public MemoEntry Memo { get; set; }
+ }
+
+ public enum StreamType
+ {
+ Consensus,
+ Ledger,
+ Manifests,
+ PeerStatus,
+ Transactions,
+ TransactionsProposed,
+ Server,
+ Validations
+ }
+
+ public class PathStep
+ {
+ public string Account { get; set; }
+ public string Currency { get; set; }
+ public string Issuer { get; set; }
+ }
+
+ public class Path
+ {
+ public List PathStep { get; set; }
+ }
+
+ public class ResponseOnlyTxInfo
+ {
+ public int Date { get; set; }
+ public string Hash { get; set; }
+ public int LedgerIndex { get; set; }
+ }
+
+ public class NFTOffer
+ {
+ public Amount Amount { get; set; }
+ public int Flags { get; set; }
+ public string NftOfferIndex { get; set; }
+ public string Owner { get; set; }
+ public string Destination { get; set; }
+ public int Expiration { get; set; }
+ }
}
}
+
diff --git a/Xrpl/Models/Common/LedgerIndex.cs b/Xrpl/Models/Common/LedgerIndex.cs
deleted file mode 100644
index df8c34f4..00000000
--- a/Xrpl/Models/Common/LedgerIndex.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Xrpl.Models.Ledger;
-
-//https://xrpl.org/ledger-header.html#ledger-index
-//https://github.com/XRPLF/xrpl.js/blob/76b73e16a97e1a371261b462ee1a24f1c01dbb0c/packages/xrpl/src/models/common/index.ts
-
-
-namespace Xrpl.Models.Common
-{
-
- public class LedgerIndex
- {
- public LedgerIndex(uint index)
- {
- Index = index;
- }
-
- public LedgerIndex(LedgerIndexType ledgerIndexType)
- {
- LedgerIndexType = ledgerIndexType;
- }
-
- public uint? Index { get; set; }
- ///
- /// Index type
- /// validated
- /// closed
- /// current
- ///
- public LedgerIndexType LedgerIndexType { get; set; }
- }
-}
diff --git a/Xrpl/Models/Enums.cs b/Xrpl/Models/Enums.cs
index 5f3d777d..74a6ab86 100644
--- a/Xrpl/Models/Enums.cs
+++ b/Xrpl/Models/Enums.cs
@@ -55,7 +55,33 @@ public enum TransactionType
/// Set aside one or more sequence numbers as Tickets.
TicketCreate,
/// Add or modify a trust line.
- TrustSet
+ TrustSet,
+ /// AMMBid is used for submitting a vote for the trading fee of an AMM Instance.
+ AMMBid,
+ ///
+ /// AMMCreate is used to create AccountRoot and the corresponding AMM ledger entries.
+ ///
+ AMMCreate,
+ ///
+ /// Delete an empty Automated Market Maker (AMM) instance that could not be fully deleted automatically.
+ ///
+ AMMDelete,
+ ///
+ /// AMMDeposit is the deposit transaction used to add liquidity to the AMM instance pool,
+ /// thus obtaining some share of the instance's pools in the form of LPTokenOut.
+ ///
+ AMMDeposit,
+ ///
+ /// AMMVote is used for submitting a vote for the trading fee of an AMM Instance.
+ ///
+ AMMVote,
+ ///
+ /// AMMWithdraw is the withdraw transaction used to remove liquidity from the AMM
+ /// instance pool, thus redeeming some share of the pools that one owns in the form
+ /// of LPTokenIn.
+ ///
+ AMMWithdraw,
+
}
///
/// Each ledger version's state data is a set of ledger objects, sometimes called ledger entries,
@@ -129,7 +155,8 @@ public enum LedgerEntryType
///
/// A record of preauthorization for sending payments to an account that requires authorization.
///
- DepositPreauth
+ DepositPreauth,
+ AMM
}
public enum StreamType
diff --git a/Xrpl/Models/Ledger/LOAccountRoot.cs b/Xrpl/Models/Ledger/LOAccountRoot.cs
index 2797de2d..40e6113a 100644
--- a/Xrpl/Models/Ledger/LOAccountRoot.cs
+++ b/Xrpl/Models/Ledger/LOAccountRoot.cs
@@ -3,6 +3,7 @@
using System;
using Xrpl.Client.Json.Converters;
using Xrpl.Models.Common;
+using Xrpl.Models.Methods;
// https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/ledger/AccountRoot.ts
diff --git a/Xrpl/Models/Ledger/LOAmm.cs b/Xrpl/Models/Ledger/LOAmm.cs
new file mode 100644
index 00000000..afb010d6
--- /dev/null
+++ b/Xrpl/Models/Ledger/LOAmm.cs
@@ -0,0 +1,132 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+using Xrpl.Client.Json.Converters;
+using Xrpl.Models.Common;
+
+namespace Xrpl.Models.Ledger
+{
+ public class LOAmm : BaseLedgerEntry
+ {
+ public LOAmm()
+ {
+ LedgerEntryType = LedgerEntryType.AccountRoot;
+ }
+ ///
+ /// The account that tracks the balance of LPTokens between the AMM instance via Trustline.
+ ///
+ public string AMMAccount { get; set; }
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Common.Currency Asset { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Common.Currency Asset2 { get; set; }
+ ///
+ /// Details of the current owner of the auction slot.
+ ///
+ public AuctionSlot AuctionSlot { get; set; }
+ ///
+ /// The total outstanding balance of liquidity provider tokens from this AMM instance.
+ /// The holders of these tokens can vote on the AMM's trading fee in proportion to their holdings,
+ /// or redeem the tokens for a share of the AMM's assets which grows with the trading fees collected.
+ ///
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Common.Currency LPTokenBalance { get; set; }
+ ///
+ /// Specifies the fee, in basis point, to be charged to the traders for the trades
+ /// executed against the AMM instance.
+ /// Trading fee is a percentage of the trading volume.
+ /// Valid values for this field are between 0 and 1000 inclusive.
+ /// A value of 1 is equivalent to 1/10 bps or 0.001%, allowing trading fee
+ /// between 0% and 1%.
+ /// This field is required.
+ ///
+ public uint TradingFee { get; set; }
+ ///
+ /// Keeps a track of up to eight active votes for the instance.
+ ///
+ public List VoteSlots { get; set; }
+ ///
+ /// The ledger index of the current in-progress ledger, which was used when
+ /// retrieving this information.
+ ///
+ public int? LedgerCurrentIndex { get; set; }
+ ///
+ /// True if this data is from a validated ledger version;
+ /// if omitted or set to false, this data is not final.
+ ///
+ public bool? Validated { get; set; }
+
+ }
+
+ public interface IAuthAccount
+ {
+ public string Account { get; set; }
+ }
+ public class AuthAccount : IAuthAccount
+ {
+ public string Account { get; set; }
+ }
+
+ public interface IVoteEntry
+ {
+ public string Account { get; set; }
+ public uint TradingFee { get; set; }
+ public uint VoteWeight { get; set; }
+ }
+ public class VoteEntry : IVoteEntry
+ {
+ [JsonProperty("account")]
+ public string Account { get; set; }
+ [JsonProperty("trading_fee")]
+ public uint TradingFee { get; set; }
+ [JsonProperty("vote_weight")]
+ public uint VoteWeight { get; set; }
+ }
+ ///
+ /// Details of the current owner of the auction slot.
+ ///
+ public class AuctionSlot
+ {
+ ///
+ /// The current owner of this auction slot.
+ ///
+ [JsonProperty("account")]
+ public string Account { get; set; }
+ ///
+ /// A list of at most 4 additional accounts that are authorized to trade at the discounted fee for this AMM instance.
+ ///
+ [JsonProperty("auth_accounts")]
+ public List AuthAccounts { get; set; }
+ ///
+ /// The trading fee to be charged to the auction owner, in the same format as TradingFee.
+ /// By default this is 0, meaning that the auction owner can trade at no fee instead of the standard fee for this AMM.
+ ///
+ [JsonProperty("discounted_fee")]
+ public uint DiscountedFee { get; set; }
+ ///
+ /// The time when this slot expires, in seconds since the Ripple Epoch.
+ ///
+ [JsonProperty("expiration")]
+ public uint Expiration { get; set; }
+ ///
+ /// The amount the auction owner paid to win this slot, in LPTokens.
+ ///
+ [JsonProperty("price")]
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Currency Price { get; set; }
+ ///
+ /// The current 72-minute time interval this auction slot is in, from 0 to 19.
+ /// The auction slot expires after 24 hours (20 intervals of 72 minutes)
+ /// and affects the cost to outbid the current holder and how much the current holder is refunded if someone outbids them.
+ ///
+ [JsonProperty("time_interval")]
+ public uint TimeInterval { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/Xrpl/Models/Ledger/LONegativeUNL.cs b/Xrpl/Models/Ledger/LONegativeUNL.cs
new file mode 100644
index 00000000..ba05d7a2
--- /dev/null
+++ b/Xrpl/Models/Ledger/LONegativeUNL.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+
+namespace Xrpl.Models.Ledger
+{
+ /// https://github.com/XRPLF/xrpl.js/blob/98f8223b23def3229a42e56d39db42d8a65f506b/packages/xrpl/src/models/ledger/NegativeUNL.ts#L3
+ ///
+ /// The NegativeUNL object type contains the current status of the Negative UNL,
+ /// a list of trusted validators currently believed to be offline.
+ ///
+ public class LONegativeUNL : BaseLedgerEntry
+ {
+ public LONegativeUNL()
+ {
+ LedgerEntryType = LedgerEntryType.NegativeUNL;
+ }
+ ///
+ /// A list of trusted validators that are currently disabled.
+ ///
+ public List DisabledValidators { get; set; }
+ ///
+ /// The public key of a trusted validator that is scheduled to be disabled in the next flag ledger.
+ ///
+ public string ValidatorToDisable { get; set; }
+ ///
+ /// The public key of a trusted validator in the Negative UNL that is scheduled to be re-enabled in the next flag ledger.
+ ///
+ public string ValidatorToReEnable { get; set; }
+ }
+ public interface IDisabledValidator
+ {
+ public long FirstLedgerSequence { get; set; }
+ public string PublicKey { get; set; }
+ }
+ public class DisabledValidator : IDisabledValidator
+ {
+ public long FirstLedgerSequence { get; set; }
+ public string PublicKey { get; set; }
+ }
+
+}
\ No newline at end of file
diff --git a/Xrpl/Models/Methods/AMMInfo.cs b/Xrpl/Models/Methods/AMMInfo.cs
new file mode 100644
index 00000000..ae573af2
--- /dev/null
+++ b/Xrpl/Models/Methods/AMMInfo.cs
@@ -0,0 +1,112 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+using Xrpl.Client.Json.Converters;
+using Xrpl.Models.Common;
+using Xrpl.Models.Ledger;
+using Xrpl.Models.Subscriptions;
+
+//https://github.com/XRPLF/xrpl.js/blob/main/packages/xrpl/src/models/ledger/AMM.ts
+namespace Xrpl.Models.Methods
+{
+ ///
+ /// The `amm_info` command retrieves information about an AMM instance.
+ ///
+ /// Returns an .
+ public class AMMInfoRequest : BaseLedgerRequest
+ {
+ public AMMInfoRequest()
+ {
+ Command = "amm_info";
+ }
+
+ [JsonProperty("amm_info")]
+ public string? AmmAccount { get; set; }
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ /// Both asset and asset2 must be defined to specify an AMM instance.
+ ///
+ [JsonProperty("asset")]
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Currency Asset { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ /// Both asset and asset2 must be defined to specify an AMM instance.
+ ///
+ [JsonProperty("asset2")]
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Currency Asset2 { get; set; }
+ }
+
+ ///
+ /// Response expected from an .
+ ///
+ public class AMMInfoResponse : BaseResponse
+ {
+ ///
+ /// The account that tracks the balance of LPTokens between the AMM instance via Trustline.
+ ///
+ [JsonProperty("auction_slot")]
+ public string Account { get; set; }
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ [JsonProperty("amount")]
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Currency Amount { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ [JsonProperty("amount2")]
+ public Currency Amount2 { get; set; }
+ [JsonConverter(typeof(CurrencyConverter))]
+ [JsonProperty("asset_frozen")]
+ public bool? AssetFrozen { get; set; }
+ [JsonProperty("asset2_frozen")]
+ public bool? Asset2Frozen { get; set; }
+ ///
+ /// Details of the current owner of the auction slot.
+ ///
+ [JsonProperty("auction_slot")]
+ public AuctionSlot AuctionSlot { get; set; }
+ ///
+ /// The total outstanding balance of liquidity provider tokens from this AMM instance.
+ /// The holders of these tokens can vote on the AMM's trading fee in proportion to their holdings,
+ /// or redeem the tokens for a share of the AMM's assets which grows with the trading fees collected.
+ ///
+ [JsonProperty("lp_token")]
+ [JsonConverter(typeof(CurrencyConverter))]
+ public Currency LPTokenBalance { get; set; }
+ ///
+ /// Specifies the fee, in basis point, to be charged to the traders for the trades
+ /// executed against the AMM instance.
+ /// Trading fee is a percentage of the trading volume.
+ /// Valid values for this field are between 0 and 1000 inclusive.
+ /// A value of 1 is equivalent to 1/10 bps or 0.001%, allowing trading fee
+ /// between 0% and 1%.
+ /// This field is required.
+ ///
+ [JsonProperty("trading_fee")]
+ public uint TradingFee { get; set; }
+ ///
+ /// Keeps a track of up to eight active votes for the instance.
+ ///
+ [JsonProperty("vote_slots")]
+ public List VoteSlots { get; set; }
+ ///
+ /// The ledger index of the ledger version that was used to generate this response.
+ ///
+ [JsonProperty("ledger_index")]
+ public int? LedgerIndex { get; set; }
+ ///
+ ///The identifying hash of the ledger that was used to generate this response.
+ ///
+ [JsonProperty("ledger_hash")]
+ public string? LedgerHash { get; set; }
+ ///
+ /// True if this data is from a validated ledger version;
+ /// if omitted or set to false, this data is not final.
+ ///
+ public bool? Validated { get; set; }
+ }
+}
diff --git a/Xrpl/Models/Transactions/AMMBid.cs b/Xrpl/Models/Transactions/AMMBid.cs
new file mode 100644
index 00000000..189dfb6c
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMBid.cs
@@ -0,0 +1,149 @@
+#nullable enable
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Ledger;
+using Xrpl.Models.Methods;
+
+// https://github.com/XRPLF/xrpl.js/blob/amm/packages/xrpl/src/models/transactions/AMMBid.ts
+
+namespace Xrpl.Models.Transactions
+{
+
+ ///
+ /// AMMBid is used for submitting a vote for the trading fee of an AMM Instance.
+ /// Any XRPL account that holds LPToken for an AMM instance may submit this
+ /// transaction to vote for the trading fee for that instance.
+ ///
+ public class AMMBid : TransactionCommon, IAMMBid
+ {
+ public AMMBid()
+ {
+ TransactionType = TransactionType.AMMBid;
+ }
+
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency? BidMin { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency? BidMax { get; set; }
+ ///
+ public List AuthAccounts { get; set; }
+ }
+ ///
+ /// AMMBid is used for submitting a vote for the trading fee of an AMM Instance.
+ /// Any XRPL account that holds LPToken for an AMM instance may submit this
+ /// transaction to vote for the trading fee for that instance.
+ ///
+ public interface IAMMBid : ITransactionCommon
+ {
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ ///
+ /// This field represents the minimum price that the bidder wants to pay for the slot.
+ /// It is specified in units of LPToken.If specified let BidMin be X and let
+ /// the slot-price computed by price scheduling algorithm be Y, then bidder always pays
+ /// the max(X, Y).
+ ///
+ public Xrpl.Models.Common.Currency? BidMin { get; set; }
+ ///
+ /// This field represents the maximum price that the bidder wants to pay for the slot.
+ /// It is specified in units of LPToken.
+ ///
+ public Xrpl.Models.Common.Currency? BidMax { get; set; }
+ ///
+ /// This field represents an array of XRPL account IDs that are authorized to trade
+ /// at the discounted fee against the AMM instance.
+ /// A maximum of four accounts can be provided.
+ ///
+ public List AuthAccounts { get; set; }
+ }
+
+ public partial class Validation
+ {
+ private const int MAX_AUTH_ACCOUNTS = 4;
+ ///
+ /// Verify the form and type of an AMMBid at runtime.
+ ///
+ /// An AMMBid Transaction.
+ ///
+ /// When the AMMBid is Malformed.
+ public static async Task ValidateAMMBid(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+
+ if (!tx.TryGetValue("Asset",out var Asset1) || Asset1 is null)
+ {
+ throw new ValidationException("AMMBid: missing field Asset");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset1))
+ {
+ throw new ValidationException("AMMBid: Asset must be an Issue");
+ }
+
+ if (!tx.TryGetValue("Asset2", out var Asset2) || Asset2 is null)
+ {
+ throw new ValidationException("AMMBid: missing field Asset2");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset2))
+ {
+ throw new ValidationException("AMMBid: Asset2 must be an Issue");
+ }
+
+ if (tx.TryGetValue("BidMin", out var BidMin) && BidMin is not null && !Common.IsAmount(BidMin))
+ {
+ throw new ValidationException("AMMBid: BidMin must be an Amount");
+ }
+
+ if (tx.TryGetValue("BidMax", out var BidMax) && BidMax is not null && !Common.IsAmount(BidMax))
+ {
+ throw new ValidationException("AMMBid: BidMax must be an Amount");
+ }
+
+ if (tx.TryGetValue("AuthAccounts", out var AuthAccounts) && AuthAccounts is not null)
+ {
+ if (AuthAccounts is not List> auth_accounts )
+ {
+ throw new ValidationException("AMMBid: AuthAccounts must be an AuthAccount array");
+ }
+ if (auth_accounts.Count > MAX_AUTH_ACCOUNTS)
+ {
+ throw new ValidationException($"AMMBid: AuthAccounts length must not be greater than {MAX_AUTH_ACCOUNTS}");
+ }
+
+ ValidateAuthAccounts(tx["Account"], auth_accounts);
+ }
+ }
+
+ public static async Task ValidateAuthAccounts(string senderAddress, List> authAccounts)
+ {
+ foreach (var account in authAccounts)
+ {
+ if (!account.TryGetValue("AuthAccount", out var auth) || auth is not Dictionary { } auth_acc)
+ throw new ValidationException("AMMBid: invalid AuthAccounts");
+
+ if (!auth_acc.TryGetValue("Account", out var acc) || acc is null)
+ throw new ValidationException("AMMBid: invalid AuthAccounts");
+ if (acc is not string {})
+ throw new ValidationException("AMMBid: invalid AuthAccounts");
+ if (acc is string {} s && s == senderAddress )
+ throw new ValidationException("AMMBid: AuthAccounts must not include sender's address");
+ }
+
+ return true;
+ }
+ }
+}
+
diff --git a/Xrpl/Models/Transactions/AMMCreate.cs b/Xrpl/Models/Transactions/AMMCreate.cs
new file mode 100644
index 00000000..7597a9f1
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMCreate.cs
@@ -0,0 +1,105 @@
+#nullable enable
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.BinaryCodec.Types;
+using Xrpl.Client.Exceptions;
+using Xrpl.Models.Methods;
+
+namespace Xrpl.Models.Transactions
+{
+
+ ///
+ /// AMMCreate is used to create AccountRoot and the corresponding AMM ledger entries.
+ /// This allows for the creation of only one AMM instance per unique asset pair.
+ ///
+ public class AMMCreate : TransactionCommon, IAMMCreate
+ {
+ public AMMCreate()
+ {
+ TransactionType = TransactionType.AMMCreate;
+ }
+
+ ///
+ public Xrpl.Models.Common.Currency Amount { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency Amount2 { get; set; }
+ ///
+ public uint TradingFee { get; set; }
+ }
+ ///
+ /// AMMCreate is used to create AccountRoot and the corresponding AMM ledger entries.
+ /// This allows for the creation of only one AMM instance per unique asset pair.
+ ///
+ public interface IAMMCreate : ITransactionCommon
+ {
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Amount { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Amount2 { get; set; }
+ ///
+ /// Specifies the fee, in basis point, to be charged
+ /// to the traders for the trades executed against the AMM instance.
+ /// Trading fee is a percentage of the trading volume.
+ /// Valid values for this field are between 0 and 1000 inclusive.
+ /// A value of 1 is equivalent to 1/10 bps or 0.001%, allowing trading fee
+ /// between 0% and 1%.
+ ///
+ public uint TradingFee { get; set; }
+ }
+
+ public partial class Validation
+ {
+ public const uint AMM_MAX_TRADING_FEE = 1000;
+ ///
+ /// Verify the form and type of an AMMCreate at runtime.
+ ///
+ /// An AMMCreate Transaction.
+ ///
+ /// When the AMMCreate is Malformed.
+ public static async Task ValidateAMMCreate(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+
+ if (!tx.TryGetValue("Amount", out var Amount1) || Amount1 is null)
+ {
+ throw new ValidationException("AMMCreate: missing field Amount");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsAmount(Amount1))
+ {
+ throw new ValidationException("AMMCreate: Amount must be an Amount");
+ }
+
+ if (!tx.TryGetValue("Amount2", out var Amount2) || Amount2 is null)
+ {
+ throw new ValidationException("AMMCreate: missing field Amount2");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsAmount(Amount2))
+ {
+ throw new ValidationException("AMMCreate: Amount2 must be an Amount");
+ }
+
+ if (!tx.TryGetValue("TradingFee", out var TradingFee) || TradingFee is null)
+ {
+ throw new ValidationException("AMMCreate: missing field TradingFee");
+ }
+
+ if (TradingFee is not uint fee)
+ {
+ throw new ValidationException("AMMCreate: TradingFee must be a number");
+ }
+
+ if (fee is < 0 or > AMM_MAX_TRADING_FEE)
+ {
+ throw new ValidationException($"AMMCreate: TradingFee must be between 0 and {AMM_MAX_TRADING_FEE}");
+ }
+ }
+ }
+}
+
diff --git a/Xrpl/Models/Transactions/AMMDelete.cs b/Xrpl/Models/Transactions/AMMDelete.cs
new file mode 100644
index 00000000..9b38bbac
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMDelete.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xrpl.Client.Exceptions;
+
+namespace Xrpl.Models.Transactions
+{
+ ///
+ /// Delete an empty Automated Market Maker (AMM) instance that could not be fully deleted automatically.
+ /// Tip: The AMMWithdraw transaction automatically tries to delete an AMM, along with associated ledger
+ /// entries such as empty trust lines, if it withdrew all the assets from the AMM's pool.
+ /// However, if there are too many trust lines to the AMM account to remove in one transaction,
+ /// it may stop before fully removing the AMM.Similarly, an AMMDelete transaction removes up to
+ /// a maximum number of trust lines; in extreme cases, it may take several AMMDelete transactions
+ /// to fully delete the trust lines and the associated AMM.
+ /// In all cases, the AMM ledger entry and AMM account are deleted by the last such transaction.
+ ///
+ public class AMMDelete : TransactionCommon, IAMMDelete
+ {
+ public AMMDelete()
+ {
+ TransactionType = TransactionType.AMMDelete;
+ }
+
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ ///
+ public uint TradingFee { get; set; }
+ }
+ ///
+ /// Delete an empty Automated Market Maker (AMM) instance that could not be fully deleted automatically.
+ /// Tip: The AMMWithdraw transaction automatically tries to delete an AMM, along with associated ledger
+ /// entries such as empty trust lines, if it withdrew all the assets from the AMM's pool.
+ /// However, if there are too many trust lines to the AMM account to remove in one transaction,
+ /// it may stop before fully removing the AMM.Similarly, an AMMDelete transaction removes up to
+ /// a maximum number of trust lines; in extreme cases, it may take several AMMDelete transactions
+ /// to fully delete the trust lines and the associated AMM.
+ /// In all cases, the AMM ledger entry and AMM account are deleted by the last such transaction.
+ ///
+ public interface IAMMDelete : ITransactionCommon
+ {
+ ///
+ /// The definition for one of the assets in the AMM's pool.
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ /// The definition for the other asset in the AMM's pool.
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ }
+
+ public partial class Validation
+ {
+ ///
+ /// Verify the form and type of an AMMDelete at runtime.
+ ///
+ /// An AMMDelete Transaction.
+ ///
+ /// When the AMMDelete is Malformed.
+ public static async Task ValidateAMMDelete(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+
+ if (!tx.TryGetValue("Asset", out var Asset) || Asset is null)
+ {
+ throw new ValidationException("AMMDelete: missing field Asset");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsAmount(Asset))
+ {
+ throw new ValidationException("AMMDelete: Asset must be a Currency");
+ }
+ if (!tx.TryGetValue("Asset2", out var Asset2) || Asset2 is null)
+ {
+ throw new ValidationException("AMMDelete: missing field Asset2");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsAmount(Asset2))
+ {
+ throw new ValidationException("AMMDelete: Asset2 must be a Currency");
+ }
+ }
+ }
+}
diff --git a/Xrpl/Models/Transactions/AMMDeposit.cs b/Xrpl/Models/Transactions/AMMDeposit.cs
new file mode 100644
index 00000000..d6349bff
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMDeposit.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using static Xrpl.Models.Common.Common;
+using Xrpl.BinaryCodec.Types;
+using Xrpl.Client.Exceptions;
+
+namespace Xrpl.Models.Transactions
+{
+ ///
+ /// Enum representing values for AMMDeposit Transaction Flags.
+ ///
+ public enum AMMDepositFlags : uint
+ {
+ ///
+ /// Perform a double-asset deposit and receive the specified amount of LP Tokens.
+ ///
+ tfLPToken = 65536,//0x00010000
+ ///
+ /// Perform a single-asset deposit with a specified amount of the asset to deposit.
+ ///
+ tfSingleAsset = 524288,//0x00080000
+ ///
+ /// Perform a double-asset deposit with specified amounts of both assets.
+ ///
+ tfTwoAsset = 1048576,//0x00100000
+ ///
+ /// Perform a single-asset deposit and receive the specified amount of LP Tokens.
+ ///
+ tfOneAssetLPToken = 2097152,//0x00200000
+ ///
+ /// Perform a single-asset deposit with a specified effective price.
+ ///
+ tfLimitLPToken = 4194304 //0x00400000
+ };
+
+ //public interface AMMDepositFlagsInterface : GlobalFlags
+ //{
+ // bool? tfLPToken { get; set; }
+ // bool? tfSingleAsset { get; set; }
+ // bool? tfTwoAsset { get; set; }
+ // bool? tfOneAssetLPToken { get; set; }
+ // bool? tfLimitLPToken { get; set; }
+ //}
+
+ ///
+ /// AMMDeposit is the deposit transaction used to add liquidity to the AMM instance pool,
+ /// thus obtaining some share of the instance's pools in the form of LPTokenOut.
+ /// The following are the recommended valid combinations:
+ /// - LPTokenOut
+ /// - Amount
+ /// - Amount and Amount2
+ /// - Amount and LPTokenOut
+ /// - Amount and EPrice
+ ///
+ public class AMMDeposit : TransactionCommon, IAMMDeposit
+ {
+ public AMMDeposit()
+ {
+ TransactionType = TransactionType.AMMDeposit;
+ }
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency? LPTokenOut { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency? Amount { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency? Amount2 { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency? EPrice { get; set; }
+ }
+
+ ///
+ /// AMMDeposit is the deposit transaction used to add liquidity to the AMM instance pool,
+ /// thus obtaining some share of the instance's pools in the form of LPTokenOut.
+ /// The following are the recommended valid combinations:
+ /// - LPTokenOut
+ /// - Amount
+ /// - Amount and Amount2
+ /// - Amount and LPTokenOut
+ /// - Amount and EPrice
+ ///
+ public interface IAMMDeposit : ITransactionCommon
+ {
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+
+ ///
+ /// Specifies the amount of shares of the AMM instance pools that the trader wants to redeem or trade in.
+ ///
+ public Xrpl.Models.Common.Currency? LPTokenOut { get; set; }
+
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance to deposit more of its value.
+ ///
+ public Xrpl.Models.Common.Currency? Amount { get; set; }
+
+ ///
+ /// Specifies the other pool asset of the AMM instance to deposit more of its value.
+ ///
+ public Xrpl.Models.Common.Currency? Amount2 { get; set; }
+
+ ///
+ /// Specifies the maximum effective-price that LPTokenOut can be traded out.
+ ///
+ public Xrpl.Models.Common.Currency? EPrice { get; set; }
+ }
+
+
+ public partial class Validation
+ {
+ ///
+ /// Verify the form and type of an AMMDeposit at runtime.
+ ///
+ /// An AMMDeposit Transaction.
+ ///
+ /// When the AMMDeposit is Malformed.
+ public static async Task ValidateAMMDeposit(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+
+ if (!tx.TryGetValue("Asset", out var Asset1) || Asset1 is null)
+ {
+ throw new ValidationException("AMMDeposit: missing field Asset");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset1))
+ {
+ throw new ValidationException("AMMDeposit: Asset must be an Issue");
+ }
+
+ if (!tx.TryGetValue("Asset2", out var Asset2) || Asset2 is null)
+ {
+ throw new ValidationException("AMMDeposit: missing field Asset2");
+ }
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset2))
+ {
+ throw new ValidationException("AMMDeposit: Asset2 must be an Issue");
+ }
+
+ tx.TryGetValue("Amount", out var Amount);
+ tx.TryGetValue("Amount2", out var Amount2);
+ tx.TryGetValue("EPrice", out var EPrice);
+ tx.TryGetValue("LPTokenOut", out var LPTokenOut);
+
+ if (Amount2 is not null && Amount is null)
+ throw new ValidationException("AMMDeposit: must set Amount with Amount2");
+ if (EPrice is not null && Amount is null)
+ throw new ValidationException("AMMDeposit: must set Amount with EPrice");
+ if (LPTokenOut is null && Amount is null)
+ throw new ValidationException("AMMDeposit: must set at least LPTokenOut or Amount");
+
+ if (LPTokenOut is not null && !Common.IsIssuedCurrency(LPTokenOut))
+ throw new ValidationException("AMMDeposit: LPTokenOut must be an IssuedCurrencyAmount");
+ if (Amount is not null && !Common.IsAmount(Amount))
+ throw new ValidationException("AMMDeposit: Amount must be an Amount");
+ if (Amount2 is not null && !Common.IsAmount(Amount2))
+ throw new ValidationException("AMMDeposit: Amount2 must be an Amount");
+ if (EPrice is not null && !Common.IsAmount(EPrice))
+ throw new ValidationException("AMMDeposit: EPrice must be an Amount");
+ }
+ }
+
+}
diff --git a/Xrpl/Models/Transactions/AMMVote.cs b/Xrpl/Models/Transactions/AMMVote.cs
new file mode 100644
index 00000000..db6387c1
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMVote.cs
@@ -0,0 +1,80 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Xrpl.Client.Exceptions;
+
+namespace Xrpl.Models.Transactions
+{
+ public class AMMVote : TransactionCommon, IAMMVote
+ {
+ public AMMVote()
+ {
+ TransactionType = TransactionType.AMMVote;
+ }
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ ///
+ public uint TradingFee { get; set; }
+ }
+
+ public interface IAMMVote : ITransactionCommon
+ {
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+ ///
+ /// Specifies the fee, in basis point.
+ /// Valid values for this field are between 0 and 1000 inclusive.
+ /// A value of 1 is equivalent to 1/10 bps or 0.001%, allowing trading fee
+ /// between 0% and 1%. This field is required.
+ ///
+ public uint TradingFee { get; set; }
+ }
+ public partial class Validation
+ {
+ ///
+ /// Verify the form and type of an AMMVote at runtime.
+ ///
+ /// An AMMVote Transaction.
+ ///
+ /// When the AMMVote is Malformed.
+ public static async Task ValidateAMMVote(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+ tx.TryGetValue("Asset", out var Asset);
+ tx.TryGetValue("Asset2", out var Asset2);
+ tx.TryGetValue("TradingFee", out var TradingFee);
+
+ if (Asset is null)
+ throw new ValidationException("AMMVote: missing field Asset");
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset))
+ throw new ValidationException("AMMVote: Asset must be an Issue");
+
+ if (Asset2 is null)
+ throw new ValidationException("AMMVote: missing field Asset2");
+
+ if (!Xrpl.Models.Transactions.Common.IsIssue(Asset2))
+ throw new ValidationException("AMMVote: Asset2 must be an Issue");
+ if(TradingFee is null)
+ throw new ValidationException("AMMVote: missing field TradingFee");
+ if (TradingFee is not uint fee)
+ {
+ throw new ValidationException("AMMVote: TradingFee must be a number");
+ }
+
+ if (fee is < 0 or > AMM_MAX_TRADING_FEE)
+ {
+ throw new ValidationException($"AMMVote: TradingFee must be between 0 and {AMM_MAX_TRADING_FEE}");
+ }
+ }
+ }
+
+}
diff --git a/Xrpl/Models/Transactions/AMMWithdraw.cs b/Xrpl/Models/Transactions/AMMWithdraw.cs
new file mode 100644
index 00000000..5a2318d4
--- /dev/null
+++ b/Xrpl/Models/Transactions/AMMWithdraw.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using static Xrpl.Models.Common.Common;
+using Xrpl.BinaryCodec.Types;
+using Xrpl.Client.Exceptions;
+
+namespace Xrpl.Models.Transactions
+{
+ ///
+ /// Enum representing values for AMMWithdrawFlags Transaction Flags
+ ///
+ /// Transaction Flags
+ public enum AMMWithdrawFlags : uint
+ {
+ ///
+ /// Perform a double-asset withdrawal and receive the specified amount of LP Tokens.
+ ///
+ tfLPToken = 65536,//0x00010000
+ ///
+ /// Perform a double-asset withdrawal returning all your LP Tokens.
+ ///
+ tfWithdrawAll =131072,//0x00020000
+ ///
+ /// Perform a single-asset withdrawal returning all of your LP Tokens.
+ ///
+ tfOneAssetWithdrawAll = 262144,//0x00040000
+ ///
+ /// Perform a single-asset withdrawal with a specified amount of the asset to withdrawal.
+ ///
+ tfSingleAsset = 524288,//0x00080000
+ ///
+ /// Perform a double-asset withdrawal with specified amounts of both assets.
+ ///
+ tfTwoAsset = 1048576,//0x00100000
+ ///
+ /// Perform a single-asset withdrawal and receive the specified amount of LP Tokens.
+ ///
+ tfOneAssetLPToken = 2097152,//0x00200000
+ ///
+ /// Perform a single-asset withdrawal with a specified effective price.
+ ///
+ tfLimitLPToken = 4194304 //0x00400000
+ }
+
+ //public interface AMMWithdrawFlagsInterface : GlobalFlags
+ //{
+ // bool? tfLPToken { get; set; }
+ // bool? tfWithdrawAll { get; set; }
+ // bool? tfOneAssetWithdrawAll { get; set; }
+ // bool? tfSingleAsset { get; set; }
+ // bool? tfTwoAsset { get; set; }
+ // bool? tfOneAssetLPToken { get; set; }
+ // bool? tfLimitLPToken { get; set; }
+ //}
+
+ ///
+ /// AMMWithdraw is the withdraw transaction used to remove liquidity from the AMM
+ /// instance pool, thus redeeming some share of the pools that one owns in the form
+ /// of LPTokenIn.
+ ///
+ public class AMMWithdraw : TransactionCommon, IAMMWithdraw
+ {
+ public AMMWithdraw()
+ {
+ TransactionType = TransactionType.AMMWithdraw;
+ }
+ #region Implementation of IAMMWithdraw
+
+ ///
+ public Xrpl.Models.Common.Currency Asset { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency Asset2 { get; set; }
+
+ ///
+ public Xrpl.Models.Common.Currency LPTokenIn { get; set; }
+
+ ///
+ public Amount Amount { get; set; }
+
+ ///
+ public Amount Amount2 { get; set; }
+
+ ///
+ public Amount EPrice { get; set; }
+
+ #endregion
+ }
+ ///
+ /// AMMWithdraw is the withdraw transaction used to remove liquidity from the AMM
+ /// instance pool, thus redeeming some share of the pools that one owns in the form
+ /// of LPTokenIn.
+ ///
+ public interface IAMMWithdraw : ITransactionCommon
+ {
+ ///
+ /// Specifies one of the pool assets (XRP or token) of the AMM instance.
+ ///
+ Xrpl.Models.Common.Currency Asset { get; set; }
+
+ ///
+ /// Specifies the other pool asset of the AMM instance.
+ ///
+ Xrpl.Models.Common.Currency Asset2 { get; set; }
+
+ ///
+ /// Specifies the amount of shares of the AMM instance pools that the trader
+ /// wants to redeem or trade in.
+ ///
+ Xrpl.Models.Common.Currency LPTokenIn { get; set; }
+
+ ///
+ /// Specifies one of the pools assets that the trader wants to remove.
+ /// If the asset is XRP, then the Amount is a string specifying the number of drops.
+ /// Otherwise it is an IssuedCurrencyAmount object.
+ ///
+ Amount Amount { get; set; }
+
+ ///
+ /// Specifies the other pool asset that the trader wants to remove.
+ ///
+ Amount Amount2 { get; set; }
+
+ ///
+ /// Specifies the effective-price of the token out after successful execution of
+ /// the transaction.
+ ///
+ Amount EPrice { get; set; }
+ }
+ public partial class Validation
+ {
+
+ ///
+ /// Verify the form and type of an AMMWithdraw at runtime.
+ ///
+ /// An AMMWithdraw Transaction.
+ /// When the AMMWithdraw is Malformed.
+ public static async Task ValidateAMMWithdraw(Dictionary tx)
+ {
+ await Common.ValidateBaseTransaction(tx);
+
+ tx.TryGetValue("Asset", out var Asset);
+ tx.TryGetValue("Asset2", out var Asset2);
+ tx.TryGetValue("Amount", out var Amount);
+ tx.TryGetValue("Amount2", out var Amount2);
+ tx.TryGetValue("EPrice", out var EPrice);
+ tx.TryGetValue("LPTokenIn", out var LPTokenIn);
+
+ if (Asset is null)
+ {
+ throw new ValidationException("AMMWithdraw: missing field Asset");
+ }
+
+ if (!Common.IsIssue(Asset))
+ {
+ throw new ValidationException("AMMWithdraw: Asset must be an Issue");
+ }
+
+ if (Asset2 is null)
+ {
+ throw new ValidationException("AMMWithdraw: missing field Asset2");
+ }
+
+ if (!Common.IsIssue(Asset2))
+ {
+ throw new ValidationException("AMMWithdraw: Asset2 must be an Issue");
+ }
+
+ if (Amount2 is not null && Amount is null)
+ {
+ throw new ValidationException("AMMWithdraw: must set Amount with Amount2");
+ }
+ else if (EPrice is not null && Amount is null)
+ {
+ throw new ValidationException("AMMWithdraw: must set Amount with EPrice");
+ }
+
+ if (LPTokenIn is not null && !Common.IsIssuedCurrency(LPTokenIn))
+ {
+ throw new ValidationException("AMMWithdraw: LPTokenIn must be an IssuedCurrencyAmount");
+ }
+
+ if (Amount is not null && !Common.IsAmount(Amount))
+ {
+ throw new ValidationException("AMMWithdraw: Amount must be an Amount");
+ }
+
+ if (Amount2 is not null && !Common.IsAmount(Amount2))
+ {
+ throw new ValidationException("AMMWithdraw: Amount2 must be an Amount");
+ }
+
+ if (EPrice is not null && !Common.IsAmount(EPrice))
+ {
+ throw new ValidationException("AMMWithdraw: EPrice must be an Amount");
+ }
+ }
+ }
+}
diff --git a/Xrpl/Models/Transactions/Common.cs b/Xrpl/Models/Transactions/Common.cs
index 35f938f6..56e7d836 100644
--- a/Xrpl/Models/Transactions/Common.cs
+++ b/Xrpl/Models/Transactions/Common.cs
@@ -124,6 +124,24 @@ public static double ParseAmountValue(dynamic amount)
CultureInfo.InvariantCulture);
}
///
+ /// Verify the form and type of an Issue at runtime.
+ ///
+ /// The object to check the form and type of.
+ /// Whether the Issue is malformed.
+ public static bool IsIssue(dynamic input)
+ {
+ if (!IsRecord(input))
+ return false;
+ if (input is not Dictionary issue)
+ return false;
+
+
+ var length = issue.Count;
+ issue.TryGetValue("currency", out var currency);
+ issue.TryGetValue("issuer", out var issuer);
+ return (length == 1 && currency == "XRP") || (length == 2 && currency is string && issuer is string);
+ }
+ ///
/// Verify the common fields of a transaction.
/// The validate functionality will be optional, and will check transaction form at runtime.
/// This should be called any time a transaction will be verified.
diff --git a/Xrpl/Models/Transactions/TxFormat.cs b/Xrpl/Models/Transactions/TxFormat.cs
index 6719d997..9849710b 100644
--- a/Xrpl/Models/Transactions/TxFormat.cs
+++ b/Xrpl/Models/Transactions/TxFormat.cs
@@ -92,13 +92,13 @@ internal static void Validate(StObject obj, Action onError)
}
}
- public static Dictionary Formats;
+ public static Dictionary Formats;
static TxFormat()
{
- Formats = new Dictionary
+ Formats = new Dictionary
{
- [BinaryCodec.Types.TransactionType.Payment] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.Payment] = new TxFormat
{
[Field.Destination] = Requirement.Required,
[Field.Amount] = Requirement.Required,
@@ -108,7 +108,7 @@ static TxFormat()
[Field.DestinationTag] = Requirement.Optional,
[Field.DeliverMin] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.EscrowCreate] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.EscrowCreate] = new TxFormat
{
[Field.Amount] = Requirement.Required,
[Field.Destination] = Requirement.Required,
@@ -117,14 +117,14 @@ static TxFormat()
[Field.FinishAfter] = Requirement.Optional,
[Field.DestinationTag] = Requirement.Optional,
},
- [BinaryCodec.Types.TransactionType.EscrowFinish] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.EscrowFinish] = new TxFormat
{
[Field.Owner] = Requirement.Required,
[Field.OfferSequence] = Requirement.Required,
[Field.Condition] = Requirement.Optional,
[Field.Fulfillment] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.AccountSet] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.AccountSet] = new TxFormat
{
[Field.EmailHash] = Requirement.Optional,
[Field.WalletLocator] = Requirement.Optional,
@@ -136,40 +136,40 @@ static TxFormat()
[Field.ClearFlag] = Requirement.Optional,
[Field.TickSize] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.EscrowCancel] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.EscrowCancel] = new TxFormat
{
[Field.Owner] = Requirement.Required,
[Field.OfferSequence] = Requirement.Required
},
- [BinaryCodec.Types.TransactionType.SetRegularKey] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.SetRegularKey] = new TxFormat
{
[Field.RegularKey] = Requirement.Optional
},
// 6
- [BinaryCodec.Types.TransactionType.OfferCreate] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.OfferCreate] = new TxFormat
{
[Field.TakerPays] = Requirement.Required,
[Field.TakerGets] = Requirement.Required,
[Field.Expiration] = Requirement.Optional,
[Field.OfferSequence] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.OfferCancel] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.OfferCancel] = new TxFormat
{
[Field.OfferSequence] = Requirement.Required
},
// 9
- [BinaryCodec.Types.TransactionType.TicketCreate] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.TicketCreate] = new TxFormat
{
[Field.Target] = Requirement.Optional,
[Field.Expiration] = Requirement.Optional
},
// 11
- [BinaryCodec.Types.TransactionType.SignerListSet] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.SignerListSet] = new TxFormat
{
[Field.SignerQuorum] = Requirement.Required,
[Field.SignerEntries] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.PaymentChannelCreate] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.PaymentChannelCreate] = new TxFormat()
{
[Field.Destination] = Requirement.Required,
[Field.Amount] = Requirement.Required,
@@ -178,13 +178,13 @@ static TxFormat()
[Field.CancelAfter] = Requirement.Optional,
[Field.DestinationTag] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.PaymentChannelFund] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.PaymentChannelFund] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Required,
[Field.Expiration] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.PaymentChannelClaim] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.PaymentChannelClaim] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Optional,
@@ -192,7 +192,7 @@ static TxFormat()
[Field.Signature] = Requirement.Optional,
[Field.PublicKey] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.CheckCreate] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.CheckCreate] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Optional,
@@ -200,7 +200,7 @@ static TxFormat()
[Field.Signature] = Requirement.Optional,
[Field.PublicKey] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.CheckCash] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.CheckCash] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Optional,
@@ -208,7 +208,7 @@ static TxFormat()
[Field.Signature] = Requirement.Optional,
[Field.PublicKey] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.CheckCancel] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.CheckCancel] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Optional,
@@ -216,7 +216,7 @@ static TxFormat()
[Field.Signature] = Requirement.Optional,
[Field.PublicKey] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.DepositPreauth] = new TxFormat()
+ [BinaryCodec.Enums.TransactionType.DepositPreauth] = new TxFormat()
{
[Field.Channel] = Requirement.Required,
[Field.Amount] = Requirement.Optional,
@@ -224,30 +224,30 @@ static TxFormat()
[Field.Signature] = Requirement.Optional,
[Field.PublicKey] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.TrustSet] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.TrustSet] = new TxFormat
{
[Field.LimitAmount] = Requirement.Optional,
[Field.QualityIn] = Requirement.Optional,
[Field.QualityOut] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.AccountDelete] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.AccountDelete] = new TxFormat
{
[Field.Destination] = Requirement.Required,
[Field.DestinationTag] = Requirement.Optional,
},
- [BinaryCodec.Types.TransactionType.NFTokenMint] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.NFTokenMint] = new TxFormat
{
[Field.NFTokenTaxon] = Requirement.Required,
[Field.Issuer] = Requirement.Optional,
[Field.TransferFee] = Requirement.Optional,
[Field.URI] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.NFTokenBurn] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.NFTokenBurn] = new TxFormat
{
[Field.NFTokenID] = Requirement.Required
},
- [BinaryCodec.Types.TransactionType.NFTokenCreateOffer] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.NFTokenCreateOffer] = new TxFormat
{
[Field.NFTokenID] = Requirement.Required,
[Field.Amount] = Requirement.Required,
@@ -255,15 +255,15 @@ static TxFormat()
[Field.Destination] = Requirement.Optional,
[Field.Expiration] = Requirement.Optional
},
- [BinaryCodec.Types.TransactionType.NFTokenCancelOffer] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.NFTokenCancelOffer] = new TxFormat
{
[Field.NFTokenOffers] = Requirement.Required
},
- [BinaryCodec.Types.TransactionType.NFTokenAcceptOffer] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.NFTokenAcceptOffer] = new TxFormat
{
[Field.NFTokenID] = Requirement.Required
},
- [BinaryCodec.Types.TransactionType.UNLModify] = new TxFormat
+ [BinaryCodec.Enums.TransactionType.UNLModify] = new TxFormat
{
[Field.LedgerSequence] = Requirement.Optional,
[Field.BaseFee] = Requirement.Required,
diff --git a/Xrpl/Models/Transactions/Validation.cs b/Xrpl/Models/Transactions/Validation.cs
index 81df0f24..1e84206b 100644
--- a/Xrpl/Models/Transactions/Validation.cs
+++ b/Xrpl/Models/Transactions/Validation.cs
@@ -1,14 +1,7 @@
-using Newtonsoft.Json;
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Xrpl.Client.Exceptions;
-using Xrpl.Client.Json.Converters;
-using Xrpl.Models.Subscriptions;
using Xrpl.Models.Utils;
namespace Xrpl.Models.Transactions
@@ -131,6 +124,24 @@ public static async Task Validate(Dictionary tx)
case "TrustSet":
await ValidateTrustSet(tx);
break;
+ case "AMMBid":
+ await ValidateAMMBid(tx);
+ break;
+ case "AMMDeposit":
+ await ValidateAMMDeposit(tx);
+ break;
+ case "AMMCreate":
+ await ValidateAMMCreate(tx);
+ break;
+ case "AMMDelete":
+ await ValidateAMMDelete(tx);
+ break;
+ case "AMMVote":
+ await ValidateAMMVote(tx);
+ break;
+ case "AMMWithdraw":
+ await ValidateAMMWithdraw(tx);
+ break;
default:
throw new ValidationException($"Invalid field TransactionType: {type}");
diff --git a/Xrpl/Models/Utils/Flags.cs b/Xrpl/Models/Utils/Flags.cs
index 741ab2b8..2ddcbf97 100644
--- a/Xrpl/Models/Utils/Flags.cs
+++ b/Xrpl/Models/Utils/Flags.cs
@@ -55,6 +55,8 @@ public static void SetTransactionFlagsToNumber(Dictionary tx)
"OfferCreate" => ConvertOfferCreateFlagsToNumber(Flags),
"Payment" => ConvertPaymentTransactionFlagsToNumber(Flags),
"PaymentChannelClaim" => ConvertPaymentChannelClaimFlagsToNumber(Flags),
+ "AMMDeposit" => ConvertAMMDepositFlagsToNumber(Flags),
+ "AMMWithdraw" => ConvertAMMWithdrawFlagsToNumber(Flags),
//TransactionType.PaymentChannelCreate => expr,
//TransactionType.PaymentChannelFund => expr,
//TransactionType.SetRegularKey => expr,
@@ -67,6 +69,18 @@ public static void SetTransactionFlagsToNumber(Dictionary tx)
}
}
+ public static uint ConvertAMMDepositFlagsToNumber(dynamic flags)
+ {
+ if (flags is not Dictionary flag)
+ return 0;
+ return ReduceFlags(flag, Enum.GetValues().ToDictionary(c => c.ToString(), c => (uint)c));
+ }
+ public static uint ConvertAMMWithdrawFlagsToNumber(dynamic flags)
+ {
+ if (flags is not Dictionary flag)
+ return 0;
+ return ReduceFlags(flag, Enum.GetValues().ToDictionary(c => c.ToString(), c => (uint)c));
+ }
public static uint ConvertAccountSetFlagsToNumber(dynamic flags)
{
if (flags is not Dictionary flag)