From 71c50b0514d62bcf2a81783a6d6bdea5030a865f Mon Sep 17 00:00:00 2001 From: mashharuki Date: Sun, 17 Dec 2023 15:44:39 +0900 Subject: [PATCH 1/6] add fully AMM sample codes --- .../_code-samples/create-amm/ts/create-amm.ts | 151 ++++ .../_code-samples/create-amm/ts/lib/amm.ts | 770 ++++++++++++++++++ .../create-amm/ts/util/consts.ts | 3 + 3 files changed, 924 insertions(+) create mode 100644 content/_code-samples/create-amm/ts/create-amm.ts create mode 100644 content/_code-samples/create-amm/ts/lib/amm.ts create mode 100644 content/_code-samples/create-amm/ts/util/consts.ts diff --git a/content/_code-samples/create-amm/ts/create-amm.ts b/content/_code-samples/create-amm/ts/create-amm.ts new file mode 100644 index 0000000000..9ce61dc4db --- /dev/null +++ b/content/_code-samples/create-amm/ts/create-amm.ts @@ -0,0 +1,151 @@ +'use strict' + +require('dotenv').config(); +var xrpl = require('xrpl') +// Configure console.log to print deeper into nested objects so you can +// better see properties of the AMM: +require('util').inspect.defaultOptions.depth = 5 +import { + AmmInfo, + TokenInfo, + acquireTokens, + bidAmm, + checkExistsAmm, + confirmAmm, + createAmm, + depositAmm, + getAmmcost, + get_new_token, + swap, + voteAmm, + withdrawAmm +} from './lib/amm'; +import { + WS_URL +} from './util/consts'; + +/** + * AMM機能を試すためのスクリプト + */ +async function main() { + const client = new xrpl.Client(WS_URL); + await client.connect() + + // Get credentials from the Faucet ------------------------------------------- + console.log("Requesting address from the faucet...") + // const wallet = (await client.fundWallet()).wallet + + // To use an existing account, use code such as the following: + const wallet = xrpl.Wallet.fromSeed(process.env.SECRET_FEED!) + + // Create New Token + const msh_amount = await get_new_token(client, wallet, "MSH", "10000") + // call get new token method (FOO トークンを発行) + const foo_amount = await get_new_token(client, wallet, "FOO", "1000") + + // Acquire tokens ------------------------------------------------------------ + await acquireTokens(client, wallet, msh_amount); + await acquireTokens(client, wallet, foo_amount); + + // create AMM Info + const amm_info_request: AmmInfo = { + "command": "amm_info", + "asset": { + "currency": msh_amount.currency!, + "issuer": msh_amount.issuer!, + }, + "asset2": { + "currency": foo_amount.currency!, + "issuer": foo_amount.issuer! + }, + "ledger_index": "validated" + } + + // Check if AMM already exists ---------------------------------------------- + await checkExistsAmm(client, amm_info_request, msh_amount, foo_amount); + + // Look up AMM transaction cost --------------------------------------------- + const amm_fee_drops = await getAmmcost(client); + + // Create AMM --------------------------------------------------------------- + // This example assumes that 15 TST ≈ 100 FOO in value. + await createAmm(client, wallet, msh_amount, foo_amount, amm_fee_drops) + + // Confirm that AMM exists -------------------------------------------------- + const { + account_lines_result: account_lines_result, + ammInfo: ammInfo + } = await confirmAmm(client, wallet, amm_info_request); + + // console.log("account_lines_result:", account_lines_result) + console.log("ammAddress:", ammInfo.issuer) + + // deposit AMM + await depositAmm(client, wallet, msh_amount, "15", foo_amount, "100") + // withdraw AMM + await withdrawAmm(client, wallet, msh_amount, "5", foo_amount, "5") + // BidAMM + await bidAmm(client, wallet, msh_amount, foo_amount, ammInfo) + // VoteAMM + await voteAmm(client, wallet, msh_amount, foo_amount, 500) + // Swap (payment Transaction) + await swap(client, wallet, ammInfo.issuer, msh_amount, foo_amount, "1", "2") + + // confirm AMM again + const { + account_lines_result: account_lines_result2, + } = await confirmAmm(client, wallet, amm_info_request); + + //console.log("account_lines_result2:", account_lines_result2) + + // ============= (another XRP pattern) =============== + + // create AMM Info (another XRP pattern) + const amm_info_request2: AmmInfo = { + "command": "amm_info", + "asset": { + "currency": msh_amount.currency!, + "issuer": msh_amount.issuer!, + }, + "asset2": { + "currency": "XRP", + "issuer": null + }, + "ledger_index": "validated" + } + + // create XRP Amount info + const xrpInfo: TokenInfo = { + "currency": null, + "value": "10000000", + "issuer": null + } + + // Check if AMM already exists ---------------------------------------------- + await checkExistsAmm(client, amm_info_request2, msh_amount, xrpInfo); + // Create AMM --------------------------------------------------------------- + // This example assumes that 15 TST ≈ 100 FOO in value. + await createAmm(client, wallet, msh_amount, xrpInfo, amm_fee_drops) + + // Confirm that AMM exists -------------------------------------------------- + const { + ammInfo: ammInfo2 + } = await confirmAmm(client, wallet, amm_info_request2); + + // console.log("account_lines_result:", account_lines_result) + console.log("ammAddress2:", ammInfo2.issuer) + // deposit AMM + await depositAmm(client, wallet, msh_amount, "15", xrpInfo, "10") + // withdraw AMM + await withdrawAmm(client, wallet, msh_amount, "5", xrpInfo, "5") + // Swap (payment Transaction) XRP ->> MSH + await swap(client, wallet, ammInfo2.issuer, msh_amount, xrpInfo, "1", "2000000") + // Swap (payment Transaction) MSH ->> XRP + await swap(client, wallet, ammInfo2.issuer, xrpInfo, msh_amount, "2000", "1") + + + // Disconnect when done ----------------------------------------------------- + await client.disconnect() +} + +main() \ No newline at end of file diff --git a/content/_code-samples/create-amm/ts/lib/amm.ts b/content/_code-samples/create-amm/ts/lib/amm.ts new file mode 100644 index 0000000000..3adda49ed5 --- /dev/null +++ b/content/_code-samples/create-amm/ts/lib/amm.ts @@ -0,0 +1,770 @@ +var xrpl = require('xrpl') +import { + EXPLORER +} from './../util/consts'; + +export type TokenInfo = { + "currency": string | null; + "value": string; + "issuer": string | null; +} + +export type AmmInfo = { + "command": string; + "asset": { + "currency": string; + "issuer": string; + }, + "asset2": { + "currency": string; + "issuer": string | null; + } | null, + "ledger_index": "validated" +} + +/** + * get token method + */ +export const acquireTokens = async( + client: any, + wallet: any, + token: TokenInfo, +) => { + try { + const offer_result = await client.submitAndWait({ + "TransactionType": "OfferCreate", + "Account": wallet.address, + "TakerPays": { + currency: token.currency, + issuer: token.issuer, + value: "1000" + }, + "TakerGets": xrpl.xrpToDrops(25*10*1.16) + }, { + autofill: true, + wallet: wallet + }) + + // get metaData & TransactionResult + const metaData: any = offer_result.result.meta!; + const transactionResult = metaData.TransactionResult; + + if (transactionResult == "tesSUCCESS") { + console.log(`MSH offer placed: ${EXPLORER}/transactions/${offer_result.result.hash}`) + const balance_changes = xrpl.getBalanceChanges(metaData) + + for (const bc of balance_changes) { + if (bc.account != wallet.address) {continue} + for (const bal of bc.balances) { + if (bal.currency == "MSH") { + console.log(`Got ${bal.value} ${bal.currency}.${bal.issuer}.`) + break + } + } + break + } + + } else { + throw `Error sending transaction: ${offer_result}` + } + } catch(err) { + console.error("Acquire tokens err: ", err) + } +}; + +/** + * check Amm pair is existed + */ +export const checkExistsAmm = async ( + client: any, + amm_info_request: AmmInfo, + token1Info: TokenInfo, + token2Info: TokenInfo, +) => { + + try { + const amm_info_result = await client.request(amm_info_request) + console.log(amm_info_result) + } catch(err: any) { + if (err.data.error === 'actNotFound') { + if(token2Info.issuer != null) { + console.log(`No AMM exists yet for the pair + ${token2Info.currency}.${token2Info.issuer} / + ${token1Info.currency}.${token1Info.issuer} + (This is probably as expected.)`) + } else { + console.log(`No AMM exists yet for the pair + XRP / + ${token1Info.currency}.${token1Info.issuer} + (This is probably as expected.)`) + } + } else { + throw(err) + } + } +}; + +/** + * get const info for craete carete AMM pair + */ +export const getAmmcost = async( + client: any +): Promise => { + const ss = await client.request({ + "command": "server_state" + }) + const amm_fee_drops = ss.result.state.validated_ledger!.reserve_inc.toString() + console.log(`Current AMMCreate transaction cost: ${xrpl.dropsToXrp(amm_fee_drops)} XRP`) + + return amm_fee_drops; +} + +/** + * create AMM method + */ +export const createAmm = async( + client: any, + wallet: any, + token1Info: TokenInfo, + token2Info: TokenInfo, + amm_fee_drops: string, +) => { + try { + var ammcreate_result; + if(token2Info.currency != null) { + ammcreate_result = await client.submitAndWait({ + "TransactionType": "AMMCreate", + "Account": wallet.address, + "Amount": { + currency: token1Info.currency, + issuer: token1Info.issuer, + value: "15" + }, + "Amount2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + "value": "100" + }, + "TradingFee": 500, // 0.5% + "Fee": amm_fee_drops + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } else { + ammcreate_result = await client.submitAndWait({ + "TransactionType": "AMMCreate", + "Account": wallet.address, + "Amount": { + currency: token1Info.currency, + issuer: token1Info.issuer, + value: "15" + }, + "Amount2": token2Info.value, + "TradingFee": 500, // 0.5% + "Fee": amm_fee_drops + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } + + // get metaData & TransactionResult + const metaData: any = ammcreate_result.result.meta!; + const transactionResult = metaData.TransactionResult; + + // Use fail_hard so you don't waste the tx cost if you mess up + if (transactionResult == "tesSUCCESS") { + console.log(`AMM created: ${EXPLORER}/transactions/${ammcreate_result.result.hash}`) + } else { + throw `Error sending transaction: ${JSON.stringify(ammcreate_result)}` + } + } catch(err) { + console.error("create amm err:", err) + } +} + +/** + * confirm AMM method + */ +export const confirmAmm = async( + client: any, + wallet: any, + amm_info_request: AmmInfo +): Promise => { + try { + // get AMM info + const amm_info_result2 = await client.request(amm_info_request) + console.log("amm_info_result2:", amm_info_result2) + + const results = amm_info_result2.result as any; + + const lp_token = results.amm.lp_token + const amount = results.amm.amount + const amount2 = results.amm.amount2 + + const ammInfo: TokenInfo = { + "currency": lp_token.currency, + "issuer": lp_token.issuer, + "value": "0" + } + + console.log(`The AMM account ${lp_token.issuer} has ${lp_token.value} total + LP tokens outstanding, and uses the currency code ${lp_token.currency}.`) + if(amount2.currency != undefined) { + console.log(`In its pool, the AMM holds ${amount.value} ${amount.currency}.${amount.issuer} + and ${amount2.value} ${amount2.currency}.${amount2.issuer}`) + } else { + console.log(`In its pool, the AMM holds ${amount.value} ${amount.currency}.${amount.issuer} + and ${amount2} XRP`) + } + + // check balanse + const account_lines_result = await client.request({ + "command": "account_lines", + "account": wallet.address, + // Tip: To look up only the new AMM's LP Tokens, uncomment: + // "peer": lp_token.issuer, + "ledger_index": "validated" + }) + return { + account_lines_result, + ammInfo + }; + } catch(err) { + console.error("Check token balances err:", err) + return null; + } +} + +/** + * bid AMM method + */ +export const bidAmm = async( + client: any, + wallet: any, + token1Info: TokenInfo, + token2Info: TokenInfo, + ammInfo: TokenInfo +) => { + try { + const result = await client.submitAndWait({ + "TransactionType": "AMMBid", + "Account": wallet.address, + "Asset": { + currency: token1Info.currency, + issuer: token1Info.issuer, + }, + "Asset2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + }, + "BidMax" : { + "currency" : ammInfo.currency, + "issuer" : ammInfo.issuer, + "value" : "5" + }, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + + // get metaData & TransactionResult + const metaData: any = result.result.meta!; + const transactionResult = metaData.TransactionResult; + + // Use fail_hard so you don't waste the tx cost if you mess up + if (transactionResult == "tesSUCCESS") { + console.log(`AMM bid: ${EXPLORER}/transactions/${result.result.hash}`) + } else { + throw `Error sending transaction: ${JSON.stringify(result)}` + } + } catch(err) { + console.error("error occuered while bidAmm:", err) + } +}; + +/** + * vote AMM method + */ +export const voteAmm = async( + client: any, + wallet: any, + token1Info: TokenInfo, + token2Info: TokenInfo, + tradingFee: number +) => { + try { + const result = await client.submitAndWait({ + "TransactionType": "AMMVote", + "Account": wallet.address, + "Asset": { + currency: token1Info.currency, + issuer: token1Info.issuer, + }, + "Asset2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + }, + "TradingFee" : tradingFee, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + + // get metaData & TransactionResult + const metaData: any = result.result.meta!; + const transactionResult = metaData.TransactionResult; + + // Use fail_hard so you don't waste the tx cost if you mess up + if (transactionResult == "tesSUCCESS") { + console.log(`AMM vote: ${EXPLORER}/transactions/${result.result.hash}`) + } else { + throw `Error sending transaction: ${JSON.stringify(result)}` + } + } catch(err) { + console.error("error occuered while voteAmm:", err) + } +}; + +/** + * deposit AMM + */ +export const depositAmm = async( + client: any, + wallet: any, + token1Info: TokenInfo, + token1Amount: string, + token2Info: TokenInfo, + token2Amount: string, +) => { + try { + var result; + if(token2Info.currency != null) { + result = await client.submitAndWait({ + "TransactionType": "AMMDeposit", + "Account": wallet.address, + "Amount": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + "value": token1Amount + }, + "Amount2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + "value": token2Amount + }, + "Asset": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + }, + "Asset2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + }, + "Flags" : 1048576, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } else { + result = await client.submitAndWait({ + "TransactionType": "AMMDeposit", + "Account": wallet.address, + "Amount": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + "value": token1Amount + }, + "Amount2": token2Amount, + "Asset": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + }, + "Asset2": { + "currency": "XRP" + }, + "Flags" : 1048576, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } + + + // get metaData & TransactionResult + const metaData: any = result.result.meta!; + const transactionResult = metaData.TransactionResult; + + // Use fail_hard so you don't waste the tx cost if you mess up + if (transactionResult == "tesSUCCESS") { + console.log(`AMM deposit: ${EXPLORER}/transactions/${result.result.hash}`) + } else { + throw `Error sending transaction: ${JSON.stringify(result)}` + } + } catch(err) { + console.error("error occuered while depositAmm:", err) + } +}; + +/** + * Withdraw AMM + */ +export const withdrawAmm = async( + client: any, + wallet: any, + token1Info: TokenInfo, + token1Amount: string, + token2Info: TokenInfo, + token2Amount: string, +) => { + try { + var result; + + if(token2Info.currency != null) { + result = await client.submitAndWait({ + "TransactionType": "AMMWithdraw", + "Account": wallet.address, + "Amount": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + "value": token1Amount + }, + "Amount2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + "value": token2Amount + }, + "Asset": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + }, + "Asset2": { + "currency": token2Info.currency, + "issuer": token2Info.issuer, + }, + "Fee" : "10", + "Flags" : 1048576, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } else { + result = await client.submitAndWait({ + "TransactionType": "AMMWithdraw", + "Account": wallet.address, + "Amount": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + "value": token1Amount + }, + "Amount2": token2Amount, + "Asset": { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + }, + "Asset2": { + "currency": "XRP" + }, + "Fee" : "10", + "Flags" : 1048576, + }, { + autofill: true, + wallet: wallet, + failHard: true + }) + } + + // get metaData & TransactionResult + const metaData: any = result.result.meta!; + const transactionResult = metaData.TransactionResult; + + // Use fail_hard so you don't waste the tx cost if you mess up + if (transactionResult == "tesSUCCESS") { + console.log(`AMM withdraw: ${EXPLORER}/transactions/${result.result.hash}`) + } else { + throw `Error sending transaction: ${JSON.stringify(result)}` + } + } catch(err) { + console.error("error occuered while withdrawAmm:", err) + } +}; + +/** + * Swap method + */ +export const swap = async( + client: any, + wallet: any, + ammAddress: string, + token1Info: TokenInfo, + token2Info: TokenInfo, + token1Value: string, + token2Value: string +) => { + client.on('path_find', (stream: any) => { + console.log(JSON.stringify(stream.alternatives, null, ' ')) + }) + // path find + var result; + + if(token1Info.currency != null && token2Info.currency != null) { + result = await client.request({ + command: 'path_find', + subcommand: 'create', + source_account: wallet.address, + source_amount: { + "currency": token2Info.currency, + "value": token2Value, + "issuer": token2Info.issuer + }, + destination_account: wallet.address, + destination_amount: { + "currency": token1Info.currency, + "value": token1Value, + "issuer": token1Info.issuer + } + }); + } else if(token2Info.currency == null) { + result = await client.request({ + command: 'path_find', + subcommand: 'create', + source_account: wallet.address, + source_amount: { + "currency": "XRP", + }, + destination_account: wallet.address, + destination_amount: { + "currency": token1Info.currency, + "value": token1Value, + "issuer": token1Info.issuer + } + }); + } + + console.log("path find:", result) + + // create swap transaction data + var swapTxData; + if(token1Info.currency != null && token2Info.currency != null) { + swapTxData = { + "TransactionType": "Payment", + "Account": wallet.address, + "Destination": wallet.address, + "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 + } + ] + ] + } + } else if (token2Info.currency == null) { // XRP > other token + swapTxData = { + "TransactionType": "Payment", + "Account": wallet.address, + "Destination": wallet.address, + "Amount": { + "currency": token1Info.currency, + "value": token1Value, + "issuer": token1Info.issuer + }, + "SendMax": token2Value, + "Paths": [ + [ + { + "currency": token1Info.currency, + "issuer": token1Info.issuer, + "type": 48 + } + ] + ] + } + } else if (token1Info.currency == null) { // other token > XRP + swapTxData = { + "TransactionType": "Payment", + "Account": wallet.address, + "Destination": wallet.address, + "Amount": token1Value, + "SendMax": { + "currency": token2Info.currency, + "value": token2Value, + "issuer": token2Info.issuer + }, + "Paths": [ + [ + { + "currency": "XRP", + "type": 16 + } + ] + ] + } + } + + try { + const pay_prepared = await client.autofill(swapTxData); + + const pay_signed = wallet.sign(pay_prepared); + + if (token1Info.currency != null) { + console.log(`Sending ${token1Info.value} ${token1Info.currency} to ${ammAddress}...`) + } else if(token2Info.currency == null) { + console.log(`Sending ${token2Info.value} ${token2Info.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); + } +}; + +/* Issue tokens function --------------------------------------------------------------- + * Fund a new issuer using the faucet, and issue some fungible tokens + * to the specified address. In production, you would not do this; instead, + * you would acquire tokens from an existing issuer (for example, you might + * buy them in the DEX, or make an off-ledger deposit at a stablecoin issuer). + * For a more thorough explanation of this process, see + * "Issue a Fungible Token": https://xrpl.org/issue-a-fungible-token.html + * Params: + * client: an xrpl.Client instance that is already connected to the network + * wallet: an xrpl.Wallet instance that should hold the new tokens + * currency_code: string currency code (3-char ISO-like or hex code) + * issue_quantity: string number of tokens to issue. Arbitrarily capped + * at "10000000000" + * Resolves to: an "Amount"-type JSON object, such as: + * { + * "currency": "TST", + * "issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd", + * "value": "123.456" + * } + * + * @param client + * @param wallet + * @param currency_code + * @param issue_quantity + * @returns + */ +export const get_new_token = async ( + client: any, + wallet: any, + currency_code: string, + issue_quantity: string +) => { + // Get credentials from the Testnet Faucet ----------------------------------- + console.log("Funding an issuer address with the faucet...") + const issuer = (await client.fundWallet()).wallet + console.log(`Got issuer address ${issuer.address}.`) + + // Enable issuer DefaultRipple ---------------------------------------------- + const issuer_setup_result = await client.submitAndWait({ + "TransactionType": "AccountSet", + "Account": issuer.address, + "SetFlag": xrpl.AccountSetAsfFlags.asfDefaultRipple + }, { + autofill: true, + wallet: issuer + } ) + + // get metaData & TransactionResult + const metaData: any = issuer_setup_result.result.meta!; + const transactionResult = metaData.TransactionResult; + + if (transactionResult == "tesSUCCESS") { + console.log(`Issuer DefaultRipple enabled: ${EXPLORER}/transactions/${issuer_setup_result.result.hash}`) + } else { + throw `Error sending transaction: ${issuer_setup_result}` + } + + // Create trust line to issuer ---------------------------------------------- + const trust_result = await client.submitAndWait({ + "TransactionType": "TrustSet", + "Account": wallet.address, + "LimitAmount": { + "currency": currency_code, + "issuer": issuer.address, + "value": "10000000000" // Large limit, arbitrarily chosen + } + }, { + autofill: true, + wallet: wallet + }) + + // get metaData & TransactionResult + const metaData2: any = issuer_setup_result.result.meta!; + const transactionResult2 = metaData2.TransactionResult; + + if (transactionResult2 == "tesSUCCESS") { + console.log(`Trust line created: ${EXPLORER}/transactions/${trust_result.result.hash}`) + } else { + throw `Error sending transaction: ${trust_result}` + } + + // Issue tokens ------------------------------------------------------------- + const issue_result = await client.submitAndWait({ + "TransactionType": "Payment", + "Account": issuer.address, + "Amount": { + "currency": currency_code, + "value": issue_quantity, + "issuer": issuer.address + }, + "Destination": wallet.address + }, { + autofill: true, + wallet: issuer + }) + + if (transactionResult == "tesSUCCESS") { + console.log(`Tokens issued: ${EXPLORER}/transactions/${issue_result.result.hash}`) + } else { + throw `Error sending transaction: ${issue_result}` + } + + const tokenInfo: TokenInfo = { + "currency": currency_code, + "value": issue_quantity, + "issuer": issuer.address + } + + return tokenInfo; +} \ No newline at end of file diff --git a/content/_code-samples/create-amm/ts/util/consts.ts b/content/_code-samples/create-amm/ts/util/consts.ts new file mode 100644 index 0000000000..859fc9a9ff --- /dev/null +++ b/content/_code-samples/create-amm/ts/util/consts.ts @@ -0,0 +1,3 @@ +// Connect to the network ----------------------------------------------------- +export const WS_URL = 'wss://s.devnet.rippletest.net:51233' +export const EXPLORER = 'https://devnet.xrpl.org' \ No newline at end of file From f01fc37e77bfb66d137efa98db612cc42c2746c6 Mon Sep 17 00:00:00 2001 From: Haruki Kondo <44923695+mashharuki@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:09:21 +0900 Subject: [PATCH 2/6] Create .env.example --- content/_code-samples/create-amm/ts/.env.example | 1 + 1 file changed, 1 insertion(+) create mode 100644 content/_code-samples/create-amm/ts/.env.example diff --git a/content/_code-samples/create-amm/ts/.env.example b/content/_code-samples/create-amm/ts/.env.example new file mode 100644 index 0000000000..4c13751fc8 --- /dev/null +++ b/content/_code-samples/create-amm/ts/.env.example @@ -0,0 +1 @@ +SECRET_FEED= From 7a18559b970b3637e93ee440ddd6ca59be59f6a3 Mon Sep 17 00:00:00 2001 From: Haruki Kondo <44923695+mashharuki@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:09:56 +0900 Subject: [PATCH 3/6] Create tsconfig.json --- .../_code-samples/create-amm/ts/tsconfig.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 content/_code-samples/create-amm/ts/tsconfig.json diff --git a/content/_code-samples/create-amm/ts/tsconfig.json b/content/_code-samples/create-amm/ts/tsconfig.json new file mode 100644 index 0000000000..78ecbf68bc --- /dev/null +++ b/content/_code-samples/create-amm/ts/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "es2016", + /* Modules */ + "module": "commonjs", + "sourceMap": true, + "outDir": "./dist", + "esModuleInterop": true, + // "preserveSymlinks": true, + "forceConsistentCasingInFileNames": true, + /* Type Checking */ + "strict": true, + "skipLibCheck": true + }, + "include": [ + "src/**/*" + ], +} From 2981e86c592c548401268a6cd0caca1b7adcdd8d Mon Sep 17 00:00:00 2001 From: Haruki Kondo <44923695+mashharuki@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:10:23 +0900 Subject: [PATCH 4/6] Create package.json --- .../_code-samples/create-amm/ts/package.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 content/_code-samples/create-amm/ts/package.json diff --git a/content/_code-samples/create-amm/ts/package.json b/content/_code-samples/create-amm/ts/package.json new file mode 100644 index 0000000000..f2821ffda0 --- /dev/null +++ b/content/_code-samples/create-amm/ts/package.json @@ -0,0 +1,19 @@ +{ + "name": "scripts", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "create-amm": "ts-node src/create-amm.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@types/node": "^20.8.10", + "dotenv": "^16.3.1", + "ts-node": "^10.9.1", + "typescript": "^5.2.2", + "xrpl": "2.11.0" + } +} From 5efe4272dec40ac259d275073a47e94f4b003d9c Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Tue, 2 Jan 2024 16:52:59 -0800 Subject: [PATCH 5/6] Clean up AMM TS code sample --- .../_code-samples/create-amm/ts/create-amm.ts | 22 +++++++++---------- .../_code-samples/create-amm/ts/package.json | 2 +- .../_code-samples/create-amm/ts/tsconfig.json | 5 ++--- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/content/_code-samples/create-amm/ts/create-amm.ts b/content/_code-samples/create-amm/ts/create-amm.ts index 9ce61dc4db..83c44d69e8 100644 --- a/content/_code-samples/create-amm/ts/create-amm.ts +++ b/content/_code-samples/create-amm/ts/create-amm.ts @@ -25,25 +25,27 @@ import { } from './util/consts'; /** + * Script for demonstrating AMM functionality, both token/token and token/XRP * AMM機能を試すためのスクリプト */ async function main() { const client = new xrpl.Client(WS_URL); await client.connect() - - // Get credentials from the Faucet ------------------------------------------- + + // Get credentials from the Faucet ------------------------------------------ console.log("Requesting address from the faucet...") - // const wallet = (await client.fundWallet()).wallet + const wallet = (await client.fundWallet()).wallet // To use an existing account, use code such as the following: - const wallet = xrpl.Wallet.fromSeed(process.env.SECRET_FEED!) + // const wallet = xrpl.Wallet.fromSeed(process.env.SECRET_FEED!) - // Create New Token + // Token<->Token AMM (FOO/MSH) example ====================================== + // Issue tokens + // トークンを発行 const msh_amount = await get_new_token(client, wallet, "MSH", "10000") - // call get new token method (FOO トークンを発行) const foo_amount = await get_new_token(client, wallet, "FOO", "1000") - // Acquire tokens ------------------------------------------------------------ + // Acquire tokens ----------------------------------------------------------- await acquireTokens(client, wallet, msh_amount); await acquireTokens(client, wallet, foo_amount); @@ -95,10 +97,8 @@ async function main() { const { account_lines_result: account_lines_result2, } = await confirmAmm(client, wallet, amm_info_request); - - //console.log("account_lines_result2:", account_lines_result2) - // ============= (another XRP pattern) =============== + // Token<->XRP AMM (FOO/XRP) example ======================================== // create AMM Info (another XRP pattern) const amm_info_request2: AmmInfo = { @@ -148,4 +148,4 @@ async function main() { await client.disconnect() } -main() \ No newline at end of file +main() diff --git a/content/_code-samples/create-amm/ts/package.json b/content/_code-samples/create-amm/ts/package.json index f2821ffda0..2e0257b230 100644 --- a/content/_code-samples/create-amm/ts/package.json +++ b/content/_code-samples/create-amm/ts/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "create-amm": "ts-node src/create-amm.ts" + "create-amm": "ts-node create-amm.ts" }, "keywords": [], "author": "", diff --git a/content/_code-samples/create-amm/ts/tsconfig.json b/content/_code-samples/create-amm/ts/tsconfig.json index 78ecbf68bc..ee2f030002 100644 --- a/content/_code-samples/create-amm/ts/tsconfig.json +++ b/content/_code-samples/create-amm/ts/tsconfig.json @@ -5,14 +5,13 @@ "module": "commonjs", "sourceMap": true, "outDir": "./dist", - "esModuleInterop": true, - // "preserveSymlinks": true, + "esModuleInterop": true, "forceConsistentCasingInFileNames": true, /* Type Checking */ "strict": true, "skipLibCheck": true }, "include": [ - "src/**/*" + "./**/*" ], } From 3393268b239e00a16091991dd6f60c8e7e0afdc6 Mon Sep 17 00:00:00 2001 From: mDuo13 Date: Tue, 2 Jan 2024 20:24:13 -0800 Subject: [PATCH 6/6] Add TS logo to code samples page --- assets/img/logos/typescript.svg | 1 + template/page-code-samples.html.jinja | 1 + 2 files changed, 2 insertions(+) create mode 100644 assets/img/logos/typescript.svg diff --git a/assets/img/logos/typescript.svg b/assets/img/logos/typescript.svg new file mode 100644 index 0000000000..b65a93a8d7 --- /dev/null +++ b/assets/img/logos/typescript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/template/page-code-samples.html.jinja b/template/page-code-samples.html.jinja index ebab6a9b77..55c79a06d1 100644 --- a/template/page-code-samples.html.jinja +++ b/template/page-code-samples.html.jinja @@ -38,6 +38,7 @@ "py": "assets/img/logos/python.svg", "php": "assets/img/logos/php.svg", "http": "assets/img/logos/globe.svg", + "ts": "assets/img/logos/typescript.svg", } %}