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 {
 | 
			
		||||
    // Disconnect from the client
 | 
			
		||||
    await client.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
    if (client && client.isConnected()) {
 | 
			
		||||
      await client.disconnect();
 | 
			
		||||
    } }
 | 
			
		||||
} // End of getAccount()
 | 
			
		||||
 | 
			
		||||
async function getNewAccount1() {
 | 
			
		||||
@@ -78,8 +79,9 @@ async function getAccountFromSeed(my_seed) {
 | 
			
		||||
  }
 | 
			
		||||
  finally {
 | 
			
		||||
    // Disconnect from the client
 | 
			
		||||
    await client.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
    if (client && client.isConnected()) {
 | 
			
		||||
      await client.disconnect();
 | 
			
		||||
    }  }
 | 
			
		||||
} // End of getAccountFromSeed()
 | 
			
		||||
 | 
			
		||||
// *****************************************************
 | 
			
		||||
@@ -169,8 +171,9 @@ async function getXrpBalance() {
 | 
			
		||||
  }
 | 
			
		||||
  finally {
 | 
			
		||||
    // Disconnect from the client
 | 
			
		||||
    await client.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
    if (client && client.isConnected()) {
 | 
			
		||||
      await client.disconnect();
 | 
			
		||||
    }  }
 | 
			
		||||
} // End of getXrpBalance()
 | 
			
		||||
 | 
			
		||||
// *******************************************************
 | 
			
		||||
@@ -202,8 +205,9 @@ async function getTokenBalance() {
 | 
			
		||||
  }
 | 
			
		||||
  finally {
 | 
			
		||||
    // Disconnect from the client
 | 
			
		||||
    await client.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
    if (client && client.isConnected()) {
 | 
			
		||||
      await client.disconnect();
 | 
			
		||||
    }  }
 | 
			
		||||
} // 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:
 | 
			
		||||
 | 
			
		||||
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. Paste the gathered information to the **Result** field.
 | 
			
		||||
        2. Click **Distribute Account Info**.
 | 
			
		||||
 
 | 
			
		||||