Before we get into the heart of the matter, lets setup a few wallets.
Let's add some wallet creation logic. We might as well create two wallets for some fun.
console.log('lets fund 2 accounts...')
const { wallet: wallet1, balance: balance1 } = await client.fundWallet()
const { wallet: wallet2, balance: balance2 } = await client.fundWallet()
console.log('wallet1', wallet1)
console.log('wallet2', wallet2)
console.log({
balance1,
address1: wallet1.address, //wallet1.seed
balance2,
address2: wallet2.address
})At this point, we should have two wallets with balances of 100 XRP.
We will save these in a more convenient way to reuse them as we progress through this tutorial.
Collect the seed values from the logs for both accounts, and let's create wallets from those seeds from now on. We'll need an issuer and a receiver so here we go:
First, we set the seed in the code
const issuerSeed = "s...";
const receiverSeed = "s...";Then we create issuer and receiver wallets from the seeds in the main function as follows:
const issuer = Wallet.fromSeed(issuerSeed);
const receiver = Wallet.fromSeed(receiverSeed);In this section we will create fungible tokens or IOUs and transfert them between accounts.
Token codes can be three letters or a padded hex string. Here is a convenience function to enable codes longer than three letters. This needs to be done to work with our training app, so you will want to include this in your code. This could easily be done via an import for instance, or placed in the index.ts file directly.
Here is the function code:
For AMMs and the whole process to work, we need to enable rippling from the issuer account. To enable rippling we use the AccountSet transaction with the appropriate flag. Here is the function.
And in the main function of index.ts we can now add, to trigger this
To create an issued token, the receiver first needs to add a trust line to the issuer. It's straightforward, we create a TrustSet transaction and sign it with the receiver account.
Once the trustline is set, we send an amount from the issuer to the receiver that is less than the trust line maximum (500M tokens in this case).
Here is the whole file for createToken.ts
We can now call this function from the main function insideindex.ts, remembering to wrap our token currency code with the convertStringToHexPadded function.
We can check in the explorer that the issuer and receiver have balances in the new token at this point.
This session will cover token issuance and providing liquidity for your tokens using the automatic market maker built in to the XRPL
// enable ripling
await enableRippling({ wallet: issuer, client });function convertStringToHexPadded(str: string): string {
// Convert string to hexadecimal
let hex: string = "";
for (let i = 0; i < str.length; i++) {
const hexChar: string = str.charCodeAt(i).toString(16);
hex += hexChar;
}
// Pad with zeros to ensure it's 40 characters long
const paddedHex: string = hex.padEnd(40, "0");
return paddedHex.toUpperCase(); // Typically, hex is handled in uppercase
}async function enableRippling({ wallet, client }: any) {
const accountSet: AccountSet = {
TransactionType: "AccountSet",
Account: wallet.address,
SetFlag: AccountSetAsfFlags.asfDefaultRipple,
};
const prepared = await client.autofill(accountSet);
const signed = wallet.sign(prepared);
const result = await client.submitAndWait(signed.tx_blob);
console.log(result);
console.log("Enable rippling tx: ", result.result.hash);
return;
}import { TrustSet, convertStringToHex, TrustSetFlags } from "xrpl";
import { Payment } from "xrpl/src/models";
async function createToken({ issuer, receiver, client, tokenCode }: any) {
// Create the trust line to send the token
const trustSet: TrustSet = {
TransactionType: "TrustSet",
Account: receiver.address,
LimitAmount: {
currency: tokenCode,
issuer: issuer.address,
value: "500000000", // 500M tokens
},
Flags: TrustSetFlags.tfClearNoRipple,
};
console.log(trustSet);
// Receiver opening trust lines
const preparedTrust = await client.autofill(trustSet);
const signedTrust = receiver.sign(preparedTrust);
const resultTrust = await client.submitAndWait(signedTrust.tx_blob);
console.log(resultTrust);
console.log("Trust line issuance tx result: ", resultTrust.result.hash);
// Send the token to the receiver
const sendPayment: Payment = {
TransactionType: "Payment",
Account: issuer.address,
Destination: receiver.address,
Amount: {
currency: tokenCode,
issuer: issuer.address,
value: "200000000", // 200M tokens
},
};
console.log(sendPayment);
const preparedPayment = await client.autofill(sendPayment);
const signedPayment = issuer.sign(preparedPayment);
const resultPayment = await client.submitAndWait(signedPayment.tx_blob);
console.log(resultPayment);
console.log("Transfer issuance tx result: ", resultPayment.result.hash);
return;
}
export default createToken;// ... previous code
// create Token
await createToken({
issuer,
receiver,
client,
tokenCode: convertStringToHexPadded("LUC"),
});Now we will create an AMM Pool to provide some liquidity for our new token.
Now that the receiver has tokens, we can use the receiver's account to create an AMM. Note that this is the usual architecture where the issuer account solely issues the token, and other proprietary accounts hold the token and can create liquidity.
For this example, we will use pools that have XRP as one side.
Here is the createAMM.ts file:
The final main function index.ts should now look like this:
Don't forget to import enableRippling, createToken, createAMM and convertStringToHexPadded if needed.
You can now go to the training website at (password is training-april-2024) and interact with other pools.
You will need to set up Xaman with the receiver account you created above. You can use the family seed import route. If you are new to Xaman don't forget to enable developer mode in the advanced settings and then switch to testnet from the home page of the Xaman app.
Using the training app, connect and add your public address to the list. When you click "view tokens" next to an address you can see that account's available tokens.
You can create Trustlines for tokens you have not interacted with yet. You can swap XRP for other tokens where you have trustlines using the pool view's swap feature.
You may need to mint more XRP for your receiver account. That's where the print money function might come in handy.
Become a liquidity provider for other pools
ou can become a Liquidity Provider for other pools by using the AMMDeposit function: ()
Withdraw from pools
You can also withdraw from pools using your LP tokens by utilizing the AMMWithdraw transaction. ()
import { AMMCreate, AMMDeposit, AMMDepositFlags } from "xrpl";
import { OfferCreate, OfferCreateFlags } from "xrpl";
async function createAMM({ issuer, receiver, client, tokenCode }: any) {
console.log("create AMM", { issuer, receiver, tokenCode });
let createAmm: AMMCreate = {
TransactionType: "AMMCreate",
Account: receiver.address,
TradingFee: 600,
Amount: {
currency: tokenCode,
issuer: issuer.classicAddress,
value: "2000000", // 2M tokens
},
Amount2: "50000000", // 50 XRP in drops
};
console.log(createAmm);
const prepared = await client.autofill(createAmm);
const signed = receiver.sign(prepared);
const result = await client.submitAndWait(signed.tx_blob);
console.log(result);
console.log("Create amm tx: ", result.result.hash);
return;
}
export default createAMM;const main = async () => {
console.log("lets get started...");
await client.connect();
// retrieve wallets
const issuer = Wallet.fromSeed(issuerSeed);
const receiver = Wallet.fromSeed(receiverSeed);
// enable ripling
await enableRippling({ wallet: issuer, client });
// create Token
await createToken({
issuer,
receiver,
client,
tokenCode: convertStringToHexPadded("LUC"),
});
// create AMM
await createAMM({
issuer,
receiver,
client,
tokenCode: convertStringToHexPadded("LUC"),
});
await client.disconnect();
console.log("all done!");
};