Highlander •
Building a Ripple Dapp (XRP)

Building a Ripple Dapp (XRP)
Let's build a basic send and receive ripple Dapp.
(tutorial is dependent on a 2.0+ release of keepkey-desktop.)
This Dapp is live, (guide)
In this tutorial, we will create an application that sends and receives the cryptocurrency XRP. This exercise will demonstrate how quickly and easily multi-chain applications can be developed on KeepKey using the KeepKey Desktop Application.
Straight to the code: https://github.com/BitHighlander/ripple-dapp
Technologies Used
- GitHub: GitHub is an open source version control system for tracking changes in source code. It is used by millions of developers and businesses to store and share their code, manage projects, and collaborate with other developers.
- Vercel.io: Vercel is a cloud platform for hosting front-end applications. It provides a simple and intuitive platform to deploy React apps quickly and easily.
- KeepKey SDK: KeepKey SDK is an open-source software development kit for building with KeepKey hardware wallet.
- Pioneer API/SDK: The Pioneer API/SDK is a toolkit for building blockchain applications and services. It provides tools for developers to quickly and easily build blockchain apps, such as wallets, exchanges, and dapps.
- XRPL: xrpl is a npm package that leverages public ripple infrastructure.
git clone https://github.com/BitHighlander/dapp-template ripple-dapp
KeepKey Dapp Template
To use this tutorial we start from the example template repo.
git clone https://github.com/BitHighlander/dapp-template dash-dapp
- Clone the project:
git clone https://github.com/BitHighlander/dapp-template dash-dapp
- Remove the template repo from upstream:
git remote rm origin
- Push to our own GitHub:
If you are using an IDE like WebStorm or VSCode, simply open the new dash-dapp directory in your IDE here.
Now push as a new project to GitHub.
WebStorm:

Push new Branch as master.
Git commands:
git remote add origin <our_repo_url> git push origin master
Let's Start Building
Now build:
yarn && yarn dev
Run this app, and connect your KeepKey. Set up a wallet if you haven't already.
KeepKey SDK
Now we need the application to load the users’ XRP balances on startup. To do this, we will import the KeepKey SDK. We will use the API call
getPubkeys
We use the SDK to get the publicKey for Dash:
//init let sdk try { sdk = await KeepKeySdk.create(configKeepKey) localStorage.setItem("apiKey", configKeepKey.apiKey); console.log("config: ", configKeepKey.apiKey) } catch (e) { setKeepKeyError('Bridge is offline!') }
First, we check if the KeepKey Desktop is running.
Setting Up Wallet
Now we import all the state vars we will need for this wallet:
//State vars const [address, setAddress] = useState('') const [balance, setBalance] = useState('0.000') const [amount, setAmount] = useState('0.00000000') const [toAddress, setToAddress] = useState('') const [txid, setTxid] = useState(null) const [signedTx, setSignedTx] = useState(null) const [keepkeyConnected, setKeepKeyConnected] = useState(false) const [keepkeyError, setKeepKeyError] = useState('') const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) const { isOpen, onOpen, onClose } = useDisclosure()
These are all generic params for any wallet. We add XRP specific next:
const [sequence, setSequence] = useState('0') const [ledgerIndexCurrent, setLedgerIndexCurrent] = useState('')
First, we get an XRP address:
//Unsigned TX let addressInfo = { addressNList: [2147483692, 2147483792, 2147483648, 0, 0], coin: 'Bitcoin', scriptType: 'p2wpkh', showDisplay: false } //rippleGetAddress let address = await sdk.address.xrpGetAddress({ address_n: addressInfo.addressNList }) console.log("address: ", address) setAddress(address)
Now we use xrpl to get Ripple network info:
let client = new xrpl.Client("wss://xrplcluster.com/") await client.connect() console.log("checkpoint2") const ledgerIndexCurrent = await client.getLedgerIndex() console.log("ledgerIndexCurrent: ", ledgerIndexCurrent) setLedgerIndexCurrent(ledgerIndexCurrent) console.log("checkpoint3") const response = await client.request({ "command": "account_info", "account": address, "ledger_index": "validated" }) console.log("checkpoint4") console.log(response.result.account_data) let balance = response.result.account_data.Balance let sequence = response.result.account_data.Sequence console.log("sequence: ", sequence) //set balance setBalance(balance / 1000000) setSequence(sequence)
Now We Add to the onSend Function
let tx = { "type": "auth/StdTx", "value": { "fee": { "amount": [ { "amount": "1000", "denom": "drop" } ], "gas": "28000" }, "memo": "KeepKey", "msg": [ { "type": "ripple-sdk/MsgSend", "value": { "amount": [ { "amount": parseFloat(amount) * 1000000, "denom": "drop" } ], "from_address": fromAddress, "to_address": toAddress } } ], "signatures": null } } //Unsigned TX let unsignedTx = { "HDwalletPayload": { addressNList: [2147483692, 2147483792, 2147483648, 0, 0], tx: tx, flags: undefined, sequence, lastLedgerSequence: parseInt(ledgerIndexCurrent + 1000000000).toString(), payment: { amount: parseInt(amount * 1000000).toString(), destination: toAddress, destinationTag: "1234567890", }, }, "verbal": "Ripple transaction" } //push tx to api console.log("unsignedTx: ", JSON.stringify(unsignedTx.HDwalletPayload)) let responseSign = await sdk.xrp.xrpSignTransaction(unsignedTx.HDwalletPayload)
And After Signed We Broadcast the Transaction
const buffer = Buffer.from(signedTx, 'base64'); const bufString = buffer.toString('hex'); console.log("bufString", bufString) setLoading(true) const submitResponse = await client.submitAndWait(bufString) console.log("submitResponse: ", submitResponse) setLoading(false) setTxid(submitResponse.result.hash)
And finally, we add a URL link to lookup your signed and broadcasted transaction!
<small><a href='https://xrpl.org/require-destination-tags.html' target="_blank">more info</a></small>
View it live here.