From 86edc58dda3cf22bb04830e6dd0cf192dec2ea3c Mon Sep 17 00:00:00 2001 From: Dennis Dawson Date: Wed, 13 Apr 2022 15:20:10 -0700 Subject: [PATCH] Add Quickstart step 4, transfer NFTokens --- .../tutorials/quickstart/transfer-nftokens.md | 1514 +++++++++++++++++ 1 file changed, 1514 insertions(+) create mode 100644 content/tutorials/quickstart/transfer-nftokens.md diff --git a/content/tutorials/quickstart/transfer-nftokens.md b/content/tutorials/quickstart/transfer-nftokens.md new file mode 100644 index 0000000000..8223c860bc --- /dev/null +++ b/content/tutorials/quickstart/transfer-nftokens.md @@ -0,0 +1,1514 @@ +--- +html: xrpl-quickstart.html +parent: quickstart.html +blurb: Use a JavaScript test harness to send XRP, trade currencies, and mint and trade NFTokens. +labels: + - Quickstart + - Tokens + - NFTokens +--- + +# 4. Transfer NFTokens + +{% include '_snippets/nfts-disclaimer.md' %} + +This example shows how to: + + + +1. Create NFToken Sell Offers. +2. Create NFToken Buy Offers. +3. Accept NFToken Sell Offers. +4. Accept NFToken Buy Offers. +5. Get a list of offers for a particular NFToken. +6. Cancel an offer. + + + +![Quickstart form with NFToken transfer fields](img/quickstart13.png) + +You can download the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/content/_code-samples/quickstart/quickstart.zip) archive to try each of the samples in your own browser. + + +# Usage + + +## Get Accounts + + + +1. Open 4.transfer-nftokens.html in a browser. +2. Get test accounts. + 1. If you have existing NFT-Devnet account seeds + 1. Paste account seeds in the **Seeds** field. + 2. Click **Get Accounts from Seeds**. + 2. If you do not have NFT-Devnet account seeds: + 3. Visit the [XRP Testnet Faucet](https://xrpl.org/xrp-testnet-faucet.html) page. + 4. Click **Generate NFT-Devnet credentials**. + 5. Copy the account **Secret**. + 6. Paste the secret in a persistent location, such as a notepad, and press return. + 7. Click **Generate NFT-Devnet credentials** to create a second account. + 8. Copy the account **Secret**. + 9. Paste the secret in the persistent location. + 10. Copy both secrets, separated by a return. + 11. Paste them in the **Account** **Seeds** field. + 12. Click **Get Accounts from Seeds**. + + + +![Form with account information](img/quickstart14.png) + + + +## Create a Sell Offer + +To create a NFToken sell offer: + + + +1. Enter the **Amount** of the sell offer in drops (millionths of an XRP). +2. Set the **Flags** field to _1_. +3. Enter the **Token ID** of the NFToken you want to sell. +4. Click **Create Sell Offer**. + +The important piece of information in the response is the Token Offer Index, labeled as _Index,_ which is used to accept the sell offer. + + + +![NFToken Sell Offer](img/quickstart15.png) + + + +## Accept Sell Offer + +Once a sell offer is available, another account can opt to accept the offer and purchase the NFToken. + +To accept an available sell offer: + + + +1. Enter the **Token Offer Index** (labeled as _Index_ in the token offer results. This is not the same as the Token ID). +2. Click **Accept Sell Offer**. + + + +![Accept Sell Offer](img/quickstart16.png) + + + +## Create a Buy Offer + +You can offer to buy a NFToken from another account. + +To create an offer to buy a NFToken: + + + +1. Enter the **Amount** of your offer. +2. Enter the **Token ID**. +3. Enter the owner’s account string in the **Owner** field. +4. Click **Create Buy Offer**. + + + +![NFToken Buy Offer](img/quickstart17.png) + + + +## Accept a Buy Offer + +To accept an offer to buy a NFToken: + + + +1. Enter the **Token Offer ID** (the **Index** of the token offer). +2. Enter the buyer’s account string in the **Owner** field (the buyer is the owner of the token offer). +3. Click **Accept Buy Offer**. + + + +![Accept Buy Offer](img/quickstart18.png) + + + +## Get Offers + +Click **Get Offers** to get the buy and sell offers associated with a particular account. + + + +![Get offers](img/quickstart19.png) + + + +## Cancel Offer + +To cancel a buy or sell offer that you have created: + + + +1. Enter the **Token Offer ID**. +2. Click **Cancel Offer**. + + + +![Cancel offer](img/quickstart20.png) + + + +# Code Walkthrough + +You can download the [Quickstart Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/content/_code-samples/quickstart/quickstart.zip) archive to try each of the samples in your own browser. + + +## Create Sell Offer + + +``` +// ******************************************************* +// ****************** Create Sell Offer ****************** +// ******************************************************* +``` + + +Connect to the XRPL and get the wallet accounts. + + +``` + async function createSellOffer() { + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results += '\nConnected. Creating sell offer...' + document.getElementById('standbyResultField').value = results + + +``` + + +Define the transaction. The _Flags_ value of 1 indicates that this transaction is a sell offer. + + +``` + const transactionBlob = { + "TransactionType": "NFTokenCreateOffer", + "Account": standby_wallet.classicAddress, + "TokenID": standbyTokenIdField.value, + "Amount": standbyAmountField.value, + "Flags": parseInt(standbyFlagsField.value) + } + + +``` + + +Submit the transaction and wait for the results. + + + + +``` + const tx = await client.submitAndWait(transactionBlob,{wallet: standby_wallet}) +``` + + + + + +``` + results += '\n\n***Sell Offers***\n' +``` + + +Request the list of sell offers for the token. + + +``` + + + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: standbyTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) + results += '\n\n***Buy Offers***\n' +``` + + +Request the list of buy offers for the token. + + +``` + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: standbyTokenIdField.value }) + } catch (err) { + results += 'No buy offers.' + } + results += JSON.stringify(nftBuyOffers,null,2) + + +``` + + +Report the results of the transaction. + + +``` + results += '\n\nTransaction result:\n' + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += '\n\nBalance changes:\n' + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) +``` + + +Get the current XRP balances for the operational and standby accounts. + + +``` + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) + document.getElementById('standbyBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + + + client.disconnect() + // End of createSellOffer() + } +``` + + + +## Create Buy Offer + + +``` +// ******************************************************* +// ***************** Create Buy Offer ******************** +// ******************************************************* + + + async function createBuyOffer() { +``` + + +Get the account wallets and connect to the XRPL. + + +``` + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + let results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results = '\nConnected. Creating buy offer...' + document.getElementById('standbyResultField').value = results + + +``` + + +Define the transaction. Setting the _Flags_ value to _null_ indicates that this is a buy offer. + + +``` + const transactionBlob = { + "TransactionType": "NFTokenCreateOffer", + "Account": standby_wallet.classicAddress, + "Owner": standbyOwnerField.value, + "TokenID": standbyTokenIdField.value, + "Amount": standbyAmountField.value, + "Flags": null + } + + +``` + + +Submit the transaction and wait for the results. + + +``` + const tx = await client.submitAndWait(transactionBlob,{wallet: standby_wallet}) +``` + + +Request the list of sell offers for the token. + + +``` + + + results += "\n\n***Sell Offers***\n" + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: standbyTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) +``` + + +Request the list of buy offers for the token. + + +``` + results += "\n\n***Buy Offers***\n" + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: standbyTokenIdField.value }) + } catch (err) { + results += "No buy offers." + } + results += JSON.stringify(nftBuyOffers,null,2) + + +``` + + +Report the results of the transaction. + + + + +``` + results += "\n\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += "\n\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + client.disconnect() + // End of operationalCreateBuyOffer() + } +``` + + + +## Cancel Offer + + +``` +// ******************************************************* +// ******************** Cancel Offer ********************* +// ******************************************************* + + async function cancelOffer() { +``` + + +Get the standby wallet and connect to the XRPL. + + +``` + const wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const client = new xrpl.Client("wss://xls20-sandbox.rippletest.net:51233") + results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results += "\nConnected. Cancelling offer..." + document.getElementById('standbyResultField').value = results +``` + + +Insert the token offer index as a new array. This example destroys one offer at a time. In practice you could implement the function to accept multiple token offer index values and destroy all of the token offers in one operation. + + +``` + const tokenOfferIDs = [standbyTokenOfferIndexField.value] + + +``` + + +Define the transaction. + + +``` + const transactionBlob = { + "TransactionType": "NFTokenCancelOffer", + "Account": wallet.classicAddress, + "TokenOffers": tokenOfferIDs + } +``` + + +Submit the transaction and wait for the results. + + +``` + const tx = await client.submitAndWait(transactionBlob,{wallet}) +``` + + +Request the list of sell offers for the token. + + +``` + results += "\n\n***Sell Offers***\n" + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: standbyTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) +``` + + +Request the list of buy offers for the token. + + +``` + results += "\n\n***Buy Offers***\n" + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: standbyTokenIdField.value }) + } catch (err) { + nftBuyOffers = "No buy offers." + } + results += JSON.stringify(nftBuyOffers,null,2) +``` + + +Report the transaction results. + + +``` + + + results += "\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += "\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + client.disconnect() + // End of cancelOffer() + } +``` + + + +## Get Offers + + +``` +// ******************************************************* +// ******************** Get Offers *********************** +// ******************************************************* + + + async function getOffers() { +``` + + +Get the standby account wallet and connect to the XRPL. + + +``` + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results += '\nConnected. Getting offers...' + document.getElementById('standbyResultField').value = results +``` + + +Request the list of sell offers for the token. + + +``` + results += '\n\n***Sell Offers***\n' + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: standbyTokenIdField.value + }) + } catch (err) { + nftSellOffers = 'No sell offers.' + } + results += JSON.stringify(nftSellOffers,null,2) + document.getElementById('standbyResultField').value = results +``` + + +Request the list of buy offers for the token. + + +``` + results += '\n\n***Buy Offers***\n' + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: standbyTokenIdField.value }) + } catch (err) { + nftBuyOffers = 'No buy offers.' + } + results += JSON.stringify(nftBuyOffers,null,2) + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + client.disconnect() + // End of getOffers() + } + + +``` + + + +## Accept Sell Offer + + +``` +// ******************************************************* +// ****************** Accept Sell Offer ****************** +// ******************************************************* + + + async function acceptSellOffer() { +``` + + +Get the account wallets and connect to the XRPL. + + +``` + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results += '\nConnected. Accepting sell offer...\n\n' + document.getElementById('standbyResultField').value = results + + +``` + + +Define the transaction. + + +``` + const transactionBlob = { + "TransactionType": "NFTokenAcceptOffer", + "Account": standby_wallet.classicAddress, + "SellOffer": standbyTokenOfferIndexField.value, + } +``` + + +Submit the transaction and wait for the results. + + +``` + const tx = await client.submitAndWait(transactionBlob,{wallet: standby_wallet}) +``` + + +Request the list of NFTs for the standby account. + + +``` + const nfts = await client.request({ + method: "account_nfts", + account: standby_wallet.classicAddress + }) + + +``` + + +Get the balances for both accounts. + + +``` + document.getElementById('standbyBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) +``` + + +Report the transaction results. + + +``` + + + results += 'Transaction result:\n' + results += JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += '\nBalance changes:' + results += JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + results += JSON.stringify(nfts,null,2) + + + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + client.disconnect() + // End of acceptSellOffer() + } +``` + + + +## Accept Buy Offer + + +``` +// ******************************************************* +// ******************* Accept Buy Offer ****************** +// ******************************************************* + + + async function acceptBuyOffer() { +``` + + +Get the account wallets and connect to the XRPL. + + +``` + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('standbyResultField').value = results + await client.connect() + results += '\nConnected. Accepting buy offer...' + document.getElementById('standbyResultField').value = results +``` + + +Prepare the transaction. + + +``` + const transactionBlob = { + "TransactionType": "NFTokenAcceptOffer", + "Account": standby_wallet.classicAddress, + "BuyOffer": standbyTokenOfferIndexField.value + } +``` + + +Submit the transaction and wait for the results. + + +``` + const tx = await client.submitAndWait(transactionBlob,{wallet: standby_wallet}) +``` + + +Request the current list of NFTs for the standby account. + + +``` + const nfts = await client.request({ + method: "account_nfts", + account: standby_wallet.classicAddress + }) + results += JSON.stringify(nfts,null,2) + document.getElementById('standbyResultField').value = results +``` + + +Report the transaction result. + + +``` + result += "\n\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + result += "\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) +``` + + +Request the XRP balance for both accounts. + + +``` + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) + document.getElementById('standbyBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('standbyResultField').value = results +``` + + +Disconnect from the XRPL. + + +``` + client.disconnect() + // End of acceptBuyOffer() + } +``` + + + +## Reciprocal Transactions + +These functions duplicate the functions of the standby account for the operational account. See the corresponding standby account function for walkthrough information. + +``` +// ******************************************************* +// *********** Operational Create Sell Offer ************* +// ******************************************************* + + + async function oPcreateSellOffer() { + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results += '\nConnected. Creating sell offer...' + document.getElementById('operationalResultField').value = results + + + // Prepare transaction ------------------------------------------------------- + const transactionBlob = { + "TransactionType": "NFTokenCreateOffer", + "Account": operational_wallet.classicAddress, + "TokenID": operationalTokenIdField.value, + "Amount": operationalAmountField.value, + "Flags": parseInt(operationalFlagsField.value) + } + + + // Submit transaction -------------------------------------------------------- + + + const tx = await client.submitAndWait(transactionBlob,{wallet: operational_wallet}) + + + results += '\n\n***Sell Offers***\n' + + + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: operationalTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) + results += '\n\n***Buy Offers***\n' + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: operationalTokenIdField.value }) + } catch (err) { + results += 'No buy offers.' + } + results += JSON.stringify(nftBuyOffers,null,2) + + + // Check transaction results ------------------------------------------------- + results += '\n\nTransaction result:\n' + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += '\n\nBalance changes:\n' + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) + document.getElementById('standbyBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('operationalResultField').value = results + + + client.disconnect() + } // End of oPcreateSellOffer() + + +// ******************************************************* +// ************** Operational Create Buy Offer *********** +// ******************************************************* + + + async function oPcreateBuyOffer() { + + + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + let results = 'Connecting to ' + net + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results += '\nConnected. Creating buy offer...' + document.getElementById('operationalResultField').value = results + + + // Prepare transaction ------------------------------------------------------- + const transactionBlob = { + "TransactionType": "NFTokenCreateOffer", + "Account": operational_wallet.classicAddress, + "Owner": operationalOwnerField.value, + "TokenID": operationalTokenIdField.value, + "Amount": operationalAmountField.value, + "Flags": null + } + + + // Submit transaction -------------------------------------------------------- + const tx = await client.submitAndWait(transactionBlob,{wallet: operational_wallet}) + + + results +="\n\n***Sell Offers***\n" + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: operationalTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) + + + results += "\n\n***Buy Offers***\n" + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: operationalTokenIdField.value }) + } catch (err) { + nftBuyOffers = "No buy offers." + } + results += JSON.stringify(nftBuyOffers,null,2) + + + // Check transaction results ------------------------------------------------- + results +="\n\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += "\n\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + client.disconnect() + // End of oPcreateBuyOffer() + } + + +// ******************************************************* +// ************* Operational Cancel Offer **************** +// ******************************************************* + + + async function oPcancelOffer() { + + + const wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + const client = new xrpl.Client("wss://xls20-sandbox.rippletest.net:51233") + results = 'Connecting to ' + getNet() + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results += "\nConnected. Cancelling offer..." + document.getElementById('operationalResultField').value = results + + + const tokenOfferIDs = [operationalTokenOfferIndexField.value] + + + // Prepare transaction ------------------------------------------------------- + const transactionBlob = { + "TransactionType": "NFTokenCancelOffer", + "Account": wallet.classicAddress, + "TokenOffers": tokenOfferIDs + } + // Submit transaction -------------------------------------------------------- + const tx = await client.submitAndWait(transactionBlob,{wallet}) + + + results += "\n\n***Sell Offers***\n" + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: operationalTokenIdField.value + }) + } catch (err) { + nftSellOffers = "No sell offers." + } + results += JSON.stringify(nftSellOffers,null,2) + results += "\n\n***Buy Offers***\n" + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: operationalTokenIdField.value }) + } catch (err) { + nftBuyOffers = "No buy offers." + } + results += JSON.stringify(nftBuyOffers,null,2) + + + // Check transaction results ------------------------------------------------- + + + results += "\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += "\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + document.getElementById('operationalResultField').value = results + + + client.disconnect() + // End of oPcancelOffer() + } + + +// ******************************************************* +// **************** Operational Get Offers *************** +// ******************************************************* + + + async function oPgetOffers() { + const standby_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results += '\nConnected. Getting offers...' + + + results += '\n\n***Sell Offers***\n' + + + let nftSellOffers + try { + nftSellOffers = await client.request({ + method: "nft_sell_offers", + tokenid: operationalTokenIdField.value + }) + } catch (err) { + nftSellOffers = 'No sell offers.' + } + results += JSON.stringify(nftSellOffers,null,2) + + + results += '\n\n***Buy Offers***\n' + let nftBuyOffers + try { + nftBuyOffers = await client.request({ + method: "nft_buy_offers", + tokenid: operationalTokenIdField.value }) + } catch (err) { + nftBuyOffers = 'No buy offers.' + } + results += JSON.stringify(nftBuyOffers,null,2) + + + document.getElementById('operationalResultField').value = results + + + client.disconnect() + // End of oPgetOffers() + } + + +// ******************************************************* +// *************** Operational Accept Sell Offer ********* +// ******************************************************* + + + async function oPacceptSellOffer() { + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results = '\nConnected. Accepting sell offer...\n\n' + document.getElementById('operationalResultField').value = results + + + // Prepare transaction ------------------------------------------------------- + const transactionBlob = { + "TransactionType": "NFTokenAcceptOffer", + "Account": operational_wallet.classicAddress, + "SellOffer": operationalTokenOfferIndexField.value, + } + // Submit transaction -------------------------------------------------------- + const tx = await client.submitAndWait(transactionBlob,{wallet: operational_wallet}) + const nfts = await client.request({ + method: "account_nfts", + account: operational_wallet.classicAddress + }) + + + // Check transaction results ------------------------------------------------- + + + + + document.getElementById('standbyBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) + + + results += 'Transaction result:\n' + results += JSON.stringify(tx.result.meta.TransactionResult, null, 2) + results += '\nBalance changes:' + results += JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + results += JSON.stringify(nfts,null,2) + + + document.getElementById('operationalResultField').value = results + + + client.disconnect() + // End of acceptSellOffer() + } + +// ******************************************************* +// ********* Operational Accept Buy Offer **************** +// ******************************************************* + + + async function oPacceptBuyOffer() { + const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value) + const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value) + let net = getNet() + const client = new xrpl.Client(net) + results = 'Connecting to ' + getNet() + '...' + document.getElementById('operationalResultField').value = results + await client.connect() + results += '\nConnected. Accepting buy offer...' + document.getElementById('operationalResultField').value = results + + // Prepare transaction ------------------------------------------------------- + const transactionBlob = { + "TransactionType": "NFTokenAcceptOffer", + "Account": operational_wallet.classicAddress, + "BuyOffer": operationalTokenOfferIndexField.value + } + // Submit transaction -------------------------------------------------------- + const tx = await client.submitAndWait(transactionBlob,{wallet: operational_wallet}) + const nfts = await client.request({ + method: "account_nfts", + account: operational_wallet.classicAddress + }) + results += JSON.stringify(nfts,null,2) + document.getElementById('operationalResultField').value = results + + // Check transaction results ------------------------------------------------- + result += "\n\nTransaction result:\n" + + JSON.stringify(tx.result.meta.TransactionResult, null, 2) + result += "\nBalance changes:\n" + + JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(operational_wallet.address)) + document.getElementById('operationalBalanceField').value = + (await client.getXrpBalance(standby_wallet.address)) + document.getElementById('operationalResultField').value = results + client.disconnect() + // End of acceptBuyOffer() + } +``` + + + +## 4.transfer-nfts.html + +Update the form with fields and buttons to support the new functions. + + +``` + + + + + +

Token Test Harness

+
+ Choose your ledger instance: + + +    + + +    + + +

+ +
+ +

+ + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Standby Account + + +
+
+ Public Key + + +
+
+ Private Key + + +
+
+ Seed + + +
+
+ XRP Balance + + +
+
+ Amount + + +
+
+ + +
+ Currency + + +
Token URL +
Flags
Token ID
Token Offer Index
Owner
+

+ +

+
+ + + + + + +
+ +

+ +
+ +
+ +

+ +
+ +
+ +

+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ + + + +
+ + + + + + + + + +
+ +

+ +
+ +
+ +

+ +
+ +
+ +

+ +
+ +
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Operational Account + + +
+
+ Public Key + + +
+
+ Private Key + + +
+
+ Seed + + +
+
+ XRP Balance + + +
+
+ Amount + + +
+
+ + + +
+ Currency + + +
Token URL +
Flags
Token ID
Token Offer Index
Owner
+

+ +

+
+
+
+
+ + + +``` + +--- + + +| Previous | Next | +| :--- | ---: | +| 3. [Mint and Burn NFTokens](mint-and-burn-nftokens.html) | |