Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ src/.DS_Store
*.secret
.env.local
.env*.local

.env
frontend/dist/
frontend/package-lock.json
frontend/.env.local
Expand Down
18 changes: 18 additions & 0 deletions deployed-vaults.testnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"USDC": {
"strategy": "CCGM3FT4HKLXGTD5FZYSIWTOPR4REIEMTTC23GU6PHSLBXBADKFQPEKR",
"token": "CDWADWK2AYWWCZOZAHAPAKJDYXAST4VSDAPTIKQZRX7ZLN4YKP5U2G5A"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:deployed-vaults.testnet.json:generic-api-key:4 >> .gitleaksignore

},
"CETES": {
"strategy": "CBK3RBS6DTTUTXSCBE3B3WCSQ5XCFPLBIL3AGAZJGNI5PZNBZ66BIGMZ",
"token": "CCUT4XNXJ6H4BFUY7V2QVKLA7UIXH2GAEGCVVTOSQW4M3APHZ3SQTGPE"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:deployed-vaults.testnet.json:generic-api-key:8 >> .gitleaksignore

},
"XLM": {
"strategy": "CCCJA2JLLODWPWEYBE6X77SAFY2ZLBHTP33PYLKKZON2LM5OPPNAJ5HB",
"token": "CDDA6LYKAJTUCB4NYS25BOUM7GRVK45ELKTB4KE3557EIHPRIHMELSTD"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:deployed-vaults.testnet.json:generic-api-key:12 >> .gitleaksignore

},
"TESOURO": {
"strategy": "CATU5FLSDYXSAXOMXBWFKHPBWW3ZIKESQMR75YR6HUYE2LJJLDKH2QIX",
"token": "CDKEYTBUW6GTHZUWXBLSVCPMGISWHSB4IWETGWUTZMKXICEUGCW4EF7N"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:deployed-vaults.testnet.json:generic-api-key:16 >> .gitleaksignore

}
}
44 changes: 43 additions & 1 deletion frontend/src/defindex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,57 @@ const MAINNET_VAULTS: VaultConfig[] = [
},
];

// Testnet rehearsal vaults across the 4 reserves of the testnet Blend pool
// (XLM, USDC, CETES, TESOURO — USTRY does not exist on testnet, so TESOURO
// stands in for the 4th vault). vaultId/shareToken are filled post-deploy from
// deployed-vaults.testnet.json (see scripts/wire_testnet_vaults.ts). Config
// mirrors scripts/deploy_strategy_testnet.ts.
const TESTNET_VAULTS: VaultConfig[] = [
{
vaultId: "CDOETIUHCETALQMBMYUXGFJFA34KDTV74AMHTWXJLY2XUVNZ23JDLJZA",
vaultId: "CCGM3FT4HKLXGTD5FZYSIWTOPR4REIEMTTC23GU6PHSLBXBADKFQPEKR",
shareToken: "CDWADWK2AYWWCZOZAHAPAKJDYXAST4VSDAPTIKQZRX7ZLN4YKP5U2G5A", // filled post-deploy

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:frontend/src/defindex.ts:generic-api-key:109 >> .gitleaksignore

assetId: "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA", // USDC
poolId: "CAPBMXIQTICKWFPWFDJWMAKBXBPJZUKLNONQH3MLPLLBKQ643CYN5PRW",
name: "Leveraged USDC (Testnet)",
assetSymbol: "USDC",
decimals: 7,
cFactor: 0.90,
targetLoops: 4,
minHf: 1.05,
},
{
vaultId: "CBK3RBS6DTTUTXSCBE3B3WCSQ5XCFPLBIL3AGAZJGNI5PZNBZ66BIGMZ",
shareToken: "CCUT4XNXJ6H4BFUY7V2QVKLA7UIXH2GAEGCVVTOSQW4M3APHZ3SQTGPE",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:frontend/src/defindex.ts:generic-api-key:121 >> .gitleaksignore

assetId: "CC72F57YTPX76HAA64JQOEGHQAPSADQWSY5DWVBR66JINPFDLNCQYHIC", // CETES
poolId: "CAPBMXIQTICKWFPWFDJWMAKBXBPJZUKLNONQH3MLPLLBKQ643CYN5PRW",
name: "Leveraged CETES (Testnet)",
assetSymbol: "CETES",
decimals: 7,
cFactor: 0.75,
targetLoops: 3,
minHf: 1.05,
},
{
vaultId: "CCCJA2JLLODWPWEYBE6X77SAFY2ZLBHTP33PYLKKZON2LM5OPPNAJ5HB",
shareToken: "CDDA6LYKAJTUCB4NYS25BOUM7GRVK45ELKTB4KE3557EIHPRIHMELSTD",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:frontend/src/defindex.ts:generic-api-key:133 >> .gitleaksignore

assetId: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC", // XLM (native)
poolId: "CAPBMXIQTICKWFPWFDJWMAKBXBPJZUKLNONQH3MLPLLBKQ643CYN5PRW",
name: "Leveraged XLM (Testnet)",
assetSymbol: "XLM",
decimals: 7,
cFactor: 0.70,
targetLoops: 2,
minHf: 1.10,
},
{
vaultId: "CATU5FLSDYXSAXOMXBWFKHPBWW3ZIKESQMR75YR6HUYE2LJJLDKH2QIX",
shareToken: "CDKEYTBUW6GTHZUWXBLSVCPMGISWHSB4IWETGWUTZMKXICEUGCW4EF7N",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 94d3d25.
If this secret is a true positive, please rotate the secret ASAP.

If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.

echo 94d3d25b4cf472f3ba87d391a1b77969863ddfc1:frontend/src/defindex.ts:generic-api-key:145 >> .gitleaksignore

assetId: "CCKA3OUWLZPX3YT335UNHIFMKSYA37M66VKGD5XZOX4BA4IKTYP4WBEE", // TESOURO
poolId: "CAPBMXIQTICKWFPWFDJWMAKBXBPJZUKLNONQH3MLPLLBKQ643CYN5PRW",
name: "Leveraged TESOURO (Testnet)",
assetSymbol: "TESOURO",
decimals: 7,
cFactor: 0.80,
targetLoops: 3,
minHf: 1.05,
},
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/views/vault.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@
}
.vault-wallet-hint { font-size: var(--tl-text-xs); color: var(--tl-text-3); margin: 0; }

.vault-dep-preview {
margin-top: calc(-1 * var(--tl-space-1));
padding: var(--tl-space-2) var(--tl-space-3);
background: var(--tl-input-bg);
border: 1px solid var(--tl-border);
border-radius: var(--tl-radius-sm);
}
.vault-dep-preview__lev { color: var(--tl-text-3); font-weight: 500; }

.vault-divider { border-top: 1px solid var(--tl-border); padding-top: var(--tl-space-3); }

/* Receipt token + Aquarius */
Expand Down
41 changes: 41 additions & 0 deletions frontend/src/views/vault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,49 @@ function yourPositionCard(
disabled: !addr || !ready,
onMax: () => {
if (vs.userWalletBalance > 0) depField.value = vs.userWalletBalance.toFixed(2);
updateDepPreview();
},
});
const depField = depInput.querySelector("input") as HTMLInputElement;

// ── Projected HF preview (before → after) for the entered deposit amount ──
// The loop levers every deposit at the same ratio, so the marginal HF is the
// deterministic target c·S/(S−1); the aggregate "after" HF blends it with the
// current position. Computed entirely client-side from cFactor + targetLoops
// and the position's underlying collateral/debt — no extra on-chain call.
const targetLeverage = (1 - vault.cFactor ** (vault.targetLoops + 1)) / (1 - vault.cFactor);
const depPreview = el("div", { class: "vault-row vault-dep-preview", style: "display:none" }, []);
function updateDepPreview() {
const amount = Number.parseFloat(depField.value);
if (!ready || !amount || amount <= 0) {
depPreview.style.display = "none";
return;
}
const cBefore = stats?.collateralValue ?? 0;
const dBefore = stats?.debtValue ?? 0;
const hfBefore = stats?.healthFactor ?? Number.POSITIVE_INFINITY;
const cAfter = cBefore + amount * targetLeverage;
const dAfter = dBefore + amount * (targetLeverage - 1);
const hfAfter = dAfter > 0 ? (vault.cFactor * cAfter) / dAfter : Number.POSITIVE_INFINITY;
const fb = formatHf(hfBefore);
const fa = formatHf(hfAfter);
depPreview.replaceChildren(
el("span", { class: "vault-row__label" }, [
lbl(
tt("vault.projectedHf", "Projected HF"),
"Health factor of the whole vault before and after your deposit, at the target leverage.",
),
]),
el("span", { class: "vault-mono vault-row__value" }, [
el("span", { class: fb.cls }, [fb.text]),
" → ",
el("span", { class: fa.cls }, [fa.text]),
el("span", { class: "vault-dep-preview__lev" }, [` (~${targetLeverage.toFixed(2)}×)`]),
]),
);
depPreview.style.display = "";
}

const depBtn = Button({
variant: "primary",
size: "lg",
Expand All @@ -311,6 +350,7 @@ function yourPositionCard(
children: `${tt("vault.deposit", "Deposit")} ${sym}`,
});
on(depBtn, "click", () => void runDeposit());
on(depField, "input", () => updateDepPreview());

// ── Withdraw ──
const wdInput = Input({
Expand Down Expand Up @@ -442,6 +482,7 @@ function yourPositionCard(
equityRow,
shareRow,
el("div", { class: "vault-field" }, [el("label", { class: "vault-field__label" }, [`Deposit ${sym}`]), depInput]),
depPreview,
depBtn,
el("div", { class: "vault-field" }, [el("label", { class: "vault-field__label" }, [`Withdraw ${sym}`]), wdInput]),
wdBtn,
Expand Down
49 changes: 49 additions & 0 deletions scripts/check_testnet_infra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Quick existence/symbol check for the testnet BLND token + Soroswap router used
* by the strategy constructor, so the testnet deploy doesn't surprise us.
* Read-only. Usage: npx tsx scripts/check_testnet_infra.ts
*/
import {
Account,
BASE_FEE,
Contract,
Networks,
rpc as SorobanRpc,
scValToNative,
TransactionBuilder,
xdr,
} from "@stellar/stellar-sdk";

const RPC_URL = "https://soroban-testnet.stellar.org";
const NETWORK = Networks.TESTNET;
const NULL_ACCOUNT = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
const server = new SorobanRpc.Server(RPC_URL);

const BLND = "CB22KRA3YZVCNCQI64JQ5WE7UY2VAV7WFLK6A2JN3HEX56T2EDAFO7QF";
const ROUTER = "CCJUD55AG6W5HAI5LRVNKAE5WDP5XGZBUDS5WNTIVDU7O264UZZE7BRD";

async function sim(op: xdr.Operation): Promise<any> {
const acc = new Account(NULL_ACCOUNT, "0");
const tx = new TransactionBuilder(acc, { fee: BASE_FEE, networkPassphrase: NETWORK })
.addOperation(op)
.setTimeout(30)
.build();
const res = await server.simulateTransaction(tx);
if (!SorobanRpc.Api.isSimulationSuccess(res)) return { __error: true };
return scValToNative(res.result!.retval);
}

async function main() {
const blndSym = await sim(new Contract(BLND).call("symbol"));
console.log(`BLND (${BLND}): symbol=${JSON.stringify(blndSym)}`);

// Soroswap router exposes get_pair / router_get_amounts_out etc.; just probe a
// cheap read that exists on the router to confirm the contract is live.
const routerProbe = await sim(new Contract(ROUTER).call("get_factory"));
console.log(`Router (${ROUTER}): get_factory=${JSON.stringify(routerProbe)}`);
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
Loading
Loading