2024-12-04 16:35:47 +11:00
<!DOCTYPE html>
2024-12-04 18:59:04 +11:00
< html data-bs-theme = "dark" lang = "en-au" >
2024-12-04 16:35:47 +11:00
< head >
2024-12-04 18:59:04 +11:00
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0, shrink-to-fit=no" >
2024-12-11 14:39:07 +11:00
< title > Vault | Woodburn< / title >
< meta name = "theme-color" content = "#ffffff" >
2024-12-04 18:59:04 +11:00
< meta name = "twitter:description" content = "Woodburn Vault" >
< meta name = "twitter:image" content = "https://vault.woodburn.au/assets/img/favicon.png" >
< meta property = "og:description" content = "Woodburn Vault" >
< meta property = "og:type" content = "website" >
< meta property = "og:title" content = "Vault | Woodburn" >
< meta name = "twitter:card" content = "summary" >
< meta name = "twitter:title" content = "Vault | Woodburn" >
2024-12-05 19:20:47 +11:00
< meta name = "description" content = "Woodburn Vault" >
< meta property = "og:image" content = "https://vault.woodburn.au/assets/img/favicon.png" >
2024-12-04 18:59:04 +11:00
< script type = "application/ld+json" >
{
"@context": "http://schema.org",
"@type": "WebSite",
"name": "Vault | Woodburn",
"url": "https://vault.woodburn.au"
}
< / script >
2024-12-11 14:39:07 +11:00
< link rel = "icon" type = "image/png" sizes = "192x192" href = "assets/img/favicon-192.png" >
2024-12-04 18:59:04 +11:00
< link rel = "icon" type = "image/png" sizes = "512x512" href = "assets/img/favicon.png" >
< link rel = "stylesheet" href = "assets/bootstrap/css/bootstrap.min.css" >
2024-12-11 14:39:07 +11:00
< link rel = "manifest" href = "manifest.json" crossorigin = "use-credentials" >
2024-12-04 18:59:04 +11:00
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Catamaran:100,200,300,400,500,600,700,800,900&display=swap" >
< link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Lato:100,100i,300,300i,400,400i,700,700i,900,900i&display=swap" >
2024-12-04 16:35:47 +11:00
< / head >
< body >
2024-12-04 18:59:04 +11:00
< nav class = "navbar navbar-expand-lg fixed-top bg-dark navbar-custom navbar-dark" >
2024-12-04 20:54:05 +11:00
< div class = "container" > < a class = "navbar-brand" href = "#" > Vault | Woodburn< / a > < / div >
2024-12-04 18:59:04 +11:00
< / nav >
< header class = "text-center text-white masthead" >
< div class = "masthead-content" >
< div class = "container" >
2024-12-05 12:26:58 +11:00
< h1 class = "masthead-heading mb-0" > Woodburn Vault< / h1 >
< h2 class = "masthead-subheading mb-0" > An easy way to buy into a diverse crypto portfolio.< / h2 >
2024-12-12 12:45:53 +11:00
< p > Woodburn Vault Balance: {{vault}} USD ({{vault_aud}} AUD)< br > stWDBRN Token Supply: {{supply}}< br > Current Token Value: {{value}} USD ({{value_aud}} AUD)< / p >
2024-12-04 18:59:04 +11:00
< / div >
< / div >
< div class = "bg-circle-1 bg-circle" > < / div >
< div class = "bg-circle-2 bg-circle" > < / div >
< div class = "bg-circle-3 bg-circle" > < / div >
< div class = "bg-circle-4 bg-circle" > < / div >
< / header >
2024-12-04 20:45:27 +11:00
< section style = "margin-top: 50px;margin-bottom: 50px;max-width: 100vw;overflow: hidden;" >
2024-12-04 20:13:36 +11:00
< div class = "text-center" >
2024-12-05 15:35:09 +11:00
< h1 data-bs-toggle = "tooltip" data-bss-tooltip = "" id = "chart-header" title = "Toggle per token view" style = "border-bottom: 5px dashed var(--bs-body-color);width: fit-content;margin: auto;margin-bottom: 20px;" > Current Vault Contents< / h1 >
< div class = "text-center" id = "data-table" > < / div >
2024-12-05 15:42:57 +11:00
< div class = "d-xl-flex justify-content-xl-center" id = "pie-chart" style = "margin: auto;" > < script type = "text/javascript" >
2024-12-04 20:13:36 +11:00
window.onload = function () {
2024-12-05 15:35:09 +11:00
google.charts.load('current', { packages: ['corechart'] });
2024-12-04 20:13:36 +11:00
// Set a callback to run when the API is loaded.
google.charts.setOnLoadCallback(drawChart);
2024-12-05 15:35:09 +11:00
let isPerTokenView = false; // Track the current view state
let chart; // Declare the chart instance globally to reuse it
let options = {
pieSliceText: 'label',
tooltip: { isHtml: false },
legend: {
position: 'right',
textStyle: { color: 'white' }
},
backgroundColor: '#212529',
2024-12-09 16:03:44 +11:00
sliceVisibilityThreshold: 0.05
2024-12-05 15:35:09 +11:00
};
async function fetchData(apiUrl) {
try {
const response = await fetch(apiUrl);
if (!response.ok) throw new Error('Failed to fetch data from API');
return await response.json();
} catch (error) {
console.error('Error fetching data:', error);
return null;
2024-12-04 20:13:36 +11:00
}
2024-12-04 20:45:27 +11:00
}
2024-12-05 15:35:09 +11:00
function transformDataForChart(data) {
const chartData = [];
for (const token in data) {
if (token !== 'total') {
chartData.push([
token, // Label for the chart
data[token].value, // Value for the chart
data[token].tooltip, // Tooltip for the chart
]);
}
}
return chartData;
}
async function drawChart() {
const apiUrl = '/api/v1/vault';
const data = await fetchData(apiUrl);
if (!data) return; // Exit if data fetch fails
const chartDataTable = new google.visualization.DataTable();
chartDataTable.addColumn('string', 'Token');
chartDataTable.addColumn('number', 'Value');
chartDataTable.addColumn({ type: 'string', role: 'tooltip', 'p': { 'html': false } });
chartDataTable.addRows(transformDataForChart(data));
chart = new google.visualization.PieChart(document.getElementById('pie-chart'));
resizeAndDraw(chart, chartDataTable, options);
updateText(true);
populateTable(data);
}
function updateText(isVault) {
let headerText = document.getElementById('chart-header');
if (isVault) {
headerText.innerText = 'Current Vault Contents';
} else {
headerText.innerText = 'Current Per Token Holding';
}
}
function populateTable(data) {
2024-12-06 13:53:19 +11:00
const tableContainer = document.getElementById('data-table');
tableContainer.innerHTML = ''; // Clear previous table data
// Create table elements
const table = document.createElement('table');
table.style.margin = 'auto';
table.style.borderCollapse = 'collapse';
table.style.maxWidth = '100%';
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
// Create table header
const headerRow = document.createElement('tr');
['Name', 'Amount', 'USD Value'].forEach((headerText, index) => {
const th = document.createElement('th');
th.textContent = headerText;
th.style.border = '1px solid #ccc';
th.style.padding = '8px 20px';
th.style.backgroundColor = '#333';
th.style.color = 'white';
if (headerText === 'USD Value') {
th.style.cursor = 'pointer'; // Make it clear this header is clickable
th.addEventListener('click', () => sortTableByValue(tbody));
}
2024-12-05 15:35:09 +11:00
2024-12-06 13:53:19 +11:00
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
2024-12-05 20:21:56 +11:00
2024-12-06 13:53:19 +11:00
// Create table rows
for (const token in data) {
if (token !== 'total') {
const row = document.createElement('tr');
const nameCell = document.createElement('td');
nameCell.textContent = data[token].name;
nameCell.style.border = '1px solid #ccc';
nameCell.style.padding = '8px 20px';
const amountCell = document.createElement('td');
2024-12-09 15:43:22 +11:00
// If token in other investments
otherInvestments = ["Lending"]
if (otherInvestments.includes(token)) {
amountCell.textContent = `${data[token].amount} Positions`;
}
else {
amountCell.textContent = `${data[token].amount} ${token}`;
}
2024-12-06 13:53:19 +11:00
amountCell.style.border = '1px solid #ccc';
amountCell.style.padding = '8px 20px';
const valueCell = document.createElement('td');
valueCell.textContent = `$${data[token].value.toFixed(2)}`;
valueCell.style.border = '1px solid #ccc';
valueCell.style.padding = '8px 20px';
row.appendChild(nameCell);
row.appendChild(amountCell);
row.appendChild(valueCell);
tbody.appendChild(row);
}
}
2024-12-05 20:21:56 +11:00
2024-12-06 13:53:19 +11:00
table.appendChild(thead);
table.appendChild(tbody);
tableContainer.appendChild(table);
sortTableByValue(tbody);
}
2024-12-05 20:21:56 +11:00
2024-12-06 13:53:19 +11:00
// Function to sort table rows by the "Value" column
function sortTableByValue(tbody) {
const rows = Array.from(tbody.querySelectorAll('tr'));
const sortedRows = rows.sort((a, b) => {
// Remove `$` and parse the value as float
const valueA = parseFloat(a.children[2].textContent.replace('$', '')) || 0;
const valueB = parseFloat(b.children[2].textContent.replace('$', '')) || 0;
return valueA - valueB;
});
2024-12-04 20:45:27 +11:00
2024-12-06 13:53:19 +11:00
// Reverse order if already sorted in ascending order
const isDescending = tbody.getAttribute('data-sort-order') === 'desc';
if (!isDescending) {
sortedRows.reverse();
tbody.setAttribute('data-sort-order', 'desc');
} else {
tbody.setAttribute('data-sort-order', 'asc');
}
// Append sorted rows back to the tbody
tbody.innerHTML = '';
sortedRows.forEach(row => tbody.appendChild(row));
}
2024-12-04 20:45:27 +11:00
2024-12-05 15:35:09 +11:00
async function toggleChart() {
isPerTokenView = !isPerTokenView;
const apiUrl = isPerTokenView ? '/api/v1/token' : '/api/v1/vault';
const data = await fetchData(apiUrl);
if (!data) return; // Exit if data fetch fails
const chartDataTable = new google.visualization.DataTable();
chartDataTable.addColumn('string', 'Token');
chartDataTable.addColumn('number', 'Value');
chartDataTable.addColumn({ type: 'string', role: 'tooltip', 'p': { 'html': false } });
chartDataTable.addRows(transformDataForChart(data));
2024-12-06 13:53:19 +11:00
resizeAndDraw(chart, chartDataTable, options);
2024-12-05 15:35:09 +11:00
updateText(!isPerTokenView);
populateTable(data);
2024-12-04 20:13:36 +11:00
}
2024-12-05 15:35:09 +11:00
function resizeAndDraw(chart, chartDataTable, options) {
function resizeChart() {
const width = window.innerWidth * 0.8;
const height = window.innerHeight * 0.5;
const dynamicOptions = { ...options };
if (width >= 700) {
dynamicOptions.width = width;
dynamicOptions.height = height;
}
chart.draw(chartDataTable, dynamicOptions);
}
resizeChart();
window.addEventListener('resize', resizeChart);
}
// Set button event listener
document.getElementById('chart-header').addEventListener('click', toggleChart);
};
2024-12-06 13:53:19 +11:00
< / script > < / div > < a class = "btn btn-secondary" role = "button" href = "https://www.coingecko.com/en/portfolios/public/vault" target = "_blank" style = "margin: 10px;" > View on Coingecko< / a >
2024-12-04 20:13:36 +11:00
< / div >
< / section >
2024-12-04 18:59:04 +11:00
< section >
< div class = "container" >
< div class = "row align-items-center" >
< div class = "col-lg-6 order-lg-2" >
< div class = "p-5" > < img class = "rounded-circle img-fluid" src = "assets/img/01.jpg" > < / div >
< / div >
< div class = "col-lg-6 order-lg-1" >
< div class = "p-5" >
< h2 class = "display-4" > 1. Buy tokens< / h2 >
2024-12-06 12:05:58 +11:00
< p > To get started buy stWDBRN tokens at the current price to buy a percent of the vault value. The buy in value is then invested in various projects in order to increase the token's value.< br > < br > Send SOL or approved tokens to vault.woodburn.sol and receive stWDBRN in exchange. (Note automated swaps only happen for deposits over 1 USDC)< / p > < button class = "btn btn-primary" id = "video-button" type = "button" style = "margin: 20px;" > See how< / button > < button class = "btn btn-primary" id = "approved-tokens-button" type = "button" style = "margin: 20px;" > Approved Tokens< / button > < div id = "video-div" style = "margin-top: 20px; display: none;" >
< video id = "video" style = "max-width: 75%; height: auto;border-radius: 25px;" controls >
< source src = "https://cloud.woodburn.au/s/dsaF9MHMz9s5H2q/download/Screen_Recording_20241205_235805_Phantom.mp4"
type="video/mp4">
< / video >
< / div >
< div id = "approved-tokens" style = "margin-top: 20px; display: none;" >
< h2 > Approved Tokens< / h2 >
< p > The following tokens are approved to be used with the stWDBRN Vault.< / p >
< ul id = "approvedTokenList" > < / ul >
< / div >
< script >
function toggleVideo() {
var video = document.getElementById("video-div");
var approvedtokens = document.getElementById("approved-tokens");
if (video.style.display === "none") {
video.style.display = "block";
approvedtokens.style.display = "none";
} else {
video.style.display = "none";
}
}
async function fetchAndRenderTokens() {
try {
// Fetch data from the API
const response = await fetch('/api/v1/tokens');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const tokens = await response.json();
// Select the container where the list will be appended
const tokenList = document.getElementById('approvedTokenList');
// Loop through the tokens and create HTML for each
tokens.forEach(token => {
const listItem = document.createElement('li'); // Create a list item
const anchor = document.createElement('a'); // Create a link element
anchor.href = token.url; // Set the URL
anchor.target = '_blank'; // Open the link in a new tab
anchor.textContent = `${token.name} (${token.symbol.toUpperCase()})`; // Set the text
listItem.appendChild(anchor); // Append the anchor to the list item
tokenList.appendChild(listItem); // Append the list item to the container
});
} catch (error) {
console.error('Error fetching or rendering tokens:', error);
}
}
function toggleApprovedTokens() {
// Fill in the approved tokens list if it isn't already
if (document.getElementById("approvedTokenList").innerHTML === "") {
fetchAndRenderTokens();
}
var approvedtokens = document.getElementById("approved-tokens");
var video = document.getElementById("video-div");
if (approvedtokens.style.display === "none") {
approvedtokens.style.display = "block";
video.style.display = "none";
} else {
approvedtokens.style.display = "none";
}
}
document.getElementById("video-button").onclick = function () {
toggleVideo();
};
document.getElementById("approved-tokens-button").onclick = function () {
toggleApprovedTokens();
};
< / script >
2024-12-04 18:59:04 +11:00
< / div >
< / div >
< / div >
< / div >
< / section >
< section >
< div class = "container" >
< div class = "row align-items-center" >
< div class = "col-lg-6 order-lg-1" >
< div class = "p-5" > < img class = "rounded-circle img-fluid" src = "assets/img/02.jpg" > < / div >
< / div >
< div class = "col-lg-6 order-lg-2" >
< div class = "p-5" >
< h2 class = "display-4" > 2. HODL and check price< / h2 >
< p > Hodl your stWDBRN while the value fluctuates. Check this site to see the current value.< / p >
< / div >
< / div >
< / div >
< / div >
< / section >
< section >
< div class = "container" >
< div class = "row align-items-center" >
< div class = "col-lg-6 order-lg-2" >
< div class = "p-5" > < img class = "rounded-circle img-fluid" src = "assets/img/03.jpg" > < / div >
< / div >
< div class = "col-lg-6 order-lg-1" >
< div class = "p-5" >
< h2 class = "display-4" > 3. Sell your tokens< / h2 >
2024-12-06 13:53:19 +11:00
< p > When you want to cash out just sell your tokens back to me at the current token price.< / p > < a class = "btn btn-primary" role = "button" href = "mailto:vault@woodburn.au" target = "_blank" > Contact to sell tokens< / a >
2024-12-04 18:59:04 +11:00
< / div >
< / div >
< / div >
< / div >
< / section >
2024-12-05 12:39:55 +11:00
< section >
< div class = "container" >
< div class = "p-5" >
< h2 class = "display-4" > Vault addresses< / h2 >
< div class = "table-responsive" >
< table class = "table" >
< thead >
< tr >
< th > Chain< / th >
< th > Address< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > Solana< / td >
2024-12-06 17:22:07 +11:00
< td > < a href = "https://explorer.solana.com/address/NWywvhcqdkJsm1s9VVviPm9UfyDtyCW9t8kDb24PDPN" target = "_blank" > NWywvhcqdkJsm1s9VVviPm9UfyDtyCW9t8kDb24PDPN< / a > < / td >
2024-12-05 12:39:55 +11:00
< / tr >
< tr >
< td > Cardano< / td >
2024-12-06 17:22:07 +11:00
< td > < a href = "https://cardanoscan.io/stakekey/e12a06f8f40e1b0f06ea9732af8ef7377453e285a163ea7c0d64481be1" target = "_blank" > stake1uy4qd785pcds7ph2jue2lrhhxa698c5959375lqdv3yphcgwc8qna< / a > < / td >
2024-12-05 12:39:55 +11:00
< / tr >
2024-12-05 22:48:43 +11:00
< tr >
< td > Sui< / td >
2024-12-06 17:22:07 +11:00
< td > < a href = "https://suivision.xyz/account/0x7e4fa1592e4fad084789f9fe1a4d7631a2e6477b658e777ae95351681bcbe8da" target = "_blank" > 0x7e4fa1592e4fad084789f9fe1a4d7631a2e6477b658e777ae95351681bcbe8da< / a > < / td >
2024-12-05 22:48:43 +11:00
< / tr >
2024-12-09 16:03:44 +11:00
< tr >
< td > dYdX< / td >
< td > < a href = "https://www.mintscan.io/dydx/address/dydx1ugraczuyfmxy8k38nps4fu7e5derryzx95fs8n" target = "_blank" > dydx1ugraczuyfmxy8k38nps4fu7e5derryzx95fs8n< / a > < / td >
< / tr >
2024-12-05 12:39:55 +11:00
< / tbody >
< / table >
< / div >
< / div >
2024-12-09 16:03:44 +11:00
< div class = "p-5" >
< h2 class = "display-4" > DeFi Positions< / h2 >
< div class = "table-responsive" id = "defi-table" >
< table class = "table" >
< thead >
< tr >
< th > Type< / th >
< th > Initial Value< / th >
< th > Date bought< / th >
< th > Current Value< / th >
2024-12-20 14:48:48 +11:00
< th > APY< / th >
2024-12-09 16:03:44 +11:00
< th > Info< / th >
< th > Last Updated< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > Position Name< / td >
< td > $0< / td >
< td > 00/00/00< / td >
< td > $0< / td >
2024-12-20 14:48:48 +11:00
< td > 0%< / td >
2024-12-09 16:03:44 +11:00
< td > Find out more< / td >
< td > 00/00/00< / td >
< / tr >
< / tbody >
< / table >
< / div > < script type = "text/javascript" >
async function fetchAndInjectDefiData() {
try {
// Fetch data from the API
const response = await fetch('/api/v1/defi');
if (!response.ok) {
throw new Error('Network response was not ok' + response.statusText);
}
const data = await response.json();
// Locate the table where the data will be injected
const tableBody = document.querySelector('#defi-table tbody');
if (!tableBody) {
console.error('Table body not found. Make sure your table has an id "defi-table" with a < tbody > element.');
return;
}
// Clear existing rows (optional, depending on use case)
tableBody.innerHTML = '';
const formatDate = (timestamp) => {
const date = new Date(timestamp * 1000); // Convert seconds to milliseconds
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are zero-based
const year = String(date.getFullYear()).slice(-2); // Get last two digits of the year
return `${day}/${month}/${year}`;
};
// Iterate over the data and create table rows
data.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
< td > ${item.name}< / td >
< td > $${item.initial}< / td >
< td > ${formatDate(item.bought)}< / td >
< td > $${item.value}< / td >
2024-12-20 14:48:48 +11:00
< td > ~${item.apy}%< / td >
< td > < a href = "${item.url}" target = "_blank" > Find out more< / a > < / td >
< td > ${formatDate(item.updated)}< / td >
`;
tableBody.appendChild(row);
});
} catch (error) {
console.error('Error fetching or injecting data:', error);
}
}
// Set on page load event listener
window.addEventListener('load', fetchAndInjectDefiData);
< / script >
< / div >
< div class = "p-5" >
< h2 class = "display-4" > Other< / h2 >
< div class = "table-responsive" id = "other-table" >
< table class = "table" >
< thead >
< tr >
< th > Asset< / th >
< th > APY< / th >
< th > Info< / th >
< th > Last Updated< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > Asset Name< / td >
< td > 0%< / td >
< td > Find out more< / td >
< td > 00/00/00< / td >
< / tr >
< / tbody >
< / table >
< / div > < script type = "text/javascript" >
async function fetchAndInjectDefiData() {
try {
// Fetch data from the API
const response = await fetch('/api/v1/apy');
if (!response.ok) {
throw new Error('Network response was not ok' + response.statusText);
}
const data = await response.json();
// Locate the table where the data will be injected
const tableBody = document.querySelector('#other-table tbody');
if (!tableBody) {
console.error('Table body not found. Make sure your table has an id "other-table" with a < tbody > element.');
return;
}
// Clear existing rows (optional, depending on use case)
tableBody.innerHTML = '';
const formatDate = (timestamp) => {
const date = new Date(timestamp * 1000); // Convert seconds to milliseconds
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are zero-based
const year = String(date.getFullYear()).slice(-2); // Get last two digits of the year
return `${day}/${month}/${year}`;
};
// Iterate over the data and create table rows
data.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
< td > ${item.name}< / td >
< td > ~${item.apy}%< / td >
2024-12-09 16:03:44 +11:00
< td > < a href = "${item.url}" target = "_blank" > Find out more< / a > < / td >
< td > ${formatDate(item.updated)}< / td >
`;
tableBody.appendChild(row);
});
} catch (error) {
console.error('Error fetching or injecting data:', error);
}
}
// Set on page load event listener
window.addEventListener('load', fetchAndInjectDefiData);
< / script >
< / div >
2024-12-05 12:39:55 +11:00
< / div >
< / section >
2024-12-04 18:59:04 +11:00
< footer class = "py-5 bg-black" >
< div class = "container" >
2024-12-06 17:22:07 +11:00
< p class = "text-center text-white m-0 small" > Copyright © < a href = "https://nathan.woodburn.au" target = "_blank" > Nathan.Woodburn/< / a > 2024< / p >
2024-12-04 18:59:04 +11:00
< / div >
< / footer >
< script src = "assets/bootstrap/js/bootstrap.min.js" > < / script >
2024-12-05 15:35:09 +11:00
< script src = "assets/js/bs-init.js" > < / script >
2024-12-04 20:13:36 +11:00
< script src = "https://www.gstatic.com/charts/loader.js" > < / script >
2024-12-04 16:35:47 +11:00
< / body >
< / html >