JavaScript를 이용한 NFT 판매 중개(Broker an NFT Sale Using JavaScript)
Last updated
Last updated
이전의 예제들은 두 계정 간에 직접 구매 및 판매 제안을 만드는 방법을 보여주었습니다. 또 다른 옵션은 세 번째 계정을 판매의 중개인으로 사용하는 것입니다. 중개인은 NFT 소유자를 대신하여 행동합니다. 판매자는 목적지로 중개 계정을 가진 제안을 생성합니다. 중개인은 구매 제안을 수집하고 평가하며, 판매를 준비하는 데 동의한 수수료를 추가하여 어느 제안을 수락할지 결정합니다. 중개 계정이 판매 제안을 구매 제안으로 수락할 때, 자금과 NFT의 소유권은 동시에 전송되어 거래가 완료됩니다. 이렇게 하면 계정이 NFT 창작자와 거래자를 위한 마켓플레이스나 개인 대리인으로 행동할 수 있게 합니다.
이 예제는 다음을 보여줍니다:
중개된 판매 제안 생성하기.
중개된 아이템에 대한 제안 목록 받기.
두개 다른 계정간의 판매를 중개하기.
Quickstart Samples 아카이브를 다운로드하여 각 샘플을 브라우저에서 시도해볼 수 있습니다.
브라우저에서 5.broker-nfts.html
을 엽니다.
ledger 인스턴스를 선택합니다.
테스트 계정을 가져옵니다.
계정 seed가 있는 경우
Seeds 필드에 계정 seed 3개를 붙여넣습니다.
Get Accounts from Seeds를 클릭합니다
계정 seed가 없는 경우
Get New Standby Account를 클릭합니다.
Get New Operational Account를 클릭합니다.
Get New Broker Account를 클릭합니다.
Standby account을 사용하여 Broker account를대상으로 하는 NFT 판매 제안을 생성합니다.
판매 제안 Amount을 드롭 단위로 입력합니다(XRP의 백만분의 일).
Flags 필드를 1로 설정합니다.
판매할 NFT의 NFT ID를 입력합니다.
선택적으로 Expiration까지 일 수를 입력합니다.
Broker 계정 번호를 Destination으로 입력합니다.
Create Sell Offer을 클릭합니다.
Operational account 사용하여 NFT 구매 제안을 작성합니다.
제안 Amount를 입력합니다.
NFT ID를 입력합니다.
Owner 필드에 소유자의 계정 문자열을 입력합니다.
선택적으로 Expiration까지 일 수를 입력합니다.
Create Buy Offer을 클릭합니다.
NFT ID를 입력합니다.
Get Offers를 클릭합니다.
판매 제안의 nft_offer_index를 복사하여 Sell NFT Offer Index 필드에 붙여넣습니다.
매입 제의 nft_offer_index를 복사하여 Buy NFT Offer Index 필드에 붙여넣습니다.
Broker Fee를 드롭 단위로 입력합니다.
Broker Sale를 클릭합니다.
중개인이 구매 제안을 수락한 후, 중개인에게 권한이 있는 경우 다른 모든 제안을 취소하는 것이 좋습니다. Get Offers를 사용하여 구매 제안의 전체 목록을 확인할 수 있습니다. 제안을 취소하려면:
Buy NFT Offer Index 필드에 취소할 구매 제안의 nft_Offer_index를 입력합니다.
Cancel Offer를 클릭합니다.
Quickstart Samples 아카이브를 다운로드하여 각 샘플을 브라우저에서 시도해볼 수 있습니다.
이 스크립트는 중개된 거래를 위한 새로운 기능과 동일한 화면에서 세 번째 계정을 지원하도록 수정된 기능을 가지고 있습니다.
// *******************************************************
// *************** Broker Get Offers *********************
// *******************************************************
async function brGetOffers() {
ledger에 연결합니다.
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + getNet() + '...'
brokerResultField.value = results
await client.connect()
results += '\nConnected. Getting offers...'
brokerResultField.value = results
토큰에 대한 판매 제안 목록을 요청합니다.
results += '\n\n***Sell Offers***\n'
let nftSellOffers
try {
nftSellOffers = await client.request({
method: "nft_sell_offers",
nft_id: brokerTokenIdField.value
})
} catch (err) {
nftSellOffers = 'No sell offers.'
}
results += JSON.stringify(nftSellOffers,null,2)
brokerResultField.value = results
토큰에 대한 구매 제안 목록을 요청합니다.
results += '\n\n***Buy Offers***\n'
let nftBuyOffers
try {
nftBuyOffers = await client.request({
method: "nft_buy_offers",
nft_id: brokerTokenIdField.value
})
} catch (err) {
nftBuyOffers = 'No buy offers.'
}
results += JSON.stringify(nftBuyOffers,null,2)
brokerResultField.value = results
ledger에서 연결을 끊습니다.
client.disconnect()
}// End of brGetOffers()
async function brokerSale() {
ledger에 연결해서 계정을 가져오세요.
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const broker_wallet = xrpl.Wallet.fromSeed (brokerSeedField.value)
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + getNet() + '...'
brokerResultField.value = results
await client.connect()
results += '\nConnected. Brokering sale...'
brokerResultField.value = results
트랜잭션을 준비합니다. 중개 판매와 직접 판매의 차이점은 합의된 중개인 수수료와 함께 판매 제안과 구매 제안을 모두 제공한다는 것입니다.
const transactionBlob = {
"TransactionType": "NFTokenAcceptOffer",
"Account": broker_wallet.classicAddress,
"NFTokenSellOffer": brokerTokenSellOfferIndexField.value,
"NFTokenBuyOffer": brokerTokenBuyOfferIndexField.value,
"NFTokenBrokerFee": brokerBrokerFeeField.value
}
트랜잭션을 제출하고 결과를 기다립니다.
const tx = await client.submitAndWait(transactionBlob,{wallet: broker_wallet})
결과를 보고합니다.
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)
operationalBalanceField.value = (await client.getXrpBalance(operational_wallet.address))
standbyBalanceField.value = (await client.getXrpBalance(standby_wallet.address))
brokerBalanceField.value = (await client.getXrpBalance(broker_wallet.address))
brokerResultField.value = results
ledger에서 연결을 끊습니다.
client.disconnect()
}// End of brokerSale()
// *******************************************************
// ************* Broker Cancel Offer ****************
// *******************************************************
async function brCancelOffer() {
broker 계정을 가져오고 ledger에 연결합니다.
const wallet = xrpl.Wallet.fromSeed(brokerSeedField.value)
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + getNet() + '...'
brokerResultField.value = results
await client.connect()
results += "\nConnected. Cancelling offer..."
brokerResultField.value = results
토큰 ID는 반드시 array로 변환되어야 합니다.
const tokenOfferIDs = [brokerTokenBuyOfferIndexField.value]
트랜잭션을 준비합니다.
const transactionBlob = {
"TransactionType": "NFTokenCancelOffer",
"Account": wallet.classicAddress,
"NFTokenOffers": tokenOfferIDs
}
트랜잭션을 제출하고 결과를 기다립니다.
const tx = await client.submitAndWait(transactionBlob,{wallet})
sell offers를 받고 결과를 보고합니다.
results += "\n\n***Sell Offers***\n"
let nftSellOffers
try {
nftSellOffers = await client.request({
method: "nft_sell_offers",
nft_id: brokerTokenBuyOfferIndexField.value
})
} catch (err) {
nftSellOffers = "No sell offers."
}
results += JSON.stringify(nftSellOffers,null,2)
buy offers를 받고 결과를 보고합니다.
results += "\n\n***Buy Offers***\n"
let nftBuyOffers
try {
nftBuyOffers = await client.request({
method: "nft_buy_offers",
nft_id: brokerTokenBuyOfferIndexField.value })
} catch (err) {
nftBuyOffers = "No buy offers."
}
results += JSON.stringify(nftBuyOffers,null,2)
트랜잭션 결과를 보고합니다.
results += "\nTransaction result:\n" +
JSON.stringify(tx.result.meta.TransactionResult, null, 2)
results += "\nBalance changes:\n" +
JSON.stringify(xrpl.getBalanceChanges(tx.result.meta), null, 2)
document.getElementById('brokerResultField').value = results
ledger에서 연결을 끊습니다.
client.disconnect()
}// End of brCancelOffer()
broker account를 수용하기 위해 getAccount(type)
함수를 재정의하여 브로커 타입을 감시하도록 변경하세요.
// ***************************************************************************
// ************** Revised Functions ******************************************
// ***************************************************************************
// *******************************************************
// ************* Get Account *****************************
// *******************************************************
async function getAccount(type) {
ledger에 연결합니다.
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + net + '....'
올바른 네트워크 호스트를 가져옵니다.
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + net + '....'
let faucetHost = null
if (type == 'standby') {
standbyResultField.value = results
}
if (type == 'operational') {
operationalResultField.value = results
}
if (type == 'broker') {
brokerResultField.value = results
}
ledger에 연결합니다.
await client.connect()
results += '\nConnected, funding wallet.'
if (type == 'standby') {
standbyResultField.value = results
}
if (type == 'operational') {
operationalResultField.value = results
}
if (type == 'broker') {
brokerResultField.value = results
}
테스트 계정을 만들고 자금을 지원하며 진행 상황을 보고합니다.
const my_wallet = (await client.fundWallet(null, { faucetHost })).wallet
results += '\nGot a wallet.'
if (type == 'standby') {
standbyResultField.value = results
}
if (type == 'operational') {
operationalResultField.value = results
}
if (type == 'broker') {
brokerResultField.value = results
}
새 계정에 대한 XRP 잔액을 가져옵니다.
const my_balance = (await client.getXrpBalance(my_wallet.address))
해당 계정의 양식 필드를 새 계정 정보로 채웁니다.
if (type == 'standby') {
standbyAccountField.value = my_wallet.address
standbyPubKeyField.value = my_wallet.publicKey
standbyPrivKeyField.value = my_wallet.privateKey
standbyBalanceField.value = (await client.getXrpBalance(my_wallet.address))
standbySeedField.value = my_wallet.seed
results += '\nStandby account created.'
standbyResultField.value = results
}
if (type == 'operational') {
operationalAccountField.value = my_wallet.address
operationalPubKeyField.value = my_wallet.publicKey
operationalPrivKeyField.value = my_wallet.privateKey
operationalSeedField.value = my_wallet.seed
operationalBalanceField.value = (await client.getXrpBalance(my_wallet.address))
results += '\nOperational account created.'
operationalResultField.value = results
}
if (type == 'broker') {
brokerAccountField.value = my_wallet.address
brokerPubKeyField.value = my_wallet.publicKey
brokerPrivKeyField.value = my_wallet.privateKey
brokerSeedField.value = my_wallet.seed
brokerBalanceField.value = (await client.getXrpBalance(my_wallet.address))
results += '\nBroker account created.'
brokerResultField.value = results
}
Account Seeds 필드의 해당 줄에 새 계정 시드를 추가합니다.
seeds.value = standbySeedField.value + '\n' + operationalSeedField.value + "\n" +
brokerSeedField.value
ledger에서 연결을 끊습니다.
client.disconnect()
} // End of getAccount()
broker account 필드를 포함하도록 getAccountsFromSeeds()
함수를 재정의합니다.
async function getAccountsFromSeeds() {
ledger에 연결합니다.
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + getNet() + '....'
standbyResultField.value = results
await client.connect()
results += '\nConnected, finding wallets.\n'
standbyResultField.value = results
split
함수를 사용하여 Seeds 필드의 값을 구문 분석합니다.
var lines = seeds.value.split('\n');
Seed 값에서 계정을 파생합니다.
const standby_wallet = xrpl.Wallet.fromSeed(lines[0])
const operational_wallet = xrpl.Wallet.fromSeed(lines[1])
const broker_wallet = xrpl.Wallet.fromSeed(lines[2])
계정에 대한 XRP 잔액을 가져옵니다.
const standby_balance = (await client.getXrpBalance(standby_wallet.address))
const operational_balance = (await client.getXrpBalance(operational_wallet.address))
const broker_balance = (await client.getXrpBalance(broker_wallet.address))
계정 값을 기준으로 양식 필드를 채웁니다.
standbyAccountField.value = standby_wallet.address
standbyPubKeyField.value = standby_wallet.publicKey
standbyPrivKeyField.value = standby_wallet.privateKey
standbySeedField.value = standby_wallet.seed
standbyBalanceField.value = (await client.getXrpBalance(standby_wallet.address))
operationalAccountField.value = operational_wallet.address
operationalPubKeyField.value = operational_wallet.publicKey
operationalPrivKeyField.value = operational_wallet.privateKey
operationalSeedField.value = operational_wallet.seed
operationalBalanceField.value = (await client.getXrpBalance(operational_wallet.address))
brokerAccountField.value = broker_wallet.address
brokerPubKeyField.value = broker_wallet.publicKey
brokerPrivKeyField.value = broker_wallet.privateKey
brokerSeedField.value = broker_wallet.seed
brokerBalanceField.value = (await client.getXrpBalance(broker_wallet.address))
ledger에서 연결을 끊습니다.
client.disconnect()
getBalance()
함수를 사용하여 법정 통화의 현재 잔액을 가져옵니다.
getBalances()
} // End of getAccountsFromSeeds()
브로커 잔액을 포함하도록 getBalances()
함수를 재정의합니다.
// *******************************************************
// ****************** Get Balances ***********************
// *******************************************************
async function getBalances() {
ledger에 연결합니다.
let net = getNet()
const client = new xrpl.Client(net)
results = 'Connecting to ' + getNet() + '....'
document.getElementById('standbyResultField').value = results
await client.connect()
results += '\nConnected.'
document.getElementById('standbyResultField').value = results
세 개의 계정을 각각 도출합니다.
const standby_wallet = xrpl.Wallet.fromSeed(standbySeedField.value)
const operational_wallet = xrpl.Wallet.fromSeed(operationalSeedField.value)
const broker_wallet = xrpl.Wallet.fromSeed(brokerSeedField.value)
Standby account 잔액을 가져오고 보고합니다.
results = "\nGetting standby account balances...\n"
const standby_balances = await client.request({
command: "gateway_balances",
account: standby_wallet.address,
ledger_index: "validated",
hotwallet: [operational_wallet.address]
})
results += JSON.stringify(standby_balances.result, null, 2)
standbyResultField.value = results
Operational account 잔액을 가져오고 보고합니다.
results= "\nGetting operational account balances...\n"
const operational_balances = await client.request({javascript
command: "account_lines",
account: operational_wallet.address,
ledger_index: "validated"
})
results += JSON.stringify(operational_balances.result, null, 2)
operationalResultField.value = results
브로커 계정 잔액을 가져오고 보고합니다.
results= "\nGetting broker account balances...\n"
const broker_balances = await client.request({
command: "account_lines",
account: broker_wallet.address,
ledger_index: "validated"
})
results += JSON.stringify(broker_balances.result, null, 2)
brokerResultField.value = results
세 계정의 XRP 잔액을 업데이트합니다.
operationalBalanceField.value = (await client.getXrpBalance(operational_wallet.address))
standbyBalanceField.value = (await client.getXrpBalance(standby_wallet.address))
brokerBalanceField.value = (await client.getXrpBalance(broker_wallet.address))
ledger에서 연결을 끊습니다.
client.disconnect()
} // end of getBalances()
HTML 양식을 수정하여 맨 위에 새 브로커 섹션을 추가합니다.
<html>
<head>
<title>Token Test Harness</title>
<link href='https://fonts.googleapis.com/css?family=Work Sans' rel='stylesheet'>
<style>
body{font-family: "Work Sans", sans-serif;padding: 20px;background: #fafafa;}
h1{font-weight: bold;}
input, button {padding: 6px;margin-bottom: 8px;}
button{font-weight: bold;font-family: "Work Sans", sans-serif;}
td{vertical-align: middle;}
</style>
<script src='https://unpkg.com/xrpl@2.7.0/build/xrpl-latest-min.js'></script>
<script src='ripplex1-send-xrp.js'></script>
<script src='ripplex2-send-currency.js'></script>
<script src='ripplex3-mint-nfts.js'></script>
<script src='ripplex4-transfer-nfts.js'></script>
<script src='ripplex5-broker-nfts.js'></script>
<script>
if (typeof module !== "undefined") {
const xrpl = require('xrpl')
}
</script>
<!-- ************************************************************** -->
<!-- ********************** The Form ****************************** -->
<!-- ************************************************************** -->
<body>
<h1>Token Test Harness</h1>
<form id="theForm">
Choose your ledger instance:
<input type="radio" id="tn" name="server"
value="wss://s.altnet.rippletest.net:51233" checked>
<label for="testnet">Testnet</label>
<input type="radio" id="dn" name="server"
value="wss://s.devnet.rippletest.net:51233">
<label for="devnet">Devnet</label>
<br/><br/>
<button type="button" onClick="getAccountsFromSeeds()">Get Accounts From Seeds</button>
<br/>
<textarea id="seeds" cols="40" rows= "3"></textarea>
<br/><br/>
<table align="center">
<tr valign="top">
<td>
<button type="button" onClick="getAccount('broker')">Get New Broker Account</button>
</td>
</tr>
<tr valign="top">
<td align="right">
Broker Account
</td>
<td>
<input type="text" id="brokerAccountField" size="40"></input>
<button type="button" id="another" onclick="brokerSale()">Broker Sale</button>
</td>
<td rowspan="7">
<textarea id="brokerResultField" cols="40" rows="12"></textarea>
</td>
</tr>
<tr>
<td align="right">
Public Key
</td>
<td>
<input type="text" id="brokerPubKeyField" size="40"></input>
<button type="button" onClick="brGetOffers()">Get Offers</button>
<br>
</td>
</tr>
<tr>
<td align="right">
Private Key
</td>
<td>
<input type="text" id="brokerPrivKeyField" size="40"></input>
<button type="button" onClick="brCancelOffer()">Cancel Offer</button>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
<br>
</td>
<td>
<input type="text" id="brokerSeedField" size="40"></input>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="brokerBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="brokerAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">NFT ID</td>
<td><input type="text" id="brokerTokenIdField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Sell NFT Offer Index</td>
<td><input type="text" id="brokerTokenSellOfferIndexField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Buy NFT Offer Index</td>
<td><input type="text" id="brokerTokenBuyOfferIndexField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Owner</td>
<td><input type="text" id="brokerOwnerField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Broker Fee</td>
<td><input type="text" id="brokerBrokerFeeField" value="" size="80"/></td>
</tr>
</table>
<br/><br/>
<table>
<tr valign="top">
<td>
<table>
<tr valign="top">
<td>
<td>
<button type="button" onClick="getAccount('standby')">Get New Standby Account</button>
<table>
<tr valign="top">
<td align="right">
Standby Account
</td>
<td>
<input type="text" id="standbyAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Public Key
</td>
<td>
<input type="text" id="standbyPubKeyField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Private Key
</td>
<td>
<input type="text" id="standbyPrivKeyField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="standbySeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="standbyBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="standbyAmountField" size="40"></input>
<br>
</td>
</tr>
<tr valign="top">
<td><button type="button" onClick="configureAccount('standby',document.querySelector('#standbyDefault').checked)">Configure Account</button></td>
<td>
<input type="checkbox" id="standbyDefault" checked="true"/>
<label for="standbyDefault">Allow Rippling</label>
</td>
</tr>
<tr>
<td align="right">
Currency
</td>
<td>
<input type="text" id="standbyCurrencyField" size="40" value="USD"></input>
</td>
</tr>
<tr>
<td align="right">NFT URL</td>
<td><input type="text" id="standbyTokenUrlField"
value = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" size="80"/>
</td>
</tr>
<tr>
<td align="right">Flags</td>
<td><input type="text" id="standbyFlagsField" value="1" size="10"/></td>
</tr>
<tr>
<td align="right">NFT ID</td>
<td><input type="text" id="standbyTokenIdField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">NFT Offer Index</td>
<td><input type="text" id="standbyTokenOfferIndexField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Owner</td>
<td><input type="text" id="standbyOwnerField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Destination</td>
<td><input type="text" id="standbyDestinationField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Expiration</td>
<td><input type="text" id="standbyExpirationField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Transfer Fee</td>
<td><input type="text" id="standbyTransferFeeField" value="" size="80"/></td>
</tr>
</table>
<p align="left">
<textarea id="standbyResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
<td>
<table>
<tr valign="top">
<td align="center" valign="top">
<button type="button" onClick="sendXRP()">Send XRP></button>
<br/><br/>
<button type="button" onClick="createTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="sendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
<br/><br/>
<button type="button" onClick="mintToken()">Mint NFT</button>
<br/>
<button type="button" onClick="getTokens()">Get NFTs</button>
<br/>
<button type="button" onClick="burnToken()">Burn NFT</button>
<br/><br/>
<button type="button" onClick="createSellOffer()">Create Sell Offer</button>
<br/>
<button type="button" onClick="acceptSellOffer()">Accept Sell Offer</button>
<br/>
<button type="button" onClick="createBuyOffer()">Create Buy Offer</button>
<br/>
<button type="button" onClick="acceptBuyOffer()">Accept Buy Offer</button>
<br/>
<button type="button" onClick="getOffers()">Get Offers</button>
<br/>
<button type="button" onClick="cancelOffer()">Cancel Offer</button>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>
<td>
<table>
<tr>
<td align="center" valign="top">
<button type="button" onClick="oPsendXRP()">< Send XRP</button>
<br/><br/>
<button type="button" onClick="oPcreateTrustline()">Create TrustLine</button>
<br/>
<button type="button" onClick="oPsendCurrency()">Send Currency</button>
<br/>
<button type="button" onClick="getBalances()">Get Balances</button>
<br/><br/>
<button type="button" onClick="oPmintToken()">Mint NFT</button>
<br/>
<button type="button" onClick="oPgetTokens()">Get NFTs</button>
<br/>
<button type="button" onClick="oPburnToken()">Burn NFT</button>
<br/><br/>
<button type="button" onClick="oPcreateSellOffer()">Create Sell Offer</button>
<br/>
<button type="button" onClick="oPacceptSellOffer()">Accept Sell Offer</button>
<br/>
<button type="button" onClick="oPcreateBuyOffer()">Create Buy Offer</button>
<br/>
<button type="button" onClick="oPacceptBuyOffer()">Accept Buy Offer</button>
<br/>
<button type="button" onClick="oPgetOffers()">Get Offers</button>
<br/>
<button type="button" onClick="oPcancelOffer()">Cancel Offer</button>
</td>
<td valign="top" align="right">
<button type="button" onClick="getAccount('operational')">Get New Operational Account</button>
<table>
<tr valign="top">
<td align="right">
Operational Account
</td>
<td>
<input type="text" id="operationalAccountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Public Key
</td>
<td>
<input type="text" id="operationalPubKeyField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Private Key
</td>
<td>
<input type="text" id="operationalPrivKeyField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Seed
</td>
<td>
<input type="text" id="operationalSeedField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
XRP Balance
</td>
<td>
<input type="text" id="operationalBalanceField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td align="right">
Amount
</td>
<td>
<input type="text" id="operationalAmountField" size="40"></input>
<br>
</td>
</tr>
<tr>
<td>
</td>
<td align="right"> <input type="checkbox" id="operationalDefault" checked="true"/>
<label for="operationalDefault">Allow Rippling</label>
<button type="button" onClick="configureAccount('operational',document.querySelector('#operationalDefault').checked)">Configure Account</button>
</td>
</tr>
<tr>
<td align="right">
Currency
</td>
<td>
<input type="text" id="operationalCurrencyField" size="40" value="USD"></input>
</td>
</tr>
<tr>
<td align="right">NFT URL</td>
<td><input type="text" id="operationalTokenUrlField"
value = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf4dfuylqabf3oclgtqy55fbzdi" size="80"/>
</td>
</tr>
<tr>
<td align="right">Flags</td>
<td><input type="text" id="operationalFlagsField" value="1" size="10"/></td>
</tr>
<tr>
<td align="right">NFT ID</td>
<td><input type="text" id="operationalTokenIdField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">NFT Offer Index</td>
<td><input type="text" id="operationalTokenOfferIndexField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Owner</td>
<td><input type="text" id="operationalOwnerField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Destination</td>
<td><input type="text" id="operationalDestinationField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Expiration</td>
<td><input type="text" id="operationalExpirationField" value="" size="80"/></td>
</tr>
<tr>
<td align="right">Transfer Fee</td>
<td><input type="text" id="operationalTransferFeeField" value="" size="80"/></td>
</tr>
</table>
<p align="right">
<textarea id="operationalResultField" cols="80" rows="20" ></textarea>
</p>
</td>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>