♻️

XRPL AMMの概要

2023/03/06に公開
14

AMMとは

AMMとはトークンのペアをプールし、アルゴリズムに従ってトレーダーに流動性を提供する仕組みのことをいいます。
AMMはトレーダーに対して取引量に応じた手数料を課し、流動性の提供者は提供したトークンの割合に応じてトレーダーが支払った手数料から利益を得ることができます。
代表的なAMMプロダクトとしてはUniswapが存在し、EthereumやPolygonチェーンなどに展開されています。

https://coinpost.jp/?p=304625

XRP LedgerのAMM

2022年に自動マーケットメーカー(AMM)の機能の提案であるXLS-30dが提出されました。

https://github.com/XRPLF/XRPL-Standards/discussions/78

この提案ではXRP LedgerでAMMを利用するために幾つかのトランザクションが追加されており、いくつかのユニークな機能も搭載しています。(後述)
これらはXRPLにプロトコルネイティブな機能(スマートトランザクタ)として実装されており、AMMの流動性はCLOBの流動性と同じくXRP Ledger内のグローバルな流動性として利用できます。

https://xrpl.org/ja/automated-market-makers.html

特徴

XRPL AMMの特徴的な機能として手数料割引権利のオークション(オークションスロット)と手数料の投票機能が挙げられます。

オークションスロット

オークションスロットはトレーダー向けの機能であり、連続オークションの仕組みで他のアカウントとスロットの保有権を競い合います。
オークションスロットを保有している間、保有アカウントとそのアカウントに許可された4アカウント(合計5アカウント)がAMMに対して割引された取引手数料(0%)でのトレードが可能になります。
1つのオークションスロットの有効期間は24時間であり、保有中のスロットが24時間経過前に他者から落札された場合、残り時間に応じて自身の落札金額の一部が払い戻されます。

スロットを落札するには該当のAMMプールのLPトークン(流動性プロバイダートークン)を使う必要があります。
落札金額と払い戻し金額の差額は全てプールに返還され、流動性提供者の1LPトークンあたりの価値を高めることになり、流動性提供者の利益となります。
トレーダーはAMMプールの取引手数料に対してボラティリティが小さい場合でもスロットを落札することで裁定取引を行うことができ、利益に繋げることができます。

https://xrpl.org/ja/automated-market-makers.html#auction-slot

取引手数料の投票

流動性提供者はAMMプールの取引手数料に対して0.001%単位(最大1%)で投票できます。投票は投票者のLPトークンの保有量によって重み付けされ、上位8アカウントの投票から取引手数料が決定されます。
高すぎる手数料は取引量の減少につながり、低すぎる手数料は手数料収益の減少に繋がるため、流動性提供者は自身の利益を最大限にするような投票をするべきです。

トレーダーの利益

トレーダーは他のAMMと同様に価格変動による裁定取引により利益を得ることができます。
加えて、オークションスロットを保有することにより、次の2点から利益を得ることができます。

  • 本来利益とならない取引手数料分からも利益を得ることができる。
  • ボラティリティがAMMプールの取引手数料より小さい場合であっても裁定取引を行うことができる。
    • 例えばAMMプールの取引手数料が1%で、価格の乖離が0.5%の場合、本来は裁定取引を行えませんが、オークションスロットにより取引手数料が0%になるため、価格が乖離している0.5%分から利益を得ることが可能になります。

流動性提供者の利益

他のAMMと同様、トレーダーの取引手数料が流動性提供者の利益となります。
加えて、次の点から利益を得ることができます。

  • トレーダーによるオークションスロットの落札金額(の一部)

取引手数料を含むこれらの利益は直接LPトークン等が流動性提供者に配布されるのではなく、LPトークンがバーンされLPトークンの総量が減ることによりLPトークンあたりの価値が増加することによって実現されます。

追加される要素

トランザクション

AMMCreate

AMMプールを作成するトランザクションです。XRPとトークンまたはトークンとトークンのペアと入金金額を指定してAMMプールを作成します。既に存在するペアのAMMプールは作成できません。

https://xrpl.org/ja/ammcreate.html

トランザクションの例
{
    "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
    "Amount" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
        "value" : "25"
    },
    "Amount2" : "250000000",
    "Fee" : "10",
    "Flags" : 2147483648,
    "Sequence" : 6,
    "TradingFee" : 500,
    "TransactionType" : "AMMCreate"
}

AMMDeposit

AMMプールに対して資産を入金し、入金した資産の量に対するLPトークンを受け取ります。ペアの両方の通貨の入金(ダブルアセット入金)も、一方の通貨のみの入金も可能(シングルアセット入金)です。
ダブルアセット入金の場合は、手数料なしで入金できますが、シングルアセット入金の場合は、資産の半分をAMMプールを通してもう一方の資産へ変換する際の手数料と同等額がかかります。

https://xrpl.org/ja/ammdeposit.html

トランザクションの例
{
    "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
    "Amount" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
        "value" : "2.5"
    },
    "Amount2" : "30000000",
    "Asset" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    },
    "Asset2" : {
        "currency" : "XRP"
    },
    "Fee" : "10",
    "Flags" : 1048576,
    "Sequence" : 7,
    "TransactionType" : "AMMDeposit"
}

AMMWithdraw

AMMへLPトークンを返還し、LPトークンの量に対する資産を受け取ります。ペアの両方の通貨の出金(ダブルアセット出金)も、一方の通貨のみの出金(シングルアセット出金)も可能です。
ダブルアセット出金の場合は、手数料なしで入金できますが、シングルアセット出金の場合は、ダブルアセット出金後に一方の資産をAMMプールを通してもう一方の資産へ変換する際の手数料と同等額がかかります。

https://xrpl.org/ja/ammwithdraw.html

トランザクションの例
{
    "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
    "Amount" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
        "value" : "5"
    },
    "Amount2" : "50000000",
    "Asset" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    },
    "Asset2" : {
        "currency" : "XRP"
    },
    "Fee" : "10",
    "Flags" : 1048576,
    "Sequence" : 10,
    "TransactionType" : "AMMWithdraw"
}

AMMVote

AMMプールの取引手数料に対して投票します。0~1%を0.001%刻みで投票できます。

https://xrpl.org/ja/ammvote.html

トランザクションの例
{
    "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
    "Asset" : {
        "currency" : "XRP"
    },
    "Asset2" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    },
    "Fee" : "10",
    "Flags" : 2147483648,
    "Sequence" : 8,
    "TradingFee" : 600,
    "TransactionType" : "AMMVote"
}

AMMBid

AMMプールのオークションスロットへ入札します。追加で最大4つのアカウトを指定でき、スロットの保有中はこの4つのアカウントも手数料の割引対象となります。

https://xrpl.org/ja/ammbid.html

トランザクションの例
{
    "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
    "Asset" : {
        "currency" : "XRP"
    },
    "Asset2" : {
        "currency" : "TST",
        "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    },
    "AuthAccounts" : [
        {
          "AuthAccount" : {
              "Account" : "rMKXGCbJ5d8LbrqthdG46q3f969MVK2Qeg"
          }
        },
        {
          "AuthAccount" : {
              "Account" : "rBepJuTLFJt3WmtLXYAxSjtBWAeQxVbncv"
          }
        }
    ],
    "BidMax" : {
        "currency" : "039C99CD9AB0B70B32ECDA51EAAE471625608EA2",
        "issuer" : "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S",
        "value" : "100"
    },
    "Fee" : "10",
    "Flags" : 2147483648,
    "Sequence" : 9,
    "TransactionType" : "AMMBid"
}

Payment

すでに存在するトランザクションです。

AMMを通してトークンをスワップに使用します。スワップする際の流動性として、AMM DEXだけでなくCLOB DEXも自動的に利用します。
Path機能を使用することで複数の経路を利用し、最良レートでのスワップも行えます。

またスワップだけでなく、クロスカレンシーペイメントの流動性としても使用可能です。

トランザクションの例(スワップ)
{
  "TransactionType" : "Payment",
  "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
  "Destination" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
  "Amount" : "5000000",
  "SendMax": {
    "currency" : "TST",
    "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
    "value" : "5"
  },
  "Fee": "12",
  "Flags": 2147483648,
  "Sequence": 2,
}

レジャーオブジェクト

AccountRoot

すでに存在するオブジェクトです。

2つの資産を持つAMMプールは既存のアカウントオブジェクト:AccountRootとして表されます。
この特殊なアカウントはプール資産としてXRPとトークンまたはトークンとトークンを保有し、LPトークンの発行者となります。

https://xrpl.org/ja/accountroot.html#special-amm-accountroot-objects

AMM

AMMオブジェクトには資産ペアやオークションスロット、手数料投票の状況、現在の取引手数料などの情報が格納されます。

https://xrpl.org/ja/amm.html

オブジェクトの例
{
    "AMMAccount" : "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S",
    "Asset" : {
      "currency" : "XRP"
    },
    "Asset2" : {
      "currency" : "TST",
      "issuer" : "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    },
    "AuctionSlot" : {
      "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
      "AuthAccounts" : [
          {
            "AuthAccount" : {
                "Account" : "rMKXGCbJ5d8LbrqthdG46q3f969MVK2Qeg"
            }
          },
          {
            "AuthAccount" : {
                "Account" : "rBepJuTLFJt3WmtLXYAxSjtBWAeQxVbncv"
            }
          }
      ],
      "DiscountedFee" : 0,
      "Expiration" : 721870180,
      "Price" : {
          "currency" : "039C99CD9AB0B70B32ECDA51EAAE471625608EA2",
          "issuer" : "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S",
          "value" : "0.8696263565463045"
      }
    },
    "Flags" : 0,
    "LPTokenBalance" : {
      "currency" : "039C99CD9AB0B70B32ECDA51EAAE471625608EA2",
      "issuer" : "rE54zDvgnghAoPopCgvtiqWNq3dU5y836S",
      "value" : "71150.53584131501"
    },
    "TradingFee" : 600,
    "VoteSlots" : [
      {
          "VoteEntry" : {
            "Account" : "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
            "TradingFee" : 600,
            "VoteWeight" : 100000
          }
      }
    ]
}

APIメソッド

amm_info

AMMオブジェクトの情報を取得するためのAPIメソッドです。

https://xrpl.org/ja/amm_info.html#amm_info

リクエストの例
{
    "command": "amm_info",
    "asset": {
      "currency": "XRP"
    },
    "asset2": {
      "currency": "TST",
      "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
    }
}
レスポンスの例
{
  "result": {
    "amm": {
      "amm_account": "rp9E3FN3gNmvePGhYnf414T2TkUuoxu8vM",
      "amount": "296890496",
      "amount2": {
        "currency": "TST",
        "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd",
        "value": "25.81656470648473"
      },
      "asset2_frozen": false,
      "auction_slot": {
        "account": "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
        "auth_accounts": [
          {
            "account": "r3f2WpQMsAd8k4Zoijv2PZ78EYFJ2EdvgV"
          },
          {
            "account": "rnW8FAPgpQgA6VoESnVrUVJHBdq9QAtRZs"
          }
        ],
        "discounted_fee": 0,
        "expiration": "2023-Jan-26 00:28:40.000000000 UTC",
        "price": {
          "currency": "039C99CD9AB0B70B32ECDA51EAAE471625608EA2",
          "issuer": "rp9E3FN3gNmvePGhYnf414T2TkUuoxu8vM",
          "value": "0"
        },
        "time_interval": 0
      },
      "lp_token": {
        "currency": "039C99CD9AB0B70B32ECDA51EAAE471625608EA2",
        "issuer": "rp9E3FN3gNmvePGhYnf414T2TkUuoxu8vM",
        "value": "87533.41976112682"
      },
      "trading_fee": 600,
      "vote_slots": [
        {
          "account": "rJVUeRqDFNs2xqA7ncVE6ZoAhPUoaJJSQm",
          "trading_fee": 600,
          "vote_weight": 9684
        }
      ]
    },
    "ledger_current_index": 316725,
    "validated": false
  },
  "status": "success",
  "type": "response"
}

まとめ

現在開発が進められているAMM機能はXRP LedgerのDEX環境に非常に大きなインパクトとなるでしょう。CLOB DEXとAMM DEXの流動性が集約され、トレーダーにとってより良い取引レートでトレードが行えるようになります。
また、XRPやトークンのホルダーは流動性を提供することでインセンティブを得ることができるようになります。

興味を持たれた方はXRP Ledger開発者のDiscordチャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
https://xrpldevs.org

Discussion

HarukiHaruki

XRPLにおけるAMMを活用した時のスワップの時のトランザクションデータについて質問です。

この場合、トランザクションの宛先 DestinationにはAMMのアカウントのアドレスを設定するのでしょうか?それともスワップするアカウントのアドレスを入力するのでしょうか?

ご教示いただければ幸いです!

下記のようにトランザクションデータを作成してswapを試みましたがエラーが返ってきました。

// Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": ammAddress,          // AMMアカウントのアドレスを指定
    "Amount": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "SendMax": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "DestinationTag": 1 
  }

エラーの内容は、error occuered while swaping: Error sending transaction: tecNO_PERMISSION というものです。

よろしくお願いします!

tequtequ

スワップ時はDestinationには自身のアカウント(=Accountフィールド)を指定します!

また、AmountフィールドとSendMaxフィールドで同じ通貨コードを指定する場合、Pathsフィールドが必要になります。

    if (account == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
    {
        // You're signing yourself a payment.
        // If bPaths is true, you might be trying some arbitrage.
        JLOG(j.trace()) << "Malformed transaction: "
                        << "Redundant payment from " << to_string(account)
                        << " to self without path for "
                        << to_string(uDstCurrency);
        return temREDUNDANT;
    }

https://github.com/XRPLF/rippled/blob/09e0f103f4472d57ca234d13e0db203386c1b921/src/ripple/app/tx/impl/Payment.cpp#L121

https://xrpl.org/ja/paths.html

AMM AccountへのPaymentは出来ないようになっています。

    if (sleDst->isFieldPresent(sfAMMID))
        return tecNO_PERMISSION;

https://github.com/XRPLF/rippled/blob/09e0f103f4472d57ca234d13e0db203386c1b921/src/ripple/app/tx/impl/Payment.cpp#L458

Paymentトランザクション内でAMMに関する情報を指定する必要はなく、変換元と変換先のトークンの情報(金額含む)を指定するだけで、あとは自動的にDEX(CLOB,AMM)を使った変換を行います。

HarukiHaruki

ありがとうございます!!

いただいた助言元にしてトランザクションデータを修正して再度トライしてみました・・・。

エラーは変わったのですが以前上手く処理されない状況が続いています。

エラーの内容は以下の通りです。
シーケンス番号が不正な値になっているということなので別のAPIを叩いて最新の値を手動で入れた方がいいんですかね?

rror occuered while depositAmm: XrplError: The latest ledger sequence 1318809 is greater than the transaction's LastLedgerSequence (1318808).

修正後のトランザクションデータは下記の通りです。

// Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": wallet.address,      // AMMの際は自分自身のアドレスを指定
    "Amount": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "DestinationTag": 1 
  }

swapの他、 AMMwithdrawとAMMDepositでも全く同じエラーが発生しています・・

AMMBidとAMMCreate、AMMvoteでは発生していません!

お手数ですがご確認よろしくお願いします!

HarukiHaruki

Swap関数全体としては以下のような実装としています!

/**
 * AMMを介してトークンをSwapするメソッド
 * @param client 
 * @param wallet 
 * @param ammAddress
 * @param token1Info
 * @param token2Info
 * @returns 
 */
export const swap = async(
  client: any,
  wallet: any,
  ammAddress: string,
  token1Info: TokenInfo,
  token2Info: TokenInfo,
  value: string
) => {
  // Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": wallet.address,      // AMMの際は自分自身のアドレスを指定
    "Amount": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "DestinationTag": 1 
  }

  try {
    const pay_prepared = await client.autofill(swapTxData);
    // トランザクションに署名
    const pay_signed = wallet.sign(pay_prepared);
    console.log(`Sending ${value} ${token1Info.currency} to ${ammAddress}...`)
    // 署名済みトランザクションをブロードキャスト
    const pay_result = await client.submitAndWait(pay_signed.tx_blob);

    if (pay_result.result.meta.TransactionResult == "tesSUCCESS") {
      console.log(`Transaction succeeded: ${EXPLORER}/transactions/${pay_signed.hash}`)
    } else {
      throw `Error sending transaction: ${pay_result.result.meta.TransactionResult}`
    };

    // Check balances ------------------------------------------------------------
    console.log("Getting hot address balances...");
    // get hot address data
    const balances = await client.request({
      command: "account_lines",
      account: wallet.address,
      ledger_index: "validated"
    })
    console.log("wallet address's balance:", balances.result);
  } catch(err) {
    console.error("error occuered while swaping:", err);
  }
};
tequtequ

PaymentトランザクションにSendMaxの指定がないためですね。

ローカル環境で確認したところtemREDUNDANTでした。

    if (account == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
    {
        // You're signing yourself a payment.
        // If bPaths is true, you might be trying some arbitrage.
        JLOG(j.trace()) << "Malformed transaction: "
                        << "Redundant payment from " << to_string(account)
                        << " to self without path for "
                        << to_string(uDstCurrency);
        return temREDUNDANT;
    }

Swapする場合はAccount=DestinationかつSendMaxの指定も必要となります。

AMMwithdrawAMMDepositに関してはトランザクション情報がないため分からないです…


xrpl.jsのclient.submitAndWaitはコンセンサスステージ前のトランザクションフォーマットチェック段階でエラーの場合、LastLedgerSequenceが無効になるまでトランザクションの送信を試行します。

LastLedgerSequenceに関するエラーの場合は基本的にトランザクションのフォーマットが間違っている可能性が高いです👍

HarukiHaruki

ありがとうございます!
もう一度見直してみたいと思います!!

HarukiHaruki

https://xrpl.org/payment.html#types-of-payments
↑ このページを確認しました!


↑ この仕様に従ってPaymentトランザクションデータを作る必要があるんですね!

pathを指定してみたんですが、invalidPathというエラーが返っている状況です・・、

// Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": wallet.address,      // AMMの際は自分自身のアドレスを指定
    "Amount": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "SendMax": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value + 1,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "Paths": [
      {
        "account": wallet.address
      },
      {
        "currency": token1Info.currency,
        "issuer": token1Info.issuer
      }
    ],
    "Flags": 65536
  }

すみません、見直すポイントについてご教示いただけると幸いです。
よろしくお願いします!

HarukiHaruki

https://zenn.dev/tequ/articles/xrpl-token-swap
↑ すみません、Pathsについてはこの記事参考に直してみましたがやはりエラーが返ってきました・・。

パス情報がやはり間違っていそうなのでPaymentの直前で、 path_findのAPIを叩いてパス情報を取得してみました。

// path find
  const result = await client.request({
    command: 'path_find',
    subcommand: 'create',
    source_account: wallet.address,
    source_amount: {
      "currency": token1Info.currency,  
      "value": value,                   
      "issuer": token1Info.issuer
    },
    destination_account: wallet.address,
    destination_amount: {
      "currency": token2Info.currency,  
      "value": value,                   
      "issuer": token2Info.issuer
    }
  });

その結果がこちらです。

{
  id: 137,
  result: {
    alternatives: [
      {
        paths_computed: [ [ [Object], [Object] ] ],
        source_amount: {
          currency: 'MSH',
          issuer: 'rw65Wsw3CCUAUwU1tAbsv9tUm8AHxYb4VK',
          value: '0.1515909469886443'
        }
      }
    ],
    destination_account: 'rw65Wsw3CCUAUwU1tAbsv9tUm8AHxYb4VK',
    destination_amount: {
      currency: 'FOO',
      issuer: 'rUddiFyvT2x1x9enGFoBiqB9zgnkHPiGAz',
      value: '1'
    },
    full_reply: false,
    id: 137,
    source_account: 'rw65Wsw3CCUAUwU1tAbsv9tUm8AHxYb4VK'
  },
  type: 'response'
}
[
  {
    "paths_computed": [
      [
        {
          "account": "rp2mqVn2NhGtTJJFGoeeJyJVWqtUsen6kF",
          "type": 1
        },
        {
          "currency": "FOO",
          "issuer": "rUddiFyvT2x1x9enGFoBiqB9zgnkHPiGAz",
          "type": 48
        }
      ]
    ],
    "source_amount": {
      "currency": "MSH",
      "issuer": "rw65Wsw3CCUAUwU1tAbsv9tUm8AHxYb4VK",
      "value": "0.1515909469886443"
    }
  }
]
[
  {
    "paths_computed": [
      [
        {
          "account": "rp2mqVn2NhGtTJJFGoeeJyJVWqtUsen6kF",
          "type": 1
        },
        {
          "currency": "FOO",
          "issuer": "rUddiFyvT2x1x9enGFoBiqB9zgnkHPiGAz",
          "type": 48
        }
      ]
    ],
    "source_amount": {
      "currency": "MSH",
      "issuer": "rw65Wsw3CCUAUwU1tAbsv9tUm8AHxYb4VK",
      "value": "0.1515909469886443"
    }
  }
HarukiHaruki

今の最新のSwap用のトランザクションデータは下記のように作成しています。

// Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": wallet.address,      // AMMの際は自分自身のアドレスを指定
    "Amount": {
      "currency": token1Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "SendMax": {
      "currency": token2Info.currency,  // ここで送金したいトークンの種類を指定する。
      "value": value,                   // ここで送金したいトークンの金額を指定する。
      "issuer": token2Info.issuer
    },
    "Paths": [
      {
        "account": token1Info.issuer
      },
      {
        "currency": token2Info.currency,
        "issuer": token2Info.issuer
      }
    ]
  }
HarukiHaruki

もう一度見直したらSwapできました!!!

お騒がせました!!!
※ でもまだ AMM Depositと AMM Withdrawが動かない・・・

でもXRPLの真の力の一端に触れられました!! スマコン作らないでこの機能が使えるのは本当にすごいですね!!!

The AMM account rhTTPVgL9eQC7ik1Xxdz9J7LfGRvXHVwn8 has 38.72208749538176 total
                LP tokens outstanding, and uses the currency code 03451AB86CDD94767A698DD826DE28F078EE0C11.
In its pool, the AMM holds 14 MSH.rhE46YAgKFbSJSymQFvTLTxT5DX5aDZDfq
                and 107.1464303580361 FOO.rnsUNnQh77RPBJtke4AaouM6a9HkRqxNGa

トランザクションデータは、最終的に以下のようになりました。

// Swap用のトランザクションデータを作成する
  const swapTxData = {
    "TransactionType": "Payment",
    "Account": wallet.address,
    "Destination": wallet.address,      // AMMの際は自分自身のアドレスを指定
    "Amount": {
      "currency": token1Info.currency,        // ここで変換先トークンの種類を指定する。
      "value": token1Value,                   // ここで変換先トークンの金額を指定する。
      "issuer": token1Info.issuer
    },
    "SendMax": {
      "currency": token2Info.currency,  // ここで変換元のトークンの種類を指定する。
      "value": token2Value,
      "issuer": token2Info.issuer
    },
    "Paths": [
      [
        {
          "account": token2Info.issuer,
          "type": 1
        },
        {
          "currency": token1Info.currency,
          "issuer": token1Info.issuer,
          "type": 48
        }
      ]
    ]
  }
tequtequ

おめでとうございます🎉🎉
Pathsはその時々で流動性が変化するため手動設定するよりもpath_findを利用する方が良いですね!

AMM DepositとAMM Withdrawのエラーとなるトランザクション情報を共有していただけますか?

tequtequ

AMM関連のトランザクションを一通り動かしてみることができたのであれば、他のほとんどのトランザクションはそれ以下のコストで学ぶことができると思います👍

個人的にはAMM関連(特にDeposit, Withdraw)のトランザクションはどちらかというと複雑な方だと思ってます