Merge branch 'master' into feedback-widget

This commit is contained in:
Phu Pham
2023-05-18 11:00:08 -04:00
89 changed files with 5883 additions and 1077 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ __pycache__
out/
package-lock.json
yarn-error.log
/.idea

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/img/events/AMAs.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
assets/img/events/Conference.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

BIN
assets/img/events/Hackathons.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

BIN
assets/img/events/XRPLZone.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 KiB

View File

@@ -5,7 +5,7 @@ certifi==2022.12.7
cffi==1.15.0
colorama==0.4.4
cryptography==39.0.1
Django==3.2.18
Django==3.2.19
ECPy==1.2.5
h11==0.12.0
httpcore==0.13.6
@@ -20,7 +20,7 @@ qrcode==7.2
rfc3986==1.5.0
six==1.16.0
sniffio==1.2.0
sqlparse==0.4.2
sqlparse==0.4.4
typing-extensions==3.10.0.0
websockets==9.1
xrpl-py==1.1.1

View File

@@ -0,0 +1,3 @@
CLIENT="wss://s.altnet.rippletest.net/"
EXPLORER_NETWORK="testnet"
SEED="s████████████████████████████"

View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"printWidth": 150,
"tabWidth": 4,
"singleQuote": true,
"semi": true
}

View File

@@ -0,0 +1,24 @@
# Pre-requisites
To implement this tutorial you should have a basic understanding of JavaScript and Node.js. You should also have a basic idea about XRP Ledger. For more information, visit the [XRP Ledger Dev Portal](https://xrpl.org) and the [XRPL Learning Portal](https://learn.xrpl.org/) for videos, libraries, and other resources.
Follow the steps below to get started:
1. [Node.js](https://nodejs.org/en/download/) (v10.15.3 or higher)
2. Install [Yarn](https://yarnpkg.com/en/docs/install) (v1.17.3 or higher) or [NPM](https://www.npmjs.com/get-npm) (v6.4.1 or higher)
3. Add your Seed, Client, and specify testnet/mainnet in .env file. Example .env file is provided in the repo.
4. Run `yarn install` or `npm install` to install dependencies
5. Start the app with `yarn dev` or `npm dev`
# Goals
At the end of this tutorial, you should be able to build a simple XRP wallet that can:
- Shows updates to the XRP Ledger in real-time.
- Can view any XRP Ledger account's activity "read-only" including showing how much XRP was delivered by each transaction.
- Shows how much XRP is set aside for the account's reserve requirement.
- Can send direct XRP payments, and provides feedback about the intended destination address, including:
- Displays available balance in your account
- Verifies that the destination address is valid
- Validates amount input to ensure it is a valid number and that the account has enough XRP to send
- Allows addition of the destination tag

View File

@@ -0,0 +1,148 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: white;
cursor: pointer;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
min-width: 320px;
min-height: 100vh;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
}
.main_content {
display: flex;
flex-direction: column;
gap: 25px;
}
.main_logo {
align-self: center;
}
.logo_link {
align-self: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vanilla:hover {
filter: drop-shadow(0 0 2em #848080f5);
}
.wallet_details {
display: flex;
flex-direction: column;
gap: 5px;
padding: 20px;
border: 1px solid white;
border-radius: 10px;
}
.ledger_details, .send_xrp_container, .tx_history_container {
display: flex;
flex-direction: column;
gap: 5px;
padding: 20px;
border: 1px solid white;
border-radius: 10px;
}
.send_xrp_container label {
padding: 10px 0 0 0;
}
.invalid {
border: 1px solid red !important;
}
.send_xrp_container input {
padding: 10px;
border-radius: 10px;
border: 1px solid black;
background: lightgray;
color: black;
outline: none;
}
.heading_h3 {
font-size: 25px;
font-weight: bold;
padding: 0 0 10px 0;
}
.links {
display: flex;
gap: 12px;
}
button {
padding: 5px 12px;
background: inherit;
cursor: pointer;
border: 1px solid white;
border-radius: 10px;
font-size: 14px;
}
button:hover {
color: black;
background: white;
}
.submit_tx_button {
color: black;
background: white;
margin: 30px 0 0 0;
}
.submit_tx_button:disabled {
color: gray;
background: lightgray;
cursor: not-allowed;
}
.tx_history_data {
display: table;
text-align: center;
border-spacing: 10px;
}
.tx_history_data th {
border-bottom: 1px solid white;
padding: 0 0 5px 0;
}

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./src/assets/xrpl.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Simple XRPL Wallet</title>
<link rel="preload" href="./src/send-xrp/send-xrp.html">
<link rel="preload" href="./src/transaction-history/transaction-history.html">
<link rel="preload" href="index.css" as="style">
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="app">
<div class="main_content">
<div class="main_logo" id="heading_logo"></div>
<div class="links">
<button class="send_xrp" id="send_xrp_button">Send XRP</button>
<button class="transaction_history" id="transaction_history_button">Transaction History</button>
</div>
<div class="wallet_details" id="wallet">
<div class="heading_h3">Account Info:</div>
<div id="loading_wallet_details">Loading Wallet Details...</div>
<span class="wallet_address"></span>
<span class="wallet_balance"></span>
<span class="wallet_reserve"></span>
<span class="wallet_xaddress"></span>
<span class="view_more"><a id="view_more_button">View More</a></span>
</div>
<div class="ledger_details">
<div class="heading_h3">Latest Validated Ledger:</div>
<div id="loading_ledger_details">Loading Ledger Details...</div>
<span class="ledger_index" id="ledger_index"></span>
<span class="ledger_hash" id="ledger_hash"></span>
<span class="close_time" id="close_time"></span>
</div>
</div>
</div>
<script type="module" src="/index.js"></script>
</body>
</html>

View File

@@ -0,0 +1,71 @@
import { Client, dropsToXrp, rippleTimeToISOTime } from 'xrpl';
import addXrplLogo from './src/helpers/render-xrpl-logo';
import getWalletDetails from './src/helpers/get-wallet-details.js';
// Optional: Render the XRPL logo
addXrplLogo();
const client = new Client(process.env.CLIENT); // Get the client from the environment variables
// Get the elements from the DOM
const sendXrpButton = document.querySelector('#send_xrp_button');
const txHistoryButton = document.querySelector('#transaction_history_button');
const walletElement = document.querySelector('#wallet');
const walletLoadingDiv = document.querySelector('#loading_wallet_details');
const ledgerLoadingDiv = document.querySelector('#loading_ledger_details');
// Add event listeners to the buttons
sendXrpButton.addEventListener('click', () => {
window.location.pathname = '/src/send-xrp/send-xrp.html';
});
txHistoryButton.addEventListener('click', () => {
window.location.pathname = '/src/transaction-history/transaction-history.html';
});
// Self-invoking function to connect to the client
(async () => {
try {
await client.connect(); // Connect to the client
// Subscribe to the ledger stream
await client.request({
command: 'subscribe',
streams: ['ledger'],
});
// Fetch the wallet details
getWalletDetails({ client })
.then(({ account_data, accountReserves, xAddress, address }) => {
walletElement.querySelector('.wallet_address').textContent = `Wallet Address: ${account_data.Account}`;
walletElement.querySelector('.wallet_balance').textContent = `Wallet Balance: ${dropsToXrp(account_data.Balance)} XRP`;
walletElement.querySelector('.wallet_reserve').textContent = `Wallet Reserve: ${accountReserves} XRP`;
walletElement.querySelector('.wallet_xaddress').textContent = `X-Address: ${xAddress}`;
// Redirect on View More link click
walletElement.querySelector('#view_more_button').addEventListener('click', () => {
window.open(`https://${process.env.EXPLORER_NETWORK}.xrpl.org/accounts/${address}`, '_blank');
});
})
.finally(() => {
walletLoadingDiv.style.display = 'none';
});
// Fetch the latest ledger details
client.on('ledgerClosed', (ledger) => {
ledgerLoadingDiv.style.display = 'none';
const ledgerIndex = document.querySelector('#ledger_index');
const ledgerHash = document.querySelector('#ledger_hash');
const closeTime = document.querySelector('#close_time');
ledgerIndex.textContent = `Ledger Index: ${ledger.ledger_index}`;
ledgerHash.textContent = `Ledger Hash: ${ledger.ledger_hash}`;
closeTime.textContent = `Close Time: ${rippleTimeToISOTime(ledger.ledger_time)}`;
});
} catch (error) {
await client.disconnect();
console.log(error);
}
})();

View File

@@ -0,0 +1,21 @@
{
"name": "simple-xrpl-wallet",
"type": "module",
"scripts": {
"dev": "vite"
},
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
"crypto-browserify": "^3.12.0",
"events": "^3.3.0",
"https-browserify": "^1.0.0",
"rollup-plugin-polyfill-node": "^0.12.0",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"vite": "^4.1.0"
},
"dependencies": {
"dotenv": "^16.0.3",
"xrpl": "^2.7.0-beta.2"
}
}

View File

@@ -0,0 +1,20 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="1.0 (4035a4fb49, 2020-05-01)" sodipodi:docname="XRPLedger_DevPortal-white.svg" id="svg991" version="1.1" fill="none" viewBox="0 0 468 116" height="116" width="468">
<metadata id="metadata997">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs id="defs995"/>
<sodipodi:namedview inkscape:current-layer="svg991" inkscape:window-maximized="1" inkscape:window-y="1" inkscape:window-x="0" inkscape:cy="58" inkscape:cx="220.57619" inkscape:zoom="2.8397436" inkscape:pagecheckerboard="true" showgrid="false" id="namedview993" inkscape:window-height="1028" inkscape:window-width="1920" inkscape:pageshadow="2" inkscape:pageopacity="0" guidetolerance="10" gridtolerance="10" objecttolerance="10" borderopacity="1" bordercolor="#666666" pagecolor="#ffffff"/>
<g style="opacity:1" id="g989" opacity="0.9">
<path style="opacity:1" id="path979" fill="white" d="M191.43 51.8301L197.43 39.7701H207.5L197.29 57.7701L207.76 76.1901H197.66L191.57 63.8701L185.47 76.1901H175.4L185.87 57.7701L175.66 39.7701H185.74L191.43 51.8301ZM223.5 63.2201H218.73V76.0801H210V39.7701H224.3C228.67 39.7701 231.98 40.7001 234.37 42.6901C235.58 43.6506 236.546 44.8828 237.191 46.2866C237.835 47.6905 238.14 49.2265 238.08 50.7701C238.155 52.9971 237.605 55.2005 236.49 57.1301C235.322 58.9247 233.668 60.3501 231.72 61.2401L239.27 75.9401V76.3401H229.86L223.5 63.2201ZM218.86 56.4701H224.43C225.109 56.5414 225.795 56.4589 226.437 56.2286C227.079 55.9984 227.661 55.6263 228.14 55.1401C229.022 54.1082 229.492 52.7871 229.46 51.4301C229.509 50.754 229.416 50.0752 229.189 49.4366C228.962 48.798 228.605 48.2135 228.14 47.7201C227.653 47.2459 227.07 46.8825 226.429 46.6547C225.789 46.4269 225.107 46.34 224.43 46.4001H218.86V56.4701ZM251.73 63.7501V76.0801H243V39.7701H257.58C260.143 39.7175 262.683 40.2618 265 41.3601C267.03 42.3389 268.758 43.8489 270 45.7301C271.199 47.6808 271.797 49.9415 271.72 52.2301C271.773 53.8434 271.455 55.4474 270.789 56.9179C270.123 58.3884 269.128 59.6859 267.88 60.7101C265.36 62.8301 261.88 63.8901 257.41 63.8901H251.72L251.73 63.7501ZM251.73 57.0001H257.42C258.12 57.0708 258.827 56.9885 259.491 56.7588C260.156 56.5292 260.763 56.1577 261.27 55.6701C261.742 55.209 262.106 54.6484 262.334 54.0291C262.563 53.4098 262.65 52.7474 262.59 52.0901C262.68 50.6061 262.209 49.1425 261.27 47.9901C260.812 47.4622 260.24 47.0449 259.597 46.7695C258.955 46.4941 258.258 46.3678 257.56 46.4001H251.73V57.0001ZM296.73 69.4501H312V76.2101H287.9V39.7701H296.65V69.4501H296.73ZM337.81 60.7101H324.07V69.4501H340.37V76.2101H315.37V39.7701H340.55V46.5301H324.25V54.2101H337.9L337.81 60.7101ZM343.37 76.0801V39.7701H355.16C358.25 39.7375 361.295 40.5058 364 42.0001C366.568 43.4425 368.655 45.6093 370 48.2301C371.442 50.9709 372.216 54.0134 372.26 57.1101V58.8301C372.324 61.9609 371.595 65.0569 370.14 67.8301C368.731 70.4528 366.622 72.6337 364.048 74.1306C361.475 75.6275 358.537 76.3819 355.56 76.3101H343.42L343.37 76.0801ZM352.12 46.5301V69.4501H355.12C356.241 69.5121 357.36 69.3038 358.383 68.8426C359.407 68.3814 360.304 67.6809 361 66.8001C362.333 64.9534 363 62.3034 363 58.8501V57.2601C363 53.6801 362.333 51.0301 361 49.3101C360.287 48.4178 359.37 47.7109 358.325 47.2495C357.28 46.7881 356.14 46.5859 355 46.6601H352.09L352.12 46.5301ZM405.83 71.7001C404.158 73.3731 402.096 74.6035 399.83 75.2801C397.058 76.2148 394.145 76.6647 391.22 76.6101C386.45 76.6101 382.6 75.1501 379.82 72.2301C377.04 69.3101 375.45 65.2301 375.18 60.0401V56.8601C375.131 53.6307 375.765 50.4274 377.04 47.4601C378.217 44.9066 380.101 42.7443 382.47 41.2301C384.959 39.7722 387.806 39.038 390.69 39.1101C395.19 39.1101 398.77 40.1701 401.29 42.2901C403.81 44.4101 405.29 47.4601 405.66 51.5601H397.18C397.066 49.909 396.355 48.3558 395.18 47.1901C394.003 46.2386 392.51 45.7671 391 45.8701C389.971 45.8449 388.953 46.0881 388.047 46.5755C387.14 47.0629 386.376 47.7779 385.83 48.6501C384.465 51.0865 383.823 53.8617 383.98 56.6501V58.9001C383.98 62.4801 384.64 65.2601 385.83 67.1201C387.02 68.9801 389.01 69.9001 391.66 69.9001C393.521 70.0287 395.363 69.4621 396.83 68.3101V62.6101H390.74V56.6101H405.58V71.7001H405.83ZM433 60.7001H419.22V69.4401H435.51V76.2001H410.51V39.7701H435.69V46.5301H419.39V54.2101H433.17V60.7101L433 60.7001ZM452.21 63.2101H447.44V76.0801H438.56V39.7701H452.87C457.25 39.7701 460.56 40.7001 462.94 42.6901C464.152 43.649 465.119 44.8809 465.764 46.2851C466.409 47.6893 466.712 49.2261 466.65 50.7701C466.725 52.9971 466.175 55.2005 465.06 57.1301C463.892 58.9247 462.238 60.3501 460.29 61.2401L467.85 75.9401V76.3401H458.44L452.21 63.2101ZM447.44 56.4601H453C453.679 56.5314 454.365 56.4489 455.007 56.2186C455.649 55.9884 456.231 55.6163 456.71 55.1301C457.579 54.0965 458.038 52.7798 458 51.4301C458.046 50.7542 457.953 50.0761 457.726 49.4378C457.499 48.7996 457.143 48.2149 456.68 47.7201C456.197 47.2499 455.618 46.8888 454.983 46.6611C454.348 46.4334 453.672 46.3444 453 46.4001H447.43L447.44 56.4601Z" opacity="0.9"/>
<path style="opacity:1" id="path981" fill="white" d="M35.4 7.20001H38.2V8.86606e-06H35.4C32.4314 -0.00262172 29.4914 0.580149 26.7482 1.71497C24.0051 2.8498 21.5126 4.5144 19.4135 6.61353C17.3144 8.71266 15.6498 11.2051 14.515 13.9483C13.3801 16.6914 12.7974 19.6314 12.8 22.6V39C12.806 42.4725 11.4835 45.8158 9.10354 48.3445C6.72359 50.8732 3.46651 52.3957 0 52.6L0.2 56.2L0 59.8C3.46651 60.0043 6.72359 61.5268 9.10354 64.0555C11.4835 66.5842 12.806 69.9275 12.8 73.4V92.3C12.7894 98.5716 15.2692 104.591 19.6945 109.035C24.1198 113.479 30.1284 115.984 36.4 116V108.8C32.0513 108.797 27.8814 107.069 24.8064 103.994C21.7314 100.919 20.0026 96.7487 20 92.4V73.4C20.003 70.0079 19.1752 66.6667 17.5889 63.6684C16.0026 60.6701 13.706 58.1059 10.9 56.2C13.698 54.286 15.9885 51.7202 17.5738 48.7237C19.1592 45.7272 19.9918 42.39 20 39V22.6C20.0184 18.5213 21.6468 14.615 24.5309 11.7309C27.415 8.84683 31.3213 7.21842 35.4 7.20001V7.20001Z" opacity="0.9"/>
<path style="opacity:1" id="path983" fill="white" d="M118.6 7.2H115.8V0H118.6C124.58 0.0158944 130.309 2.40525 134.528 6.643C138.747 10.8808 141.111 16.6202 141.1 22.6V39C141.094 42.4725 142.416 45.8158 144.796 48.3445C147.176 50.8732 150.433 52.3957 153.9 52.6L153.7 56.2L153.9 59.8C150.433 60.0043 147.176 61.5268 144.796 64.0555C142.416 66.5842 141.094 69.9275 141.1 73.4V92.3C141.111 98.5716 138.631 104.591 134.206 109.035C129.78 113.479 123.772 115.984 117.5 116V108.8C121.849 108.797 126.019 107.069 129.094 103.994C132.169 100.919 133.897 96.7487 133.9 92.4V73.4C133.897 70.0079 134.725 66.6667 136.311 63.6684C137.897 60.6701 140.194 58.1059 143 56.2C140.202 54.286 137.911 51.7201 136.326 48.7237C134.741 45.7272 133.908 42.39 133.9 39V22.6C133.911 20.5831 133.523 18.584 132.759 16.7173C131.995 14.8507 130.87 13.1533 129.448 11.7225C128.027 10.2916 126.337 9.1556 124.475 8.37952C122.613 7.60345 120.617 7.20261 118.6 7.2V7.2Z" opacity="0.9"/>
<path style="opacity:1" id="path985" fill="white" d="M103.2 29H113.9L91.6 49.9C87.599 53.5203 82.3957 55.525 77 55.525C71.6042 55.525 66.4009 53.5203 62.4 49.9L40.1 29H50.8L67.7 44.8C70.2237 47.1162 73.5245 48.4013 76.95 48.4013C80.3754 48.4013 83.6763 47.1162 86.2 44.8L103.2 29Z" opacity="0.9"/>
<path style="opacity:1" id="path987" fill="white" d="M50.7 87H40L62.4 66C66.3788 62.3351 71.5905 60.3007 77 60.3007C82.4095 60.3007 87.6212 62.3351 91.6 66L114 87H103.3L86.3 71C83.7763 68.6838 80.4755 67.3987 77.05 67.3987C73.6245 67.3987 70.3237 68.6838 67.8 71L50.7 87Z" opacity="0.9"/>
</g>
<script xmlns=""/></svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,44 @@
import { Client, Wallet, classicAddressToXAddress } from 'xrpl';
export default async function getWalletDetails({ client }) {
try {
const wallet = Wallet.fromSeed(process.env.SEED); // Convert the seed to a wallet : https://xrpl.org/cryptographic-keys.html
// Get the wallet details: https://xrpl.org/account_info.html
const {
result: { account_data },
} = await client.request({
command: 'account_info',
account: wallet.address,
ledger_index: 'validated',
});
const ownerCount = account_data.OwnerCount || 0;
// Get the reserve base and increment
const {
result: {
info: {
validated_ledger: { reserve_base_xrp, reserve_inc_xrp },
},
},
} = await client.request({
command: 'server_info',
});
// Calculate the reserves by multiplying the owner count by the increment and adding the base reserve to it.
const accountReserves = ownerCount * reserve_inc_xrp + reserve_base_xrp;
console.log('Got wallet details!');
return {
account_data,
accountReserves,
xAddress: classicAddressToXAddress(wallet.address, false, false), // Learn more: https://xrpaddress.info/
address: wallet.address
};
} catch (error) {
console.log('Error getting wallet details', error);
return error;
}
}

View File

@@ -0,0 +1,13 @@
import xrplLogo from '../assets/xrpl.svg';
export default function renderXrplLogo() {
document.getElementById('heading_logo').innerHTML = `
<a
href="https://xrpl.org/"
target="_blank"
class="logo_link"
>
<img id="xrpl_logo" class="logo vanilla" alt="XRPL logo" src="${xrplLogo}" />
</a>
`;
}

View File

@@ -0,0 +1,18 @@
import { Wallet } from 'xrpl';
export default async function submitTransaction({ client, tx }) {
try {
// Create a wallet using the seed
const wallet = await Wallet.fromSeed(process.env.SEED);
tx.Account = wallet.address;
// Sign and submit the transaction : https://xrpl.org/send-xrp.html#send-xrp
const response = await client.submit(tx, { wallet });
console.log(response);
return response;
} catch (error) {
console.log(error);
return null;
}
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="../assets/xrpl.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Simple XRPL Wallet</title>
<link rel="preload" href="../../index.css" as="style">
<link rel="stylesheet" href="../../index.css">
</head>
<body>
<div id="app">
<div class="main_content">
<div class="main_logo" id="heading_logo"></div>
<div class="links">
<button class="home" id="home_button">Home</button>
<button class="transaction_history" id="transaction_history_button">Transaction History</button>
</div>
<div class="send_xrp_container">
<div class="heading_h3">Send XRP</div>
<div class="available_balance" id="available_balance"></div>
<label for="destination_address">Destination Address:</label>
<input type="text" id="destination_address" placeholder="Destination Address" maxlength="35" />
<span class="isvalid_destination_address" id="isvalid_destination_address"></span>
<label for="amount">Amount:</label>
<input type="text" id="amount" placeholder="Amount" type="mobile" />
<label for="destination_tag">Destination Tag:</label>
<input type="text" id="destination_tag" placeholder="Destination Tag" />
<button class="submit_tx_button" id="submit_tx_button">Submit Transaction</button>
</div>
</div>
</div>
<script type="module" src="./send-xrp.js"></script>
</body>
</html>

View File

@@ -0,0 +1,146 @@
import { Client, Wallet, dropsToXrp, isValidClassicAddress, xrpToDrops } from 'xrpl';
import getWalletDetails from '../helpers/get-wallet-details';
import renderXrplLogo from '../helpers/render-xrpl-logo';
import submitTransaction from '../helpers/submit-transaction';
// Optional: Render the XRPL logo
renderXrplLogo();
const client = new Client(process.env.CLIENT); // Get the client from the environment variables
// Self-invoking function to connect to the client
(async () => {
try {
await client.connect(); // Connect to the client
const wallet = Wallet.fromSeed(process.env.SEED); // Convert the seed to a wallet : https://xrpl.org/cryptographic-keys.html
// Subscribe to account transaction stream
await client.request({
command: 'subscribe',
accounts: [wallet.address],
});
// Fetch the wallet details and show the available balance
await getWalletDetails({ client }).then(({ accountReserves, account_data }) => {
availableBalanceElement.textContent = `Available Balance: ${dropsToXrp(account_data.Balance) - accountReserves} XRP`;
});
} catch (error) {
await client.disconnect();
console.log(error);
}
})();
// Get the elements from the DOM
const homeButton = document.querySelector('#home_button');
const txHistoryButton = document.querySelector('#transaction_history_button');
const destinationAddress = document.querySelector('#destination_address');
const amount = document.querySelector('#amount');
const destinationTag = document.querySelector('#destination_tag');
const submitTxBtn = document.querySelector('#submit_tx_button');
const availableBalanceElement = document.querySelector('#available_balance');
// Disable the submit button by default
submitTxBtn.disabled = true;
let isValidDestinationAddress = false;
const allInputs = document.querySelectorAll('#destination_address, #amount');
// Add event listener to the redirect buttons
homeButton.addEventListener('click', () => {
window.location.pathname = '/index.html';
});
txHistoryButton.addEventListener('click', () => {
window.location.pathname = '/src/transaction-history/transaction-history.html';
});
// Update the account balance on successful transaction
client.on('transaction', (response) => {
if (response.validated && response.transaction.TransactionType === 'Payment') {
getWalletDetails({ client }).then(({ accountReserves, account_data }) => {
availableBalanceElement.textContent = `Available Balance: ${dropsToXrp(account_data.Balance) - accountReserves} XRP`;
});
}
});
const validateAddress = () => {
destinationAddress.value = destinationAddress.value.trim();
// Check if the address is valid
if (isValidClassicAddress(destinationAddress.value)) {
// Remove the invalid class if the address is valid
destinationAddress.classList.remove('invalid');
isValidDestinationAddress = true;
} else {
// Add the invalid class if the address is invalid
isValidDestinationAddress = false;
destinationAddress.classList.add('invalid');
}
};
// Add event listener to the destination address
destinationAddress.addEventListener('input', validateAddress);
// Add event listener to the amount input
amount.addEventListener('keydown', (event) => {
const codes = [8, 190];
const regex = /^[0-9\b.]+$/;
// Allow: backspace, delete, tab, escape, enter and .
if (!(regex.test(event.key) || codes.includes(event.keyCode))) {
event.preventDefault();
return false;
}
return true;
});
// NOTE: Keep this code at the bottom of the other input event listeners
// All the inputs should have a value to enable the submit button
for (let i = 0; i < allInputs.length; i++) {
allInputs[i].addEventListener('input', () => {
let values = [];
allInputs.forEach((v) => values.push(v.value));
submitTxBtn.disabled = !isValidDestinationAddress || values.includes('');
});
}
// Add event listener to the submit button
submitTxBtn.addEventListener('click', async () => {
try {
console.log('Submitting transaction');
submitTxBtn.disabled = true;
submitTxBtn.textContent = 'Submitting...';
// Create the transaction object: https://xrpl.org/transaction-common-fields.html
const txJson = {
TransactionType: 'Payment',
Amount: xrpToDrops(amount.value), // Convert XRP to drops: https://xrpl.org/basic-data-types.html#specifying-currency-amounts
Destination: destinationAddress.value,
};
// Get the destination tag if it exists
if (destinationTag?.value !== '') {
txJson.DestinationTag = destinationTag.value;
}
// Submit the transaction to the ledger
const { result } = await submitTransaction({ client, tx: txJson });
const txResult = result?.meta?.TransactionResult || result?.engine_result || ''; // Response format: https://xrpl.org/transaction-results.html
// Check if the transaction was successful or not and show the appropriate message to the user
if (txResult === 'tesSUCCESS') {
alert('Transaction submitted successfully!');
} else {
throw new Error(txResult);
}
} catch (error) {
alert('Error submitting transaction, Please try again.');
console.error(error);
} finally {
// Re-enable the submit button after the transaction is submitted so the user can submit another transaction
submitTxBtn.disabled = false;
submitTxBtn.textContent = 'Submit Transaction';
}
});

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="../assets/xrpl.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Simple XRPL Wallet</title>
<link rel="preload" href="../../index.css" as="style">
<link rel="stylesheet" href="../../index.css">
</head>
<body>
<div id="app">
<div class="main_content">
<div class="main_logo" id="heading_logo"></div>
<div class="links">
<button class="home" id="home_button">Home</button>
<button class="send_xrp" id="send_xrp_button">Send XRP</button>
</div>
<div class="tx_history_container">
<div class="heading_h3">Transaction History</div>
<div class="tx_history_data" id="tx_history_data"></div>
<button class="load_more_button" id="load_more_button">Load More</button>
</div>
</div>
</div>
<script type="module" src="./transaction-history.js"></script>
</body>
</html>

View File

@@ -0,0 +1,146 @@
import { Client, Wallet, convertHexToString, dropsToXrp } from 'xrpl';
import renderXrplLogo from '../helpers/render-xrpl-logo';
// Optional: Render the XRPL logo
renderXrplLogo();
// Declare the variables
let marker = null;
// Get the elements from the DOM
const txHistoryElement = document.querySelector('#tx_history_data');
const sendXrpButton = document.querySelector('#send_xrp_button');
const homeButton = document.querySelector('#home_button');
const loadMore = document.querySelector('#load_more_button');
// Add event listeners to the buttons
sendXrpButton.addEventListener('click', () => {
window.location.pathname = '/src/send-xrp/send-xrp.html';
});
homeButton.addEventListener('click', () => {
window.location.pathname = '/index.html';
});
// Add the header to the table
const header = document.createElement('tr');
header.innerHTML = `
<th>Account</th>
<th>Destination</th>
<th>Fee (XRP)</th>
<th>Amount</th>
<th>Transaction Type</th>
<th>Result</th>
<th>Link</th>
`;
txHistoryElement.appendChild(header);
// Converts the hex value to a string
const getTokenName = (value) => (value.length === 40 ? convertHexToString(value).replaceAll('\u0000', '') : value);
function renderTokenValueColumn(value) {
return value.Amount
? `<td>${
typeof value.Amount === 'object' ? `${value.Amount.value} ${getTokenName(value.Amount.currency)}` : `${dropsToXrp(value.Amount)} XRP`
}</td>`
: '-';
}
// Fetches the transaction history from the ledger
async function fetchTxHistory() {
try {
loadMore.textContent = 'Loading...';
loadMore.disabled = true;
const wallet = Wallet.fromSeed(process.env.SEED);
const client = new Client(process.env.CLIENT);
// Wait for the client to connect
await client.connect();
// Get the transaction history
const payload = {
command: 'account_tx',
account: wallet.address,
limit: 10,
};
if (marker) {
payload.marker = marker;
}
// Wait for the response: use the client.request() method to send the payload
const { result } = await client.request(payload);
const { transactions, marker: nextMarker } = result;
// Add the transactions to the table
const values = transactions.map((transaction) => {
const { meta, tx } = transaction;
return {
Account: tx.Account,
Destination: tx.Destination,
Fee: tx.Fee,
Amount: tx.Amount,
Hash: tx.hash,
TransactionType: tx.TransactionType,
result: meta?.TransactionResult,
};
});
// If there are no more transactions, hide the load more button
loadMore.style.display = nextMarker ? 'block' : 'none';
// If there are no transactions, show a message
// Create a new row: https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
// Add the row to the table: https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild
if (values.length === 0) {
const row = document.createElement('tr');
row.innerHTML = `<td colspan="6">No transactions found</td>`;
txHistoryElement.appendChild(row);
} else {
// Otherwise, show the transactions by iterating over each transaction and adding it to the table
values.forEach((value) => {
const row = document.createElement('tr');
// Add the transaction details to the row
row.innerHTML = `
${value.Account ? `<td>${value.Account}</td>` : '-'}
${value.Destination ? `<td>${value.Destination}</td>` : '-'}
${value.Fee ? `<td>${dropsToXrp(value.Fee)}</td>` : '-'}
${renderTokenValueColumn(value)}
${value.TransactionType ? `<td>${value.TransactionType}</td>` : '-'}
${value.result ? `<td>${value.result}</td>` : '-'}
${value.Hash ? `<td><a href="https://${process.env.EXPLORER_NETWORK}.xrpl.org/transactions/${value.Hash}" target="_blank">View</a></td>` : '-'}`;
// Add the row to the table
txHistoryElement.appendChild(row);
});
}
// Disconnect
await client.disconnect();
// Enable the load more button only if there are more transactions
loadMore.textContent = 'Load More';
loadMore.disabled = false;
// Return the marker
return nextMarker ?? null;
} catch (error) {
console.log(error);
return null;
}
}
// Render the transaction history
async function renderTxHistory() {
// Fetch the transaction history
marker = await fetchTxHistory();
loadMore.addEventListener('click', async () => {
const nextMarker = await fetchTxHistory();
marker = nextMarker;
});
}
// Call the renderTxHistory() function
renderTxHistory();

View File

@@ -0,0 +1,43 @@
import { defineConfig, loadEnv } from 'vite';
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
import polyfillNode from 'rollup-plugin-polyfill-node';
const viteConfig = ({ mode }) => {
process.env = { ...process.env, ...loadEnv(mode, '', '') };
return defineConfig({
define: {
'process.env': process.env,
},
optimizeDeps: {
esbuildOptions: {
define: {
global: 'globalThis',
},
plugins: [
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
}),
],
},
},
build: {
rollupOptions: {
plugins: [polyfillNode()],
},
},
resolve: {
alias: {
events: 'events',
crypto: 'crypto-browserify',
stream: 'stream-browserify',
http: 'stream-http',
https: 'https-browserify',
ws: 'xrpl/dist/npm/client/WSWrapper',
},
},
});
};
export default viteConfig;

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,26 @@
// Construct a network client
HttpUrl rippledUrl = HttpUrl
.get("https://s.altnet.rippletest.net:51234/");
HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/");
System.out.println("Constructing an XrplClient connected to " + rippledUrl);
XrplClient xrplClient = new XrplClient(rippledUrl);
// Create a Wallet using a WalletFactory
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
Wallet testWallet = walletFactory.randomWallet(true).wallet();
// Create a random KeyPair
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
System.out.println("Generated KeyPair: " + randomKeyPair);
// Get the Classic and X-Addresses from testWallet
Address classicAddress = testWallet.classicAddress();
XAddress xAddress = testWallet.xAddress();
// Derive the Classic and X-Addresses from testWallet
Address classicAddress = randomKeyPair.publicKey().deriveAddress();
XAddress xAddress = AddressCodec.getInstance().classicAddressToXAddress(classicAddress, true);
System.out.println("Classic Address: " + classicAddress);
System.out.println("X-Address: " + xAddress);
// Fund the account using the testnet Faucet
FaucetClient faucetClient = FaucetClient
.construct(HttpUrl.get("https://faucet.altnet.rippletest.net"));
FaucetClient faucetClient = FaucetClient.construct(HttpUrl.get("https://faucet.altnet.rippletest.net"));
faucetClient.fundAccount(FundAccountRequest.of(classicAddress));
System.out.println("Funded the account using the Testnet faucet.");
// Look up your Account Info
AccountInfoRequestParams requestParams =
AccountInfoRequestParams.of(classicAddress);
AccountInfoResult accountInfoResult =
xrplClient.accountInfo(requestParams);
AccountInfoRequestParams requestParams = AccountInfoRequestParams.of(classicAddress);
AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams);
// Print the result
System.out.println(accountInfoResult);

View File

@@ -4,21 +4,22 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
import okhttp3.HttpUrl;
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
import org.xrpl.xrpl4j.client.XrplClient;
import org.xrpl.xrpl4j.client.faucet.FaucetClient;
import org.xrpl.xrpl4j.client.faucet.FundAccountRequest;
import org.xrpl.xrpl4j.crypto.KeyMetadata;
import org.xrpl.xrpl4j.crypto.PrivateKey;
import org.xrpl.xrpl4j.crypto.keys.KeyPair;
import org.xrpl.xrpl4j.crypto.keys.PrivateKey;
import org.xrpl.xrpl4j.crypto.keys.Seed;
import org.xrpl.xrpl4j.crypto.signing.SignatureService;
import org.xrpl.xrpl4j.crypto.signing.SignedTransaction;
import org.xrpl.xrpl4j.crypto.signing.SingleKeySignatureService;
import org.xrpl.xrpl4j.crypto.signing.SingleSignedTransaction;
import org.xrpl.xrpl4j.crypto.signing.bc.BcSignatureService;
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoRequestParams;
import org.xrpl.xrpl4j.model.client.accounts.AccountLinesRequestParams;
import org.xrpl.xrpl4j.model.client.accounts.TrustLine;
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
import org.xrpl.xrpl4j.model.client.fees.FeeResult;
import org.xrpl.xrpl4j.model.client.ledger.LedgerRequestParams;
import org.xrpl.xrpl4j.model.client.transactions.TransactionRequestParams;
@@ -29,9 +30,6 @@ import org.xrpl.xrpl4j.model.transactions.ImmutableTrustSet;
import org.xrpl.xrpl4j.model.transactions.IssuedCurrencyAmount;
import org.xrpl.xrpl4j.model.transactions.Payment;
import org.xrpl.xrpl4j.model.transactions.TrustSet;
import org.xrpl.xrpl4j.wallet.DefaultWalletFactory;
import org.xrpl.xrpl4j.wallet.Wallet;
import org.xrpl.xrpl4j.wallet.WalletFactory;
import java.util.List;
@@ -47,16 +45,15 @@ public class IssueToken {
FeeResult feeResult = xrplClient.fee();
// Create cold and hot Wallets using a WalletFactory -----------------------
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
Wallet coldWallet = walletFactory.randomWallet(true).wallet();
Wallet hotWallet = walletFactory.randomWallet(true).wallet();
// Create cold and hot KeyPairs -----------------------
KeyPair coldWalletKeyPair = Seed.ed25519Seed().deriveKeyPair();
KeyPair hotWalletKeyPair = Seed.ed25519Seed().deriveKeyPair();
// Fund the account using the testnet Faucet -------------------------------
FaucetClient faucetClient = FaucetClient
.construct(HttpUrl.get("https://faucet.altnet.rippletest.net"));
faucetClient.fundAccount(FundAccountRequest.of(coldWallet.classicAddress()));
faucetClient.fundAccount(FundAccountRequest.of(hotWallet.classicAddress()));
faucetClient.fundAccount(FundAccountRequest.of(coldWalletKeyPair.publicKey().deriveAddress()));
faucetClient.fundAccount(FundAccountRequest.of(hotWalletKeyPair.publicKey().deriveAddress()));
// If you go too soon, the funding transaction might slip back a ledger and
// then your starting Sequence number will be off. This is mostly relevant
@@ -67,15 +64,15 @@ public class IssueToken {
try {
xrplClient.accountInfo(
AccountInfoRequestParams.builder()
.ledgerIndex(LedgerIndex.VALIDATED)
.account(coldWallet.classicAddress())
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.account(coldWalletKeyPair.publicKey().deriveAddress())
.build()
);
xrplClient.accountInfo(
AccountInfoRequestParams.builder()
.ledgerIndex(LedgerIndex.VALIDATED)
.account(hotWallet.classicAddress())
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.account(hotWalletKeyPair.publicKey().deriveAddress())
.build()
);
@@ -91,99 +88,85 @@ public class IssueToken {
// Configure issuer settings -----------------------------------------------
UnsignedInteger coldWalletSequence = xrplClient.accountInfo(
AccountInfoRequestParams.builder()
.ledgerIndex(LedgerIndex.CURRENT)
.account(coldWallet.classicAddress())
.ledgerSpecifier(LedgerSpecifier.CURRENT)
.account(coldWalletKeyPair.publicKey().deriveAddress())
.build()
).accountData().sequence();
AccountSet setDefaultRipple = AccountSet.builder()
.account(coldWallet.classicAddress())
.account(coldWalletKeyPair.publicKey().deriveAddress())
.fee(feeResult.drops().minimumFee())
.sequence(coldWalletSequence)
.signingPublicKey(coldWallet.publicKey())
.signingPublicKey(coldWalletKeyPair.publicKey())
.setFlag(AccountSet.AccountSetFlag.DEFAULT_RIPPLE)
.lastLedgerSequence(computeLastLedgerSequence(xrplClient))
.build();
PrivateKey coldWalletPrivateKey = PrivateKey.fromBase16EncodedPrivateKey(
coldWallet.privateKey().get()
);
SignatureService coldWalletSignatureService = new SingleKeySignatureService(coldWalletPrivateKey);
SignedTransaction<AccountSet> signedSetDefaultRipple = coldWalletSignatureService.sign(
KeyMetadata.EMPTY,
setDefaultRipple
SignatureService<PrivateKey> signatureService = new BcSignatureService();
SingleSignedTransaction<AccountSet> signedAccountSet = signatureService.sign(
coldWalletKeyPair.privateKey(), setDefaultRipple
);
submitAndWaitForValidation(signedSetDefaultRipple, xrplClient);
submitAndWaitForValidation(signedAccountSet, xrplClient);
// Configure hot address settings ------------------------------------------
UnsignedInteger hotWalletSequence = xrplClient.accountInfo(
AccountInfoRequestParams.builder()
.ledgerIndex(LedgerIndex.CURRENT)
.account(hotWallet.classicAddress())
.ledgerSpecifier(LedgerSpecifier.CURRENT)
.account(hotWalletKeyPair.publicKey().deriveAddress())
.build()
).accountData().sequence();
AccountSet setRequireAuth = AccountSet.builder()
.account(hotWallet.classicAddress())
.account(hotWalletKeyPair.publicKey().deriveAddress())
.fee(feeResult.drops().minimumFee())
.sequence(hotWalletSequence)
.signingPublicKey(hotWallet.publicKey())
.signingPublicKey(hotWalletKeyPair.publicKey())
.setFlag(AccountSet.AccountSetFlag.REQUIRE_AUTH)
.lastLedgerSequence(computeLastLedgerSequence(xrplClient))
.build();
PrivateKey hotWalletPrivateKey = PrivateKey.fromBase16EncodedPrivateKey(
hotWallet.privateKey().get()
SingleSignedTransaction<AccountSet> signedSetRequireAuth = signatureService.sign(
hotWalletKeyPair.privateKey(), setRequireAuth
);
SignatureService hotWalletSignatureService = new SingleKeySignatureService(hotWalletPrivateKey);
SignedTransaction<AccountSet> signedSetRequireAuth = hotWalletSignatureService.sign(
KeyMetadata.EMPTY,
setRequireAuth
);
submitAndWaitForValidation(signedSetRequireAuth, xrplClient);
// Create trust line -------------------------------------------------------
String currencyCode = "FOO";
ImmutableTrustSet trustSet = TrustSet.builder()
.account(hotWallet.classicAddress())
.account(hotWalletKeyPair.publicKey().deriveAddress())
.fee(feeResult.drops().openLedgerFee())
.sequence(hotWalletSequence.plus(UnsignedInteger.ONE))
.limitAmount(IssuedCurrencyAmount.builder()
.currency(currencyCode)
.issuer(coldWallet.classicAddress())
.issuer(coldWalletKeyPair.publicKey().deriveAddress())
.value("10000000000")
.build())
.signingPublicKey(hotWallet.publicKey())
.signingPublicKey(hotWalletKeyPair.publicKey())
.build();
SignedTransaction<TrustSet> signedTrustSet = hotWalletSignatureService.sign(
KeyMetadata.EMPTY,
trustSet
SingleSignedTransaction<TrustSet> signedTrustSet = signatureService.sign(
hotWalletKeyPair.privateKey(), trustSet
);
submitAndWaitForValidation(signedTrustSet, xrplClient);
// Send token --------------------------------------------------------------
Payment payment = Payment.builder()
.account(coldWallet.classicAddress())
.account(coldWalletKeyPair.publicKey().deriveAddress())
.fee(feeResult.drops().openLedgerFee())
.sequence(coldWalletSequence.plus(UnsignedInteger.ONE))
.destination(hotWallet.classicAddress())
.destination(hotWalletKeyPair.publicKey().deriveAddress())
.amount(IssuedCurrencyAmount.builder()
.issuer(coldWallet.classicAddress())
.issuer(coldWalletKeyPair.publicKey().deriveAddress())
.currency(currencyCode)
.value("3840")
.build())
.signingPublicKey(coldWallet.publicKey())
.signingPublicKey(coldWalletKeyPair.publicKey())
.build();
SignedTransaction<Payment> signedPayment = coldWalletSignatureService.sign(
KeyMetadata.EMPTY,
payment
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(
coldWalletKeyPair.privateKey(), payment
);
submitAndWaitForValidation(signedPayment, xrplClient);
@@ -191,8 +174,8 @@ public class IssueToken {
// Check balances ----------------------------------------------------------
List<TrustLine> lines = xrplClient.accountLines(
AccountLinesRequestParams.builder()
.account(hotWallet.classicAddress())
.ledgerIndex(LedgerIndex.VALIDATED)
.account(hotWalletKeyPair.publicKey().deriveAddress())
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.build()
).lines();
System.out.println("Hot wallet TrustLines: " + lines);
@@ -203,20 +186,20 @@ public class IssueToken {
throws JsonRpcClientErrorException {
// Get the latest validated ledger index
LedgerIndex validatedLedger = xrplClient.ledger(
LedgerRequestParams.builder()
.ledgerIndex(LedgerIndex.VALIDATED)
.build()
)
LedgerRequestParams.builder()
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.build()
)
.ledgerIndex()
.orElseThrow(() -> new RuntimeException("LedgerIndex not available."));
// Workaround for https://github.com/XRPLF/xrpl4j/issues/84
return UnsignedInteger.valueOf(
validatedLedger.plus(UnsignedLong.valueOf(4)).unsignedLongValue().intValue()
validatedLedger.plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue().intValue()
);
}
private static void submitAndWaitForValidation(SignedTransaction<?> signedTransaction, XrplClient xrplClient)
private static void submitAndWaitForValidation(SingleSignedTransaction<?> signedTransaction, XrplClient xrplClient)
throws InterruptedException, JsonRpcClientErrorException, JsonProcessingException {
xrplClient.submit(signedTransaction);
@@ -224,10 +207,10 @@ public class IssueToken {
boolean transactionValidated = false;
boolean transactionExpired = false;
while (!transactionValidated && !transactionExpired) {
Thread.sleep(4 * 1000);
Thread.sleep(1000);
LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger(
LedgerRequestParams.builder().ledgerIndex(LedgerIndex.VALIDATED).build()
)
LedgerRequestParams.builder().ledgerSpecifier(LedgerSpecifier.VALIDATED).build()
)
.ledgerIndex()
.orElseThrow(() ->
new RuntimeException("Ledger response did not contain a LedgerIndex.")
@@ -243,12 +226,14 @@ public class IssueToken {
transactionResult.metadata().get().transactionResult());
transactionValidated = true;
} else {
boolean lastLedgerSequenceHasPassed = FluentCompareTo.
is(latestValidatedLedgerIndex.unsignedLongValue())
.greaterThan(UnsignedLong.valueOf(
signedTransaction.signedTransaction().lastLedgerSequence().get().intValue()
)
);
boolean lastLedgerSequenceHasPassed = signedTransaction.signedTransaction().lastLedgerSequence()
.map((signedTransactionLastLedgerSeq) ->
FluentCompareTo.is(latestValidatedLedgerIndex.unsignedIntegerValue())
.greaterThan(signedTransactionLastLedgerSeq)
)
.orElse(false);
if (lastLedgerSequenceHasPassed) {
System.out.println("LastLedgerSequence has passed. Last tx response: " +
transactionResult);
@@ -259,5 +244,4 @@ public class IssueToken {
}
}
}
}

View File

@@ -1,35 +1,29 @@
////////////////////////////////////////////////////////////////////////////
// Sign using a SingleKeySignatureService:
// This implementation of SignatureService simply holds a PrivateKey in
// memory and signs Transactions using that PrivateKey. This may be
// suitable for some applications, but is likely not secure enough for
// server side applications, as keys must be stored and kept in memory.
// This implementation of SignatureService signs Transactions using a
// supplied PrivateKey. This may be suitable for some applications, but is
// likely not secure enough for server side applications, as keys should not
// be stored in memory whenever possible.
////////////////////////////////////////////////////////////////////////////
// Create a random wallet
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
Wallet wallet = walletFactory.randomWallet(true).wallet();
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
PublicKey publicKey = randomKeyPair.publicKey();
PrivateKey privateKey = randomKeyPair.privateKey()
// Construct a SingleKeySignatureService from the Wallet private key
PrivateKey privateKey = PrivateKey.fromBase16EncodedPrivateKey(
wallet.privateKey().get()
);
SingleKeySignatureService signatureService =
new SingleKeySignatureService(privateKey);
// Construct a SignatureService
SignatureService<PrivateKey> signatureService = new BcSignatureService();
// Construct and sign the Payment
Payment payment = Payment.builder()
.account(wallet.classicAddress())
.account(publicKey.deriveAddress())
.destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
.amount(XrpCurrencyAmount.ofDrops(1000))
.fee(XrpCurrencyAmount.ofDrops(10))
.sequence(UnsignedInteger.valueOf(16126889))
.signingPublicKey(signatureService.getPublicKey(KeyMetadata.EMPTY))
.signingPublicKey(publicKey)
.build();
SignedTransaction<Payment> signedPayment = signatureService.sign(
KeyMetadata.EMPTY,
payment
);
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(privateKey, payment);
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
@@ -47,25 +41,26 @@ System.out.println("Signed Payment: " + signedPayment.signedTransaction());
// implementation.
////////////////////////////////////////////////////////////////////////////
// Construct a DerivedKeysSignatureService with a server secret
// (in this case "shh")
DerivedKeysSignatureService signatureService =
new DerivedKeysSignatureService("shh"::getBytes, VersionType.ED25519);
// Construct a DerivedKeysSignatureService with a server secret (in this case "shh")
SignatureService<PrivateKeyReference> derivedKeySignatureService = new BcDerivedKeySignatureService(
() -> ServerSecret.of("shh".getBytes())
);
// Choose a walletId. This can be anything as long as it is unique to your system.
String walletId = "sample-wallet";
KeyMetadata keyMetadata = KeyMetadata.builder()
.platformIdentifier("jks")
.keyringIdentifier("n/a")
.keyIdentifier(walletId)
.keyVersion("1")
.keyPassword("password")
.build();
PrivateKeyReference privateKeyReference = new PrivateKeyReference() {
@Override
public KeyType keyType() {
return KeyType.ED25519;
}
@Override
public String keyIdentifier() {
return "sample-keypair";
}
};
// Get the public key and classic address for the given walletId
PublicKey publicKey = signatureService.getPublicKey(keyMetadata);
Address classicAddress = DefaultKeyPairService.getInstance()
.deriveAddress(publicKey.value());
PublicKey publicKey = derivedKeySignatureService.derivePublicKey(privateKeyReference);
Address classicAddress = publicKey.deriveAddress();
// Construct and sign the Payment
Payment payment = Payment.builder()
@@ -74,9 +69,8 @@ Payment payment = Payment.builder()
.amount(XrpCurrencyAmount.ofDrops(1000))
.fee(XrpCurrencyAmount.ofDrops(10))
.sequence(UnsignedInteger.valueOf(16126889))
.signingPublicKey(publicKey.base16Encoded())
.signingPublicKey(publicKey)
.build();
SignedTransaction<Payment> signedPayment = signatureService
.sign(keyMetadata, payment);
SingleSignedTransaction<Payment> signedPayment = derivedKeySignatureService.sign(privateKeyReference, payment);
System.out.println("Signed Payment: " + signedPayment.signedTransaction());

View File

@@ -0,0 +1,7 @@
# JavaScript send Memo examples
Generates a random account and creates a payment transaction with Memo field.
### Random seed
npm start

View File

@@ -0,0 +1,14 @@
{
"name": "send-a-memo",
"version": "1.0.0",
"description": "",
"main": "send-a-memo.js",
"scripts": {
"start": "node send-a-memo.js"
},
"author": "",
"license": "CC0-1.0",
"dependencies": {
"xrpl": "^2.0.0"
}
}

View File

@@ -23,7 +23,7 @@ if (typeof module !== "undefined") {
// Enter memo data to insert into a transaction
const MemoData = xrpl.convertStringToHex(string="Example Memo - 123 -=+");
const MemoType = xrpl.convertStringToHex(string="Text");
// MemoFormat values: # MemoFormat values: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
// MemoFormat values: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
const MemoFormat = xrpl.convertStringToHex(string="text/plain");
// Send AccountSet transaction
@@ -42,7 +42,7 @@ if (typeof module !== "undefined") {
})
const signed = wallet.sign(prepared)
print("Submitting a payment transaction with our memo field...")
console.log("Submitting a payment transaction with our memo field...")
const submit_result = await client.submitAndWait(signed.tx_blob)
xrpl.convertHexToString
const tx_MemoData = xrpl.convertHexToString(string=submit_result.result.Memos[0].Memo.MemoData);

View File

@@ -1,12 +1,8 @@
// Example Credentials --------------------------------------------------------
WalletFactory walletFactory = DefaultWalletFactory.getInstance();
Wallet testWallet = walletFactory
.fromSeed("sn3nxiW7v8KXzPzAqzyHXbSSKNuN9", true)
.wallet();
// Create a KeyPair
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
// Get the Classic address from testWallet
Address classicAddress = testWallet.classicAddress();
System.out.println(classicAddress); // "rMCcNuTcajgw7YTgBy1sys3b89QqjUrMpH"
Address classicAddress = randomKeyPair.publicKey().deriveAddress();
// Connect --------------------------------------------------------------------
HttpUrl rippledUrl = HttpUrl.get("https://s.altnet.rippletest.net:51234/");
@@ -15,9 +11,9 @@ XrplClient xrplClient = new XrplClient(rippledUrl);
// Prepare transaction --------------------------------------------------------
// Look up your Account Info
AccountInfoRequestParams requestParams = AccountInfoRequestParams.builder()
.ledgerIndex(LedgerIndex.VALIDATED)
.account(classicAddress)
.build();
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.build();
AccountInfoResult accountInfoResult = xrplClient.accountInfo(requestParams);
UnsignedInteger sequence = accountInfoResult.accountData().sequence();
@@ -27,17 +23,15 @@ XrpCurrencyAmount openLedgerFee = feeResult.drops().openLedgerFee();
// Get the latest validated ledger index
LedgerIndex validatedLedger = xrplClient.ledger(
LedgerRequestParams.builder()
.ledgerIndex(LedgerIndex.VALIDATED)
.build()
)
LedgerRequestParams.builder()
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.build()
)
.ledgerIndex()
.orElseThrow(() -> new RuntimeException("LedgerIndex not available."));
// Workaround for https://github.com/XRPLF/xrpl4j/issues/84
UnsignedInteger lastLedgerSequence = UnsignedInteger.valueOf(
validatedLedger.plus(UnsignedLong.valueOf(4)).unsignedLongValue().intValue()
);
// LastLedgerSequence is the current ledger index + 4
UnsignedInteger lastLedgerSequence = validatedLedger.plus(UnsignedInteger.valueOf(4)).unsignedIntegerValue();
// Construct a Payment
Payment payment = Payment.builder()
@@ -46,75 +40,61 @@ Payment payment = Payment.builder()
.destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
.sequence(sequence)
.fee(openLedgerFee)
.signingPublicKey(testWallet.publicKey())
.signingPublicKey(randomKeyPair.publicKey())
.lastLedgerSequence(lastLedgerSequence)
.build();
System.out.println("Constructed Payment: " + payment);
// Sign transaction -----------------------------------------------------------
// Construct a SignatureService to sign the Payment
PrivateKey privateKey = PrivateKey.fromBase16EncodedPrivateKey(
testWallet.privateKey().get()
);
SignatureService signatureService = new SingleKeySignatureService(privateKey);
SignatureService<PrivateKey> signatureService = new BcSignatureService();
// Sign the Payment
SignedTransaction<Payment> signedPayment = signatureService.sign(
KeyMetadata.EMPTY,
payment
);
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(randomKeyPair.privateKey(), payment);
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
// Submit transaction ---------------------------------------------------------
SubmitResult<Transaction> prelimResult = xrplClient.submit(signedPayment);
System.out.println(prelimResult);
SubmitResult<Payment> paymentSubmitResult = xrplClient.submit(signedPayment);
System.out.println(paymentSubmitResult);
// Wait for validation --------------------------------------------------------
TransactionResult<Payment> transactionResult = null;
boolean transactionValidated = false;
boolean transactionExpired = false;
while (!transactionValidated && !transactionExpired) {
Thread.sleep(4 * 1000);
LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger(
LedgerRequestParams.builder().ledgerIndex(LedgerIndex.VALIDATED).build()
)
.ledgerIndex()
.orElseThrow(() ->
new RuntimeException("Ledger response did not contain a LedgerIndex.")
);
TransactionResult<Payment> transactionResult = xrplClient.transaction(
TransactionRequestParams.of(signedPayment.hash()),
Payment.class
);
LedgerIndex latestValidatedLedgerIndex = xrplClient.ledger(
LedgerRequestParams.builder()
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
.build()
)
.ledgerIndex()
.orElseThrow(() -> new RuntimeException("Ledger response did not contain a LedgerIndex."));
transactionResult = xrplClient.transaction(TransactionRequestParams.of(signedPayment.hash()), Payment.class);
if (transactionResult.validated()) {
System.out.println("Payment was validated with result code " +
transactionResult.metadata().get().transactionResult());
System.out.println("Payment was validated with result code " + transactionResult.metadata().get().transactionResult());
transactionValidated = true;
} else {
boolean lastLedgerSequenceHasPassed = FluentCompareTo.
is(latestValidatedLedgerIndex.unsignedLongValue())
.greaterThan(UnsignedLong.valueOf(lastLedgerSequence.intValue()));
boolean lastLedgerSequenceHasPassed = FluentCompareTo.is(latestValidatedLedgerIndex.unsignedIntegerValue())
.greaterThan(UnsignedInteger.valueOf(lastLedgerSequence.intValue()));
if (lastLedgerSequenceHasPassed) {
System.out.println("LastLedgerSequence has passed. Last tx response: "
transactionResult);
);
System.out.println("LastLedgerSequence has passed. Last tx response: " + transactionResult);
transactionExpired = true;
} else {
System.out.println("Payment not yet validated.");
}
}
}
// Check transaction results --------------------------------------------------
System.out.println(transactionResult);
System.out.println("Explorer link: https://testnet.xrpl.org/transactions/" +
signedPayment.hash());
System.out.println("Explorer link: https://testnet.xrpl.org/transactions/" + signedPayment.hash());
transactionResult.metadata().ifPresent(metadata -> {
System.out.println("Result code: " + metadata.transactionResult());
metadata.deliveredAmount().ifPresent(deliveredAmount ->
System.out.println("XRP Delivered: " +
((XrpCurrencyAmount) deliveredAmount).toXrp())
);
});
System.out.println("XRP Delivered: " + ((XrpCurrencyAmount) deliveredAmount).toXrp()));
}
);

View File

@@ -156,7 +156,8 @@ An example of a successful response:
*JSON-RPC*
```json
"result": {
{
"result": {
"ledger_index_min": 21377274,
"ledger_index_max": 27876163,
"transactions": [
@@ -274,7 +275,8 @@ With the `binary` parameter set to _true_, you receive a compact response that u
*JSON-RPC*
```json
"result": {
{
"result": {
"ledger_index_min": 21377274,
"ledger_index_max": 27876275,
"transactions": [

View File

@@ -65,6 +65,8 @@ The ID of a `Check` object is the [SHA-512Half][] of the following values, conca
* The `Sequence` number of the [CheckCreate transaction][] that created the `Check` object.
If the CheckCreate transaction used a [Ticket](tickets.html), use the `TicketSequence` value instead.
See the tutorial showing how to [Send a Check](send-a-check.html).
<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}

View File

@@ -184,12 +184,13 @@ curated_anchors:
| [Hash256][] | 5 | 256 | いいえ | 256ビットの任意のバイナリ値。これは通常、トランザクション、レジャーバージョン、またはレジャーデータオブジェクトの「SHA-512ハーフ」ハッシュを表します。 |
| [PathSet][] | 18 | 可変 | いいえ | [複数通貨間ペイメント](cross-currency-payments.html)の有効な[ペイメントパス](paths.html)のセット。 |
| [STArray][] | 15 | 可変 | いいえ | 可変数のメンバーからなる配列。フィールドによってタイプが異なる場合があります。この例として、[memos](transaction-common-fields.html#memosフィールド)や[マルチ署名](multi-signing.html)で使用される署名者のリストがあります。 |
| [STIssue][] | 24 | 320 | いいえ | :not_enabled: 数量を含まない、資産(XRPまたはトークン)を指定します。 |
| [STObject][] | 14 | 可変 | いいえ | 1つ以上のネストされたフィールドを含むオブジェクト。 |
| [UInt8][] | 16 | 8 | いいえ | 8ビットの符号なし整数。 |
| [UInt16][] | 1 | 16 | いいえ | 16ビットの符号なし整数。`TransactionType`は、このタイプの特殊なフィールドで、特定の文字列から整数値へのマッピングを含みます。 |
| [UInt32][] | 2 | 32 | いいえ | 32ビットの符号なし整数。このタイプの例として、すべてのトランザクションの`Flags`フィールドと`Sequence`フィールドがあります。 |
<!-- | [STIssue][] | 24 | 320 | いいえ | :not_enabled: 数量を含まない、資産(XRPまたはトークン)を指定します。 | -->
[長さプレフィクスを付加する]: #長さプレフィクスを付加する
上記のフィールドタイプの他に、[レジャーオブジェクト](ledger-object-types.html)や[トランザクションメタデータ](transaction-metadata.html)などのコンテキストでは以下のタイプが含まれることがあります。

View File

@@ -184,7 +184,6 @@ Transaction instructions may contain fields of any of the following types:
| [Hash256][] | 5 | 256 | No | A 256-bit arbitrary binary value. This usually represents the "SHA-512Half" hash of a transaction, ledger version, or ledger data object. |
| [PathSet][] | 18 | Variable | No | A set of possible [payment paths](paths.html) for a [cross-currency payment](cross-currency-payments.html). |
| [STArray][] | 15 | Variable | No | An array containing a variable number of members, which can be different types depending on the field. Two cases of this include [memos](transaction-common-fields.html#memos-field) and lists of signers used in [multi-signing](multi-signing.html). |
<!-- | [STIssue][] | 24 | 160 or 320 | No | :not_enabled: An asset definition, XRP or a token, with no quantity. | -->
| [STObject][] | 14 | Variable | No | An object containing one or more nested fields. |
| [UInt8][] | 16 | 8 | No | An 8-bit unsigned integer. |
| [UInt16][] | 1 | 16 | No | A 16-bit unsigned integer. The `TransactionType` is a special case of this type, with specific strings mapping to integer values. |
@@ -192,6 +191,9 @@ Transaction instructions may contain fields of any of the following types:
[Length-prefixed]: #length-prefixing
<!-- | [STIssue][] | 24 | 160 or 320 | No | :not_enabled: An asset definition, XRP or a token, with no quantity. | -->
In addition to all of the above field types, the following types may appear in other contexts, such as [ledger objects](ledger-object-types.html) and [transaction metadata](transaction-metadata.html):
| Type Name | Type Code | [Length-prefixed]? | Description |

View File

@@ -0,0 +1,211 @@
---
parent: build-apps.html
targets:
- en
- ja # TODO: translate this page
blurb: Build a graphical browser wallet for the XRPL using Javascript.
---
# Build A Browser Wallet Using JS
<!-- STYLE_OVERRIDE: wallet -->
This tutorial demonstrates how to build a browser wallet for the XRP Ledger using the Javascript programming language and various libraries. This application can be used as a starting point for building a more complete and powerful application, as a reference point for building comparable apps, or as a learning experience to better understand how to integrate XRP Ledger functionality into a larger project.
## Prerequisites
To complete this tutorial, you should meet the following guidelines:
1. You have [Node.js](https://nodejs.org/en/download/) v14 or higher installed.
2. You have [Yarn](https://yarnpkg.com/en/docs/install) (v1.17.3 or higher) installed.
3. You are somewhat familiar with coding with JavaScript and have completed the [Get Started Using JavaScript](get-started-using-javascript.html) tutorial.
## Source Code
You can find the complete source code for all of this tutorial's examples in the [code samples section of this website's repository]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/).
## Goals
At the end of this tutorial, you should be able to build a simple XRP wallet displayed below.
![Home Page Screenshot](img/js-wallet-home.png)
This application can:
- Show updates to the XRP Ledger in real-time.
- View any XRP Ledger account's activity, including showing how much XRP was delivered by each transaction.
- Show how much XRP is set aside for the account's [reserve requirement](reserves.html).
- Send [direct XRP payments](direct-xrp-payments.html), and provide feedback about the intended destination address, including:
- Displaying your account's available balance
- Verifying that the destination address is valid
- Validating the account has enough XRP to send
- Allowing you to specify a destination tag
## Steps
Before you begin, make sure you have the prerequisites installed. Check your node version by running `node -v`. If necessary, [download Node.js](https://nodejs.org/en/download/).
**Tip:** If you get stuck while doing this tutorial, or working on another project, feel free to ask for help in the XRPL's [Developer Discord](https://discord.com/invite/KTNmhJDXqa).
### 1. Set up the project
1. Navigate to the directory that you want to create the project in.
2. Create a new Vite project:
```bash
yarn create vite simple-xrpl-wallet --template vanilla
```
3. Create or modify the file `package.json` to have the following contents:
{{ include_code("_code-samples/build-a-wallet/js/package.json", language="js") }}
- Alternatively you can also do `yarn add <package-name>` for each individual package to add them to your `package.json` file.
4. Install dependencies:
```bash
yarn
```
5. Create a new file `.env` in the root directory of the project and add the following variables:
```bash
CLIENT="wss://s.altnet.rippletest.net:51233/"
EXPLORER_NETWORK="testnet"
SEED="s████████████████████████████"
```
6. Change the seed to your own seed. You can get credentials from [the Testnet faucet](xrp-test-net-faucet.html).
7. Set up a Vite bundler. Create a file named `vite.config.js` in the root directory of the project and fill it with the following code:
{{ include_code("_code-samples/build-a-wallet/js/vite.config.js", language="js") }}
This example includes the necessary configuration to make [xrpl.js work with Vite](https://github.com/XRPLF/xrpl.js/blob/main/UNIQUE_SETUPS.md#using-xrpljs-with-vite-react).
8. Add script to `package.json`
In your `package.json` file, add the following section if it's not there already:
```json
"scripts": {
"dev": "vite"
}
```
### 2. Create the Home Page (Displaying Account & Ledger Details)
In this step, we create a home page that displays account and ledger details.
![Home Page Screenshot](img/js-wallet-home.png)
1. If not already present, create new files in the root folder named `index.html`, `index.js` and `index.css`.
2. Make a new folder named `src` in the root directory of the project.
3. Copy the contents of [index.html]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/index.html) in your code.
4. Add styling to your [index.css]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/index.css) file by following the link.
This basic setup creates a homepage and applies some visual styles. The goal is for the homepage to:
- Display our account info
- Show what's happening on the ledger
- And add a little logo for fun
To make that happen, we need to connect to the XRP Ledger and look up the account and the latest validated ledger.
5. In the `src/` directory, make a new folder named `helpers`. Create a new file there named `get-wallet-details.js` and define a function named `getWalletDetails` there. This function uses the [account_info method](account_info.html) to fetch account details and the [server_info method](server_info.html) to calculate the current [reserves](reserves.html). The code to do all this is as follows:
{{ include_code("_code-samples/build-a-wallet/js/src/helpers/get-wallet-details.js", language="js") }}
6. Now, let's add the code to `index.js` file to fetch the account and ledger details and display them on the home page. Copy the code written below to the `index.js` file. Here we render the wallet details using the function we defined in `get-wallet-details.js`. In order to make sure we have up to date ledger data, we are using the [ledger stream](subscribe.html#ledger-stream) to listen for ledger close events.
{{ include_code("_code-samples/build-a-wallet/js/index.js", language="js") }}
7. In the `helpers` folder, add [render-xrpl-logo.js]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/src/helpers/render-xrpl-logo.js) to handle displaying a logo.
8. Finally create a new folder named `assets` in the `src/` directory and add the file [`xrpl.svg`]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/src/assets/xrpl.svg) there.
These files are used to render the XRPL logo for aesthetic purposes.
The one other thing we do here is add events to two buttons - one to send XRP and one to view transaction history. They won't work just yet — we'll implement them in the next steps.
Now the application is ready to run. You can start it in dev mode using the following command:
```bash
yarn dev
```
Your terminal should output a URL which you can use to open your app in a browser. This dev site automatically updates to reflect any changes you make to the code.
### 3. Create the Send XRP Page
Now that we've created the home page, we can move on to the "Send XRP" page. This is what allows this wallet to manage your account's funds.
![Send XRP Page Screenshot](img/js-wallet-send-xrp.png)
1. Create a folder named `send-xrp` in the `src` directory.
2. Inside the `send-xrp` folder, create two files named `send-xrp.js` and `send-xrp.html`.
3. Copy the contents of the [send-xrp.html]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/src/send-xrp/send-xrp.html) file to your `send-xrp.html` file. The provided HTML code includes three input fields for the destination address, amount, and destination tag, each with their corresponding labels.
4. Now that we have the HTML code, let's add the JavaScript code. In the `helpers` folder, create a new file named `submit-transaction.js` and copy the code written below to the file. In this file, we are using the [submit](submit.html) method to submit the transaction to the XRPL. Before submitting every transaction needs to be signed by a wallet, learn more about [signing](sign.html) a transaction.
{{ include_code("_code-samples/build-a-wallet/js/src/helpers/submit-transaction.js", language="js") }}
5. Now back to the `send-xrp.js` file, copy the code written below to the file. In this piece of code we are first getting all the DOM elements from HTML and adding event listners to update & validate the fields based on the user input. Using `renderAvailableBalance` method we display the current available balance of the wallet. `validateAddress` function validates the user address, and the amount is validated using a regular expression. When all the fields are filled with correct inputs, we call the `submitTransaction` function to submit the transaction to the ledger.
{{ include_code("_code-samples/build-a-wallet/js/src/send-xrp/send-xrp.js", language="js") }}
You can now click 'Send XRP' to try creating your own transaction! You can use this example to send XRP to the testnet faucet to try it out.
Testnet faucet account: `rHbZCHJSGLWVMt8D6AsidnbuULHffBFvEN`
Amount: 9
Destination Tag: (Not usually necessary unless you're paying an account tied to an exchange)
![Send XRP Transaction Screenshot](img/js-wallet-send-xrp-transaction-details.png)
### 4. Create the Transactions Page
Now that we have created the home page and the send XRP page, let's create the transactions page that will display the transaction history of the account. In order to see what's happening on the ledger, we're going to display the following fields:
- Account: The account that sent the transaction.
- Destination: The account that received the transaction.
- Amount: The amount of XRP sent in the transaction.
- Transaction Type: The type of transaction.
- Result: The result of the transaction.
- Link: A link to the transaction on the XRP Ledger Explorer.
![Transactions Page Screenshot](img/js-wallet-transaction.png)
1. Create a folder named `transaction-history` in the src directory.
2. Create a file named `transaction-history.js` and copy the code written below.
{{ include_code("_code-samples/build-a-wallet/js/src/transaction-history/transaction-history.js", language="js") }}
This code uses [account_tx](account_tx.html) to fetch transactions we've sent to and from this account. In order to get all the results, we're using the `marker` parameter to paginate through the incomplete list of transactions until we reach the end.
3. Create a file named `transaction-history.html` and copy the code from [transaction-history.html]({{target.github_forkurl}}/tree/{{target.github_branch}}/content/_code-samples/build-a-wallet/js/src/transaction-history/transaction-history.html) into it.
`transaction-history.html` defines a table which displays the fields mentioned above.
You can use this code as a starting point for displaying your account's transaction history. If you want an additional challenge, try expanding it to support different transaction types (e.g. [TrustSet](trustset.html)). If you want inspiration for how to handle this, you can check out the [XRP Ledger Explorer](https://livenet.xrpl.org/) to see how the transaction details are displayed.
## Next Steps
Now that you have a functional wallet, you can take it in several new directions. The following are a few ideas:
- You could support more of the XRP Ledger's [transaction types](transaction-types.html) including [tokens](issued-currencies.html) and [cross-currency payments](cross-currency-payments.html)
- You could add support for displaying multiple tokens, beyond just XRP
- You could support creating [offers](offers.html) in the [decentralized exchange](decentralized-exchange.html)
- You could add new ways to request payments, such as with QR codes or URIs that open in your wallet.
- You could support better account security including allowing users to set [regular key pairs](cryptographic-keys.html#regular-key-pair) or handle [multi-signing](multi-signing.html).
- Or you could take your code to production by following the [Building for Production with Vite](https://vitejs.dev/guide/build.html#public-base-path) guide.
<!--{## common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}
{% include '_snippets/rippled_versions.md' %}

View File

@@ -44,27 +44,31 @@ In this tutorial, you need the [xrpl4j-client](https://javadoc.io/doc/org.xrpl/x
To install with Maven, add the following to your project's `pom.xml` file and then run `mvn install`:
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-bom</artifactId>
<version>3.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
```
```xml
<dependencies>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-core</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-client</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-address-codec</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-keypairs</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.xrpl</groupId>
<artifactId>xrpl4j-model</artifactId>
<version>2.0.0</version>
<version>3.0.1</version>
</dependency>
</dependencies>
```
@@ -86,9 +90,9 @@ Here are the basic steps you'll need to cover for almost any XRP Ledger project:
### {{n.next()}}. Connect to the XRP Ledger
To make queries and submit transactions, you need to connect to the XRP Ledger. To do this with `xrpl4j`,
you can use an [`XrplClient`](https://javadoc.io/doc/org.xrpl/xrpl4j-client/latest/org/xrpl/xrpl4j/client/XrplClient.html):
you can use an [`XrplClient`](https://javadoc.io/doc/org.xrpl/xrpl4j-client/3.0.1/org/xrpl/xrpl4j/client/XrplClient.html):
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Construct a network client", end_before="// Create a Wallet using a WalletFactory", language="java") }}
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Construct a network client", end_before="// Create a random KeyPair", language="java") }}
#### Connect to the production XRP Ledger
@@ -112,7 +116,7 @@ To store value and execute transactions on the XRP Ledger, you need to get an ac
To generate a new account, `xrpl4j` provides the [`DefaultWalletFactory`](https://javadoc.io/doc/org.xrpl/xrpl4j-keypairs/latest/org/xrpl/xrpl4j/wallet/DefaultWalletFactory.html).
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Create a Wallet using a WalletFactory", end_before="// Get the Classic and X-Addresses from testWallet", language="java") }}
{{ include_code("_code-samples/get-started/java/GetAccountInfo.java", start_with="// Create a random KeyPair", end_before="// Derive the Classic and X-Addresses from testWallet", language="java") }}
The result of a call to `walletFactory.randomWallet(true).wallet()` is a [`Wallet` instance](https://javadoc.io/doc/org.xrpl/xrpl4j-keypairs/latest/org/xrpl/xrpl4j/wallet/Wallet.html):
@@ -170,26 +174,33 @@ You should see output similar to this example:
```sh
Running the GetAccountInfo sample...
Constructing an XrplClient connected to https://s.altnet.rippletest.net:51234/
Generated a wallet with the following public key: ED015D922B5EACF09DF01168141FF27FA6229B0FAB9B4CD88D2B6DA036090EFAA4
Generated KeyPair: KeyPair{
privateKey=PrivateKey{value=[redacted], destroyed=false},
publicKey=PublicKey{value=UnsignedByteArray{unsignedBytes=List(size=33)},
base58Value=aKGgrZL2WTc85HJSkQGuKfinem5oMH1uCJankSWFATGUhqvygxir,
base16Value=EDFB1073327CCBDA342AD685AF1C04530294866B9CB10C21126DC004BFDBA287D1,
keyType=ED25519
}
}
Classic Address: rBXHGshqXu3Smy9FUsQTmo49bGpQUQEm3X
X-Address: T7yMiiJJCmgY2yg5WB2davUedDeBFAG5B8r9KHjKCxDdvv3
Funded the account using the Testnet faucet.
AccountInfoResult{
status=success,
accountData=AccountRootObject{
ledgerEntryType=ACCOUNT_ROOT,
account=rBXHGshqXu3Smy9FUsQTmo49bGpQUQEm3X,
balance=1000000000,
flags=0,
ownerCount=0,
previousTransactionId=0000000000000000000000000000000000000000000000000000000000000000,
previousTransactionLedgerSequence=0,
sequence=17178149,
signerLists=[],
index=0DC1B13C73A7F3D2D82446526D0C5D08E88F89BA442D54291117F1A08E447685
},
ledgerCurrentIndex=17178149,
validated=false
status=success,
accountData=AccountRootObject{
ledgerEntryType=ACCOUNT_ROOT,
account=rDNwS2t4afhBogKqSFFmsDi1k7gmeGhz4p,
balance=10000000000,
flags=0,
ownerCount=0,
previousTransactionId=0000000000000000000000000000000000000000000000000000000000000000,
previousTransactionLedgerSequence=0,
sequence=37649083,
signerLists=[],
index=F607809578C2A413774B9A240480B8B7B10C3E296CA609337D2F41813F566B92
},
ledgerCurrentIndex=37649083,
validated=false
}
```

View File

@@ -187,8 +187,6 @@ AMM
<!-- MULTICODE_BLOCK_END -->
(On Mainnet, Testnet, and Devnet, no you)
**Warning:** Do not use the `[features]` stanza when connecting to Mainnet or Testnet. Forcefully enabling different features than the rest of the network could cause your server to diverge from the network.
## 4. Restart the server.

View File

@@ -61,17 +61,19 @@ To load a specific historical ledger, start the server with the `--load` paramet
rippled -a --load --ledger 19860944 --conf=/path/to/rippled.cfg
```
This makes the saved ledger version the "current" (open) ledger for the server when it starts.
For more information on the options you can use when starting `rippled` in stand-alone mode, see [Commandline Usage: Stand-Alone Mode Options](commandline-usage.html#stand-alone-mode-options).
## 6. Manually advance the ledger.
In stand-alone mode, you must manually advance the ledger with the `ledger_accept` method:
To process the saved ledger, manually advance it with the `ledger_accept` method:
```
rippled ledger_accept --conf=/path/to/rippled.cfg
```
If a transaction depends on the result of a transaction from a different address, advance the ledger to ensure they are processed in the correct order. Otherwise, you can submit multiple transactions from a single address `rippled` sorts transactions from the same address by ascending `Sequence` number.
This puts the transactions in canonical order and processes them to make a closed ledger.
## See Also

View File

@@ -95,7 +95,7 @@ Here are examples of how to sign transaction instructions locally using the foll
* **Python** - [`xrpl-py`](https://github.com/XRPLF/xrpl-py)
* **Java** - [`xrpl4j-crypto-bouncycastle`](https://javadoc.io/doc/org.xrpl/xrpl4j-crypto-bouncycastle/latest/index.html)
* **Java** - [`xrpl4j`](https://github.com/XRPLF/xrpl4j)
<!-- MULTICODE_BLOCK_START -->

View File

@@ -400,7 +400,7 @@ pages:
html: docs.html
parent: index.html
template: page-docs.html.jinja
sidebar: disabled
sidebar: left_only
top_nav_name: Docs
top_nav_shortcuts:
# Programming Languages
@@ -468,6 +468,16 @@ pages:
- labels
targets:
- ja
- name: Documentation Index
longer_name: Full Documentation Index
template: page-docs-index.html.jinja
html: docs-index.html
parent: docs.html
sidebar: disabled
targets:
- en
- ja
# Concepts ---------------------------------------------------------------------
@@ -1406,6 +1416,11 @@ pages:
- en
- ja # TODO: translate this page
- md: tutorials/build-apps/build-a-browser-wallet-in-js.md
targets:
- en
- ja # TODO: translate this page
- name: Production Readiness
html: production-readiness.html
parent: tutorials.html

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -0,0 +1,763 @@
<svg width="560" height="301" viewBox="0 0 560 301" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1160_6791)">
<g clip-path="url(#clip1_1160_6791)">
<rect width="879.52" height="489.915" transform="translate(-116.75 -115.41)" fill="#232325"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -540.129 45.3008)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -358.131 -107.445)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -205.191 -148.059)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -69.0747 -198.385)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 130.514 -148.061)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 283.455 -107.446)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 395.101 -42.9927)" stroke="#454549" stroke-width="0.638871"/>
<path d="M515.603 15.9372L-204.912 432.62" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 552.628 123.88)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -469.777 -42.9905)" stroke="#838386" stroke-width="0.638871"/>
<rect width="15.1271" height="15.1271" transform="matrix(0.866044 -0.499967 0.866044 0.499967 61.6851 269.692)" fill="#232325"/>
<path d="M74.4629 271.074L186.265 206.548L75.1018 142.022L183.071 80.0513" stroke="#E0E0E1" stroke-width="0.638871" stroke-linecap="round" stroke-dasharray="0.64 1.92"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -181.374 -5.16992)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -94.1973 -83.7498)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 -23.8457 -172.041)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 87.8003 -236.496)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 240.74 -277.109)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(0.866044 0.499967 -0.866044 0.499967 376.856 -327.436)" stroke="#343437" stroke-width="0.638871"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 440.33 -327.434)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 576.445 -277.108)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="869.734" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 729.386 -236.494)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="774.372" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 911.383 -83.7517)" stroke="#454549" stroke-width="0.638871"/>
<line y1="-0.319435" x2="717.862" y2="-0.319435" transform="matrix(-0.866044 0.499967 -0.866044 -0.499967 998.559 -5.17188)" stroke="#454549" stroke-width="0.638871"/>
<path d="M192.015 74.6208L297.109 13.6086" stroke="#E0E0E1" stroke-width="0.638871" stroke-linecap="round" stroke-dasharray="0.64 1.92"/>
<path d="M837.515 180.805L385.305 442.6L237.646 356.905" stroke="#E0E0E1" stroke-width="0.878926" stroke-linecap="round" stroke-dasharray="0.88 2.64"/>
<rect width="15.1271" height="15.1271" transform="matrix(0.866044 -0.499967 0.866044 0.499967 61.6865 12.6377)" fill="#232325"/>
<rect width="15.1271" height="15.1271" transform="matrix(0.866044 -0.499967 0.866044 0.499967 507.617 140.641)" fill="#232325"/>
<path d="M297.428 13.2909L408.911 -51.2351L303.817 -112.567" stroke="#E0E0E1" stroke-width="0.638871" stroke-linecap="round" stroke-dasharray="0.64 1.92"/>
<path d="M395.979 78.8535V75.8H421.017V78.8535L408.498 85.8765L395.979 78.8535Z" fill="url(#paint0_linear_1160_6791)"/>
<g filter="url(#filter0_d_1160_6791)">
<mask id="mask0_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="395" y="68" width="27" height="15">
<rect width="14.4599" height="14.4599" transform="matrix(0.866044 -0.499967 0.866044 0.499967 395.979 75.7017)" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask0_1160_6791)">
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint1_linear_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint2_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint3_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint4_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint5_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint6_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint7_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint8_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint9_linear_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint10_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint11_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint12_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint13_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint14_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint15_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 408.501 75.702)" fill="url(#paint16_radial_1160_6791)"/>
</g>
</g>
</g>
<path d="M398.592 202.979V199.926L423.936 203.895V206.948L405.309 217.635L398.592 202.979Z" fill="url(#paint17_linear_1160_6791)"/>
<g filter="url(#filter1_d_1160_6791)">
<mask id="mask1_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="398" y="199" width="26" height="16">
<path d="M398.592 199.925L423.935 203.895L405.239 214.491L398.592 199.925Z" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask1_1160_6791)">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint18_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint19_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint20_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint21_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint22_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint23_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint24_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint25_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint26_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint27_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint28_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint29_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint30_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint31_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint32_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 409.19 205.978)" fill="url(#paint33_radial_1160_6791)"/>
</g>
</g>
</g>
<path d="M288.82 137.809V134.756L314.164 138.725V141.779L295.538 152.466L288.82 137.809Z" fill="url(#paint34_linear_1160_6791)"/>
<g filter="url(#filter2_d_1160_6791)">
<mask id="mask2_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="288" y="134" width="27" height="16">
<path d="M288.82 134.755L314.164 138.725L295.467 149.321L288.82 134.755Z" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask2_1160_6791)">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint35_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint36_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint37_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint38_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint39_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint40_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint41_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint42_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint43_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint44_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint45_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint46_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint47_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint48_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint49_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 299.419 140.808)" fill="url(#paint50_radial_1160_6791)"/>
</g>
</g>
</g>
<path d="M62.7617 135.629V132.575L88.1055 136.545V139.598L69.4793 150.285L62.7617 135.629Z" fill="url(#paint51_linear_1160_6791)"/>
<g filter="url(#filter3_d_1160_6791)">
<mask id="mask3_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="62" y="132" width="27" height="16">
<path d="M62.7615 132.575L88.1053 136.545L69.4087 147.141L62.7615 132.575Z" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask3_1160_6791)">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint52_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint53_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint54_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint55_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint56_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint57_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint58_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint59_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint60_linear_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint61_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint62_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint63_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint64_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint65_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint66_radial_1160_6791)"/>
<circle r="14.4599" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 73.3604 138.627)" fill="url(#paint67_radial_1160_6791)"/>
</g>
</g>
</g>
<path d="M175.559 209.283L175.559 206.329L200.605 206.329V209.283L188.082 216.513L175.559 209.283Z" fill="#232325"/>
<g filter="url(#filter4_d_1160_6791)">
<rect width="14.4599" height="14.4599" transform="matrix(0.866044 -0.499967 0.866044 0.499967 175.559 206.229)" fill="#232325"/>
</g>
<path d="M61.7129 271.395L61.7128 268.441L86.7587 268.441V271.395L74.2358 278.625L61.7129 271.395Z" fill="#232325"/>
<g filter="url(#filter5_d_1160_6791)">
<rect width="14.4599" height="14.4599" transform="matrix(0.866044 -0.499967 0.866044 0.499967 61.7129 268.342)" fill="#232325"/>
</g>
<path d="M62.4394 13.3538L62.4394 10.3991L87.4853 10.3991V13.3538L74.9623 20.5833L62.4394 13.3538Z" fill="#232325"/>
<g filter="url(#filter6_d_1160_6791)">
<rect width="14.4599" height="14.4599" transform="matrix(0.866044 -0.499967 0.866044 0.499967 62.4395 10.3)" fill="#232325"/>
</g>
<path d="M508.837 143.066V140.013H533.876V143.066L521.357 150.089L508.837 143.066Z" fill="url(#paint68_linear_1160_6791)"/>
<g filter="url(#filter7_d_1160_6791)">
<mask id="mask4_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="508" y="132" width="26" height="16">
<rect width="14.4599" height="14.4599" transform="matrix(0.866044 -0.499967 0.866044 0.499967 508.837 139.914)" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask4_1160_6791)">
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint69_linear_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint70_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint71_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint72_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint73_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint74_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint75_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint76_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint77_linear_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint78_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint79_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint80_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint81_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint82_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint83_radial_1160_6791)"/>
<circle r="11.4157" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 521.36 139.915)" fill="url(#paint84_radial_1160_6791)"/>
</g>
</g>
</g>
<path d="M184.507 90.1918L180.873 81.8327V78.5618L209.584 82.5596V86.194L199.044 92.3724L184.507 90.1918Z" fill="url(#paint85_linear_1160_6791)"/>
<mask id="mask5_1160_6791" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="181" y="72" width="29" height="17">
<path d="M209.712 82.7606L199.273 88.7871L184.842 86.4828L181.004 78.2407L191.443 72.2141L205.874 74.3411L209.712 82.7606Z" fill="#454549"/>
</mask>
<g mask="url(#mask5_1160_6791)">
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint86_linear_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint87_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint88_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint89_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint90_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint91_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint92_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint93_radial_1160_6791)"/>
<g style="mix-blend-mode:soft-light" opacity="0.5">
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint94_linear_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint95_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint96_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint97_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint98_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint99_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint100_radial_1160_6791)"/>
<circle r="12.9971" transform="matrix(0.866044 -0.499967 -0.866044 -0.499967 195.962 79.9061)" fill="url(#paint101_radial_1160_6791)"/>
</g>
</g>
<path d="M196.232 77.1104L196.973 81.3852L193.27 81.3852" stroke="white" stroke-width="0.944939" stroke-linecap="square" stroke-linejoin="round"/>
<rect x="587.25" y="-9.40991" width="78" height="712" transform="rotate(90 587.25 -9.40991)" fill="url(#paint102_linear_1160_6791)"/>
</g>
<path d="M127.901 155.401C127.901 154.076 128.832 153.539 129.98 154.201L134.829 157.001L134.829 199.5L129.98 196.7C128.832 196.037 127.901 194.425 127.901 193.1L127.901 155.401Z" fill="#232325"/>
<rect width="75.2483" height="9.37373" rx="2.39987" transform="matrix(0.866025 -0.5 0.866025 0.5 127.263 153.059)" fill="#343437"/>
<g filter="url(#filter8_d_1160_6791)">
<rect width="79.2084" height="45.5975" rx="6.39966" transform="matrix(0.865887 -0.517775 2.12708e-08 1 133.858 158.331)" fill="#232325"/>
<path d="M208.613 135.035C209.512 135.451 209.512 137.13 208.613 138.622L201.261 150.824L201.261 131.625L208.613 135.035Z" fill="#232325"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M177.645 140.636C177.979 139.569 177.637 138.746 176.881 138.796C176.124 138.846 175.24 139.752 174.905 140.819L163.214 178.089C162.879 179.156 163.221 179.98 163.978 179.93C164.735 179.879 165.619 178.974 165.954 177.907L177.645 140.636ZM161.357 152.226C161.942 152.563 161.942 153.659 161.357 154.672L151.996 170.886L161.357 176.29C161.942 176.628 161.942 177.723 161.357 178.736C160.772 179.749 159.823 180.297 159.239 179.959L149.877 174.555C148.708 173.879 148.708 171.689 149.877 169.663L159.239 153.449C159.823 152.436 160.772 151.888 161.357 152.226ZM179.502 168.26C178.917 167.922 178.917 166.827 179.502 165.814L188.863 149.6L179.502 144.195C178.917 143.858 178.917 142.763 179.502 141.749C180.087 140.736 181.036 140.189 181.621 140.527L190.982 145.931C192.152 146.607 192.152 148.797 190.982 150.823L181.621 167.037C181.036 168.05 180.087 168.598 179.502 168.26Z" fill="url(#paint103_linear_1160_6791)"/>
<path d="M225.67 92.0962C225.67 90.0317 227.12 89.1949 228.908 90.2272L236.461 94.5882L236.461 217.798L225.67 211.568L225.67 92.0962Z" fill="#232325"/>
<path d="M227.913 92.4657C226.126 91.4335 226.126 89.7599 227.913 88.7277L302.299 45.7812C304.087 44.7489 306.986 44.7489 308.773 45.7812L313.864 48.7204C316.248 50.0967 316.248 52.3281 313.864 53.7044L240.558 96.0279C238.77 97.0601 235.871 97.0601 234.083 96.0279L227.913 92.4657Z" fill="#343437"/>
<g filter="url(#filter9_d_1160_6791)">
<path d="M237.1 93.6614C235.216 94.7495 234.393 96.6653 234.392 101.992L234.392 109.02L234.389 214.129C234.389 215.505 235.355 216.063 236.547 215.375L313.926 170.697C315.118 170.009 316.084 168.335 316.084 166.959L316.087 61.8501L316.087 54.8217C316.088 49.4951 315.264 48.53 313.38 49.6181L307.58 52.9669L307.141 53.2202L242.724 90.4145L237.1 93.6614Z" fill="#343437"/>
</g>
<path d="M243.114 102.541L307.357 65.4505" stroke="#9A52FF" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 113.668L260.246 103.777" stroke="#5BEB9D" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 124.177L307.357 87.0867" stroke="#838386" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 135.304L293.438 106.25" stroke="#838386" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 145.814L293.438 116.76" stroke="#838386" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 188.981L293.438 159.926" stroke="#454549" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 156.178L293.438 127.124" stroke="#838386" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M243.114 199.345L293.438 170.29" stroke="#454549" stroke-width="4.99465" stroke-linecap="round"/>
<path d="M329.879 142.977C329.879 141.629 330.826 141.082 331.993 141.756L336.928 144.605L336.928 225.087L329.879 221.017L329.879 142.977Z" fill="#232325"/>
<path d="M331.344 143.219C330.176 142.545 330.176 141.451 331.344 140.777L379.933 112.724C381.101 112.05 382.995 112.05 384.162 112.724L387.488 114.644C389.045 115.543 389.045 117.001 387.488 117.9L339.603 145.546C338.436 146.22 336.542 146.22 335.374 145.546L331.344 143.219Z" fill="#343437"/>
<g filter="url(#filter10_d_1160_6791)">
<path d="M337.345 143.999C336.114 144.71 335.576 145.961 335.576 149.441L335.576 154.032L335.574 222.69C335.574 223.589 336.205 223.953 336.983 223.503L387.528 194.319C388.306 193.87 388.938 192.777 388.938 191.878L388.94 123.22L388.94 118.629C388.94 115.149 388.402 114.519 387.171 115.23L383.383 117.417L383.096 117.583L341.018 141.878L337.345 143.999Z" fill="#343437"/>
</g>
<path d="M341.273 149.799L383.237 125.571" stroke="#454549" stroke-width="3.26255" stroke-linecap="round"/>
<path d="M341.273 157.068L352.464 150.607" stroke="#5BEB9D" stroke-width="3.26255" stroke-linecap="round"/>
<path d="M341.273 163.932L383.237 139.704" stroke="#454549" stroke-width="3.26255" stroke-linecap="round"/>
<path d="M341.273 171.2L374.145 152.222" stroke="#454549" stroke-width="3.26255" stroke-linecap="round"/>
<path d="M341.273 178.066L374.145 159.087" stroke="#454549" stroke-width="3.26255" stroke-linecap="round"/>
<path d="M341.273 184.835L374.145 165.857" stroke="#454549" stroke-width="3.26255" stroke-linecap="round"/>
</g>
<defs>
<filter id="filter0_d_1160_6791" x="363.194" y="39.786" width="90.6142" height="80.0273" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4.09802"/>
<feGaussianBlur stdDeviation="16.3921"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter1_d_1160_6791" x="365.808" y="171.239" width="90.912" height="80.1342" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4.09802"/>
<feGaussianBlur stdDeviation="16.3921"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter2_d_1160_6791" x="256.036" y="106.069" width="90.912" height="80.1342" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4.09802"/>
<feGaussianBlur stdDeviation="16.3921"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter3_d_1160_6791" x="29.9776" y="103.889" width="90.912" height="80.1342" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4.09802"/>
<feGaussianBlur stdDeviation="16.3921"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter4_d_1160_6791" x="155.541" y="181.485" width="65.0829" height="54.496" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2.50384"/>
<feGaussianBlur stdDeviation="10.0093"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter5_d_1160_6791" x="41.6944" y="243.597" width="65.0829" height="54.496" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2.50384"/>
<feGaussianBlur stdDeviation="10.0093"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter6_d_1160_6791" x="42.4209" y="-14.4441" width="65.0829" height="54.496" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2.50384"/>
<feGaussianBlur stdDeviation="10.0093"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter7_d_1160_6791" x="476.053" y="103.999" width="90.6142" height="80.0273" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4.09802"/>
<feGaussianBlur stdDeviation="16.3921"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter8_d_1160_6791" x="107.635" y="94.3761" width="127.875" height="139.055" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="3.27982"/>
<feGaussianBlur stdDeviation="13.1113"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter9_d_1160_6791" x="193.539" y="13.478" width="163.397" height="248.147" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="5.10617"/>
<feGaussianBlur stdDeviation="20.4247"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<filter id="filter10_d_1160_6791" x="308.891" y="91.6227" width="106.732" height="162.092" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="3.33539"/>
<feGaussianBlur stdDeviation="13.3416"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0666667 0 0 0 0 0.0666667 0 0 0 0 0.0705882 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1160_6791"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1160_6791" result="shape"/>
</filter>
<linearGradient id="paint0_linear_1160_6791" x1="399.337" y1="77.9378" x2="421.017" y2="77.9378" gradientUnits="userSpaceOnUse">
<stop stop-color="#C9FA68"/>
<stop offset="1" stop-color="#7AF097"/>
</linearGradient>
<linearGradient id="paint1_linear_1160_6791" x1="11.4157" y1="2.6161" x2="16.6479" y2="19.7397" gradientUnits="userSpaceOnUse">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#28B86A"/>
</linearGradient>
<radialGradient id="paint2_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.85393 17.5992) rotate(-41.6335) scale(11.4553 10.9804)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint3_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.9775 21.4045) rotate(-130.855) scale(11.6341 11.1518)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint4_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(26.3988 9.75092) rotate(154.29) scale(14.2538 13.6629)">
<stop stop-color="#5BEB9D"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint5_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.1236 1.17665e-06) rotate(116.565) scale(12.7632 12.2341)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FCFF80" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint6_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.85393 -0.95131) rotate(36.6071) scale(20.7388 16.8162)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint7_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.90262 1.90262) rotate(45) scale(8.40847 6.10705)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint8_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.8263 11.4157) rotate(49.8991) scale(6.44456 5.31743)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint9_linear_1160_6791" x1="11.4157" y1="2.6161" x2="16.6479" y2="19.7397" gradientUnits="userSpaceOnUse">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#28B86A"/>
</linearGradient>
<radialGradient id="paint10_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.85393 17.5992) rotate(-41.6335) scale(11.4553 10.9804)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint11_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.9775 21.4045) rotate(-130.855) scale(11.6341 11.1518)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint12_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(26.3988 9.75092) rotate(154.29) scale(14.2538 13.6629)">
<stop stop-color="#5BEB9D"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint13_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.1236 1.76773e-06) rotate(116.189) scale(14.878 14.2612)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.5"/>
</radialGradient>
<radialGradient id="paint14_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.85393 -0.95131) rotate(39.6947) scale(21.1925 17.1841)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint15_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.90262 1.90262) rotate(43.5113) scale(12.0512 8.75276)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint16_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(16.1778 11.4157) rotate(22.0971) scale(7.18108 5.92513)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FBFF4C" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint17_linear_1160_6791" x1="400.424" y1="203.284" x2="420.577" y2="207.254" gradientUnits="userSpaceOnUse">
<stop stop-color="#FCC2B7"/>
<stop offset="1" stop-color="#F97089"/>
</linearGradient>
<linearGradient id="paint18_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint19_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint20_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint21_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint22_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 1.49042e-06) rotate(116.565) scale(16.1667 15.4965)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF198B" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint23_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(36.6071) scale(26.2691 21.3005)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint24_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(45) scale(10.6507 7.7356)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint25_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.0467 14.4599) rotate(49.8991) scale(8.16311 6.73541)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint26_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint27_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint28_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint29_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint30_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 2.23912e-06) rotate(116.189) scale(18.8454 18.0642)">
<stop stop-color="#FF6719"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint31_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(39.6947) scale(26.8438 21.7665)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint32_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(43.5113) scale(15.2648 11.0868)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint33_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.4919 14.4599) rotate(22.0971) scale(9.09603 7.50517)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint34_linear_1160_6791" x1="290.652" y1="138.114" x2="310.805" y2="142.084" gradientUnits="userSpaceOnUse">
<stop stop-color="#FCC2B7"/>
<stop offset="1" stop-color="#F97089"/>
</linearGradient>
<linearGradient id="paint35_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint36_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint37_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint38_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint39_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 1.49042e-06) rotate(116.565) scale(16.1667 15.4965)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF198B" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint40_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(36.6071) scale(26.2691 21.3005)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint41_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(45) scale(10.6507 7.7356)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint42_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.0467 14.4599) rotate(49.8991) scale(8.16311 6.73541)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint43_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint44_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint45_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint46_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint47_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 2.23912e-06) rotate(116.189) scale(18.8454 18.0642)">
<stop stop-color="#FF6719"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint48_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(39.6947) scale(26.8438 21.7665)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint49_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(43.5113) scale(15.2648 11.0868)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint50_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.4919 14.4599) rotate(22.0971) scale(9.09603 7.50517)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint51_linear_1160_6791" x1="64.5938" y1="135.934" x2="84.7467" y2="139.903" gradientUnits="userSpaceOnUse">
<stop stop-color="#FCC2B7"/>
<stop offset="1" stop-color="#F97089"/>
</linearGradient>
<linearGradient id="paint52_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint53_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint54_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint55_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint56_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 1.49042e-06) rotate(116.565) scale(16.1667 15.4965)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF198B" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint57_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(36.6071) scale(26.2691 21.3005)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint58_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(45) scale(10.6507 7.7356)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint59_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.0467 14.4599) rotate(49.8991) scale(8.16311 6.73541)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint60_linear_1160_6791" x1="14.4599" y1="3.31373" x2="21.0874" y2="25.0036" gradientUnits="userSpaceOnUse">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#E54D00"/>
</linearGradient>
<radialGradient id="paint61_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.61498 22.2924) rotate(-41.6335) scale(14.51 13.9085)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint62_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(25.3048 27.1123) rotate(-130.855) scale(14.7365 14.1256)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint63_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(33.4385 12.3512) rotate(154.29) scale(18.0548 17.3063)">
<stop stop-color="#D919FF"/>
<stop offset="1" stop-color="#FFB2D8" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint64_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.6899 2.23912e-06) rotate(116.189) scale(18.8454 18.0642)">
<stop stop-color="#FF6719"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint65_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.61498 -1.20499) rotate(39.6947) scale(26.8438 21.7665)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint66_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.40998 2.40998) rotate(43.5113) scale(15.2648 11.0868)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint67_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(20.4919 14.4599) rotate(22.0971) scale(9.09603 7.50517)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FF6719" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint68_linear_1160_6791" x1="512.196" y1="142.15" x2="533.876" y2="142.15" gradientUnits="userSpaceOnUse">
<stop stop-color="#C9FA68"/>
<stop offset="1" stop-color="#7AF097"/>
</linearGradient>
<linearGradient id="paint69_linear_1160_6791" x1="11.4157" y1="2.6161" x2="16.6479" y2="19.7397" gradientUnits="userSpaceOnUse">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#28B86A"/>
</linearGradient>
<radialGradient id="paint70_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.85393 17.5992) rotate(-41.6335) scale(11.4553 10.9804)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint71_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.9775 21.4045) rotate(-130.855) scale(11.6341 11.1518)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint72_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(26.3988 9.75092) rotate(154.29) scale(14.2538 13.6629)">
<stop stop-color="#5BEB9D"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint73_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.1236 1.17665e-06) rotate(116.565) scale(12.7632 12.2341)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FCFF80" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint74_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.85393 -0.95131) rotate(36.6071) scale(20.7388 16.8162)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint75_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.90262 1.90262) rotate(45) scale(8.40847 6.10705)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint76_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.8263 11.4157) rotate(49.8991) scale(6.44456 5.31743)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint77_linear_1160_6791" x1="11.4157" y1="2.6161" x2="16.6479" y2="19.7397" gradientUnits="userSpaceOnUse">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#28B86A"/>
</linearGradient>
<radialGradient id="paint78_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.85393 17.5992) rotate(-41.6335) scale(11.4553 10.9804)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FAFF19" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint79_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.9775 21.4045) rotate(-130.855) scale(11.6341 11.1518)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint80_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(26.3988 9.75092) rotate(154.29) scale(14.2538 13.6629)">
<stop stop-color="#5BEB9D"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint81_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(17.1236 1.76773e-06) rotate(116.189) scale(14.878 14.2612)">
<stop stop-color="#2DCF78"/>
<stop offset="1" stop-color="#84F0B6" stop-opacity="0.5"/>
</radialGradient>
<radialGradient id="paint82_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-2.85393 -0.95131) rotate(39.6947) scale(21.1925 17.1841)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint83_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1.90262 1.90262) rotate(43.5113) scale(12.0512 8.75276)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint84_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(16.1778 11.4157) rotate(22.0971) scale(7.18108 5.92513)">
<stop stop-color="#FAFF19"/>
<stop offset="1" stop-color="#FBFF4C" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint85_linear_1160_6791" x1="180.146" y1="80.0155" x2="210.674" y2="84.0133" gradientUnits="userSpaceOnUse">
<stop stop-color="#20A1FF"/>
<stop offset="1" stop-color="#8082FF"/>
</linearGradient>
<linearGradient id="paint86_linear_1160_6791" x1="12.9971" y1="2.9785" x2="18.9541" y2="22.4741" gradientUnits="userSpaceOnUse">
<stop stop-color="#9A52FF"/>
<stop offset="1" stop-color="#B480FF"/>
</linearGradient>
<radialGradient id="paint87_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.24927 20.0372) rotate(-41.6335) scale(13.0421 12.5015)">
<stop offset="0.0884655" stop-color="#19A3FF"/>
<stop offset="1" stop-color="#19A3FF" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint88_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(22.7449 24.3695) rotate(-130.855) scale(13.2457 12.6966)">
<stop stop-color="#5F00E5"/>
<stop offset="1" stop-color="#909ADD" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint89_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(30.0558 11.1017) rotate(154.29) scale(16.2283 15.5556)">
<stop stop-color="#9A52FF"/>
<stop offset="1" stop-color="#FCA1FE" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint90_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.4956 1.33964e-06) rotate(116.565) scale(14.5312 13.9288)">
<stop stop-color="#8874FF"/>
<stop offset="1" stop-color="#8874FF" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint91_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.24927 -1.08309) rotate(36.6071) scale(23.6116 19.1457)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint92_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.16618 2.16618) rotate(45) scale(9.57326 6.95304)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint93_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(18.0187 12.9971) rotate(49.8991) scale(7.33729 6.05403)">
<stop stop-color="white" stop-opacity="0.15"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint94_linear_1160_6791" x1="12.9971" y1="2.9785" x2="18.9541" y2="22.4741" gradientUnits="userSpaceOnUse">
<stop stop-color="#9A52FF"/>
<stop offset="1" stop-color="#B480FF"/>
</linearGradient>
<radialGradient id="paint95_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.24927 20.0372) rotate(-41.6335) scale(13.0421 12.5015)">
<stop offset="0.0884655" stop-color="#19A3FF"/>
<stop offset="1" stop-color="#19A3FF" stop-opacity="0.4"/>
</radialGradient>
<radialGradient id="paint96_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(22.7449 24.3695) rotate(-130.855) scale(13.2457 12.6966)">
<stop stop-color="#5F00E5"/>
<stop offset="1" stop-color="#909ADD" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint97_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(30.0558 11.1017) rotate(154.29) scale(16.2283 15.5556)">
<stop stop-color="#9A52FF"/>
<stop offset="1" stop-color="#FCA1FE" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint98_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(19.4956 2.01261e-06) rotate(116.189) scale(16.9389 16.2368)">
<stop stop-color="#8874FF"/>
<stop offset="1" stop-color="#8874FF" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint99_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-3.24927 -1.08309) rotate(39.6947) scale(24.1282 19.5645)">
<stop stop-color="white" stop-opacity="0.79"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint100_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2.16618 2.16618) rotate(43.5113) scale(13.7206 9.96524)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint101_radial_1160_6791" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(18.4189 12.9971) rotate(22.0971) scale(8.17584 6.74591)">
<stop stop-color="white" stop-opacity="0.49"/>
<stop offset="1" stop-color="#19A3FF" stop-opacity="0.5"/>
</radialGradient>
<linearGradient id="paint102_linear_1160_6791" x1="605.97" y1="324.682" x2="670.97" y2="324.682" gradientUnits="userSpaceOnUse">
<stop stop-color="#232325"/>
<stop offset="1" stop-color="#232325" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint103_linear_1160_6791" x1="148.862" y1="171.819" x2="191.998" y2="171.819" gradientUnits="userSpaceOnUse">
<stop stop-color="#B480FF"/>
<stop offset="0.328125" stop-color="#5F00E6"/>
<stop offset="0.614583" stop-color="#1AA4FF"/>
<stop offset="1" stop-color="#19FF83"/>
</linearGradient>
<clipPath id="clip0_1160_6791">
<rect width="560" height="301" rx="7.78337" fill="white"/>
</clipPath>
<clipPath id="clip1_1160_6791">
<rect width="879.52" height="489.915" fill="white" transform="translate(-116.75 -115.41)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
img/graphics/nodes-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
img/graphics/ref-book.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
img/graphics/sdk-black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

BIN
img/graphics/sdk-white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

BIN
img/js-wallet-home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
img/js-wallet-send-xrp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

View File

@@ -76,6 +76,28 @@ button[disabled="disabled"] {
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
/* (Jump to) "Top" button */
.jump-to-top {

View File

@@ -144,6 +144,10 @@ a.card:hover h3 {
border: 2px solid #232325;
}
.light .circled-logo {
border: none;
}
.card-deck {
margin-top: 2.5rem;
margin-left: (-$card-deck-margin);

View File

@@ -68,7 +68,6 @@
}
}
.rpc-tool .main {
h1::before, h2::before, h3::before {
// These aren't anchors, and the placement of the anchor fix thing

352
styles/_docs-landing.scss Normal file
View File

@@ -0,0 +1,352 @@
.sdk-img {
align-self: center;
}
.light {
.sdk-img {
content:url(../../img/graphics/sdk-white.png);
}
.ref-book-illustration {
content:url(../../img/graphics/ref-book-light.png)
}
.tutorial-illustration {
content:url(../../img/graphics/tutorials-illustration-light.png)
}
.concepts-doc-illustration {
content:url(../../img/graphics/concepts-docs-light.png)
}
.use-cases {
.wallet-illustration {
content:url(../../img/graphics/wallet-light.svg)
}
.token-illustration {
content:url(../../img/graphics/tokens-light.png)
}
.connections-illustration {
content:url(../../img/graphics/nodes-light.svg)
}
}
.quickstart-image {
content:url(../../img/graphics/getting-started-pages-light.png)
}
.dev-tools-img {
content:url(../../img/graphics/dev-tools-light.svg)
}
.dev-tools-link:hover p {
color: $black
}
}
.dark {
.sdk-img {
content:url(../../img/graphics/sdk-black.png);
}
.ref-book-illustration {
content:url(../../img/graphics/ref-book.png)
}
.tutorial-illustration {
content:url(../../img/graphics/tutorials-illustration.png)
}
.concepts-doc-illustration {
content:url(../../img/graphics/concepts-doc.png)
}
.use-cases {
.wallet-illustration {
content:url(../../img/graphics/wallet-dark.png)
}
.token-illustration {
content:url(../../img/graphics/tokens-dark.png)
}
.connections-illustration {
content:url(../../img/graphics/nodes-dark.png)
}
}
.quickstart-image {
content:url(../../img/graphics/getting-started-pages-dark.svg)
}
.dev-tools-img {
content:url(../../img/graphics/dev-tools-dark.png)
}
.dev-tools-link:hover p {
color: $white;
}
.flat-card-grid .nav-link:hover {
color: $gray-200;
}
}
// Video Cards
.get-started-img, .flat-card {
max-width:100%;
max-height:100%;
}
.faded-text {
font-family: 'Work Sans';
font-style: normal;
font-weight: 400;
font-size: 15.5667px;
line-height: 23px;
}
.page-docs-index {
section {
padding-top: 64px;
padding-bottom:64px;
}
.dev-tools-link {
h6::before {
margin-top: -20px;
height: 20px;
}
h6:hover {
text-decoration: underline;
text-decoration-color: $purple;
background: none!important;
}
&:hover p {
text-decoration: none !important;
background: none !important;
display: inline-block; // Inline blocks don't have underlines
}
a:hover {
color: $purple;
text-decoration: none !important;
}
.btn-arrow::after{
content: url(../img/icons/arrow-right-purple.svg);
width: 1.5rem;
height: 1.5rem;
}
}
.langs {
h5:hover {
text-decoration: underline;
text-decoration-color: $purple;
background: none!important;
}
a:hover{
text-decoration: none !important;
}
.btn-arrow::after{
content: url(../img/icons/arrow-right-purple.svg);
vertical-align: baseline;
width: 1.5rem;
height: 1.5rem;
}
h5 {
margin-block-start: 0 !important;
}
}
h1 {
font-size: 3.875rem;
}
}
@media (max-width: 765px) {
.page-docs-index {
h1 {
font-size: 3rem;
}
.flat-card-grid {
grid-gap: 24px;
.flat-card {
padding: 32px 12px;
}
}
}
.page-docs-index::before {
display: none;
}
}
#langs-cards {
grid-gap: 40px;
}
@media (max-width: 991.98px) {
/* Fix dropdown size with top banner present */
.page-docs-index .langs-cards {
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
}
}
.dev-tools-img {
max-width:100%;
max-height: 100%;
margin:auto;
}
.page-docs {
.h4::before {
margin-top: 0;
height: 0;
}
.row {
margin-right: 0;
margin-left: 0;
}
.video-grid {
grid-gap: 35px;
}
.title-space {
margin-bottom: 16px;
}
.circled-logo {
margin-left:0.1rem;
}
}
.flat-card-grid {
grid-gap: 15px;
max-width: 100%;
min-height: 384px;
.flat-card {
padding: 32px 50px;
height: 100%;
width: 100%;
box-shadow: none;
}
.flat-card-padding {
margin-bottom: 75px;
}
img {
width: auto;
height: 115px;
margin-left: auto;
margin-right: auto;
}
.nav-link {
border: none !important;
&:hover {
text-decoration: underline;
text-decoration-color: $purple;
}
&::after {
content: none !important;
}
}
@include media-breakpoint-down(md) {
.flat-card-padding {
margin-bottom: 0;
}
.nav-link::after {
content: ' ' !important;
}
.flat-card .btn {
display: none;
}
}
}
.float-up-on-hover {
transition: all 0.35s ease-out;
cursor: pointer;
&:hover {
-webkit-transform: translateY(-16px);
-moz-transform: translateY(-16px);
-ms-transform: translateY(-16px);
-o-transform: translateY(-16px);
transform: translateY(-16px);
}
// Make the floating idempotent
.video-image {
&:hover {
-webkit-transform: none;
-moz-transform: none;
-ms-transform: none;
-o-transform: none;
transform: none;
}
}
}
// On mobile the vertical spacing is correct without adjustment.
@media (min-width: 992px) {
.align-button-on-bottom {
.btn-primary {
position: absolute;
bottom: 0;
}
}
}
.center-image {
display: flex;
justify-content: center;
}
.quickstart-card {
.quickstart-image {
margin-left: -20px;
margin-right: -20px;
margin-bottom: -20px;
}
@include media-breakpoint-up(lg) {
margin-left: -32px;
margin-right: -32px;
margin-bottom: -32px;
width: calc(100% + 64px);
}
}
.explore-links {
.card-grid {
grid-gap: 40px;
}
}
.full-documentation-link {
margin-top: -35px;
}

View File

@@ -118,6 +118,7 @@ section {
.col {
padding-left: 0;
padding-right: 0;
min-width: 100%;
}
&.card-grid-3xN {

View File

@@ -456,33 +456,8 @@
}
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
}
.page-funding {
.funding-list {
@@ -499,28 +474,6 @@
left: -4px;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
// even out height on large
@media (min-width: 992px) {
.funding-box{
@@ -553,29 +506,6 @@
padding: .75rem;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
#container-scroll {
height:160px;
position:relative;
@@ -698,27 +628,6 @@
padding: .75rem;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
.event-card {
max-width: 311px;
margin: 32px auto;
@@ -1060,7 +969,8 @@
.page-docs-index {
&::before {
background-image: url(../img/backgrounds/bg-docs.png);
background-image: url(../../img/backgrounds/docs-splash.svg);
background-position-x: right;
}
.center-search {
@@ -1075,21 +985,6 @@
}
}
section {
@include media-breakpoint-down(md) {
margin-bottom: 2.5rem;
}
@include media-breakpoint-up(lg) {
.row .col-lg-6:first-child {
padding-right: 40px;
}
.row .col-lg-6:last-child {
padding-left: 40px;
}
}
}
#software-and-sdks .card-deck {
.card:nth-child(1) .card-footer {
background-image: url(../img/cards/4col-green.svg);
@@ -1376,27 +1271,6 @@
.btn {
padding: 0.75rem;
}
@media (max-width: 767.98px) {
.btn-arrow-out {
display: block;
width: 100%;
}
}
.btn-arrow-out::after {
background-position: left 0px bottom 0px;
content: "\00a0";
background-image: url(../img/icons/arrow-up-right-white.svg);
background-repeat: no-repeat;
display: inline-block;
padding: 4px 8px 4px 12px;
transition: background-position 0.3s ease-in-out;
margin-left: 4px;
}
.btn-arrow-out:hover::after {
background-position: left 4px bottom 4px;
}
}
html.light {
.page-dev-tools {

View File

@@ -1,12 +1,12 @@
{
"devDependencies": {
"bootstrap": "^4.6.0",
"bootstrap": "^4.6.1",
"node-sass": "^7.0.0"
},
"scripts": {
"build-css": "node-sass --include-path scss xrpl.scss ../assets/css/devportal2022-v16.css --output-style compressed",
"build-css-out": "node-sass --include-path scss xrpl.scss ../out/assets/css/devportal2022-v16.css --output-style compressed --source-map true",
"build-css-watch-out": "node-sass --recursive --watch --include-path scss xrpl.scss ../out/assets/css/devportal2022-v16.css --output-style compressed --source-map true"
"build-css": "node-sass --include-path scss xrpl.scss ../assets/css/devportal2022-v17.css --output-style compressed",
"build-css-out": "node-sass --include-path scss xrpl.scss ../out/assets/css/devportal2022-v17.css --output-style compressed --source-map true",
"build-css-watch-out": "node-sass --recursive --watch --include-path scss xrpl.scss ../out/assets/css/devportal2022-v17.css --output-style compressed --source-map true"
},
"dependencies": {
"sass": "^1.26.10"

View File

@@ -69,6 +69,7 @@ $line-height-base: 1.5;
@import "_video.scss";
//@import "_top-banner.scss";
@import "_toml-checker.scss";
@import "_docs-landing.scss";
// Light/Dark theme settings ---------------------------------------------------
// Option to only change theme on user system settings. No toggle.

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,7 @@
{% if target.lang=="ja" %}
<link href="{{currentpage.prefix}}assets/css/fonts-ja.css" rel="stylesheet" />
{% endif %}
<link href="{{currentpage.prefix}}assets/css/devportal2022-v16.css" rel="stylesheet" />
<link href="{{currentpage.prefix}}assets/css/devportal2022-v17.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3" />

View File

@@ -4,7 +4,7 @@
<article class="pt-3 p-md-3">
<h1>Not Found</h1>
<div class="content">
<p>Sorry, this page does not exist. Try looking in the <a href="/docs.html#full-doc-index">Full Documentation Index</a>, or you can search the site:</p>
<p>Sorry, this page does not exist. Try looking in the <a href="/docs-index.html">Full Documentation Index</a>, or you can search the site:</p>
<form role="search">
<div class="form-group">
<div class="input-group" id="centersearchboxcontainer">

View File

@@ -0,0 +1,24 @@
{% extends "base.html.jinja" %}
{% block breadcrumbs %}{% endblock %}
{% block mainclasses %}landing page-docs page-docs-index landing-builtin-bg overflow-hidden styled-page{% endblock %}
{% block main %}
<section class="container-new py-26 doc-index">
<div class="d-flex flex-column-reverse w-100">
<h2 id="full-doc-index" class="h4">{% trans %}Full documentation index{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}See Everything{% endtrans %}</h6>
</div>
{% set docpages = pages|selectattr('html', 'defined_and_equalto', 'docs.html')|list|first %}
<div class="row">
{% for page in docpages.children if page.html not in ("by-label.html", "faq.html", 'docs-index.html') %}
{% set parent_html = page.html %}
{% set depth = 6 %}
{% set show_blurbs = False %}
<div class="col-md-6 mt-20">
<a href="{% if '//' not in page.html %}{{target.prefix}}{% endif %}{{page.html}}"><h5 class="mb-3">{{page.name}}</h5></a>
{% include 'children.html' %}
</div>
{% endfor %}
</div>
</section>
{% endblock %}

View File

@@ -1,126 +1,426 @@
{% extends "base.html.jinja" %}
{% block mainclasses %}landing page-docs-index landing-builtin-bg{% endblock %}
{% block mainclasses %}landing page-docs page-docs-index landing-builtin-bg overflow-hidden styled-page{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block left_sidebar %}
{% set tree_top = pages|selectattr("html", "defined_and_equalto", "docs.html")|first %}
{% include 'component-tree-nav.html.jinja' %}
{% endblock %}
{% block main %}
<section class="py-26 text-center">
<div class="col-xl-4 col-lg-6 mx-auto text-center">
<div class="d-flex flex-column-reverse w-100">
<h1 class="mb-18">{% trans %}What Would You Like to Learn?{% endtrans %}</h1>
<h6 class="eyebrow mb-3">{% trans %}XRP Ledger Documentation{% endtrans %}</h6>
<section class="text-center title-space">
<div class="col-lg-9 mx-auto text-center">
<div class="d-flex flex-column-reverse">
<h1 class="">{% trans %}XRP Ledger Developer Resources{% endtrans %}</h1>
<h6 class="eyebrow mb-3">{% trans %}Documentation{% endtrans %}</h6>
</div>
</div>
</section>
<section class="container-new mb-50-until-sm" id="docs-browse-by">
<div class="row">
<div class="col-lg-6 mb-10" id="popular-topics">
<h2 class="h4">{% trans %}Browse By Popular Topics{% endtrans %}</h2>
<ul class="nav flex-column">
{% for pg_html in currentpage.popular_pages %}
{% set page = pages|selectattr("html", "defined_and_equalto", pg_html)|first %}
{% if page.html is not defined %}
{% include "ERROR: Couldn't find page "+pg_html+" from popular_pages" %}
{% endif %}
<li class="nav-item"><a href="{% if '//' not in page.html %}{{target.prefix}}{% endif %}{{page.html}}" class="nav-link">{{page.name}}</a>
{% endfor %}
</ul>
</div><!--/#popular-topics-->
{# Macros #}
{% macro primaryButton(href, text, isArrowUp) %}
{% if isArrowUp %}
<a class="btn btn-primary btn-arrow-out" id="{{href}}-button" href="{{href}}">{{ text }}</a>
{% else %}
<a class="btn btn-primary btn-arrow" id="{{href}}-button" href="{{href}}">{{ text }}</a>
{% endif %}
{% endmacro %}
<div class="col-lg-6" id="browse-by-label">
<h2 class="h4">{% trans %}Browse By Label{% endtrans %}</h2>
{% include 'component-tag-cloud.html.jinja' %}
</div><!--/#browse-by-label-->
{% macro flatCard(href, title, description, linkText, imgClass) %}
<a href="{{href}}" class="card flat-card float-up-on-hover">
<img
class="mb-2 {{imgClass}}"
alt={{title}}
/>
<h5 class="row">
<div class="nav-link">{{ title }}</div>
</h5>
<p class="row faded-text flat-card-padding">
{{ description }}
</p>
<div class="col align-button-on-bottom">
<div class="btn btn-primary btn-arrow" id="{{href}}-button">{{ linkText }}</div>
</div>
</a>
{% endmacro %}
{% macro videoCard(url, title, src)%}
<div class="col float-up-on-hover">
<iframe id="video1" style="display:none;" src="{{url}}" title="{{title}}" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<a href="{{url}}" id="playvideo" class="btn1" data-url={{url}}>
<img
class="get-started-img video-image"
id={{title}}
src={{src}}
/>
<h6 class="pt-3">{{ title }}</h6>
</a>
</div>
{% endmacro %}
{% macro useCasesCard(subItems, title, imgClass, id) %}
<div class="col">
<img
class="use-cases-img img-fluid mb-2 shadow {{imgClass}}"
alt="{{title}}"
id={{id}}
>
<h5 class="mt-4">{{title}} </h5>
<ul class="nav flex-column">
{% for item in subItems %}
<li class="nav-item"><a href="{{item.link}}" class="nav-link">{{item.description}}</a>
{% endfor %}
</ul>
</div>
{% endmacro %}
{% macro devToolsCard(link, title, description) %}
<a href="{{ link }}" class="col dev-tools-link">
<h6 class="btn-arrow">{{ title }}</h6>
<p> {{ description }}</p>
</a>
{% endmacro %}
{% set recommendedPages = [
{
"description": _("rippled API Reference"),
"link": "./manage-the-rippled-server.html",
},
{
"description": _("XRP Faucet"),
"link": "./xrp-testnet-faucet.html",
},
{
"description": _("Getting Started with Python"),
"link": "./get-started-using-python.html#get-started-using-python",
},
{
"description": _("Websocket API Tool"),
"link": "./websocket-api-tool.html",
},
{ "description": _("XRP Ledger Explorer"), "link": "https://livenet.xrpl.org" },
] %}
{%
set intermediateVideos = [
{
"src": "./assets/img/backgrounds/docs-advanced-payment-features@2x.png",
"title": "Advanced Payment Features",
"url": "https://www.youtube.com/embed/e2Iwsk37LMk?rel=0&amp;showinfo=0&amp;autoplay=1",
},
{
"src": "./assets/img/backgrounds/docs-governance@2x.png",
"title": "Governance and the Amendment Process",
"url": "https://www.youtube.com/embed/4GbRdanHoR4?rel=0&amp;showinfo=0&amp;autoplay=1",
},
{
"src": "./assets/img/backgrounds/docs-sidechains@2x.png",
"title": "Federated Sidechains",
"url": "https://www.youtube.com/embed/NhH4LM8NxgY?rel=0&amp;showinfo=0&amp;autoplay=1",
},
]
%}
{% set useCases = [
{
"title": "On-Chain Finance",
"id": "on-chain-finance-use-cases",
"imgClass": "wallet-illustration",
"subItems": [
{
"description": "Trade on the decentralized exchange",
"link": "./trade-in-the-decentralized-exchange.html",
},
{
"description": "Make payments",
"link": "./send-xrp.html",
},
{
"description": "Use specialized payment types",
"link": "./use-specialized-payment-types.html"
}
],
},
{
"title": "Tokens",
"id": "token-use-cases",
"imgClass": "token-illustration",
"subItems": [
{
"description": "Non-fungible Tokens",
"link": "./non-fungible-tokens.html",
},
{
"description": "Issue a stablecoin",
"link": "./issue-a-fungible-token.html",
},
{
"description": "Assign an authorized minter",
"link": "./authorize-minter.html",
},
],
},
{
"title": "Payments",
"id": "payments-use-cases",
"imgClass": "connections-illustration",
"subItems": [
{
"description": "Peer to peer payments",
"link": "./direct-xrp-payments.html",
},
{
"description": "Cross-currency payments",
"link": "./cross-currency-payments.html",
},
{
"description": "Escrows",
"link": "./escrow.html",
},
],
},
]
%}
{%
set getStartedVideos = [
{
"src": "./assets/img/backgrounds/docs-intro-to-XRP-ledger@2x.png",
"title": "Intro to XRP Ledger",
"url": "https://www.youtube.com/embed/sVTybJ3cNyo?rel=0&amp;showinfo=0&amp;autoplay=1",
},
{
"src": "./assets/img/backgrounds/docs-accounts@2x.png",
"title": "Accounts",
"url": "https://www.youtube.com/embed/eO8jE6PftX8?rel=0&amp;showinfo=0&amp;autoplay=1",
},
{
"src": "./assets/img/backgrounds/docs-decentralized-exchange@2x.png",
"title": "Decentralized Exchange",
"url": "https://www.youtube.com/embed/VWNrHBDfXvA?rel=0&amp;showinfo=0&amp;autoplay=1",
},
{
"src": "./assets/img/backgrounds/docs-tokenization@2x.png",
"title": "Tokenization",
"url": "https://www.youtube.com/embed/Oj4cWOiWf4A?rel=0&amp;showinfo=0&amp;autoplay=1",
},
]
%}
{%
set devTools = [
{
"title": "Faucets",
"link": "./xrp-testnet-faucet.html",
"description":
"Get credentials and test-XRP for XRP Ledger Testnet or Devnet.",
},
{
"title": "WebSocket Tool",
"link": "./websocket-api-tool.html",
"description":
"Send sample requests and get responses from the rippled API.",
},
{
"title": "XRP Ledger Explorer",
"link": "https://livenet.xrpl.org",
"description":
"View validations of new ledger versions in real-time, chart the location of servers in the XRP Ledger.",
},
{
"title": "Transaction Sender",
"link": "./tx-sender.html",
"description":
"Test how your code handles various XRP Ledger transactions by sending them over the Testnet to the address.",
},
]
%}
<section class="container-new ">
<div class="nav card-grid flat-card-grid card-grid-3xN">
<div class="col">
{{ flatCard("./concepts.html",
"Concepts",
"Learn the \"what\" and the \"why\" behind fundamental aspects of the XRP Ledger.",
"Read the Docs",
"concepts-doc-illustration") }}
</div>
<div class="col">
{{ flatCard("./tutorials.html",
"Tutorials",
"Get step-by-step guidance to perform common tasks with the XRP Ledger.",
"View Tutorials",
"tutorial-illustration") }}
</div>
<div class="col">
{{ flatCard("./references.html",
"References",
"Look up reference documentation for the XRP Ledger protocol, API methods, and more.",
"View References",
"ref-book-illustration") }}
</div>
</div>
</section>
<section class="container-new mb-50-until-sm" id="software-and-sdks">
<div class="d-flex flex-column-reverse w-100">
<h2 class="h4">{% trans %}Software and SDKs{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}Start Developing{% endtrans %}</h6>
<section class="container-new">
<h4 class="pb-4">{% trans %}Use Cases{% endtrans %}</h4>
<div class="card-grid card-grid-3xN use-cases">
{% for useCase in useCases %}
{{ useCasesCard(useCase.subItems, useCase.title, useCase.imgClass, useCase.id)}}
{% endfor %}
</div>
</section>
{% set curated_cards = [
"get-started-using-javascript.html",
"get-started-using-python.html",
"get-started-using-java.html",
"get-started-using-http-websocket-apis.html"
] %}
{% set mobile_cols = 2 %}
{% set show_blurbs = False %}
{% include 'component-curated-cards.html.jinja' %}
</section><!--/#software-and-sdks-->
<section class="container-new mb-50-until-sm" id="doc-types">
<div class="d-flex flex-column-reverse w-100">
<h2 class="h4">{% trans %}Article types{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}Dive In{% endtrans %}</h6>
<section class="container-new ">
<h4 class="pb-4">{% trans %}Getting Started{% endtrans %}</h4>
<div class="card-grid card-grid-2xN quickstart-card">
<div class="col">
<a href="./xrpl-quickstart.html" class="card float-up-on-hover">
<h5 class="mt-7">{% trans %}Quickstart to XRP Ledger{% endtrans %}</h5>
<p class="mb-8 mt-4">
{% trans %}An introduction to fundamental aspects of the XRP Ledger{% endtrans %}.
</p>
<div class="dg-lg-block mb-3">
<div
class="btn btn-primary btn-arrow get-started-button"
>
{% trans %}Get Started{% endtrans %}
</div>
</div>
<img
alt="quick-start"
id="quick-start-img"
class="quickstart-image"
/>
</a>
</div>
<div class="col">
<div class="card-grid card-grid-2xN video-grid">
{% set test = "./assets/img/backgrounds/docs-intro-to-XRP-ledger@2x.png"%}
{% for video in getStartedVideos %}
{{ videoCard(video.url, video.title, video.src) }}
{% endfor %}
</div>
<div class="align-button-on-bottom">
{{ primaryButton("https://www.youtube.com/playlist?list=PLJQ55Tj1hIVZtJ_JdTvSum2qMTsedWkNi", "Watch Full Series", true) }}
</div>
</div>
</div>
{% set curated_cards = currentpage.children|selectattr("html","ne","by-label.html")|selectattr("html","ne","faq.html")|selectattr("html","ne","https://learn.xrpl.org/")|selectattr("html","ne","dev-tools.html")|map(attribute="html")|list %}
{% set mobile_cols = 1 %}
{% set show_blurbs = True %}
{% include 'component-curated-cards.html.jinja' %}
</section><!--/#doc-types-->
</section>
<section class="container-new mb-50-until-sm" id="run-a-network-node">
<div class="d-flex flex-column-reverse w-100">
<h2 class="h4">{% trans %}Run an XRP Ledger network node{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}Participate in the Network{% endtrans %}</h6>
<section class="container-new ">
<div class="d-flex flex-column-reverse col-sm-8 p-0">
<h3 class="h4 h2-sm">{% trans %}Interact with the XRP Ledger in a language of your choice{% endtrans %}</h3>
<h6 class="eyebrow mb-3">{% trans %}Explore SDKs{% endtrans %}</h6>
</div>
{% set curated_cards = [
"the-rippled-server.html",
"install-rippled.html",
"run-rippled-as-a-validator.html",
"troubleshoot-the-rippled-server.html"
] %}
{% include 'component-curated-cards.html.jinja' %}
</section><!--/#run-a-network-node-->
<div class="card-grid card-grid-2xN">
<div class="col">
<div class="card-grid langs-cards card-grid-2xN mt-10" id="langs-cards">
<div class="col langs">
<a href="./get-started-using-javascript.html">
<img
src="./assets/img/logos/javascript.svg"
class="circled-logo"
>
<h5 class="btn-arrow">{% trans %}Javascript{% endtrans %}</h5>
</a>
</div>
<div class="col langs">
<a href="./get-started-using-python.html">
<img
src="./assets/img/logos/python.svg"
class="circled-logo"
>
<h5 class="btn-arrow">{% trans %}Python{% endtrans %}</h5>
</a>
</div>
<div class="col langs">
<a href="./get-started-using-java.html">
<img
src="./assets/img/logos/java.svg"
class="circled-logo"
>
<h5 class="btn-arrow">{% trans %}Java{% endtrans %}</h5>
</a>
</div>
</div>
</div>
<div class="col center-image">
<img
class="img-fluid sdk-img"
/>
</div>
</div>
</section>
<section class="container-new mb-50-until-sm" id="docs-hot-topic">
<div class="d-flex flex-column-reverse w-100">
<h2 class="h4">{% trans %}NFTs{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}Hot Topic{% endtrans %}</h6>
</div>
<div class="row">
<div class="col-lg-6">
<p class="longform">{% trans %}Interested in non-fungible tokens, but concerned about their <a href="impact.html">large carbon footprint</a>? Read more about issuing NFTs on the XRP Ledger:{% endtrans %}</p>
<section class="container-new ">
<h4 class="pb-4">Intermediate Learning Sources</h4>
<div class="card-grid card-grid-3xN">
{% for video in intermediateVideos %}
{{ videoCard(video.url, video.title, video.src) }}
{% endfor %}
</div>
<div class="col-lg-6">
<ul class="nav flex-column">
<li class="nav-item"><a href="nft-conceptual-overview.html" class="nav-link">NFT Conceptual Overview</a></li>
<li class="nav-item"><a href="nftoken.html" class="nav-link">NFToken Format</a></li>
</ul>
</div>
</div>
</section><!--/#docs-hot-topic-->
</section>
<section class="container-new mb-50-until-sm doc-index">
<div class="d-flex flex-column-reverse w-100">
<h2 id="full-doc-index" class="h4">{% trans %}Full documentation index{% endtrans %}</h2>
<h6 class="eyebrow mb-3">{% trans %}See Everything{% endtrans %}</h6>
</div>
<div class="row">
{% for page in currentpage.children if page.html not in ("by-label.html", "faq.html") %}
{% set parent_html = page.html %}
{% set depth = 6 %}
{% set show_blurbs = False %}
<div class="col-md-6 mt-20">
<a href="{% if '//' not in page.html %}{{target.prefix}}{% endif %}{{page.html}}"><h5 class="mb-3">{{page.name}}</h5></a>
{% include 'children.html' %}
<section class="container-new ">
<div class="card-grid card-grid-2xN">
<div class="col d-flex align-items-center justify-content-center">
<img
class="dev-tools-img"
>
</div>
<div class="col explore-links">
<div class="d-flex flex-column-reverse w-100">
<h4 class="mb-10">{% trans %}Explore, Test, Verify{% endtrans %}</h4>
<h6 class="mb-3">{% trans %}Explore Dev Tools{% endtrans %}</h6>
</div>
<p class="mb-20">
{% trans %}Use these web-based tools to assist during all stages of development, from getting your first payment to testing your implementation for best practices.{% endtrans %}
</p>
<div class="card-grid card-grid-2xN">
{% for card in devTools %}
{{ devToolsCard(card.link, card.title, card.description) }}
{% endfor %}
</div>
{{ primaryButton("./dev-tools.html", "View All tools", false) }}
</div>
</div>
{% endfor %}
</div>
</section><!--/.doc-index-->
</section>
<section class="container-new " id="docs-browse-by">
<div class="row card-grid card-grid-2xN">
<div class="col" id="popular-topics">
<h2 class="h4">{% trans %}Browse By Recommended Pages{% endtrans %}</h2>
<ul class="nav flex-column">
{% for page in recommendedPages %}
<li class="nav-item"><a href="{{page.link}}" class="nav-link">{{page.description}}</a>
{% endfor %}
</ul>
</div><!--/#popular-topics-->
<div class="col">
<div class="card cta-card p-8-sm p-10-until-sm br-8">
<img src="./img/backgrounds/cta-home-purple.svg" class="d-none-sm cta cta-top-left">
<img src="./img/backgrounds/cta-home-green.svg" class="cta cta-bottom-right">
<div class="z-index-1 position-relative">
<h2 class="h4 mb-8-sm mb-10-until-sm">{% trans %}Get Free Test XRP{% endtrans %}</h2>
<p class="mb-10">{% trans %}Connect to the XRP Ledger Testnet network to develop and test your apps built on the XRP Ledger, without risking real money or impacting production XRP Ledger users.{% endtrans %}</p>
<a class="btn btn-primary btn-arrow" href="xrp-testnet-faucet.html">{% trans %}Generate Testnet Credentials{% endtrans %}</a>
</div>
</div>
</div>
</div>
</section><!-- Browse by recommended and Generate Testnet Credentials -->
<section class="container-new">
<a href="./docs-index.html" class="ml-auto">{% trans %}See full documenation index{% endtrans %}</a>
</section>
{% endblock %}
{% block endbody %}
{% endblock %}
{% block analytics %}
<script type="application/javascript">
window.dataLayer = window.dataLayer || [];

View File

@@ -81,23 +81,35 @@
<div class="form-check form-check-inline">
<input value="hackathon" id="hackathon-upcoming" name="hackathon-upcoming" type="checkbox" class="events-filter" checked />
<label for="hackathon-upcoming">Hackathons</label>
</div>
<div class="form-check form-check-inline">
<input value="ama" id="ama-upcoming" name="ama-upcoming" type="checkbox" class="events-filter" checked />
<label for="ama-upcoming">AMAs</label>
</div>
<div class="form-check form-check-inline">
<input value="cc" id="cc-upcoming" name="cc-upcoming" type="checkbox" class="events-filter" checked />
<label for="cc-upcoming">Community Calls</label>
</div>
<div class="form-check form-check-inline">
<input value="zone" id="zone-upcoming" name="zone-upcoming" type="checkbox" class="events-filter" checked />
<label for="zone-upcoming">XRPL Zone</label>
</div>
</div>
</div>
{% set events = [
{ "name": "Hackathon: 2021",
"description": "Explore the exciting project submissions from the fall 2021 XRPL Hackathon that focused on the NFT and Hooks smart contract functionalities on the ledger.",
"type": "hackathon-past",
"type": "hackathon",
"link": "https://xrpl-hackathon-2021.devpost.com/project-gallery",
"location": "Virtual",
"date": "September 13-October 6, 2021",
"image": "event-hack-2021.svg",
"image": "Hackathons.png",
"end_date": "October 6, 2021",
},
{ "name": "XRPL Community Meetup: San Diego",
"description": "The first official Meetup hosted by the XRPL Community. Community members in Southern California gathered around a firepit and shared their experiences with the XRPL.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrpl-community/events/281806645/",
"location": "San Diego, CA",
"date": "Saturday, November 20, 2021",
@@ -107,7 +119,7 @@
{ "name": "XRPL Community Meetup: Atlanta",
"description": "The inaugural Meetup in the Southeast region of the United States got community members excited to meet like-minded individuals in their area.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrpl-community/events/281980446/",
"location": "Atlanta, GA",
"date": "Saturday, November 27, 2021",
@@ -117,7 +129,7 @@
{ "name": "XRPL Community Meetup: San Francisco",
"description": "Community members in the Bay Area with diverse backgrounds in technology and beyond met in downtown San Francisco.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrpl-community/events/281806676/",
"location": "San Francisco, CA",
"date": "Monday, November 29, 2021",
@@ -127,7 +139,7 @@
{ "name": "XRPL Community Meetup: Miami",
"description": "One of the biggest Meetups held so far, this was the first of an ongoing series of local XRPL Community Meetup events in Miami. ",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrpl-community/events/281829463/",
"location": "Miami, FL ",
"date": "Thursday, December 9, 2021",
@@ -137,7 +149,7 @@
{ "name": "XRPL Community Meetup: Nashville",
"description": "Nashville-based members of the XRPL Community came together to network, learn, share ideas, and form new partnerships. ",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-nashville-community/events/282538189/",
"location": "Nashville, TN",
"date": "Saturday, December 18, 2021",
@@ -149,7 +161,7 @@
{ "name": "NYC Meetup/Hackathon XRPL Celebration",
"id": "upcoming-xrpl-new-york",
"description": "The NYC/XRP community and Dev Null Productions cordially invites you to attend our 10th meetup, being held in celebration of the on-going XRPL Hackathon, at the unique and artistic TALS studio in Midtown Manhattan.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/NYC-XRP/events/284485901/",
"location": "NYC, NY",
"date": "March 30, 2022",
@@ -160,7 +172,7 @@
{ "name": "XRPL Community Meetup: London",
"id": "upcoming-xrpl-london",
"description": "Join for an evening of programming and networking with members of the XRPL Community in London, co-organised by Peerkat - the NFT platform for creators on the XRPL.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-london-community/events/283536458/",
"location": "IDEALondon",
"date": "March 31, 2022",
@@ -171,7 +183,7 @@
{ "name": "XRPL Community Meetup: Toronto",
"id": "upcoming-xrpl-toronto",
"description": "Join us for our first Toronto meetup with an evening of programming and networking with other members of the XRP Ledger Community with special guests from the XUMM Wallet and ARK PLATES teams!",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrpl-toronto-community-meetup/events/284177188/",
"location": "Toronto",
"date": "March 31, 2022",
@@ -182,7 +194,7 @@
{ "name": "XRPL Community Meetup: San Diego",
"id": "upcoming-xrpl-san-diego",
"description": "Get together with other San Diego-based members of the XRP Ledger Community to network and discuss all things XRPL! Join us for our second San Diego XRPL Meetup.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-san-diego-community/events/284663355/",
"location": "San Diego, CA",
"date": "April 1st 2022",
@@ -193,7 +205,7 @@
{ "name": "XRPL Community Meetup: Irvine LA",
"id": "upcoming-xrpl-irvine",
"description": "Get together with other LA-based members of the XRP Ledger Community to network and discuss all things XRPL.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-la-community-meetup/events/284824635/",
"location": "UC Irvine, CA",
"date": "April 3rd 2022",
@@ -204,7 +216,7 @@
{ "name": "XRPL Community Meetup: Miami #2",
"id": "upcoming-xrpl-miami-2",
"description": "We're excited to host our second Miami meetup for XRP Ledger community members on April 6th from 6-8pm, featuring Marco Neri, Developer Advocate at Ripple, who will join us to give a presentation on the XRP Ledger.",
"type": "meetup-past",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-miami-community/events/284463736/",
"location": "The LAB Miami, FL",
"date": "April 6th 2022",
@@ -215,110 +227,132 @@
{ "name": "Hackathon:<br />New Year, New NFT",
"id": "upcoming-xrpl-hackathon-new-year",
"description": "Build Functional NFTs that span across a full range of use cases.",
"type": "hackathon-past",
"type": "hackathon",
"link": "https://xrplnft2022.devpost.com/",
"location": "Virtual",
"date": "January 31 - March 14, 2022",
"image": "event-hack-nft@2x.png",
"image": "Hackathons.png",
"end_date": "March 14, 2022",
},
{ "name": "Hackathon: Creating Real World Impact",
"description": "Build apps to improve lives in the real world using any of the SDKs and APIs for the XRP Ledger.",
"type": "hackathon-past",
"type": "hackathon",
"link": "https://xrplimpact.devpost.com/",
"location": "Virtual",
"date": "May 26 - Jul 11, 2022",
"image": "event-hack-nft@2x.png",
"image": "Hackathons.png",
"end_date" : "July 11, 2022",
},
{ "name": "Conference:<br />Apex 2021",
"description": "View sessions from the Apex 2021 stages in Las Vegas and Tallinn.",
"type": "conference-past",
"type": "conference",
"link": "https://www.youtube.com/playlist?list=PLJQ55Tj1hIVZgnreb8ODgxJW032M9Z2XZ",
"location": "Las Vegas, Tallinn",
"date": "September 29-30, 2021",
"image": "event-conference-apex-2021.png",
"image": "Conference.png",
"end_date": "September 30, 2022",
},
{ "name": "Hackathon:<br />NFT Launch Party",
"description": "Build Functional NFTs that span across a full range of use cases.",
"type": "hackathon-past",
"type": "hackathon",
"link": "https://xrplnft.devpost.com/",
"location": "Virtual",
"date": "Oct 31 - Dec 12, 2022",
"image": "event-hack-nft@2x.png",
"image": "Hackathons.png",
"end_date": "December 12, 2022",
},
{ "name": "XRPL Zone @ Consensus",
"description": "XRPL Zone: your all-in-one location for creating and collaborating on XRP Ledger (XRPL) projects.",
"type": "conference-upcoming",
"type": "zone",
"link": "https://xrplzone-consensus.splashthat.com/",
"location": "Austin, Texas",
"date": "April 27, 2023",
"image": "xrpl-card@2x.jpg",
"image": "XRPLZone.png",
"end_date": "April 27, 2023"
},
{ "name": "XRPL Developer AMAs",
"description": "A chat with Crossmark about wallet development on the XRP Ledger!",
"type": "conference-upcoming",
"type": "ama",
"link": "https://discord.com/invite/xrpl",
"location": "XRPL Developers Discord",
"date": "April 14, 2023",
"image": "event-hack-nft@2x.png",
"image": "AMAs.png",
"end_date": "April 14, 2023"
},
{ "name": "NFTs with xrp.cafe",
"description": "A cozy discussion with xrp.cafe about NFTs and the future of NFT infrastructure on the XRP Ledger.",
"type": "conference-past",
"type": "ama",
"link": "https://dev.to/ripplexdev/xrpcafe-ama-on-xrpl-developers-discord-36gp",
"location": "XRPL Developers Discord",
"date": "January 1, 2023",
"image": "event-hack-nft@2x.png",
"image": "AMAs.png",
"end_date": "January 1, 2023"
},
{ "name": "Community Calls #2",
"description": "A community call about XRPL amendments with Chris McKay.",
"type": "conference-past",
"type": "cc",
"link": "https://youtu.be/oNJ1Qqns2Gw",
"location": "XRPL Developers Discord",
"date": "August 8, 2022",
"image": "event-hack-nft@2x.png",
"image": "CommunityCalls.png",
"end_date": "August 8, 2022"
},
{ "name": "Community Calls #1",
"description": "An open discussion about the development of XLS-20 and NFTs on the XRP Ledger.",
"type": "conference-past",
"type": "cc",
"link": "https://youtu.be/KpSt0PFT2QM",
"location": "XRPL Developers Discord",
"date": "June 02, 2022",
"image": "event-hack-nft@2x.png",
"image": "CommunityCalls.png",
"end_date": "June 02, 2022"
},
{ "name": "AMAs: POS and Crypto Payments with FriiPay",
"description": "A discussion with FriiPay about payment rails and POS integrations through the XRP Ledger",
"type": "conference-past",
"type": "ama",
"link": "https://dev.to/ripplexdev/xrpl-developer-ama-pos-and-crypto-payments-with-friipay-13hm",
"location": "XRPL Developers Discord",
"date": "February 15, 2023",
"image": "event-hack-nft@2x.png",
"image": "AMAs.png",
"end_date": "February 15, 2023"
},
{ "name": "AMAs: On-chain Data with Bithomp",
"description": "A discuss with Bithomp about data infrastructure and their NFT integrations in one of the most popular explorers on the XRP Ledger.",
"type": "conference-past",
"type": "ama",
"link": "https://dev.to/ripplexdev/xrpl-developer-ama-bithomp-4a8d",
"location": "XRPL Developers Discord",
"date": "March 15, 2023",
"image": "event-hack-nft@2x.png",
"image": "AMAs.png",
"end_date": "March 15, 2023"
},
{
"name": "XRPL Community Meetup: Madrid",
"description": "Get together with other Madrid-based members of the XRP Ledger community to network and discuss all things XRPL.",
"type": "meetup",
"link": "https://www.meetup.com/xrp-ledger-espana-madrid-y-barcelona/events/292597878",
"location": "Madrid",
"date": "April 29, 2023",
"image": "Madrid.png",
"end_date": "April 29, 2023"
},
{
"name": "APEX 2023: The XRPL Developer Summit",
"description": "Apex XRPL Developer Summit is the annual event where developers, contributors, and thought leaders come together to learn, build, share, network, and celebrate all things XRP Ledger.",
"type": "conference",
"link": "http://apexdevsummit.com",
"location": "Amsterdam",
"date": "September 6 - 8, 2023",
"image": "Conference.png",
"end_date": "September 8, 2023"
}
]
%}
{# Available Types - conference, hackathon, ama, cc, zone, meetup #}
{% set results = categorize_dates(events) %}
{% set upcoming = results.upcoming %}
{% set past = results.past %}
@@ -363,6 +397,18 @@
<input value="hackathon" id="hackathon-past" name="hackathon-past" type="checkbox" class="events-filter" checked />
<label for="hackathon-past">Hackathons</label>
</div>
<div class="form-check form-check-inline">
<input value="ama" id="ama-past" name="ama-past" type="checkbox" class="events-filter" checked />
<label for="ama-past">AMAs</label>
</div>
<div class="form-check form-check-inline">
<input value="cc" id="cc-past" name="cc-past" type="checkbox" class="events-filter" checked />
<label for="cc-past">Community Calls</label>
</div>
<div class="form-check form-check-inline">
<input value="zone" id="zone-past" name="zone-past" type="checkbox" class="events-filter" checked />
<label for="zone-past">XRPL Zone</label>
</div>
</div>
</div>
@@ -410,6 +456,27 @@
$('.hackathon-upcoming').hide();
}
});
$('#ama-upcoming').change(function () {
if ($('#ama-upcoming').is(':checked')) {
$('.ama-upcoming').show();
} else {
$('.ama-upcoming').hide();
}
});
$('#cc-upcoming').change(function () {
if ($('#cc-upcoming').is(':checked')) {
$('.cc-upcoming').show();
} else {
$('.cc-upcoming').hide();
}
});
$('#zone-upcoming').change(function () {
if ($('#zone-upcoming').is(':checked')) {
$('.zone-upcoming').show();
} else {
$('.zone-upcoming').hide();
}
});
$('#conference-past').change(function () {
if ($('#conference-past').is(':checked')) {
@@ -432,6 +499,27 @@
$('.hackathon-past').hide();
}
});
$('#ama-past').change(function () {
if ($('#ama-past').is(':checked')) {
$('.ama-past').show();
} else {
$('.ama-past').hide();
}
});
$('#cc-past').change(function () {
if ($('#cc-past').is(':checked')) {
$('.cc-past').show();
} else {
$('.cc-past').hide();
}
});
$('#zone-past').change(function () {
if ($('#zone-past').is(':checked')) {
$('.zone-past').show();
} else {
$('.zone-past').hide();
}
});
</script>

View File

@@ -176,8 +176,8 @@
"href": "https://hooks-testnet.xrpl-labs.com/" },
{ "chip": _("Enabled"),
"title": _("Non-Fungible Tokens"),
"description": _("Lower fees, faster transactions, and custom token functionality make the XRPL ideally suited for building an ecosystem for NFTs. Explore <a href='docs.html#docs-hot-topic'>proposed standards</a> for issuing NFTs."),
"href": "docs.html#docs-hot-topic"},
"description": _("Lower fees, faster transactions, and custom token functionality make the XRPL ideally suited for building an ecosystem for NFTs. Explore the XRP Ledger's NFT capabilities."),
"href": "non-fungible-tokens.html"},
] %}
{% for feat in features %}
<li class="col ls-none pt-2">

View File

@@ -8,10 +8,11 @@ def categorize_dates(arr):
for obj in arr:
end_date = datetime.strptime(obj['end_date'], '%B %d, %Y')
if end_date < today:
obj['type'] = obj['type'] + '-past'
past.append(obj)
else:
obj['type'] = obj['type'] + '-upcoming'
upcoming.append(obj)
return {'past': past, 'upcoming': upcoming}
export = {