Merge pull request #3122 from XRPLF/NFT_refactor
Refactor NFT code samples and update the tutorials and screenshots
@@ -32,8 +32,9 @@ async function getAccount() {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Disconnect from the client
|
// Disconnect from the client
|
||||||
await client.disconnect();
|
if (client && client.isConnected()) {
|
||||||
}
|
await client.disconnect();
|
||||||
|
} }
|
||||||
} // End of getAccount()
|
} // End of getAccount()
|
||||||
|
|
||||||
async function getNewAccount1() {
|
async function getNewAccount1() {
|
||||||
@@ -78,8 +79,9 @@ async function getAccountFromSeed(my_seed) {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Disconnect from the client
|
// Disconnect from the client
|
||||||
await client.disconnect();
|
if (client && client.isConnected()) {
|
||||||
}
|
await client.disconnect();
|
||||||
|
} }
|
||||||
} // End of getAccountFromSeed()
|
} // End of getAccountFromSeed()
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
@@ -169,8 +171,9 @@ async function getXrpBalance() {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Disconnect from the client
|
// Disconnect from the client
|
||||||
await client.disconnect();
|
if (client && client.isConnected()) {
|
||||||
}
|
await client.disconnect();
|
||||||
|
} }
|
||||||
} // End of getXrpBalance()
|
} // End of getXrpBalance()
|
||||||
|
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
@@ -202,8 +205,9 @@ async function getTokenBalance() {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Disconnect from the client
|
// Disconnect from the client
|
||||||
await client.disconnect();
|
if (client && client.isConnected()) {
|
||||||
}
|
await client.disconnect();
|
||||||
|
} }
|
||||||
} // End of getTokenBalance()
|
} // End of getTokenBalance()
|
||||||
|
|
||||||
// *******************************************************
|
// *******************************************************
|
||||||
|
|||||||
209
_code-samples/nft-modular-tutorials/account-support.js
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// ******************************************************
|
||||||
|
// ************* Get the Preferred Network **************
|
||||||
|
// ******************************************************
|
||||||
|
|
||||||
|
function getNet() {
|
||||||
|
let net
|
||||||
|
if (document.getElementById("tn").checked) net = "wss://s.altnet.rippletest.net:51233/"
|
||||||
|
if (document.getElementById("dn").checked) net = "wss://s.devnet.rippletest.net:51233/"
|
||||||
|
return net
|
||||||
|
} // End of getNet()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ************* Get Account *****************************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getAccount() {
|
||||||
|
let net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
resultField.value = `===Getting Account===\n\nConnected to ${net}.`
|
||||||
|
try {
|
||||||
|
let faucetHost = null
|
||||||
|
const my_wallet = (await client.fundWallet(null, { faucetHost})).wallet
|
||||||
|
const newAccount = [my_wallet.address, my_wallet.seed]
|
||||||
|
return newAccount
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('===Error getting account:', error);
|
||||||
|
results += `\nError: ${error.message}\n`
|
||||||
|
resultField.value = results
|
||||||
|
throw error; // Re-throw the error to be handled by the caller
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Disconnect from the client
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of getAccount()
|
||||||
|
|
||||||
|
async function getNewAccount1() {
|
||||||
|
account1address.value = "=== Getting new account. ===\n\n"
|
||||||
|
account1seed.value = ""
|
||||||
|
const accountInfo= await getAccount()
|
||||||
|
account1address.value = accountInfo[0]
|
||||||
|
account1seed.value = accountInfo[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getNewAccount2() {
|
||||||
|
account2address.value = "=== Getting new account. ===\n\n"
|
||||||
|
account2seed.value = ""
|
||||||
|
const accountInfo= await getAccount()
|
||||||
|
account2address.value = accountInfo[0]
|
||||||
|
account2seed.value = accountInfo[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ********** Get Account from Seed ********************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
async function getAccountFromSeed(my_seed) {
|
||||||
|
const net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
let results = '===Finding wallet.===\n\n'
|
||||||
|
resultField.value = results
|
||||||
|
try {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(my_seed)
|
||||||
|
const address = wallet.address
|
||||||
|
results += "===Wallet found.===\n\n"
|
||||||
|
results += "Account address: " + address + "\n\n"
|
||||||
|
resultField.value = results
|
||||||
|
return (address)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('===Error getting account from seed:', error);
|
||||||
|
results += `\nError: ${error.message}\n`
|
||||||
|
resultField.value = results
|
||||||
|
throw error; // Re-throw the error to be handled by the caller
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Disconnect from the client
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
} // End of getAccountFromSeed()
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ********** Get Account from Seed1 *******************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
async function getAccountFromSeed1() {
|
||||||
|
account1address.value = await getAccountFromSeed(account1seed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ********** Get Account from Seed2 *******************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
async function getAccountFromSeed2() {
|
||||||
|
account2address.value = await getAccountFromSeed(account2seed.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ************ Gather Account Info ********************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
function gatherAccountInfo() {
|
||||||
|
let accountData = account1name.value + "\n" + account1address.value + "\n" + account1seed.value + "\n"
|
||||||
|
accountData += account2name.value + "\n" + account2address.value + "\n" + account2seed.value
|
||||||
|
resultField.value = accountData
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ********** Distribute Account Info ******************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
function distributeAccountInfo() {
|
||||||
|
let accountInfo = resultField.value.split("\n")
|
||||||
|
account1name.value = accountInfo[0]
|
||||||
|
account1address.value = accountInfo[1]
|
||||||
|
account1seed.value = accountInfo[2]
|
||||||
|
account2name.value = accountInfo[3]
|
||||||
|
account2address.value = accountInfo[4]
|
||||||
|
account2seed.value = accountInfo[5]
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ************ Populate Active Form 1 *****************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
function populate1() {
|
||||||
|
accountNameField.value = account1name.value
|
||||||
|
accountAddressField.value = account1address.value
|
||||||
|
accountSeedField.value = account1seed.value
|
||||||
|
getXrpBalance()
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// ************ Populate Active Form 2 *****************
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
function populate2() {
|
||||||
|
accountNameField.value = account2name.value
|
||||||
|
accountAddressField.value = account2address.value
|
||||||
|
accountSeedField.value = account2seed.value
|
||||||
|
getXrpBalance()
|
||||||
|
}
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// **************** Get XRP Balance *********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getXrpBalance() {
|
||||||
|
const net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
let results = `\n===Getting XRP balance...===\n\n`
|
||||||
|
resultField.value = results
|
||||||
|
try {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
const balance = await client.getXrpBalance(wallet.address)
|
||||||
|
results += accountNameField.value + " current XRP balance: " + balance + "\n\n"
|
||||||
|
xrpBalanceField.value = await client.getXrpBalance(accountAddressField.value)
|
||||||
|
resultField.value = results
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Error getting XRP balance:', error);
|
||||||
|
results += `\nError: ${error.message}\n`
|
||||||
|
resultField.value = results
|
||||||
|
throw error; // Re-throw the error to be handled by the caller
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Disconnect from the client
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
} // End of getXrpBalance()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ************** Get Token Balance *********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getTokenBalance() {
|
||||||
|
let net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
let results = `===Connected to ${net}.===\n===Getting account token balance...===\n\n`
|
||||||
|
resultField.value += results
|
||||||
|
try {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
const balance = await client.request({
|
||||||
|
command: "gateway_balances",
|
||||||
|
account: wallet.address,
|
||||||
|
ledger_index: "validated",
|
||||||
|
})
|
||||||
|
results = accountNameField.value + "\'s token balance(s): " + JSON.stringify(balance.result, null, 2) + "\n"
|
||||||
|
resultField.value += results
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address))
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Error getting token balance:', error);
|
||||||
|
results = `\nError: ${error.message}\n`
|
||||||
|
resultField.value += results
|
||||||
|
throw error; // Re-throw the error to be handled by the caller
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Disconnect from the client
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
} // End of getTokenBalance()
|
||||||
340
_code-samples/nft-modular-tutorials/authorized-minter.html
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Authorize Minter of NFTs</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||||
|
<link href="modular-tutorials.css" rel="stylesheet">
|
||||||
|
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||||
|
<script src="account-support.js"></script>
|
||||||
|
<script src='transaction-support.js'></script>
|
||||||
|
<script src='mint-nfts.js'></script>
|
||||||
|
<script src='authorized-minter.js'></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Authorize Minter of NFTs</h1>
|
||||||
|
<form id="theForm">
|
||||||
|
<span class="tooltip" tooltip-data="Choose the XRPL host server for your account.">
|
||||||
|
Choose your ledger instance:
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233" checked>
|
||||||
|
<label for="dn">Devnet</label>
|
||||||
|
|
||||||
|
<input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233">
|
||||||
|
<label for="tn">Testnet</label>
|
||||||
|
<br /><br />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount1()">Get New Account 1</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed1()">Get Account 1 From Seed</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount2()">Get New Account 2</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed2()">Get Account 2 From Seed</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account."><label
|
||||||
|
for="account1name">Account 1 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account.">
|
||||||
|
<label for="account2name">Account 2 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account1address">Account 1 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account2address">Account 2 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account1seed">Account 1 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account2seed">Account 2 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
<table>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Name of the currently selected account.">
|
||||||
|
<label for="accountNameField">Account Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountNameField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account1" name="accounts" value="account1">
|
||||||
|
<label for="account1">Account 1</label>
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" align="center">
|
||||||
|
<p>
|
||||||
|
<img id="nftImage"
|
||||||
|
src="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"
|
||||||
|
width="150" height="150">
|
||||||
|
</td>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Address of the currently selected account.">
|
||||||
|
<label for="accountAddressField">Account Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountAddressField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account2" name="accounts" value="account2">
|
||||||
|
<label for="account2">Account 2</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Seed of the currently selected account.">
|
||||||
|
<label for="accountSeedField">Account Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountSeedField" size="40" readonly></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="XRP balance for the currently selected account.">
|
||||||
|
<label for="xrpBalanceField">XRP Balance</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="xrpBalanceField" size="40" readonly></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT configuration flags.">
|
||||||
|
<label for="flagsField">Flags</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="flagsField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="URL to the stored NFT.">
|
||||||
|
<label for="nftURLfield">NFT URL</label>
|
||||||
|
</span>
|
||||||
|
<input type="text" id="nftURLfield" size="30"
|
||||||
|
value="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Percentage of sale price collected by the issuer when the NFT is sold. Enter a value from 0 to 50000, where 1000=1%.">
|
||||||
|
<label for="transferFeeField">Transfer Fee</label>
|
||||||
|
</span>
|
||||||
|
<p id="error-message"></p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="transferFeeField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="mintNFT()">Mint NFT</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT Taxon. Integer value used to identify NFTs minted in a series or collection. This value is required. Set it to 0 if you have no use for it.">
|
||||||
|
<label for="nftTaxonField">NFT Taxon</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftTaxonField" size="40" value="0"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNFTs()">Get NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Currency for the offer.">
|
||||||
|
<label for="currencyField">Currency</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="currencyField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="burnNFT()">Burn NFT</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Issuer of the currency used.">
|
||||||
|
<label for="issuerField">Issuer</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="issuerField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Amount of XRP to send.">
|
||||||
|
<label for="amountField">Amount</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="amountField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="authorizeMinter()">Authorize Minter</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Destination account address where XRP is sent.">
|
||||||
|
<label for="destinationField">Destination</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="destinationField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="mintOther()">Mint Other</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Number of days the offer is valid.">
|
||||||
|
<label for="expirationField">Expiration (days)</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="expirationField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT ID, used to transfer or burn the NFT after it is created.">
|
||||||
|
<label for="nftIdField">NFT ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Account address that is authorized to mint NFTs for this account.">
|
||||||
|
<label for="authorizedMinterField">Authorized Minter</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="authorizedMinterField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Account that is the original issuer of the NFT.">
|
||||||
|
<label for="nftIssuerField">NFT Issuer</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIssuerField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<p align="left">
|
||||||
|
<textarea id="resultField" cols="75" rows="20"></textarea>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="gatherAccountInfo()">Gather Account Info</button><br />
|
||||||
|
<button type="button" onClick="distributeAccountInfo()">Distribute Account Info</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const imageURLInput = document.getElementById('nftURLfield'); // Correct ID to nftURLfield
|
||||||
|
const displayImage = document.getElementById('nftImage');
|
||||||
|
const errorMessage = document.getElementById('error-message');
|
||||||
|
|
||||||
|
if (imageURLInput) {
|
||||||
|
imageURLInput.addEventListener('change', () => {
|
||||||
|
const newURL = imageURLInput.value;
|
||||||
|
displayImage.src = ''; // Clear previous image
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
try {
|
||||||
|
new URL(newURL);
|
||||||
|
} catch (_) {
|
||||||
|
errorMessage.textContent = 'Invalid URL. Please enter a valid URL, including "https://" or "http://".';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
displayImage.onload = () => {
|
||||||
|
// Image loaded. You might add a console log here, or update UI.
|
||||||
|
console.log(`Image loaded from: ${newURL}`);
|
||||||
|
};
|
||||||
|
displayImage.onerror = () => {
|
||||||
|
errorMessage.textContent = 'Error loading image from the provided URL.';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
displayImage.src = ''; // Clear the image on error
|
||||||
|
};
|
||||||
|
displayImage.src = newURL; // Load the image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||||
|
radioButtons.forEach(radio => {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
if (this.value === 'account1') {
|
||||||
|
populate1()
|
||||||
|
} else if (this.value === 'account2') {
|
||||||
|
populate2()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
97
_code-samples/nft-modular-tutorials/authorized-minter.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// *******************************************************
|
||||||
|
// ************ Authorize Minter ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function authorizeMinter() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
const net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = `\n=== Connected. Authorizing Minter. ===`;
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
tx_json = {
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"Account": wallet.address,
|
||||||
|
"NFTokenMinter": authorizedMinterField.value,
|
||||||
|
"SetFlag": xrpl.AccountSetAsfFlags.asfAuthorizedNFTokenMinter
|
||||||
|
}
|
||||||
|
|
||||||
|
const prepared = await client.autofill(tx_json)
|
||||||
|
const signed = wallet.sign(prepared)
|
||||||
|
const result = await client.submitAndWait(signed.tx_blob)
|
||||||
|
results += '\nAccount setting succeeded.\n'
|
||||||
|
results += JSON.stringify(result, null, 2)
|
||||||
|
resultField.value = results
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error setting minter:", error);
|
||||||
|
results = `\n\n=== Error setting minter: ${error.message}`;
|
||||||
|
resultField.value += results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of authorizeMinter()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// **************** Mint Other *************************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function mintOther() {
|
||||||
|
let results = 'Connecting to ' + getNet() + '....'
|
||||||
|
resultField.value = results
|
||||||
|
const net = getNet()
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect()
|
||||||
|
results += '\nConnected. Minting NFT.'
|
||||||
|
resultField.value = results
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
const tx_json = {
|
||||||
|
"TransactionType": "NFTokenMint",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"URI": xrpl.convertStringToHex(nftURLfield.value),
|
||||||
|
"Flags": parseInt(flagsField.value),
|
||||||
|
"TransferFee": parseInt(transferFeeField.value),
|
||||||
|
"Issuer": nftIssuerField.value,
|
||||||
|
"NFTokenTaxon": nftTaxonField.value //Required, but if you have no use for it, set to zero.
|
||||||
|
}
|
||||||
|
if (amountField.value) {
|
||||||
|
tx_json.Amount = configureAmount(amountField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expirationField.value) {
|
||||||
|
tx_json.Expiration = configureExpiration(expirationField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationField.value) {
|
||||||
|
tx_json.Destination = destinationField.value;
|
||||||
|
}
|
||||||
|
// ----------------------------------------------------- Submit transaction
|
||||||
|
const tx = await client.submitAndWait(tx_json, { wallet: wallet })
|
||||||
|
const nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress
|
||||||
|
})
|
||||||
|
// ------------------------------------------------------- Report results
|
||||||
|
results += '\n\n=== Transaction result: ' + tx.result.meta.TransactionResult
|
||||||
|
results += '\n\n=== NFTs: ' + JSON.stringify(nfts, null, 2)
|
||||||
|
resultField.value = results + (await client.getXrpBalance(wallet.address))
|
||||||
|
} catch (error) {
|
||||||
|
results += '\n\nAn error occurred: ' + error.message
|
||||||
|
console.error(error) // Log the error for debugging
|
||||||
|
resultField.value = results
|
||||||
|
} finally {
|
||||||
|
if (client.isConnected()) { // Check if the client is connected before attempting to disconnect
|
||||||
|
client.disconnect()
|
||||||
|
results += '\nDisconnected from XRPL.'
|
||||||
|
resultField.value = results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //End of mintOther()
|
||||||
|
|
||||||
320
_code-samples/nft-modular-tutorials/batch-minting.html
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Batch Mint NFTs</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||||
|
<link href="modular-tutorials.css" rel="stylesheet">
|
||||||
|
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||||
|
<script src="account-support.js"></script>
|
||||||
|
<script src='transaction-support.js'></script>
|
||||||
|
<script src='mint-nfts.js'></script>
|
||||||
|
<script src="batch-minting.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Batch Mint NFTs</h1>
|
||||||
|
<form id="theForm">
|
||||||
|
<span class="tooltip" tooltip-data="Choose the XRPL host server for your account.">
|
||||||
|
Choose your ledger instance:
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233" checked>
|
||||||
|
<label for="dn">Devnet</label>
|
||||||
|
|
||||||
|
<input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233">
|
||||||
|
<label for="tn">Testnet</label>
|
||||||
|
<br /><br />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount1()">Get New Account 1</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed1()">Get Account 1 From Seed</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount2()">Get New Account 2</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed2()">Get Account 2 From Seed</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account."><label
|
||||||
|
for="account1name">Account 1 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account.">
|
||||||
|
<label for="account2name">Account 2 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account1address">Account 1 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account2address">Account 2 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account1seed">Account 1 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account2seed">Account 2 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
<table>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Name of the currently selected account.">
|
||||||
|
<label for="accountNameField">Account Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountNameField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account1" name="accounts" value="account1">
|
||||||
|
<label for="account1">Account 1</label>
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" align="center">
|
||||||
|
<p>
|
||||||
|
<img id="nftImage"
|
||||||
|
src="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"
|
||||||
|
width="150" height="150">
|
||||||
|
</td>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Address of the currently selected account.">
|
||||||
|
<label for="accountAddressField">Account Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountAddressField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account2" name="accounts" value="account2">
|
||||||
|
<label for="account2">Account 2</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Seed of the currently selected account.">
|
||||||
|
<label for="accountSeedField">Account Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountSeedField" size="40" readonly></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="XRP balance for the currently selected account.">
|
||||||
|
<label for="xrpBalanceField">XRP Balance</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="xrpBalanceField" size="40" readonly></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT configuration flags.">
|
||||||
|
<label for="flagsField">Flags</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="flagsField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="URL to the stored NFT.">
|
||||||
|
<label for="nftURLfield">NFT URL</label>
|
||||||
|
</span>
|
||||||
|
<input type="text" id="nftURLfield" size="30"
|
||||||
|
value="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Percentage of sale price collected by the issuer when the NFT is sold. Enter a value from 0 to 50000, where 1000=1%.">
|
||||||
|
<label for="transferFeeField">Transfer Fee</label>
|
||||||
|
</span>
|
||||||
|
<p id="error-message"></p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="transferFeeField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="batchMintNFTs()">Batch Mint NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT Taxon. Integer value used to identify NFTs minted in a series or collection. This value is required. Set it to 0 if you have no use for it.">
|
||||||
|
<label for="nftTaxonField">NFT Taxon</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftTaxonField" size="40" value="0"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getBatchNFTs()">Get Batch NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Currency for the offer.">
|
||||||
|
<label for="currencyField">Currency</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="currencyField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Issuer of the currency used.">
|
||||||
|
<label for="issuerField">Issuer</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="issuerField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Amount of XRP to send.">
|
||||||
|
<label for="amountField">Amount</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="amountField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Destination account address where XRP is sent.">
|
||||||
|
<label for="destinationField">Destination</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="destinationField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Number of days the offer is valid.">
|
||||||
|
<label for="expirationField">Expiration (days)</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="expirationField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Number of NFTs to produce in a batch.">
|
||||||
|
<label for="nftCountField">NFT Count</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftCountField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT ID, used to transfer or burn the NFT after it is created.">
|
||||||
|
<label for="nftIdField">NFT ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr> <tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<p align="left">
|
||||||
|
<textarea id="resultField" cols="75" rows="20"></textarea>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="gatherAccountInfo()">Gather Account Info</button><br />
|
||||||
|
<button type="button" onClick="distributeAccountInfo()">Distribute Account Info</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const imageURLInput = document.getElementById('nftURLfield'); // Correct ID to nftURLfield
|
||||||
|
const displayImage = document.getElementById('nftImage');
|
||||||
|
const errorMessage = document.getElementById('error-message');
|
||||||
|
|
||||||
|
if (imageURLInput) {
|
||||||
|
imageURLInput.addEventListener('change', () => {
|
||||||
|
const newURL = imageURLInput.value;
|
||||||
|
displayImage.src = ''; // Clear previous image
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
try {
|
||||||
|
new URL(newURL);
|
||||||
|
} catch (_) {
|
||||||
|
errorMessage.textContent = 'Invalid URL. Please enter a valid URL, including "https://" or "http://".';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
displayImage.onload = () => {
|
||||||
|
// Image loaded. You might add a console log here, or update UI.
|
||||||
|
console.log(`Image loaded from: ${newURL}`);
|
||||||
|
};
|
||||||
|
displayImage.onerror = () => {
|
||||||
|
errorMessage.textContent = 'Error loading image from the provided URL.';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
displayImage.src = ''; // Clear the image on error
|
||||||
|
};
|
||||||
|
displayImage.src = newURL; // Load the image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||||
|
radioButtons.forEach(radio => {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
if (this.value === 'account1') {
|
||||||
|
populate1()
|
||||||
|
} else if (this.value === 'account2') {
|
||||||
|
populate2()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
272
_code-samples/nft-modular-tutorials/batch-minting.js
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
// *******************************************************
|
||||||
|
// ****************** Batch Mint ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function batchMintNFTs() {
|
||||||
|
let client; // Declare client here so it's accessible in finally block
|
||||||
|
try {
|
||||||
|
//--------------------- Connect to the XRP Ledger and get the account wallet.
|
||||||
|
let net = getNet();
|
||||||
|
client = new xrpl.Client(net); // Assign client
|
||||||
|
results = 'Connecting to ' + getNet() + '....';
|
||||||
|
resultField.value = results;
|
||||||
|
await client.connect();
|
||||||
|
results += '\nConnected, finding wallet.';
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
let wallet;
|
||||||
|
try {
|
||||||
|
wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
} catch (error) {
|
||||||
|
results += '\nError: Invalid account seed. Please check your seed.';
|
||||||
|
resultField.value = results;
|
||||||
|
return; // Stop execution if wallet cannot be derived
|
||||||
|
}
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
//----------------- Get account information, particularly the Sequence number.
|
||||||
|
let account_info;
|
||||||
|
try {
|
||||||
|
account_info = await client.request({
|
||||||
|
"command": "account_info",
|
||||||
|
"account": wallet.address
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError retrieving account info for ${wallet.address}: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let my_sequence = account_info.result.account_data.Sequence;
|
||||||
|
results += "\n\nSequence Number: " + my_sequence + "\n\n";
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
/* ###################################
|
||||||
|
Create ticket numbers for the batch
|
||||||
|
|
||||||
|
Without tickets, if one transaction fails, all others in the batch fail.
|
||||||
|
With tickets, there can be failures, but the rest will continue, and you
|
||||||
|
can investigate any problems afterward.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------------------- Parse the requested number from nftCountField.
|
||||||
|
const nftCount = parseInt(nftCountField.value);
|
||||||
|
if (isNaN(nftCount) || nftCount <= 0) {
|
||||||
|
results += '\nError: Please enter a valid number of NFTs to mint.';
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------- Create the transaction hash.
|
||||||
|
let ticketTransaction;
|
||||||
|
try {
|
||||||
|
ticketTransaction = await client.autofill({
|
||||||
|
"TransactionType": "TicketCreate",
|
||||||
|
"Account": wallet.address,
|
||||||
|
"TicketCount": nftCount,
|
||||||
|
"Sequence": my_sequence
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError autofilling ticket creation transaction: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------- Sign the transaction.
|
||||||
|
const signedTransaction = wallet.sign(ticketTransaction);
|
||||||
|
|
||||||
|
//-------------------------- Submit the transaction and wait for the result.
|
||||||
|
let tx;
|
||||||
|
try {
|
||||||
|
tx = await client.submitAndWait(signedTransaction.tx_blob);
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError submitting ticket creation transaction: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||||
|
results += `\nError creating tickets. Transaction failed with result: ${tx.result.meta.TransactionResult}`;
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
results += `\nTickets created successfully. Transaction result: ${tx.result.meta.TransactionResult}\n\n`;
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await client.request({
|
||||||
|
"command": "account_objects",
|
||||||
|
"account": wallet.address,
|
||||||
|
"type": "ticket"
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError retrieving account tickets: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------ Populate the tickets array variable.
|
||||||
|
let tickets = [];
|
||||||
|
if (response.result.account_objects && response.result.account_objects.length > 0) {
|
||||||
|
for (let i = 0; i < nftCount; i++) {
|
||||||
|
if (response.result.account_objects[i]) {
|
||||||
|
tickets[i] = response.result.account_objects[i].TicketSequence;
|
||||||
|
} else {
|
||||||
|
results += `\nWarning: Fewer tickets found than requested. Expected ${nftCount}, found ${response.result.account_objects.length}.`;
|
||||||
|
resultField.value = results;
|
||||||
|
break; // Exit loop if tickets run out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results += '\nError: No tickets found for the account.';
|
||||||
|
resultField.value = results;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------- Report progress.
|
||||||
|
results += "Tickets generated, minting NFTs.\n\n";
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
// ###################################
|
||||||
|
// Mint NFTs
|
||||||
|
|
||||||
|
let mintedNFTsCount = 0;
|
||||||
|
for (let i = 0; i < tickets.length; i++) {
|
||||||
|
const transactionParams = {
|
||||||
|
"TransactionType": "NFTokenMint",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"URI": xrpl.convertStringToHex(nftURLfield.value),
|
||||||
|
"Flags": parseInt(flagsField.value),
|
||||||
|
"TransferFee": parseInt(transferFeeField.value),
|
||||||
|
"Sequence": 0, // Sequence is 0 when using TicketSequence
|
||||||
|
"TicketSequence": tickets[i],
|
||||||
|
"LastLedgerSequence": null, // Optional, can be used for time limits
|
||||||
|
"NFTokenTaxon": nftTaxonField.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add optional fields
|
||||||
|
if (amountField.value) {
|
||||||
|
transactionParams.Amount = configureAmount(amountField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expirationField.value) {
|
||||||
|
transactionParams.Expiration = configureExpiration(expirationField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationField.value) {
|
||||||
|
transactionParams.Destination = destinationField.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const mintTx = await client.submit(transactionParams, {
|
||||||
|
wallet: wallet
|
||||||
|
});
|
||||||
|
results += `\nNFT ${i+1} minted successfully.`;
|
||||||
|
mintedNFTsCount++;
|
||||||
|
resultField.value = results;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
// Add a small delay to avoid hitting rate limits if many NFTs are being minted
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
}
|
||||||
|
|
||||||
|
results += `\n\nAttempted to mint ${nftCount} NFTs. Successfully minted ${mintedNFTsCount} NFTs.`;
|
||||||
|
|
||||||
|
results += "\n\nFetching minted NFTs...\n";
|
||||||
|
let nfts;
|
||||||
|
try {
|
||||||
|
nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
limit: 400
|
||||||
|
});
|
||||||
|
results += JSON.stringify(nfts, null, 2);
|
||||||
|
|
||||||
|
while (nfts.result.marker) {
|
||||||
|
nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
limit: 400,
|
||||||
|
marker: nfts.result.marker
|
||||||
|
});
|
||||||
|
results += '\n' + JSON.stringify(nfts, null, 2);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError fetching account NFTs: ${error.message}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address));
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError fetching XRP balance: ${error.message}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nAn unexpected error occurred during batch minting: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
client.disconnect();
|
||||||
|
results += '\nDisconnected from XRP Ledger.';
|
||||||
|
resultField.value = results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of batchMint()
|
||||||
|
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// **************** Get Batch Tokens *********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getBatchNFTs() {
|
||||||
|
let client; // Declare client here for finally block access
|
||||||
|
try {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
let net = getNet();
|
||||||
|
client = new xrpl.Client(net); // Assign client
|
||||||
|
results = 'Connecting to ' + net + '...';
|
||||||
|
resultField.value = results;
|
||||||
|
await client.connect();
|
||||||
|
results += '\nConnected. Getting NFTs...';
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
results += "\n\nNFTs:\n";
|
||||||
|
let nfts;
|
||||||
|
try {
|
||||||
|
nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
limit: 400
|
||||||
|
});
|
||||||
|
|
||||||
|
results += JSON.stringify(nfts, null, 2);
|
||||||
|
while (nfts.result.marker) {
|
||||||
|
nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
limit: 400,
|
||||||
|
marker: nfts.result.marker
|
||||||
|
});
|
||||||
|
results += '\n' + JSON.stringify(nfts, null, 2);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nError fetching account NFTs: ${error.message}`;
|
||||||
|
}
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
results += `\nAn unexpected error occurred while getting batch NFTs: ${error.message}`;
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
client.disconnect();
|
||||||
|
results += '\nDisconnected from XRP Ledger.';
|
||||||
|
resultField.value = results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //End of getBatchNFTs()
|
||||||
291
_code-samples/nft-modular-tutorials/broker-nfts.html
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Broker NFTs</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||||
|
<link href="modular-tutorials.css" rel="stylesheet">
|
||||||
|
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||||
|
<script src="account-support.js"></script>
|
||||||
|
<script src="transaction-support.js"></script>
|
||||||
|
<script src="mint-nfts.js"></script>
|
||||||
|
<script src="transfer-nfts.js"></script>
|
||||||
|
<script src="broker-nfts.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Broker NFTs</h1>
|
||||||
|
<form id="theForm">
|
||||||
|
<span class="tooltip" tooltip-data="Choose the XRPL host server for your account.">
|
||||||
|
Choose your ledger instance:
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233" checked>
|
||||||
|
<label for="dn">Devnet</label>
|
||||||
|
|
||||||
|
<input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233">
|
||||||
|
<label for="tn">Testnet</label>
|
||||||
|
<br /><br />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount1()">Get New Account 1</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed1()">Get Account 1 From Seed</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount2()">Get New Account 2</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed2()">Get Account 2 From Seed</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account."><label
|
||||||
|
for="account1name">Account 1 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account.">
|
||||||
|
<label for="account2name">Account 2 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account1address">Account 1 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account2address">Account 2 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account1seed">Account 1 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account2seed">Account 2 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
<table>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Name of the currently selected account.">
|
||||||
|
<label for="accountNameField">Account Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountNameField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account1" name="accounts" value="account1">
|
||||||
|
<label for="account1">Account 1</label>
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" align="center">
|
||||||
|
<p>
|
||||||
|
<img id="nftImage"
|
||||||
|
src="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"
|
||||||
|
width="150" height="150">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Address of the currently selected account.">
|
||||||
|
<label for="accountAddressField">Account Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountAddressField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account2" name="accounts" value="account2">
|
||||||
|
<label for="account2">Account 2</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Seed of the currently selected account.">
|
||||||
|
<label for="accountSeedField">Account Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountSeedField" size="40" readonly></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="XRP balance for the currently selected account.">
|
||||||
|
<label for="xrpBalanceField">XRP Balance</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="xrpBalanceField" size="40" readonly></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="URL to the stored NFT.">
|
||||||
|
<label for="nftURLfield">NFT URL</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftURLfield" size="40"
|
||||||
|
placeholder="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"></input>
|
||||||
|
<br />
|
||||||
|
<p id="error-message"></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT ID code, used to identify the token after it's minted.">
|
||||||
|
<label for="nftIdField">NFT ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td align="center" valign="top">
|
||||||
|
<button type="button" onClick="getNFTs()">Get NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Account address of the Owner of an NFT offered to sell or buy.">
|
||||||
|
<label for="nftOwnerField">NFT Owner Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftOwnerField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td colspan="2" align="center" valign="top">
|
||||||
|
<button type="button" onClick="getOffers()" width="40">Get Offers</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Index of the sell offer to broker.">
|
||||||
|
<label for="nftSellOfferIndexField">Sell Offer Index</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftSellOfferIndexField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td align="middle" valign="top" colspan="2">
|
||||||
|
<button type="button" onClick="brokerSale()">Broker Sale</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Index of the buy offer to broker.">
|
||||||
|
<label for="nftBuyOfferIndexField">Buy Offer Index</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftBuyOfferIndexField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td align="middle" valign="top" colspan="2">
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Fee collected by the broker account when the brokered deal is complete.">
|
||||||
|
<label for="brokerFeeField">Broker Fee</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="brokerFeeField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td colspan="2">
|
||||||
|
<p align="left">
|
||||||
|
<textarea id="resultField" cols="75" rows="20"></textarea>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="gatherAccountInfo()">Gather Account Info</button><br />
|
||||||
|
<button type="button" onClick="distributeAccountInfo()">Distribute Account Info</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const imageURLInput = document.getElementById('nftURLfield'); // Correct ID to nftURLfield
|
||||||
|
const displayImage = document.getElementById('nftImage');
|
||||||
|
const loadButton = document.getElementById('showNFTbutton');
|
||||||
|
const errorMessage = document.getElementById('error-message');
|
||||||
|
|
||||||
|
if (imageURLInput) {
|
||||||
|
imageURLInput.addEventListener('change', () => {
|
||||||
|
const newURL = imageURLInput.value;
|
||||||
|
displayImage.src = ''; // Clear previous image
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
try {
|
||||||
|
new URL(newURL);
|
||||||
|
} catch (_) {
|
||||||
|
errorMessage.textContent = 'Invalid URL. Please enter a valid URL, including "https://" or "http://".';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
displayImage.onload = () => {
|
||||||
|
// Image loaded. You might add a console log here, or update UI.
|
||||||
|
console.log(`Image loaded from: ${newURL}`);
|
||||||
|
};
|
||||||
|
displayImage.onerror = () => {
|
||||||
|
errorMessage.textContent = 'Error loading image from the provided URL.';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
displayImage.src = ''; // Clear the image on error
|
||||||
|
};
|
||||||
|
displayImage.src = newURL; // Load the image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||||
|
radioButtons.forEach(radio => {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
if (this.value === 'account1') {
|
||||||
|
populate1()
|
||||||
|
} else if (this.value === 'account2') {
|
||||||
|
populate2()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
44
_code-samples/nft-modular-tutorials/broker-nfts.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// *******************************************************
|
||||||
|
// ******************* Broker Sale ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function brokerSale() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
const net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = `\n=== Connected. Brokering the sale. ===`;
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
// Prepare transaction -------------------------------------------------------
|
||||||
|
const brokerTx = {
|
||||||
|
"TransactionType": "NFTokenAcceptOffer",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"NFTokenSellOffer": nftSellOfferIndexField.value,
|
||||||
|
"NFTokenBuyOffer": nftBuyOfferIndexField.value,
|
||||||
|
"NFTokenBrokerFee": brokerFeeField.value
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify(brokerTx, null, 2));
|
||||||
|
// Submit transaction --------------------------------------------------------
|
||||||
|
const tx = await client.submitAndWait(brokerTx, { wallet: wallet })
|
||||||
|
|
||||||
|
// Check transaction results -------------------------------------------------
|
||||||
|
results += "\n\nTransaction result:\n" +
|
||||||
|
JSON.stringify(tx.result.meta.TransactionResult, null, 2)
|
||||||
|
results += "\nBalance changes:\n" +
|
||||||
|
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address))
|
||||||
|
resultField.value += results
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in broker sale:", error);
|
||||||
|
results = `\n\n=== Error in broker sale: ${error.message} ===`; // User friendly
|
||||||
|
resultField.value += results;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}// End of brokerSale()
|
||||||
313
_code-samples/nft-modular-tutorials/mint-nfts.html
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Mint NFTs</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||||
|
<link href="modular-tutorials.css" rel="stylesheet">
|
||||||
|
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||||
|
<script src="account-support.js"></script>
|
||||||
|
<script src='transaction-support.js'></script>
|
||||||
|
<script src='mint-nfts.js'></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Mint NFTs</h1>
|
||||||
|
<form id="theForm">
|
||||||
|
<span class="tooltip" tooltip-data="Choose the XRPL host server for your account.">
|
||||||
|
Choose your ledger instance:
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233" checked>
|
||||||
|
<label for="dn">Devnet</label>
|
||||||
|
|
||||||
|
<input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233">
|
||||||
|
<label for="tn">Testnet</label>
|
||||||
|
<br /><br />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount1()">Get New Account 1</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed1()">Get Account 1 From Seed</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount2()">Get New Account 2</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed2()">Get Account 2 From Seed</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account."><label
|
||||||
|
for="account1name">Account 1 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account.">
|
||||||
|
<label for="account2name">Account 2 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account1address">Account 1 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account2address">Account 2 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account1seed">Account 1 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account2seed">Account 2 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
<table>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Name of the currently selected account.">
|
||||||
|
<label for="accountNameField">Account Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountNameField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account1" name="accounts" value="account1">
|
||||||
|
<label for="account1">Account 1</label>
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" align="center">
|
||||||
|
<p>
|
||||||
|
<img id="nftImage"
|
||||||
|
src="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"
|
||||||
|
width="150" height="150">
|
||||||
|
</td>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Address of the currently selected account.">
|
||||||
|
<label for="accountAddressField">Account Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountAddressField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account2" name="accounts" value="account2">
|
||||||
|
<label for="account2">Account 2</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Seed of the currently selected account.">
|
||||||
|
<label for="accountSeedField">Account Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountSeedField" size="40" readonly></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="XRP balance for the currently selected account.">
|
||||||
|
<label for="xrpBalanceField">XRP Balance</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="xrpBalanceField" size="40" readonly></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT configuration flags.">
|
||||||
|
<label for="flagsField">Flags</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="flagsField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="URL to the stored NFT.">
|
||||||
|
<label for="nftURLfield">NFT URL</label>
|
||||||
|
</span>
|
||||||
|
<input type="text" id="nftURLfield" size="30"
|
||||||
|
value="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Percentage of sale price collected by the issuer when the NFT is sold. Enter a value from 0 to 50000, where 1000=1%.">
|
||||||
|
<label for="transferFeeField">Transfer Fee</label>
|
||||||
|
</span>
|
||||||
|
<p id="error-message"></p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="transferFeeField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="mintNFT()">Mint NFT</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT Taxon. Integer value used to identify NFTs minted in a series or collection. This value is required. Set it to 0 if you have no use for it.">
|
||||||
|
<label for="nftTaxonField">NFT Taxon</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftTaxonField" size="40" value="0"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNFTs()">Get NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Currency for the offer.">
|
||||||
|
<label for="currencyField">Currency</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="currencyField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="burnNFT()">Burn NFT</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Issuer of the currency used.">
|
||||||
|
<label for="issuerField">Issuer</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="issuerField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Amount of currency to send. If XRP, you can enter 1 per XRP: the amount is converted to drops for you.">
|
||||||
|
<label for="amountField">Amount</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="amountField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Destination account address where XRP is sent.">
|
||||||
|
<label for="destinationField">Destination</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="destinationField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Number of days the offer is valid.">
|
||||||
|
<label for="expirationField">Expiration (days)</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="expirationField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT ID, used to transfer or burn the NFT after it is created.">
|
||||||
|
<label for="nftIdField">NFT ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<p align="left">
|
||||||
|
<textarea id="resultField" cols="75" rows="20"></textarea>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="gatherAccountInfo()">Gather Account Info</button><br />
|
||||||
|
<button type="button" onClick="distributeAccountInfo()">Distribute Account Info</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const imageURLInput = document.getElementById('nftURLfield'); // Correct ID to nftURLfield
|
||||||
|
const displayImage = document.getElementById('nftImage');
|
||||||
|
const errorMessage = document.getElementById('error-message');
|
||||||
|
|
||||||
|
if (imageURLInput) {
|
||||||
|
imageURLInput.addEventListener('change', () => {
|
||||||
|
const newURL = imageURLInput.value;
|
||||||
|
displayImage.src = ''; // Clear previous image
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
try {
|
||||||
|
new URL(newURL);
|
||||||
|
} catch (_) {
|
||||||
|
errorMessage.textContent = 'Invalid URL. Please enter a valid URL, including "https://" or "http://".';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
displayImage.onload = () => {
|
||||||
|
// Image loaded. You might add a console log here, or update UI.
|
||||||
|
console.log(`Image loaded from: ${newURL}`);
|
||||||
|
};
|
||||||
|
displayImage.onerror = () => {
|
||||||
|
errorMessage.textContent = 'Error loading image from the provided URL.';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
displayImage.src = ''; // Clear the image on error
|
||||||
|
};
|
||||||
|
displayImage.src = newURL; // Load the image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||||
|
radioButtons.forEach(radio => {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
if (this.value === 'account1') {
|
||||||
|
populate1()
|
||||||
|
} else if (this.value === 'account2') {
|
||||||
|
populate2()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
141
_code-samples/nft-modular-tutorials/mint-nfts.js
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// *******************************************************
|
||||||
|
// ********************** Mint NFT ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function mintNFT() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
const net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = `\n=== Connected. Minting NFT ===`;
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
// Prepare transaction parameters
|
||||||
|
const transactionParams = {
|
||||||
|
TransactionType: "NFTokenMint",
|
||||||
|
Account: wallet.classicAddress,
|
||||||
|
URI: xrpl.convertStringToHex(nftURLfield.value),
|
||||||
|
Flags: parseInt(flagsField.value, 10), // Parse to integer
|
||||||
|
TransferFee: parseInt(transferFeeField.value, 10), // Parse to integer
|
||||||
|
NFTokenTaxon: parseInt(nftTaxonField.value, 10), // Parse to integer
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add optional fields
|
||||||
|
if (amountField.value) {
|
||||||
|
transactionParams.Amount = configureAmount(amountField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expirationField.value) {
|
||||||
|
transactionParams.Expiration = configureExpiration(expirationField.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationField.value) {
|
||||||
|
transactionParams.Destination = destinationField.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Mint NFT Transaction Parameters:", transactionParams); // Log before submitting
|
||||||
|
|
||||||
|
// Submit transaction
|
||||||
|
const tx = await client.submitAndWait(transactionParams, { wallet });
|
||||||
|
|
||||||
|
// Get minted NFTs
|
||||||
|
const nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Report results
|
||||||
|
results += `\n\n=== Transaction result: ${tx.result.meta.TransactionResult} ===`;
|
||||||
|
results += `\n\n=== NFTs: ${JSON.stringify(nfts, null, 2)} ===`;
|
||||||
|
results += `\n\n=== XRP Balance: ${await client.getXrpBalance(wallet.address)} ===`; // Await here
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error minting NFT:", error);
|
||||||
|
results += `\n\n=== Error minting NFT: ${error.message} ===`; // Use error.message
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) { // Check if connected before disconnecting
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of mintToken()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ******************** Get NFTs *************************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getNFTs() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
const net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = '\n=== Connected. Getting NFTs. ===';
|
||||||
|
resultField.value = results;
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
const nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
});
|
||||||
|
results = '\n=== NFTs:\n ' + JSON.stringify(nfts, null, 2) + ' ==='; // Consistent formatting
|
||||||
|
resultField.value = results;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error getting NFTs:", error);
|
||||||
|
results += `\n\n=== Error getting NFTs: ${error.message} ===`; // User-friendly
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of getNFTs()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ********************** Burn NFT ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function burnNFT() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
const net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = '\n=== Connected. Burning NFT. ===';
|
||||||
|
resultField.value = results;
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
// Prepare transaction
|
||||||
|
const transactionBlob = {
|
||||||
|
TransactionType: "NFTokenBurn",
|
||||||
|
Account: wallet.classicAddress,
|
||||||
|
NFTokenID: nftIdField.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Burn NFT Transaction Parameters:", transactionBlob); // Log before submit
|
||||||
|
|
||||||
|
// Submit transaction and wait for the results
|
||||||
|
const tx = await client.submitAndWait(transactionBlob, { wallet });
|
||||||
|
const nfts = await client.request({ // Get nfts after burning.
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress,
|
||||||
|
});
|
||||||
|
|
||||||
|
results = `\n=== Transaction result: ${tx.result.meta.TransactionResult} ===`;
|
||||||
|
results += '\n\n=== Balance changes: ' +
|
||||||
|
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2) + ' ===';
|
||||||
|
results += '\n\n=== NFTs: \n' + JSON.stringify(nfts, null, 2) + ' ===';
|
||||||
|
resultField.value = results;
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address)); // Await
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error burning NFT:", error);
|
||||||
|
results = `\n\n=== Error burning NFT: ${error.message} ===`; // User friendly
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
await client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of burnNFT()
|
||||||
153
_code-samples/nft-modular-tutorials/modular-tutorials.css
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
body {
|
||||||
|
font-family: "Inter", sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
background: #abe2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding-left: 25px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button {
|
||||||
|
padding: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: none
|
||||||
|
}
|
||||||
|
|
||||||
|
input:read-only {
|
||||||
|
background-color:rgb(11, 96, 132);
|
||||||
|
color:white;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: "Work Sans", sans-serif;
|
||||||
|
background-color: #006aff;
|
||||||
|
-webkit-text-fill-color: white;
|
||||||
|
width: 144px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #0555c5;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The switch - the box around the slider */
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide default HTML checkbox */
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The slider */
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 13px;
|
||||||
|
width: 13px;
|
||||||
|
left: 4px;
|
||||||
|
bottom: 2px;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked+.slider {
|
||||||
|
background-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus+.slider {
|
||||||
|
box-shadow: 0 0 1px #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked+.slider:before {
|
||||||
|
-webkit-transform: translateX(13px);
|
||||||
|
-ms-transform: translateX(13px);
|
||||||
|
transform: translateX(13px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rounded sliders */
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.tooltip {
|
||||||
|
position: relative;
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:before {
|
||||||
|
content: attr(tooltip-data);
|
||||||
|
position: absolute;
|
||||||
|
width: 250px;
|
||||||
|
background-color: #006aff;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
line-height: 1.1;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .5s;
|
||||||
|
bottom: 125%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -60px;
|
||||||
|
font-size: 0.70em;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 75%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-width: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .5s;
|
||||||
|
border-color: #000 transparent transparent transparent;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:hover:before,
|
||||||
|
.tooltip:hover:after {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
BIN
_code-samples/nft-modular-tutorials/nft-modular-tutorials.zip
Normal file
36
_code-samples/nft-modular-tutorials/transaction-support.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// ****************************************
|
||||||
|
// ********* Configure Amount *************
|
||||||
|
// ****************************************
|
||||||
|
|
||||||
|
function configureAmount() {
|
||||||
|
let amount = '';
|
||||||
|
if (currencyField.value === "XRP" || currencyField.value === "") {
|
||||||
|
if (amountField.value !== '') {
|
||||||
|
amount = amountField.value; // XRP amount should be a string of drops
|
||||||
|
} else {
|
||||||
|
amount = undefined;
|
||||||
|
}
|
||||||
|
} else if (currencyField.value !== "") {
|
||||||
|
amount = {
|
||||||
|
currency: currencyField.value,
|
||||||
|
issuer: issuerField.value,
|
||||||
|
value: amountField.value,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
amount = undefined; // Or handle the case where no currency is provided
|
||||||
|
}
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****************************************
|
||||||
|
// ********* Configure Expiration *********
|
||||||
|
// ****************************************
|
||||||
|
|
||||||
|
function configureExpiration() {
|
||||||
|
let expiration = ""
|
||||||
|
var days = expirationField.value
|
||||||
|
let d = new Date()
|
||||||
|
d.setDate(d.getDate() + parseInt(days))
|
||||||
|
expiration = xrpl.isoTimeToRippleTime(d)
|
||||||
|
return expiration
|
||||||
|
} // End of configureExpiration()
|
||||||
328
_code-samples/nft-modular-tutorials/transfer-nfts.html
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Transfer NFTs</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
|
||||||
|
<link href="modular-tutorials.css" rel="stylesheet">
|
||||||
|
<script src='https://unpkg.com/xrpl@4.1.0/build/xrpl-latest.js'></script>
|
||||||
|
<script src="account-support.js"></script>
|
||||||
|
<script src="transaction-support.js"></script>
|
||||||
|
<!-- <script src='send-xrp.js'></script> -->
|
||||||
|
<script src="transfer-nfts.js"></script>
|
||||||
|
<script src="mint-nfts.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Transfer NFTs</h1>
|
||||||
|
<form id="theForm">
|
||||||
|
<span class="tooltip" tooltip-data="Choose the XRPL host server for your account.">
|
||||||
|
Choose your ledger instance:
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="radio" id="dn" name="server" value="wss://s.devnet.rippletest.net:51233" checked>
|
||||||
|
<label for="dn">Devnet</label>
|
||||||
|
|
||||||
|
<input type="radio" id="tn" name="server" value="wss://s.altnet.rippletest.net:51233">
|
||||||
|
<label for="tn">Testnet</label>
|
||||||
|
<br /><br />
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount1()">Get New Account 1</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed1()">Get Account 1 From Seed</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getNewAccount2()">Get New Account 2</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="getAccountFromSeed2()">Get Account 2 From Seed</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account."><label
|
||||||
|
for="account1name">Account 1 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Arbitrary human-readable name for the account.">
|
||||||
|
<label for="account2name">Account 2 Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2name" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account1address">Account 1 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Identifying address for the account.">
|
||||||
|
<label for="account2address">Account 2 Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2address" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account1seed">Account 1 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account1seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="Seed for deriving public and private keys for the account.">
|
||||||
|
<label for="account2seed">Account 2 Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="account2seed" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
<table>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Name of the currently selected account.">
|
||||||
|
<label for="accountNameField">Account Name</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountNameField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account1" name="accounts" value="account1">
|
||||||
|
<label for="account1">Account 1</label>
|
||||||
|
</td>
|
||||||
|
<td rowspan="4" align="center">
|
||||||
|
<p>
|
||||||
|
<img id="nftImage"
|
||||||
|
src="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"
|
||||||
|
width="150" height="150">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Address of the currently selected account.">
|
||||||
|
<label for="accountAddressField">Account Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountAddressField" size="40" readonly></input>
|
||||||
|
<input type="radio" id="account2" name="accounts" value="account2">
|
||||||
|
<label for="account2">Account 2</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Seed of the currently selected account.">
|
||||||
|
<label for="accountSeedField">Account Seed</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="accountSeedField" size="40" readonly></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="XRP balance for the currently selected account.">
|
||||||
|
<label for="xrpBalanceField">XRP Balance</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="xrpBalanceField" size="40" readonly></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="tooltip" tooltip-data="URL to the stored NFT.">
|
||||||
|
<label for="nftURLfield">NFT URL</label>
|
||||||
|
</span>
|
||||||
|
<input type="text" id="nftURLfield" size="30"
|
||||||
|
placeholder="https://ipfs.io/ipfs/bafybeigjro2d2tc43bgv7e4sxqg7f5jga7kjizbk7nnmmyhmq35dtz6deq"></input>
|
||||||
|
<br />
|
||||||
|
<p id="error-message"></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right" >
|
||||||
|
<span class="tooltip" tooltip-data="Currency for the offer.">
|
||||||
|
<label for="currencyField">Currency</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="currencyField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td align="center" valign="top">
|
||||||
|
<button type="button" onClick="getNFTs()">Get NFTs</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Issuer of the currency used.">
|
||||||
|
<label for="issuerField">Issuer</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="issuerField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" onClick="createSellOffer()">Create Sell Offer</button>
|
||||||
|
|
||||||
|
<button type="button" onClick="createBuyOffer()">Create Buy Offer</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Amount of XRP to send.">
|
||||||
|
<label for="amountField">Amount</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="amountField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="acceptSellOffer()">Accept Sell Offer</button>
|
||||||
|
|
||||||
|
<button type="button" onClick="acceptBuyOffer()">Accept Buy Offer</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Destination account address where XRP is sent.">
|
||||||
|
<label for="destinationField">Destination</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="destinationField" size="40"></input>
|
||||||
|
<br>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="getOffers()" width="40">Get Offers</button>
|
||||||
|
<button type="button" onClick="cancelOffer()">Cancel Offer</button>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Number of days the offer is valid.">
|
||||||
|
<label for="expirationField">Expiration (days)</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="expirationField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT ID code, used to identify the token after it's minted.">
|
||||||
|
<label for="nftIdField">NFT ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="NFT Offer ID code, used to identify an offer to sell or buy an NFT.">
|
||||||
|
<label for="nftOfferIdField">NFT Offer ID</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftOfferIdField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">
|
||||||
|
<span class="tooltip" tooltip-data="Account address of the Owner of an NFT offered to sell or buy.">
|
||||||
|
<label for="nftOwnerField">NFT Owner Address</label>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" id="nftOwnerField" size="40"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr valign="top">
|
||||||
|
<td colspan="2">
|
||||||
|
<p align="left">
|
||||||
|
<textarea id="resultField" cols="75" rows="20"></textarea>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td align="left" valign="top">
|
||||||
|
<button type="button" onClick="gatherAccountInfo()">Gather Account Info</button><br />
|
||||||
|
<button type="button" onClick="distributeAccountInfo()">Distribute Account Info</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const imageURLInput = document.getElementById('nftURLfield'); // Correct ID to nftURLfield
|
||||||
|
const displayImage = document.getElementById('nftImage');
|
||||||
|
const loadButton = document.getElementById('showNFTbutton');
|
||||||
|
const errorMessage = document.getElementById('error-message');
|
||||||
|
|
||||||
|
if (imageURLInput) {
|
||||||
|
imageURLInput.addEventListener('change', () => {
|
||||||
|
const newURL = imageURLInput.value;
|
||||||
|
displayImage.src = ''; // Clear previous image
|
||||||
|
errorMessage.style.display = 'none';
|
||||||
|
try {
|
||||||
|
new URL(newURL);
|
||||||
|
} catch (_) {
|
||||||
|
errorMessage.textContent = 'Invalid URL. Please enter a valid URL, including "https://" or "http://".';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
displayImage.onload = () => {
|
||||||
|
// Image loaded. You might add a console log here, or update UI.
|
||||||
|
console.log(`Image loaded from: ${newURL}`);
|
||||||
|
};
|
||||||
|
displayImage.onerror = () => {
|
||||||
|
errorMessage.textContent = 'Error loading image from the provided URL.';
|
||||||
|
errorMessage.style.display = 'block';
|
||||||
|
displayImage.src = ''; // Clear the image on error
|
||||||
|
};
|
||||||
|
displayImage.src = newURL; // Load the image
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const radioButtons = document.querySelectorAll('input[type="radio"]');
|
||||||
|
radioButtons.forEach(radio => {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
if (this.value === 'account1') {
|
||||||
|
populate1()
|
||||||
|
} else if (this.value === 'account2') {
|
||||||
|
populate2()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
||||||
339
_code-samples/nft-modular-tutorials/transfer-nfts.js
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
|
||||||
|
// *********************************************************
|
||||||
|
// *************** Create Sell Offer ***********************
|
||||||
|
// *********************************************************
|
||||||
|
|
||||||
|
async function createSellOffer() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
let results = '\nCreating sell offer...';
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const client = new xrpl.Client(getNet());
|
||||||
|
await client.connect();
|
||||||
|
try {
|
||||||
|
const destination = destinationField.value || undefined;
|
||||||
|
const expiration = expirationField.value ? configureExpiration() : undefined;
|
||||||
|
|
||||||
|
const transactionJson = {
|
||||||
|
TransactionType: "NFTokenCreateOffer",
|
||||||
|
Account: wallet.classicAddress,
|
||||||
|
NFTokenID: nftIdField.value,
|
||||||
|
Flags: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const amount = configureAmount();
|
||||||
|
if (amount) { // Only add Amount if it's defined
|
||||||
|
transactionJson.Amount = amount;
|
||||||
|
} else {
|
||||||
|
console.warn("Amount is undefined. Sell offer might be invalid.");
|
||||||
|
results += "\nWarning: Amount is undefined. Sell offer might be invalid, unless you plan to give away the NFT.";
|
||||||
|
resultField.value = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expiration) {
|
||||||
|
transactionJson.Expiration = expiration;
|
||||||
|
}
|
||||||
|
if (destination) {
|
||||||
|
transactionJson.Destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tx = await client.submitAndWait(transactionJson, { wallet });
|
||||||
|
results += `\nSell offer created successfully!\nTransaction Hash: ${tx.result.hash}\nEngine Result: ${tx.result.engine_result}`;
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating sell offer:", error);
|
||||||
|
results = `\nError: ${error.message || error}`;
|
||||||
|
resultField.value = results;
|
||||||
|
}
|
||||||
|
}// End of createSellOffer()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ***************** Create Buy Offer ********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function createBuyOffer() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
let net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
await client.connect();
|
||||||
|
let results = '\n=== Connected. Creating buy offer. ===';
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Use the external configureAmount() function
|
||||||
|
let amount = configureAmount();
|
||||||
|
// Use the external configureExpiration() function
|
||||||
|
let expiration = configureExpiration(); // This will return a number or an empty string from the original logic
|
||||||
|
|
||||||
|
let transactionJson = {
|
||||||
|
"TransactionType": "NFTokenCreateOffer",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"Owner": nftOwnerField.value,
|
||||||
|
"NFTokenID": nftIdField.value,
|
||||||
|
"Flags": 0, // Ensure no tfSellNFToken flag for a buy offer
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only add Amount if it's defined (not undefined or an empty string)
|
||||||
|
if (amount !== undefined && amount !== '') {
|
||||||
|
transactionJson.Amount = amount;
|
||||||
|
} else {
|
||||||
|
results += "\nError: Amount field is required for a buy offer.";
|
||||||
|
resultField.value = results;
|
||||||
|
client.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destinationField.value !== '') {
|
||||||
|
transactionJson.Destination = destinationField.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add Expiration if it's not an empty string
|
||||||
|
if (expiration > 0) {
|
||||||
|
transactionJson.Expiration = expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tx = await client.submitAndWait(transactionJson, { wallet: wallet });
|
||||||
|
|
||||||
|
results += "\n\n=== Sell Offers ===\n";
|
||||||
|
let nftSellOffers;
|
||||||
|
try {
|
||||||
|
nftSellOffers = await client.request({
|
||||||
|
method: "nft_sell_offers",
|
||||||
|
nft_id: nftIdField.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",
|
||||||
|
nft_id: nftIdField.value
|
||||||
|
});
|
||||||
|
results += JSON.stringify(nftBuyOffers, null, 2);
|
||||||
|
} catch (err) {
|
||||||
|
results += "=== No buy offers. ===";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check transaction results -------------------------------------------------
|
||||||
|
results += "\n\n=== Transaction result:\n" +
|
||||||
|
JSON.stringify(tx.result.meta.TransactionResult, null, 2);
|
||||||
|
results += "\n\n=== Balance changes:\n" +
|
||||||
|
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating buy offer:', error);
|
||||||
|
results += "\n\n=== Error: " + error;
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
}// End of createBuyOffer()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ******************** Cancel Offer *********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function cancelOffer() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
let net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
let results = "\n=== Connected. Cancelling offer. ==="
|
||||||
|
resultField.value = results
|
||||||
|
|
||||||
|
const tokenOfferIDs = [nftOfferIdField.value]
|
||||||
|
|
||||||
|
// Prepare transaction -------------------------------------------------------
|
||||||
|
const transactionJson = {
|
||||||
|
"TransactionType": "NFTokenCancelOffer",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"NFTokenOffers": tokenOfferIDs
|
||||||
|
}
|
||||||
|
// Submit transaction --------------------------------------------------------
|
||||||
|
const tx = await client.submitAndWait(transactionJson, { wallet })
|
||||||
|
|
||||||
|
results = "\n\n=== Sell Offers===\n"
|
||||||
|
let nftSellOffers
|
||||||
|
try {
|
||||||
|
nftSellOffers = await client.request({
|
||||||
|
method: "nft_sell_offers",
|
||||||
|
nft_id: nftIdField.value
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
nftSellOffers = '=== No sell offers. ===\n'
|
||||||
|
}
|
||||||
|
results += JSON.stringify(nftSellOffers, null, 2)
|
||||||
|
results += "\n\n=== Buy Offers ===\n"
|
||||||
|
let nftBuyOffers
|
||||||
|
try {
|
||||||
|
nftBuyOffers = await client.request({
|
||||||
|
method: "nft_buy_offers",
|
||||||
|
nft_id: nftIdField.value
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
nftBuyOffers = '=== No buy offers. ==='
|
||||||
|
}
|
||||||
|
results += JSON.stringify(nftBuyOffers, null, 2)
|
||||||
|
resultField.value += results
|
||||||
|
|
||||||
|
// Check transaction results -------------------------------------------------
|
||||||
|
|
||||||
|
results = "\n=== Transaction result:\n" +
|
||||||
|
JSON.stringify(tx.result.meta.TransactionResult, null, 2)
|
||||||
|
results += "\n\n=== Balance changes:\n" +
|
||||||
|
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
|
||||||
|
resultField.value += results
|
||||||
|
|
||||||
|
client.disconnect() // End of cancelOffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ******************** Get Offers ***********************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function getOffers() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
let net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
await client.connect()
|
||||||
|
|
||||||
|
let results = '\nConnected. Getting offers...'
|
||||||
|
resultField.value = results
|
||||||
|
|
||||||
|
// --- Sell Offers ---
|
||||||
|
results += '\n\n=== Sell Offers ===\n'
|
||||||
|
let nftSellOffers
|
||||||
|
try {
|
||||||
|
nftSellOffers = await client.request({
|
||||||
|
method: "nft_sell_offers",
|
||||||
|
nft_id: nftIdField.value
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
nftSellOffers = 'No sell offers found for this NFT ID.'
|
||||||
|
}
|
||||||
|
results += JSON.stringify(nftSellOffers, null, 2)
|
||||||
|
resultField.value = results
|
||||||
|
|
||||||
|
// --- Buy Offers ---
|
||||||
|
results = '\n\n=== Buy Offers ===\n'
|
||||||
|
let nftBuyOffers
|
||||||
|
try {
|
||||||
|
nftBuyOffers = await client.request({
|
||||||
|
method: "nft_buy_offers",
|
||||||
|
nft_id: nftIdField.value
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
// Log the actual error for debugging
|
||||||
|
nftBuyOffers = 'No buy offers found for this NFT ID.' // More descriptive
|
||||||
|
}
|
||||||
|
results += JSON.stringify(nftBuyOffers, null, 2) // Append the JSON string
|
||||||
|
resultField.value += results // Update the display with buy offers
|
||||||
|
|
||||||
|
client.disconnect()
|
||||||
|
}// End of getOffers()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ****************** Accept Sell Offer ******************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function acceptSellOffer() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value)
|
||||||
|
let net = getNet()
|
||||||
|
const client = new xrpl.Client(net)
|
||||||
|
try {
|
||||||
|
await client.connect()
|
||||||
|
let results = '\n=== Connected. Accepting sell offer. ===\n\n'
|
||||||
|
resultField.value = results
|
||||||
|
|
||||||
|
// Prepare transaction -------------------------------------------------------
|
||||||
|
const transactionJson = {
|
||||||
|
"TransactionType": "NFTokenAcceptOffer",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"NFTokenSellOffer": nftOfferIdField.value,
|
||||||
|
}
|
||||||
|
// Submit transaction --------------------------------------------------------
|
||||||
|
const tx = await client.submitAndWait(transactionJson, { wallet: wallet })
|
||||||
|
const nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check transaction results -------------------------------------------------
|
||||||
|
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address))
|
||||||
|
|
||||||
|
|
||||||
|
results += '=== Transaction result:\n'
|
||||||
|
results += JSON.stringify(tx.result.meta.TransactionResult, null, 2)
|
||||||
|
results += '\n=== Balance changes:'
|
||||||
|
results += JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
|
||||||
|
results += JSON.stringify(nfts, null, 2)
|
||||||
|
resultField.value += results
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error accepting sell offer:', error)
|
||||||
|
resultField.value = `Error: ${error.message || error}`
|
||||||
|
} finally {
|
||||||
|
client.disconnect()
|
||||||
|
}
|
||||||
|
}// End of acceptSellOffer()
|
||||||
|
|
||||||
|
// *******************************************************
|
||||||
|
// ******************* Accept Buy Offer ******************
|
||||||
|
// *******************************************************
|
||||||
|
|
||||||
|
async function acceptBuyOffer() {
|
||||||
|
const wallet = xrpl.Wallet.fromSeed(accountSeedField.value);
|
||||||
|
let net = getNet();
|
||||||
|
const client = new xrpl.Client(net);
|
||||||
|
let results = '\n=== Connected. Accepting buy offer. ==='; // Declare results locally
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
resultField.value = results; // Update UI after connection
|
||||||
|
|
||||||
|
// Prepare transaction -------------------------------------------------------
|
||||||
|
const transactionJson = {
|
||||||
|
"TransactionType": "NFTokenAcceptOffer",
|
||||||
|
"Account": wallet.classicAddress,
|
||||||
|
"NFTokenBuyOffer": nftOfferIdField.value
|
||||||
|
};
|
||||||
|
|
||||||
|
// Submit transaction --------------------------------------------------------
|
||||||
|
const tx = await client.submitAndWait(transactionJson, { wallet: wallet });
|
||||||
|
|
||||||
|
const nfts = await client.request({
|
||||||
|
method: "account_nfts",
|
||||||
|
account: wallet.classicAddress
|
||||||
|
});
|
||||||
|
|
||||||
|
results += JSON.stringify(nfts, null, 2);
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
// Check transaction results -------------------------------------------------
|
||||||
|
results += "\n\nTransaction result:\n" +
|
||||||
|
JSON.stringify(tx.result.meta.TransactionResult, null, 2);
|
||||||
|
results += "\nBalance changes:\n" +
|
||||||
|
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2);
|
||||||
|
xrpBalanceField.value = (await client.getXrpBalance(wallet.address));
|
||||||
|
resultField.value = results;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in acceptBuyOffer:', error); // Log the full error
|
||||||
|
results = `\n=== Error accepting buy offer: ${error.message || 'Unknown error'} ===`;
|
||||||
|
resultField.value = results;
|
||||||
|
} finally {
|
||||||
|
if (client && client.isConnected()) {
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of acceptBuyOffer()
|
||||||
BIN
docs/img/mt-auth-minter-1-empty-form.png
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
docs/img/mt-auth-minter-2-authorize-minter.png
Normal file
|
After Width: | Height: | Size: 376 KiB |
BIN
docs/img/mt-auth-minter-3-mint-other.png
Normal file
|
After Width: | Height: | Size: 372 KiB |
BIN
docs/img/mt-batch-mint-1-empty-form.png
Normal file
|
After Width: | Height: | Size: 239 KiB |
BIN
docs/img/mt-batch-mint-2-batch-mint.png
Normal file
|
After Width: | Height: | Size: 352 KiB |
BIN
docs/img/mt-batch-mint-3-get-batch-mint.png
Normal file
|
After Width: | Height: | Size: 388 KiB |
BIN
docs/img/mt-broker-nfts-1-empty-form.png
Normal file
|
After Width: | Height: | Size: 260 KiB |
BIN
docs/img/mt-broker-nfts-2-broker-form-with-accounts.png
Normal file
|
After Width: | Height: | Size: 317 KiB |
BIN
docs/img/mt-broker-nfts-3-get-offers.png
Normal file
|
After Width: | Height: | Size: 344 KiB |
BIN
docs/img/mt-broker-nfts-4-broker-sale.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
docs/img/mt-mint-token-1-empty-form.png
Normal file
|
After Width: | Height: | Size: 233 KiB |
BIN
docs/img/mt-mint-token-2-accounts.png
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
docs/img/mt-mint-token-3-mint-token.png
Normal file
|
After Width: | Height: | Size: 385 KiB |
BIN
docs/img/mt-mint-token-4-get-tokens.png
Normal file
|
After Width: | Height: | Size: 377 KiB |
BIN
docs/img/mt-mint-token-5-burn-token.png
Normal file
|
After Width: | Height: | Size: 336 KiB |
BIN
docs/img/mt-transfer-nft-1-empty-form.png
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
docs/img/mt-transfer-nft-2-accounts-loaded.png
Normal file
|
After Width: | Height: | Size: 318 KiB |
BIN
docs/img/mt-transfer-nfts-3-create-sell-offer.png
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
docs/img/mt-transfer-nfts-4-get-offers.png
Normal file
|
After Width: | Height: | Size: 419 KiB |
BIN
docs/img/mt-transfer-nfts-5-accept-sell-offer.png
Normal file
|
After Width: | Height: | Size: 394 KiB |
BIN
docs/img/mt-transfer-nfts-6-create-buy-offer.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
docs/img/mt-transfer-nfts-7-accept-buy-offer.png
Normal file
|
After Width: | Height: | Size: 365 KiB |
BIN
docs/img/mt-transfer-nfts-8-cancel-offer.png
Normal file
|
After Width: | Height: | Size: 351 KiB |
@@ -28,7 +28,8 @@ Download and expand the [Modular Tutorials](../../../../_code-samples/modular-tu
|
|||||||
To get test accounts:
|
To get test accounts:
|
||||||
|
|
||||||
1. Open `create-offers.html` in a browser.
|
1. Open `create-offers.html` in a browser.
|
||||||
2. Get test accounts.
|
2. Choose your preferred test network (**Devnet** or **Testnet**).
|
||||||
|
3. Get test accounts.
|
||||||
1. If you copied the gathered information from another tutorial:
|
1. If you copied the gathered information from another tutorial:
|
||||||
1. Paste the gathered information to the **Result** field.
|
1. Paste the gathered information to the **Result** field.
|
||||||
2. Click **Distribute Account Info**.
|
2. Click **Distribute Account Info**.
|
||||||
|
|||||||