From 60a51a372e3136f29f471ad1db7e1dc1db6a5a0d Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:51:39 +0100 Subject: [PATCH 01/14] Add Dioxus configuration for web app --- frontend/Dioxus.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 frontend/Dioxus.toml diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml new file mode 100644 index 0000000..9af2ae2 --- /dev/null +++ b/frontend/Dioxus.toml @@ -0,0 +1,3 @@ +[web.app] +title = "cAssets dToken Wrapper" +base_path = "cAssets_dToken_wrapper" From d9deedeb0b4e013aa411dd29ac3a3e7540b9a080 Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:54:36 +0100 Subject: [PATCH 02/14] Update GitHub Actions workflow for deployment add missing path to frontend folder --- .github/workflows/deploy.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d669c3f..57717b2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Deploy Dioxus app to GitHub Pages on: push: - branches: [ deploy ] # or your default branch + branches: [ main ] # or your default branch workflow_dispatch: permissions: @@ -24,14 +24,16 @@ jobs: - name: Install Dioxus CLI run: cargo install dioxus-cli --locked - - name: Build Dioxus Web App + - name: Build Dioxus Web App (in frontend/) + working-directory: frontend run: dx build --release - - name: Upload artifact + - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@v3 with: - path: target/dioxus/release/web - + # IMPORTANT: path from repo root: + path: frontend/target/dioxus/release/web + deploy: runs-on: ubuntu-latest needs: build From 0b97fbbdada68623dd14aa63742a056633f4be4e Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:10:01 +0100 Subject: [PATCH 03/14] Change deployment branch from 'main' to 'deploy' fix deploy branch name from main to deploy --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 57717b2..039d0c0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Deploy Dioxus app to GitHub Pages on: push: - branches: [ main ] # or your default branch + branches: [ deploy ] # or your default branch workflow_dispatch: permissions: From 5c5a91521b3b8df7c2ba4e129a717fe015ed858f Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:13:49 +0100 Subject: [PATCH 04/14] Add application name and default platform to Dioxus --- frontend/Dioxus.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index 9af2ae2..2f00969 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -1,3 +1,7 @@ +[application] +name = "cAssets dToken Wrapper" +default_platform = "web" + [web.app] title = "cAssets dToken Wrapper" base_path = "cAssets_dToken_wrapper" From 0267ec23468f8749fdafbae8ed101292e48b2ed8 Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:31:38 +0100 Subject: [PATCH 05/14] fix dx build path --- .github/workflows/deploy.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 039d0c0..84d9402 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -31,9 +31,8 @@ jobs: - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@v3 with: - # IMPORTANT: path from repo root: - path: frontend/target/dioxus/release/web - + path: frontend/target/dx/dioxus_meta_app/release/web + deploy: runs-on: ubuntu-latest needs: build From 2f584f2feef96d4743da61d5781647f7815b733c Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:57:36 +0100 Subject: [PATCH 06/14] fix github pages by enabling csp hashing --- frontend/Dioxus.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index 2f00969..4a3ca7e 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -5,3 +5,4 @@ default_platform = "web" [web.app] title = "cAssets dToken Wrapper" base_path = "cAssets_dToken_wrapper" +csp_hash = true \ No newline at end of file From 27d9a524ed78c74be3f2d99142e3cf5fe64ad560 Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:14:57 +0100 Subject: [PATCH 07/14] extend build path to go into public folder --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 84d9402..f633c21 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -31,7 +31,7 @@ jobs: - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@v3 with: - path: frontend/target/dx/dioxus_meta_app/release/web + path: frontend/target/dx/dioxus_meta_app/release/web/public deploy: runs-on: ubuntu-latest From 658e3d158d337408d9da3ed49e8c85b2cc5b906a Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Thu, 13 Nov 2025 23:49:02 +0100 Subject: [PATCH 08/14] enable bundling --- frontend/Dioxus.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index 4a3ca7e..33e61bb 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -5,4 +5,7 @@ default_platform = "web" [web.app] title = "cAssets dToken Wrapper" base_path = "cAssets_dToken_wrapper" -csp_hash = true \ No newline at end of file +csp_hash = true + +[web.wasm] +mode = "bundled" \ No newline at end of file From 12cfb9d4b44a1810ed5288c8f93bc097fe44f377 Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:08:02 +0100 Subject: [PATCH 09/14] disable minify --- frontend/Dioxus.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index 33e61bb..81f6b23 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -5,7 +5,13 @@ default_platform = "web" [web.app] title = "cAssets dToken Wrapper" base_path = "cAssets_dToken_wrapper" +## keeps CSP happy csp_hash = true +## avoids SWC minifier errors +minify_js = false [web.wasm] -mode = "bundled" \ No newline at end of file +## ensures WASM + JS are together +mode = "bundled" +## forces Dioxus to generate the snippets/ folder for wasm-bindgen helpers +## snippets = true \ No newline at end of file From 95ce4924ea2c9a43fcc9641adee445c879458f1b Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:24:46 +0100 Subject: [PATCH 10/14] disable --release --- .github/workflows/deploy.yml | 4 ++-- frontend/Dioxus.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f633c21..b2c5539 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,12 +26,12 @@ jobs: - name: Build Dioxus Web App (in frontend/) working-directory: frontend - run: dx build --release + run: dx build - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@v3 with: - path: frontend/target/dx/dioxus_meta_app/release/web/public + path: frontend/target/dx/dioxus_meta_app/debug/web/public deploy: runs-on: ubuntu-latest diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index 81f6b23..b031ca3 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -1,9 +1,9 @@ [application] -name = "cAssets dToken Wrapper" +name = "cAssets_dToken_Wrapper" default_platform = "web" [web.app] -title = "cAssets dToken Wrapper" +title = "cAssets_dToken_Wrapper" base_path = "cAssets_dToken_wrapper" ## keeps CSP happy csp_hash = true From 7e072eac29415a356d2879b65afa4621048b2cab Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:41:02 +0100 Subject: [PATCH 11/14] cleanup --- frontend/Cargo.toml | 4 ++-- frontend/Dioxus.toml | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 6e6fc9e..7b236ed 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -dioxus = { version = "0.7", features = ["macro","web"] } -dioxus-web = "0.7" +dioxus = { version = "0.7.1", features = ["macro","web"] } +#dioxus = { version = "0.7.1", features = ["macro","web"], git = "https://github.com/dioxuslabs/dioxus", branch="main"} wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" js-sys = "0.3" diff --git a/frontend/Dioxus.toml b/frontend/Dioxus.toml index b031ca3..4e5ceb4 100644 --- a/frontend/Dioxus.toml +++ b/frontend/Dioxus.toml @@ -13,5 +13,3 @@ minify_js = false [web.wasm] ## ensures WASM + JS are together mode = "bundled" -## forces Dioxus to generate the snippets/ folder for wasm-bindgen helpers -## snippets = true \ No newline at end of file From 8a006c7d1936a6a94a6c5eaaca86125a248dc4fc Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:34:28 +0100 Subject: [PATCH 12/14] handle js errors better --- frontend/Cargo.toml | 16 ++-- frontend/src/app.rs | 42 +++++---- frontend/src/metamask.js | 183 ++++++++++++++++++++++++--------------- frontend/src/metamask.rs | 82 +++++++++++++++--- 4 files changed, 215 insertions(+), 108 deletions(-) diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index 7b236ed..829f485 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -4,14 +4,13 @@ version = "0.1.0" edition = "2024" [dependencies] -dioxus = { version = "0.7.1", features = ["macro","web"] } -#dioxus = { version = "0.7.1", features = ["macro","web"], git = "https://github.com/dioxuslabs/dioxus", branch="main"} -wasm-bindgen = "0.2" -wasm-bindgen-futures = "0.4" -js-sys = "0.3" -web-sys = { version = "0.3", features = ["Window", "console", "HtmlInputElement"] } +dioxus = { version = "0.7.1", features = ["asset", "devtools", "document", "hooks", "html", "launch", "macro", "signals"], default-features = false } +wasm-bindgen = { version = "0.2", default-features = false } +wasm-bindgen-futures = { version = "0.4", default-features = false } +js-sys = { version = "0.3", default-features = false } +web-sys = { version = "0.3", default-features = false } serde-wasm-bindgen = "0.6" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", default-features = false } serde_json = "1.0" log = "0.4" console_log = "1.0" @@ -19,6 +18,9 @@ alloy = {version = "1.1", default-features = false } [profile] +# [profile.release] +# strip = false + [profile.wasm-dev] inherits = "dev" opt-level = 1 diff --git a/frontend/src/app.rs b/frontend/src/app.rs index f2c8d59..94ece3a 100644 --- a/frontend/src/app.rs +++ b/frontend/src/app.rs @@ -2,7 +2,7 @@ use alloy::primitives::{utils::{format_units, parse_units},U256}; use dioxus::prelude::*; use wasm_bindgen_futures::spawn_local; use serde_wasm_bindgen::from_value; -use crate::metamask::{TokenWrapperInfo, connect_metamask, get_token_balance, fetch_wrappers, wrap_tokens, unwrap_tokens}; +use crate::metamask::{TokenWrapperInfo, connect_metamask, get_token_balance, get_all_wrappers, wrap_tokens, unwrap_tokens}; #[derive(Clone, Debug)] struct TokenInfo { @@ -84,23 +84,27 @@ pub fn App() -> Element { let mut to_selected = to_selected; async move { - let addr = connect_metamask().await; - address.set(addr.as_string().unwrap_or_default()); - let addr = address.read().clone(); - match fetch_wrappers(factory_address).await { - Ok(list) => { - if let Some(first) = list.first() { - let (from,to) = update_pair(&first.d_token_symbol, &list); - to_selected.set(to); - from_selected.set(from); - if let Ok(bal) = from_value::(get_token_balance(&addr, &first.d_token_address).await) { - log::debug!("GetTokenBalance of address {} for token address {} :{:?}",addr, first.d_token_address, bal); - balance.set(bal); - } + match connect_metamask().await{ + Ok(addr) => { + address.set(addr); + let addr = address.read().clone(); + match get_all_wrappers(factory_address).await { + Ok(list) => { + if let Some(first) = list.first() { + let (from,to) = update_pair(&first.d_token_symbol, &list); + to_selected.set(to); + from_selected.set(from); + if let Ok(bal) = get_token_balance(&addr, &first.d_token_address).await { + log::debug!("GetTokenBalance of address {} for token address {} :{:?}",addr, first.d_token_address, bal); + balance.set(bal); + } + } + wrappers.set(list); + }, + Err(e) => log::error!("Error fetching wrappers: {:?}", e) } - wrappers.set(list); }, - Err(e) => log::error!("Error fetching wrappers: {:?}", e) + Err(e) => log::error!("Error connecting metamask: {:?}", e) } } }); @@ -114,7 +118,7 @@ pub fn App() -> Element { spawn_local(async move { if let Some(from_sel) = from_sel - && let Ok(bal) = from_value::(get_token_balance(&addr, &from_sel.address).await) { + && let Ok(bal) = get_token_balance(&addr, &from_sel.address).await { log::debug!("GetTokenBalance of address {} for token address {} :{:?}",addr, from_sel.address, bal); balance.set(bal); } @@ -285,8 +289,8 @@ pub fn App() -> Element { } else { unwrap_tokens(router_address, &from_selected.address.to_string(), &amount.read(), &to_selected.address.to_string()).await }; - tx_status.set(format!("{:?}", serde_wasm_bindgen::from_value::(res))); - if let Ok(bal) = from_value::(get_token_balance(&address(), &from_selected.address.to_string()).await) { + tx_status.set(format!("{:?}", res)); + if let Ok(bal) = get_token_balance(&address(), &from_selected.address.to_string()).await { log::debug!("TokenBalance {:?}",bal); balance.set(bal); } diff --git a/frontend/src/metamask.js b/frontend/src/metamask.js index 6e05863..82612e8 100644 --- a/frontend/src/metamask.js +++ b/frontend/src/metamask.js @@ -5,92 +5,123 @@ let provider; let signer; // METAMASK -export async function connect_metamask() { - if (!window.ethereum) throw new Error("MetaMask not installed"); - await window.ethereum.request({ method: 'eth_requestAccounts' }); - provider = new ethers.BrowserProvider(window.ethereum); - signer = await provider.getSigner(); - return await signer.getAddress(); +export async function js_connect_metamask() { + try { + if (!window.ethereum) throw new Error("MetaMask not installed"); + await window.ethereum.request({ method: 'eth_requestAccounts' }); + provider = new ethers.BrowserProvider(window.ethereum); + signer = await provider.getSigner(); + const addr = await signer.getAddress(); + return { + ok: true, + value: JSON.stringify(addr) + }; + }catch (err) { + console.error(err); + return { + ok: false, + value: err.reason || err.message || "Unknown error" + }; + } } // ERC20 -export async function get_token_balance(user, token) { +export async function js_get_token_balance(user, token) { const abi = ["function balanceOf(address) view returns (uint256)", "function decimals() view returns (uint8)"]; try { const erc20 = new ethers.Contract(token, abi, provider); const [bal, decimals] = await Promise.all([erc20.balanceOf(user), erc20.decimals()]); - return ethers.formatUnits(bal, decimals); + return { + ok: true, + value: JSON.stringify(ethers.formatUnits(bal, decimals)) + }; } catch (err) { - // console.error("ERC20 get balance error: ",err); - return `Error: ${err.reason || err.message}`; + console.error(err); + return { + ok: false, + value: err.reason || err.message || "Unknown error" + }; } } // FACTORY -export async function get_all_wrappers(factoryAddress) { +export async function js_get_all_wrappers(factoryAddress) { // Factory ABI console.log("GetAllWrappers called"); - const factoryAbi = ["function getAllWraps() view returns (address[])"]; - const factory = new ethers.Contract(factoryAddress, factoryAbi, provider); - // Wrapper ABI - const wrapperAbi = ["function info() view returns (tuple(address dTokenAddress, address cAssetAddress, uint8 dTokenDecimals, uint8 cAssetDecimals, uint256 dTokenInFeeBps, uint256 dTokenOutFeeBps, address dTokenTreasury, address cAssetTreasury))"]; - const wrapAddresses = await factory.getAllWraps(); - // console.log("WrapAddresses:", wrapAddresses); - const tokenList = []; - - for (const wrapperAddr of wrapAddresses) { - console.log("WrapperAddress:", wrapperAddr); - try { - const wrapper = new ethers.Contract(wrapperAddr, wrapperAbi, provider); - const info = await wrapper.info(); - - const dTokenContract = new ethers.Contract( - info.dTokenAddress, - ["function symbol() view returns (string)", "function decimals() view returns (uint8)"], - provider - ); - - const [dtoken_symbol, dtoken_decimals] = await Promise.all([ - dTokenContract.symbol(), - dTokenContract.decimals() - ]); - - const cAssetContract = new ethers.Contract( - info.cAssetAddress, - ["function symbol() view returns (string)", "function decimals() view returns (uint8)"], - provider - ); - - const [casset_symbol, casset_decimals] = await Promise.all([ - cAssetContract.symbol(), - cAssetContract.decimals() - ]); - - - tokenList.push({ - wrapper: wrapperAddr, - dTokenSymbol: dtoken_symbol, - dTokenAddress: info.dTokenAddress, - dTokenDecimals: info.dTokenDecimals, - cAssetSymbol: casset_symbol, - cAssetAddress: info.cAssetAddress, - cAssetDecimals: info.cAssetDecimals, - fees: { - inBps: info.dTokenInFeeBps, - outBps: info.dTokenOutFeeBps - } - }); - } catch (err) { - console.warn("Skipping wrapper", wrapperAddr, err); + try { + const factoryAbi = ["function getAllWraps() view returns (address[])"]; + const factory = new ethers.Contract(factoryAddress, factoryAbi, provider); + // Wrapper ABI + const wrapperAbi = ["function info() view returns (tuple(address dTokenAddress, address cAssetAddress, uint8 dTokenDecimals, uint8 cAssetDecimals, uint256 dTokenInFeeBps, uint256 dTokenOutFeeBps, address dTokenTreasury, address cAssetTreasury))"]; + const wrapAddresses = await factory.getAllWraps(); + // console.log("WrapAddresses:", wrapAddresses); + const tokenList = []; + + for (const wrapperAddr of wrapAddresses) { + console.log("WrapperAddress:", wrapperAddr); + try { + const wrapper = new ethers.Contract(wrapperAddr, wrapperAbi, provider); + const info = await wrapper.info(); + + const dTokenContract = new ethers.Contract( + info.dTokenAddress, + ["function symbol() view returns (string)", "function decimals() view returns (uint8)"], + provider + ); + + const [dtoken_symbol, dtoken_decimals] = await Promise.all([ + dTokenContract.symbol(), + dTokenContract.decimals() + ]); + + const cAssetContract = new ethers.Contract( + info.cAssetAddress, + ["function symbol() view returns (string)", "function decimals() view returns (uint8)"], + provider + ); + + const [casset_symbol, casset_decimals] = await Promise.all([ + cAssetContract.symbol(), + cAssetContract.decimals() + ]); + + + tokenList.push({ + wrapper: wrapperAddr, + dTokenSymbol: dtoken_symbol, + dTokenAddress: info.dTokenAddress, + dTokenDecimals: info.dTokenDecimals, + cAssetSymbol: casset_symbol, + cAssetAddress: info.cAssetAddress, + cAssetDecimals: info.cAssetDecimals, + fees: { + inBps: info.dTokenInFeeBps, + outBps: info.dTokenOutFeeBps + } + }); + } catch (err) { + console.warn("Skipping wrapper", wrapperAddr, err); + } } + return { + ok: true, + value: JSON.stringify(tokenList , (key, value) => + typeof value === "bigint" ? value.toString() : value + ) + }; + } catch (err) { + return { + ok: false, + value: err.reason || err.message || "Unknown error" + }; + } - return tokenList; // Array of objects with wrapper + cAsset info } // ROUTER -export async function wrap_tokens(contractAddress, dToken, amount, cAsset) { +export async function js_wrap_tokens(contractAddress, dToken, amount, cAsset) { try { const abi = ["function wrap(address dTokent, uint256 amount, address cAsset) external"]; const approveAbi = ["function approve(address spender, uint256 amount) external returns (bool)", @@ -106,15 +137,21 @@ export async function wrap_tokens(contractAddress, dToken, amount, cAsset) { const connected = contract.connect(signer); const tx = await connected.wrap(dToken, amount_u256, cAsset); const receipt = await tx.wait(); - return "Wrap successful: ", receipt.hash; + return { + ok: true, + value: JSON.stringify(`${receipt.hash}`) + }; } catch (err) { console.error(err); - return `Error: ${err.reason || err.message}`; + return { + ok: false, + value: err.reason || err.message || "Unknown error" + }; } } -export async function unwrap_tokens(contractAddress, cAsset, amount, dToken) { +export async function js_unwrap_tokens(contractAddress, cAsset, amount, dToken) { try { const abi = ["function unwrap(address cAsset, uint256 amount, address dToken) external"]; const approveAbi = ["function approve(address spender, uint256 amount) external returns (bool)", @@ -130,9 +167,15 @@ export async function unwrap_tokens(contractAddress, cAsset, amount, dToken) { const connected = contract.connect(signer); const tx = await connected.unwrap(cAsset, amount_u256, dToken); const receipt = await tx.wait(); - return "Unwrap successful: ", receipt.hash; + return { + ok: true, + value: JSON.stringify(`${receipt.hash}`) + }; } catch (err) { console.error(err); - return `Error: ${err.reason || err.message}`; + return { + ok: false, + value: err.reason || err.message || "Unknown error" + }; } } diff --git a/frontend/src/metamask.rs b/frontend/src/metamask.rs index 8bef9e9..394ef31 100644 --- a/frontend/src/metamask.rs +++ b/frontend/src/metamask.rs @@ -1,7 +1,48 @@ +use std::error::Error; use wasm_bindgen::prelude::*; use serde::Deserialize; +use serde::de::DeserializeOwned; use serde_wasm_bindgen::from_value; +// Bind JS functions in metamask.js +#[wasm_bindgen(module = "/src/metamask.js")] +extern "C" { + pub async fn js_connect_metamask() -> JsValue; + pub async fn js_get_token_balance(user: &str, token: &str) -> JsValue; + pub async fn js_get_all_wrappers(factory_address: &str) -> JsValue; + pub async fn js_wrap_tokens(contract: &str, dToken: &str, amount: &str, cAsset: &str,) -> JsValue; + pub async fn js_unwrap_tokens(contract: &str, cAsset: &str, amount: &str, dToken: &str) -> JsValue; +} + +pub fn js_parse(js: JsValue) -> Result { + // Parse the wrapper + let wrapper: JsReturn = + serde_wasm_bindgen::from_value(js).map_err(|e| format!("{:?}", e))?; + + if !wrapper.ok { + return Err(wrapper.value); // This is already a string + } + + // Now parse the inner JSON + serde_json::from_str(&wrapper.value).map_err(|e| format!("{:?}", e)) +} + +#[macro_export] +macro_rules! js_try { + ($expr:expr => $ty:ty) => {{ + let js_val = $expr.await; + Ok(js_parse::<$ty>(js_val)?) + }}; +} + +fn from_str_to_u64<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s: &str = Deserialize::deserialize(deserializer)?; + s.parse::().map_err(serde::de::Error::custom) +} + #[derive(Deserialize, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct TokenWrapperInfo { @@ -9,9 +50,11 @@ pub struct TokenWrapperInfo { pub wrapper: String, pub d_token_symbol: String, pub d_token_address: String, + #[serde(deserialize_with = "from_str_to_u64")] pub d_token_decimals: u64, pub c_asset_symbol: String, pub c_asset_address: String, + #[serde(deserialize_with = "from_str_to_u64")] pub c_asset_decimals: u64, pub fees: Fees, } @@ -19,22 +62,37 @@ pub struct TokenWrapperInfo { #[derive(Deserialize, Clone, Debug)] #[serde(rename_all = "camelCase")] pub struct Fees { + #[serde(deserialize_with = "from_str_to_u64")] pub in_bps: u64, + #[serde(deserialize_with = "from_str_to_u64")] pub out_bps: u64, } -// Bind JS functions in metamask.js -#[wasm_bindgen(module = "/src/metamask.js")] -extern "C" { - pub async fn connect_metamask() -> JsValue; - pub async fn get_token_balance(user: &str, token: &str) -> JsValue; - pub async fn get_all_wrappers(factory_address: &str) -> JsValue; - pub async fn wrap_tokens(contract: &str, dToken: &str, amount: &str, cAsset: &str,) -> JsValue; - pub async fn unwrap_tokens(contract: &str, cAsset: &str, amount: &str, dToken: &str) -> JsValue; + +#[derive(Deserialize)] +struct JsReturn { + ok: bool, + value: String, +} + + + +pub async fn get_all_wrappers(factory_address: &str) -> Result, Box> { + js_try!(js_get_all_wrappers(factory_address) => Vec) +} + +pub async fn connect_metamask() -> Result>{ + js_try!(js_connect_metamask() => String) +} + +pub async fn get_token_balance(user: &str, token: &str) -> Result>{ + js_try!(js_get_token_balance(user, token) => String) +} + +pub async fn wrap_tokens(contract: &str, dToken: &str, amount: &str, cAsset: &str,) -> Result>{ + js_try!(js_wrap_tokens(contract, dToken, amount, cAsset) => String) } -pub async fn fetch_wrappers(factory_address: &str) -> Result, JsValue> { - let js_val = get_all_wrappers(factory_address).await; - let parsed: Vec = from_value(js_val)?; // <-- use serde_wasm_bindgen - Ok(parsed) +pub async fn unwrap_tokens(contract: &str, cAsset: &str, amount: &str, dToken: &str,) -> Result>{ + js_try!(js_unwrap_tokens(contract, cAsset, amount, dToken) => String) } From c36529eb311ebbef98587d660dc94f55966ce0ec Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:56:04 +0100 Subject: [PATCH 13/14] Add platform option to Dioxus build command --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b2c5539..db4dde4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -26,7 +26,7 @@ jobs: - name: Build Dioxus Web App (in frontend/) working-directory: frontend - run: dx build + run: dx build --platform web - name: Upload GitHub Pages artifact uses: actions/upload-pages-artifact@v3 From c486ebd66da4adf8534affbabf8c6def0638d077 Mon Sep 17 00:00:00 2001 From: skutcher <59061311+skutcher@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:56:16 +0100 Subject: [PATCH 14/14] fix info interface (removed treasury addresses) --- frontend/src/metamask.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/metamask.js b/frontend/src/metamask.js index 82612e8..2c285c0 100644 --- a/frontend/src/metamask.js +++ b/frontend/src/metamask.js @@ -53,7 +53,7 @@ export async function js_get_all_wrappers(factoryAddress) { const factoryAbi = ["function getAllWraps() view returns (address[])"]; const factory = new ethers.Contract(factoryAddress, factoryAbi, provider); // Wrapper ABI - const wrapperAbi = ["function info() view returns (tuple(address dTokenAddress, address cAssetAddress, uint8 dTokenDecimals, uint8 cAssetDecimals, uint256 dTokenInFeeBps, uint256 dTokenOutFeeBps, address dTokenTreasury, address cAssetTreasury))"]; + const wrapperAbi = ["function info() view returns (tuple(address dTokenAddress, address cAssetAddress, uint8 dTokenDecimals, uint8 cAssetDecimals, uint256 dTokenInFeeBps, uint256 dTokenOutFeeBps))"]; const wrapAddresses = await factory.getAllWraps(); // console.log("WrapAddresses:", wrapAddresses); const tokenList = [];