From 354aa1354db16adf17e4bb0dff1be8a6e0d80ba8 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Mon, 13 Oct 2025 23:14:20 +0700 Subject: [PATCH 01/12] fix: use mainnet fork --- packages/nextjs/services/web3/connectors.tsx | 4 ++-- packages/nextjs/supportedChains.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/nextjs/services/web3/connectors.tsx b/packages/nextjs/services/web3/connectors.tsx index 7dc7205..251d77b 100644 --- a/packages/nextjs/services/web3/connectors.tsx +++ b/packages/nextjs/services/web3/connectors.tsx @@ -4,7 +4,6 @@ import { BurnerConnector } from "@scaffold-stark/stark-burner"; import scaffoldConfig from "~~/scaffold.config"; import { LAST_CONNECTED_TIME_LOCALSTORAGE_KEY } from "~~/utils/Constants"; import { KeplrConnector } from "./keplr"; -import { supportedChains } from "~~/supportedChains"; const targetNetworks = getTargetNetworks(); @@ -34,7 +33,8 @@ function getConnectors() { connectors.push(new KeplrConnector()); } else { const burnerConnector = new BurnerConnector(); - burnerConnector.chain = supportedChains.devnet; + // burnerConnector's should be initialized with dynamic network instead of hardcoded devnet to support mainnetFork + burnerConnector.chain = targetNetworks[0]; connectors.push(burnerConnector as unknown as InjectedConnector); } diff --git a/packages/nextjs/supportedChains.ts b/packages/nextjs/supportedChains.ts index 6d10bed..fe9148a 100644 --- a/packages/nextjs/supportedChains.ts +++ b/packages/nextjs/supportedChains.ts @@ -4,7 +4,7 @@ const rpcUrlDevnet = process.env.NEXT_PUBLIC_DEVNET_PROVIDER_URL || "http://127.0.0.1:5050"; // devnet with mainnet network ID const mainnetFork = { - id: BigInt("0x534e5f4d41494e"), + id: chains.mainnet.id, network: "devnet", name: "Starknet Devnet", nativeCurrency: { @@ -24,8 +24,8 @@ const mainnetFork = { }, }, paymasterRpcUrls: { - default: { - http: [], + avnu: { + http: [rpcUrlDevnet], }, }, } as chains.Chain; From d50b25eb00bae1ed5145f41cf6c303a43158c533 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Mon, 13 Oct 2025 23:15:15 +0700 Subject: [PATCH 02/12] feat: integrate Vesu deposit and withdraw --- packages/nextjs/app/page.tsx | 416 ++++------ .../contracts/configExternalContracts.ts | 18 + packages/nextjs/utils/vesu/constants.ts | 9 + packages/nextjs/utils/vesu/vTokenAbi.ts | 780 ++++++++++++++++++ packages/snfoundry/contracts/Scarb.toml | 2 +- 5 files changed, 963 insertions(+), 262 deletions(-) create mode 100644 packages/nextjs/utils/vesu/constants.ts create mode 100644 packages/nextjs/utils/vesu/vTokenAbi.ts diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 45eceb4..2084487 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -3,118 +3,76 @@ import { ConnectedAddress } from "~~/components/ConnectedAddress"; import { useState } from "react"; import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; -import { useBlockNumber } from "@starknet-react/core"; -import { useDeployedContractInfo } from "~~/hooks/scaffold-stark/useDeployedContractInfo"; +import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork"; -import { CairoOption, CairoOptionVariant, BlockTag } from "starknet"; +import { useAccount } from "@starknet-react/core"; +import useScaffoldStrkBalance from "~~/hooks/scaffold-stark/useScaffoldStrkBalance"; +import { VSTRK_ADDRESS } from "~~/utils/vesu/constants"; const Home = () => { - const [selectedToken, setSelectedToken] = useState<"ETH" | "STRK">("STRK"); - const [inputAmount, setInputAmount] = useState(0n); - const [greeting, setGreeting] = useState(""); const [displayAmount, setDisplayAmount] = useState(""); - const [isNoneOption, setIsNoneOption] = useState(true); + const [amountWei, setAmountWei] = useState(0n); const { targetNetwork } = useTargetNetwork(); - const { data: YourContract } = useDeployedContractInfo("YourContract"); - const { data: EthContract } = useDeployedContractInfo("Eth"); - const { data: StrkContract } = useDeployedContractInfo("Strk"); + const { address: connectedAddress } = useAccount(); - const { data: currentGreeting } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "greeting", - }); + const toHex = (v: unknown) => + typeof v === "bigint" ? `0x${v.toString(16)}` : (v as string); - const { data: premium } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "premium", + // Deposited amount = user's vSTRK balance (shares) + const { data: vStrkBalance } = useScaffoldReadContract({ + contractName: "vStrk", + functionName: "balance_of", + args: [connectedAddress], }); - const { data: ethBalance } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "token_deposits", - args: [EthContract?.address], + // Available STRK balance of user + const { value: availableStrk } = useScaffoldStrkBalance({ + address: connectedAddress || undefined, }); - const { data: strkBalance } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "token_deposits", - args: [StrkContract?.address], - }); + // Redeem (withdraw) all vSTRK shares to STRK + const { sendAsync: redeemAll, isPending: isRedeeming } = + useScaffoldWriteContract({ + contractName: "vStrk", + functionName: "redeem", + args: [vStrkBalance as any, connectedAddress, connectedAddress], + }); - const { data: lastBlock } = useBlockNumber({ - blockIdentifier: "pending" as BlockTag, - }); + // STRK-only deposit flow: approve STRK to vSTRK, then deposit assets + const { sendAsync: depositStrk, isPending: isDepositing } = + useScaffoldMultiWriteContract({ + calls: [ + { + contractName: "Strk", + functionName: "approve", + args: [VSTRK_ADDRESS, amountWei], + }, + { + contractName: "vStrk", + functionName: "deposit", + args: [amountWei, connectedAddress], + }, + ], + }); - const { data: events } = useScaffoldEventHistory({ - contractName: "YourContract", - eventName: "GreetingChanged", - fromBlock: 1028886n, // NOTE : For now keep this block number as it is. When running local mainnet fork, use this block number as the starting block number. For example: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_7 --fork-block 1028886` + // Event history for vSTRK Deposit and Withdraw + const { data: depositEvents } = useScaffoldEventHistory({ + contractName: "vStrk", + eventName: "Deposit", + fromBlock: 1540452n, // NOTE : For now keep this block number as it is. When running local mainnet fork, use this block number as the starting block number. For example: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_9 --fork-block 1540452` watch: true, }); - - const noneOptionBigInt: CairoOption = new CairoOption( - CairoOptionVariant.None, - ); - - const noneOptionString: CairoOption = new CairoOption( - CairoOptionVariant.None, - ); - - const { sendAsync: setGreetingNoPayment } = useScaffoldWriteContract({ - contractName: "YourContract", - functionName: "set_greeting", - args: [greeting, noneOptionBigInt, noneOptionString], - }); - - const { sendAsync: withdrawAll } = useScaffoldWriteContract({ - contractName: "YourContract", - functionName: "withdraw", - }); - - const someOptionBigInt: CairoOption = new CairoOption( - CairoOptionVariant.Some, - inputAmount, - ); - - // Helper function to determine the token address option - const getTokenAddressOption = () => { - if (selectedToken === "ETH" && EthContract?.address) { - return new CairoOption(CairoOptionVariant.Some, EthContract.address); - } else if (selectedToken === "STRK" && StrkContract?.address) { - return new CairoOption(CairoOptionVariant.Some, StrkContract.address); - } else { - return noneOptionString; - } - }; - - const { sendAsync: setGreetingWithPayment } = useScaffoldMultiWriteContract({ - calls: [ - { - contractName: selectedToken === "STRK" ? "Strk" : "Eth", - functionName: "approve", - args: [YourContract?.address, someOptionBigInt.unwrap()], - }, - { - contractName: "YourContract", - functionName: "set_greeting", - args: [greeting, someOptionBigInt, getTokenAddressOption()], - }, - ], + const { data: withdrawEvents } = useScaffoldEventHistory({ + contractName: "vStrk", + eventName: "Withdraw", + fromBlock: 1540452n, + watch: true, }); - const handleSetGreeting = async () => { - if (isNoneOption) { - await setGreetingNoPayment(); - } else { - await setGreetingWithPayment(); - } - }; - return (
@@ -130,31 +88,7 @@ const Home = () => {
-
-

- Contract Status -

-
-
-

Current Greeting

-

- {currentGreeting?.toString() ?? "No greeting set"} -

-
- -
-

Premium Status

-
-
- - {premium ? "Active" : "Inactive"} - -
-
-
-
+ {/* Contract Status removed for Vesu demo */}

@@ -162,26 +96,35 @@ const Home = () => {

- This action will withdraw all deposited tokens back to the - contract owner. + Redeem all your vSTRK shares back to STRK.
- Available ETH + Deposited vSTRK (shares) - {ethBalance - ? (Number(ethBalance) / 10 ** 18).toFixed(6) + {vStrkBalance + ? (Number(vStrkBalance) / 10 ** 18).toFixed(6) : "0.000000"}{" "} - ETH + vSTRK
@@ -189,8 +132,8 @@ const Home = () => { Available STRK - {strkBalance - ? (Number(strkBalance) / 10 ** 18).toFixed(6) + {availableStrk + ? (Number(availableStrk) / 10 ** 18).toFixed(6) : "0.000000"}{" "} STRK @@ -199,164 +142,115 @@ const Home = () => {
-

- Set Greeting & Deposit -

+

Deposit

-
- -
- - -
-
-
- {/* Some Option */} - - - {/* None Option */} -
-
- - setGreeting(e.target.value)} - placeholder="Enter your greeting" - /> -

- Transaction History + vSTRK Activity

-
- {events?.map((event, index) => ( -
-

- Set Greeting to {event.args.new_greeting} - {event.args.value.unwrap() > 0n && ( - - with{" "} - {(Number(event.args.value.unwrap()) / 10 ** 18).toFixed( - 6, - )} - {event.args.token.unwrap() === - BigInt(StrkContract?.address || "") - ? " STRK" - : " ETH"} - - )} -

+
+
+

Deposits

+
+ {depositEvents?.length ? ( + depositEvents.map((evt, idx) => ( +
+

+ Owner: {toHex(evt.args.owner)} +

+

+ Assets:{" "} + {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK + · Shares:{" "} + {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} + vSTRK +

+
+ )) + ) : ( + No deposit events + )} +
+
+
+

Withdrawals

+
+ {withdrawEvents?.length ? ( + withdrawEvents.map((evt, idx) => ( +
+

+ Owner: {toHex(evt.args.owner)} +

+

+ Assets:{" "} + {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK + · Shares:{" "} + {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} + vSTRK +

+
+ )) + ) : ( + No withdraw events + )}
- ))} +
diff --git a/packages/nextjs/contracts/configExternalContracts.ts b/packages/nextjs/contracts/configExternalContracts.ts index a011b38..9847773 100644 --- a/packages/nextjs/contracts/configExternalContracts.ts +++ b/packages/nextjs/contracts/configExternalContracts.ts @@ -3,6 +3,12 @@ * You should not edit it manually or your changes might be overwritten. */ +import { + VSTRK_ABI, + VSTRK_ADDRESS, + VSTRK_CLASS_HASH, +} from "~~/utils/vesu/constants"; + const configExternalContracts = { devnet: { Eth: { @@ -391,6 +397,18 @@ const configExternalContracts = { }, ], }, + vStrk: { + address: VSTRK_ADDRESS, + classHash: VSTRK_CLASS_HASH, + abi: VSTRK_ABI, + }, + }, + mainnet: { + vStrk: { + address: VSTRK_ADDRESS, + classHash: VSTRK_CLASS_HASH, + abi: VSTRK_ABI, + }, }, } as const; diff --git a/packages/nextjs/utils/vesu/constants.ts b/packages/nextjs/utils/vesu/constants.ts new file mode 100644 index 0000000..cce8dc5 --- /dev/null +++ b/packages/nextjs/utils/vesu/constants.ts @@ -0,0 +1,9 @@ +import { vTokenAbi } from "./vTokenAbi"; + +export const VSTRK_ADDRESS = + "0x0147ae3337b168ac9abe80a7214f0cb9e874b25c3db530a8e04beb98a134e07a" as const; + +export const VSTRK_CLASS_HASH = + "0x035c58475afe0f44fa5267ffee18facd535ae5bb64085035369d07ce2b3afb4d" as const; + +export const VSTRK_ABI = vTokenAbi; diff --git a/packages/nextjs/utils/vesu/vTokenAbi.ts b/packages/nextjs/utils/vesu/vTokenAbi.ts new file mode 100644 index 0000000..9947413 --- /dev/null +++ b/packages/nextjs/utils/vesu/vTokenAbi.ts @@ -0,0 +1,780 @@ +export const vTokenAbi = [ + { + name: "VToken", + type: "impl", + interface_name: "vesu::v_token::IVToken", + }, + { + name: "core::integer::u256", + type: "struct", + members: [ + { + name: "low", + type: "core::integer::u128", + }, + { + name: "high", + type: "core::integer::u128", + }, + ], + }, + { + name: "core::bool", + type: "enum", + variants: [ + { + name: "False", + type: "()", + }, + { + name: "True", + type: "()", + }, + ], + }, + { + name: "vesu::v_token::IVToken", + type: "interface", + items: [ + { + name: "extension", + type: "function", + inputs: [], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + name: "approve_extension", + type: "function", + inputs: [], + outputs: [], + state_mutability: "external", + }, + { + name: "mint_v_token", + type: "function", + inputs: [ + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + { + name: "burn_v_token", + type: "function", + inputs: [ + { + name: "from", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + ], + }, + { + name: "IERC4626", + type: "impl", + interface_name: "vesu::v_token::IERC4626", + }, + { + name: "vesu::v_token::IERC4626", + type: "interface", + items: [ + { + name: "asset", + type: "function", + inputs: [], + outputs: [ + { + type: "core::starknet::contract_address::ContractAddress", + }, + ], + state_mutability: "view", + }, + { + name: "total_assets", + type: "function", + inputs: [], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "convert_to_shares", + type: "function", + inputs: [ + { + name: "assets", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "convert_to_assets", + type: "function", + inputs: [ + { + name: "shares", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "max_deposit", + type: "function", + inputs: [ + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "preview_deposit", + type: "function", + inputs: [ + { + name: "assets", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "deposit", + type: "function", + inputs: [ + { + name: "assets", + type: "core::integer::u256", + }, + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "external", + }, + { + name: "max_mint", + type: "function", + inputs: [ + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "preview_mint", + type: "function", + inputs: [ + { + name: "shares", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "mint", + type: "function", + inputs: [ + { + name: "shares", + type: "core::integer::u256", + }, + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "external", + }, + { + name: "max_withdraw", + type: "function", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "preview_withdraw", + type: "function", + inputs: [ + { + name: "assets", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "withdraw", + type: "function", + inputs: [ + { + name: "assets", + type: "core::integer::u256", + }, + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "external", + }, + { + name: "max_redeem", + type: "function", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "preview_redeem", + type: "function", + inputs: [ + { + name: "shares", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "redeem", + type: "function", + inputs: [ + { + name: "shares", + type: "core::integer::u256", + }, + { + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "external", + }, + ], + }, + { + name: "ERC20Impl", + type: "impl", + interface_name: "vesu::vendor::erc20::IERC20", + }, + { + name: "vesu::vendor::erc20::IERC20", + type: "interface", + items: [ + { + name: "total_supply", + type: "function", + inputs: [], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "balance_of", + type: "function", + inputs: [ + { + name: "account", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "allowance", + type: "function", + inputs: [ + { + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "spender", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "transfer", + type: "function", + inputs: [ + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + { + name: "transfer_from", + type: "function", + inputs: [ + { + name: "sender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + { + name: "approve", + type: "function", + inputs: [ + { + name: "spender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + ], + }, + { + name: "ERC20MetadataImpl", + type: "impl", + interface_name: "vesu::vendor::erc20::IERC20Metadata", + }, + { + name: "vesu::vendor::erc20::IERC20Metadata", + type: "interface", + items: [ + { + name: "name", + type: "function", + inputs: [], + outputs: [ + { + type: "core::felt252", + }, + ], + state_mutability: "view", + }, + { + name: "symbol", + type: "function", + inputs: [], + outputs: [ + { + type: "core::felt252", + }, + ], + state_mutability: "view", + }, + { + name: "decimals", + type: "function", + inputs: [], + outputs: [ + { + type: "core::integer::u8", + }, + ], + state_mutability: "view", + }, + ], + }, + { + name: "ERC20CamelOnlyImpl", + type: "impl", + interface_name: "vesu::vendor::erc20::IERC20CamelOnly", + }, + { + name: "vesu::vendor::erc20::IERC20CamelOnly", + type: "interface", + items: [ + { + name: "totalSupply", + type: "function", + inputs: [], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "balanceOf", + type: "function", + inputs: [ + { + name: "account", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, + { + name: "transferFrom", + type: "function", + inputs: [ + { + name: "sender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "recipient", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "amount", + type: "core::integer::u256", + }, + ], + outputs: [ + { + type: "core::bool", + }, + ], + state_mutability: "external", + }, + ], + }, + { + name: "constructor", + type: "constructor", + inputs: [ + { + name: "name", + type: "core::felt252", + }, + { + name: "symbol", + type: "core::felt252", + }, + { + name: "decimals", + type: "core::integer::u8", + }, + { + name: "pool_id", + type: "core::felt252", + }, + { + name: "extension", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "asset", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + }, + { + kind: "struct", + name: "vesu::vendor::erc20_component::ERC20Component::Transfer", + type: "event", + members: [ + { + kind: "key", + name: "from", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "key", + name: "to", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "data", + name: "value", + type: "core::integer::u256", + }, + ], + }, + { + kind: "struct", + name: "vesu::vendor::erc20_component::ERC20Component::Approval", + type: "event", + members: [ + { + kind: "key", + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "key", + name: "spender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "data", + name: "value", + type: "core::integer::u256", + }, + ], + }, + { + kind: "enum", + name: "vesu::vendor::erc20_component::ERC20Component::Event", + type: "event", + variants: [ + { + kind: "nested", + name: "Transfer", + type: "vesu::vendor::erc20_component::ERC20Component::Transfer", + }, + { + kind: "nested", + name: "Approval", + type: "vesu::vendor::erc20_component::ERC20Component::Approval", + }, + ], + }, + { + kind: "struct", + name: "vesu::v_token::VToken::Deposit", + type: "event", + members: [ + { + kind: "key", + name: "sender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "key", + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "data", + name: "assets", + type: "core::integer::u256", + }, + { + kind: "data", + name: "shares", + type: "core::integer::u256", + }, + ], + }, + { + kind: "struct", + name: "vesu::v_token::VToken::Withdraw", + type: "event", + members: [ + { + kind: "key", + name: "sender", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "key", + name: "receiver", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "key", + name: "owner", + type: "core::starknet::contract_address::ContractAddress", + }, + { + kind: "data", + name: "assets", + type: "core::integer::u256", + }, + { + kind: "data", + name: "shares", + type: "core::integer::u256", + }, + ], + }, + { + kind: "enum", + name: "vesu::v_token::VToken::Event", + type: "event", + variants: [ + { + kind: "flat", + name: "ERC20Event", + type: "vesu::vendor::erc20_component::ERC20Component::Event", + }, + { + kind: "nested", + name: "Deposit", + type: "vesu::v_token::VToken::Deposit", + }, + { + kind: "nested", + name: "Withdraw", + type: "vesu::v_token::VToken::Withdraw", + }, + ], + }, +] as const; diff --git a/packages/snfoundry/contracts/Scarb.toml b/packages/snfoundry/contracts/Scarb.toml index dbdf5d0..c081319 100644 --- a/packages/snfoundry/contracts/Scarb.toml +++ b/packages/snfoundry/contracts/Scarb.toml @@ -29,7 +29,7 @@ sort-module-level-items = true [[tool.snforge.fork]] name = "MAINNET_LATEST" url = "https://starknet-mainnet.public.blastapi.io/rpc/v0_9" -block_id.number = "1028886" +block_id.number = "1540452" block_id.tag = "latest" [tool] From f772cce1021e41e7583c2ae9cfe520523e637ea4 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Mon, 13 Oct 2025 23:15:31 +0700 Subject: [PATCH 03/12] chore: remove zklend --- .../nextjs/contracts/deployedContracts.ts | 114 ++--------- .../contracts/src/your_contract.cairo | 182 ++++-------------- .../contracts/tests/test_contract.cairo | 54 ++---- 3 files changed, 58 insertions(+), 292 deletions(-) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 8e089af..7abef3b 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,12 +7,12 @@ const deployedContracts = { devnet: { YourContract: { address: - "0x1a2542704c7588b9c5eb86c9a1b2391b93b77b67694268b74db51097031839d", + "0x3760a55e55c5d737d14e527c4c09c5b828f5476fd6f9b7148482ec4185afa17", abi: [ { type: "impl", name: "YourContractImpl", - interface_name: "contracts::YourContract::IYourContract", + interface_name: "contracts::your_contract::IYourContract", }, { type: "struct", @@ -76,7 +76,7 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::YourContract::IYourContract", + name: "contracts::your_contract::IYourContract", items: [ { type: "function", @@ -229,7 +229,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::YourContract::YourContract::GreetingChanged", + name: "contracts::your_contract::YourContract::GreetingChanged", kind: "struct", members: [ { @@ -256,7 +256,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::YourContract::YourContract::Event", + name: "contracts::your_contract::YourContract::Event", kind: "enum", variants: [ { @@ -266,111 +266,25 @@ const deployedContracts = { }, { name: "GreetingChanged", - type: "contracts::YourContract::YourContract::GreetingChanged", + type: "contracts::your_contract::YourContract::GreetingChanged", kind: "nested", }, ], }, ], classHash: - "0x5e4c766477764df946dcce9b0d2c865468882ac572c0d3767aeb98d23cbe74b", - }, - }, - mainnet: { - Multicall: { - address: - "0x7ca5ccfeb2e4d6e13e9382d70042712f1f736c003f3a40243d9a397a7317251", - abi: [ - { - type: "impl", - name: "MulticallImpl", - interface_name: "contracts::multicall::IMulticall", - }, - { - type: "struct", - name: "core::array::Span::", - members: [ - { - name: "snapshot", - type: "@core::array::Array::", - }, - ], - }, - { - type: "struct", - name: "core::array::Span::", - members: [ - { - name: "snapshot", - type: "@core::array::Array::", - }, - ], - }, - { - type: "struct", - name: "core::array::Span::>", - members: [ - { - name: "snapshot", - type: "@core::array::Array::>", - }, - ], - }, - { - type: "interface", - name: "contracts::multicall::IMulticall", - items: [ - { - type: "function", - name: "call_contracts", - inputs: [ - { - name: "contracts", - type: "core::array::Span::", - }, - { - name: "entry_point_selectors", - type: "core::array::Span::", - }, - { - name: "calldata", - type: "core::array::Span::>", - }, - ], - outputs: [ - { - type: "core::array::Array::>", - }, - ], - state_mutability: "view", - }, - ], - }, - { - type: "constructor", - name: "constructor", - inputs: [], - }, - { - type: "event", - name: "contracts::multicall::Multicall::Event", - kind: "enum", - variants: [], - }, - ], - classHash: - "0x67be8d0979b1012f4222674cb81e3a0413e45e16897b8d7c650ae84ba4a3f23", + "0x21e2aa81952de7b6851d5e76ea1f70283373407b22bfb4d32fafa4c5e2c8f1d", }, }, sepolia: { YourContract: { address: - "0x62eb9272c7523ee445d223bae15b5b44a79c3fdbb5216d3412534a47bcc5255", + "0x6a5b250d1eeda1cdc9e98078d3dadbe1d2bacd7a4a44f55e9e250bfe18c4288", abi: [ { type: "impl", name: "YourContractImpl", - interface_name: "contracts::YourContract::IYourContract", + interface_name: "contracts::your_contract::IYourContract", }, { type: "struct", @@ -434,7 +348,7 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::YourContract::IYourContract", + name: "contracts::your_contract::IYourContract", items: [ { type: "function", @@ -587,7 +501,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::YourContract::YourContract::GreetingChanged", + name: "contracts::your_contract::YourContract::GreetingChanged", kind: "struct", members: [ { @@ -614,7 +528,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::YourContract::YourContract::Event", + name: "contracts::your_contract::YourContract::Event", kind: "enum", variants: [ { @@ -624,14 +538,14 @@ const deployedContracts = { }, { name: "GreetingChanged", - type: "contracts::YourContract::YourContract::GreetingChanged", + type: "contracts::your_contract::YourContract::GreetingChanged", kind: "nested", }, ], }, ], classHash: - "0x5e4c766477764df946dcce9b0d2c865468882ac572c0d3767aeb98d23cbe74b", + "0x73b00366d0117bee7ae7620469abc7ceefb8b78ff9257b77b3531a9c4411688", }, }, } as const; diff --git a/packages/snfoundry/contracts/src/your_contract.cairo b/packages/snfoundry/contracts/src/your_contract.cairo index c4a3ae9..a6ea14f 100644 --- a/packages/snfoundry/contracts/src/your_contract.cairo +++ b/packages/snfoundry/contracts/src/your_contract.cairo @@ -1,23 +1,9 @@ -use starknet::ContractAddress; - #[starknet::interface] pub trait IYourContract { fn greeting(self: @TContractState) -> ByteArray; - fn set_greeting( - ref self: TContractState, - new_greeting: ByteArray, - option_amount: Option, - option_token: Option, - ); + fn set_greeting(ref self: TContractState, new_greeting: ByteArray, amount_strk: Option); fn withdraw(ref self: TContractState); fn premium(self: @TContractState) -> bool; - fn token_deposits(self: @TContractState, token: ContractAddress) -> u256; -} - -#[starknet::interface] -pub trait IZklendMarket { - fn deposit(ref self: TContractState, asset: ContractAddress, amount: felt252); - fn withdraw_all(ref self: TContractState, asset: ContractAddress); } #[starknet::contract] @@ -29,7 +15,7 @@ pub mod YourContract { StoragePointerWriteAccess, }; use starknet::{ContractAddress, get_caller_address, get_contract_address}; - use super::{IYourContract, IZklendMarketDispatcher, IZklendMarketDispatcherTrait}; + use super::IYourContract; component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); @@ -37,12 +23,8 @@ pub mod YourContract { impl OwnableImpl = OwnableComponent::OwnableImpl; impl OwnableInternalImpl = OwnableComponent::InternalImpl; - pub const FELT_ETH_CONTRACT: felt252 = - 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7; pub const FELT_STRK_CONTRACT: felt252 = 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d; - const ZKLEND_MARKET: felt252 = - 0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05; #[event] #[derive(Drop, starknet::Event)] @@ -60,7 +42,6 @@ pub mod YourContract { new_greeting: ByteArray, premium: bool, value: Option, - token: Option, } #[storage] @@ -69,8 +50,6 @@ pub mod YourContract { premium: bool, total_counter: u256, user_greeting_counter: Map, - zklend_dispatcher: IZklendMarketDispatcher, - token_deposits: Map, #[substorage(v0)] ownable: OwnableComponent::Storage, } @@ -79,11 +58,6 @@ pub mod YourContract { fn constructor(ref self: ContractState, owner: ContractAddress) { self.greeting.write("Building Unstoppable Apps!!!"); self.ownable.initializer(owner); - - // setup dispatchers - self - .zklend_dispatcher - .write(IZklendMarketDispatcher { contract_address: ZKLEND_MARKET.try_into().unwrap() }); } #[abi(embed_v0)] @@ -91,143 +65,53 @@ pub mod YourContract { fn greeting(self: @ContractState) -> ByteArray { self.greeting.read() } - fn set_greeting( - ref self: ContractState, - new_greeting: ByteArray, - option_amount: Option, - option_token: Option, + ref self: ContractState, new_greeting: ByteArray, amount_strk: Option, ) { - self._require_supported_token(option_token); self.greeting.write(new_greeting); self.total_counter.write(self.total_counter.read() + 1); let user_counter = self.user_greeting_counter.read(get_caller_address()); self.user_greeting_counter.write(get_caller_address(), user_counter + 1); - match (option_amount, option_token) { - ( - Option::Some(amount), Option::Some(token), - ) => { - if amount > 0 { - self - ._get_token_dispatcher(token) - .transfer_from(get_caller_address(), get_contract_address(), amount); - self.premium.write(true); - self._deposit_all_tokens_to_zklend(); - self.token_deposits.write(token, self.token_deposits.read(token) + amount); - self - .emit( - GreetingChanged { - greeting_setter: get_caller_address(), - new_greeting: self.greeting.read(), - premium: true, - value: Option::Some(amount), - token: Option::Some(token), - }, + match amount_strk { + Option::Some(amount_strk) => { + // In `Debug Contract` or UI implementation, call `approve` on STRK contract + // before invoking fn set_greeting() + if amount_strk > 0 { + let strk_contract_address: ContractAddress = FELT_STRK_CONTRACT + .try_into() + .unwrap(); + let strk_dispatcher = IERC20Dispatcher { + contract_address: strk_contract_address, + }; + strk_dispatcher + .transfer_from( + get_caller_address(), get_contract_address(), amount_strk, ); - } else { - panic!("Amount must be greater than 0"); + self.premium.write(true); } }, - ( - Option::None, Option::None, - ) => { - self.premium.write(false); - self - .emit( - GreetingChanged { - greeting_setter: get_caller_address(), - new_greeting: self.greeting.read(), - premium: false, - value: Option::None, - token: Option::None, - }, - ); - }, - _ => { panic!("Unreachable"); }, + Option::None => { self.premium.write(false); }, } + self + .emit( + GreetingChanged { + greeting_setter: get_caller_address(), + new_greeting: self.greeting.read(), + premium: self.premium.read(), + value: amount_strk, + }, + ); } - fn premium(self: @ContractState) -> bool { - self.premium.read() - } - - fn token_deposits(self: @ContractState, token: ContractAddress) -> u256 { - self.token_deposits.read(token) - } - fn withdraw(ref self: ContractState) { self.ownable.assert_only_owner(); - self._withdraw_all_tokens_from_zklend(); - let eth_contract_address = FELT_ETH_CONTRACT.try_into().unwrap(); let strk_contract_address = FELT_STRK_CONTRACT.try_into().unwrap(); - - let eth_dispatcher = self._get_token_dispatcher(eth_contract_address); - let strk_dispatcher = self._get_token_dispatcher(strk_contract_address); - - let eth_balance = eth_dispatcher.balance_of(get_contract_address()); - let strk_balance = strk_dispatcher.balance_of(get_contract_address()); - - eth_dispatcher.transfer(self.ownable.owner(), eth_balance); - strk_dispatcher.transfer(self.ownable.owner(), strk_balance); + let strk_dispatcher = IERC20Dispatcher { contract_address: strk_contract_address }; + let balance = strk_dispatcher.balance_of(get_contract_address()); + strk_dispatcher.transfer(self.ownable.owner(), balance); } - } - // internal - #[generate_trait] - impl InternalImpl of InternalTrait { - fn _get_token_dispatcher( - ref self: ContractState, token: ContractAddress, - ) -> IERC20Dispatcher { - return IERC20Dispatcher { contract_address: token }; - } - - fn _deposit_all_tokens_to_zklend(ref self: ContractState) { - let eth_dispatcher = self._get_token_dispatcher(FELT_ETH_CONTRACT.try_into().unwrap()); - let strk_dispatcher = self - ._get_token_dispatcher(FELT_STRK_CONTRACT.try_into().unwrap()); - - let eth_balance = eth_dispatcher.balance_of(get_contract_address()); - let strk_balance = strk_dispatcher.balance_of(get_contract_address()); - - let eth_balance_felt: felt252 = eth_balance.try_into().expect('Amount too large'); - let strk_balance_felt: felt252 = strk_balance.try_into().expect('Amount too large'); - - if eth_balance > 0 { - eth_dispatcher.approve(ZKLEND_MARKET.try_into().unwrap(), eth_balance); - self - .zklend_dispatcher - .read() - .deposit(eth_dispatcher.contract_address, eth_balance_felt); - } - if strk_balance > 0 { - strk_dispatcher.approve(ZKLEND_MARKET.try_into().unwrap(), strk_balance); - self - .zklend_dispatcher - .read() - .deposit(strk_dispatcher.contract_address, strk_balance_felt); - } - } - - fn _withdraw_all_tokens_from_zklend(ref self: ContractState) { - if self.token_deposits.read(FELT_STRK_CONTRACT.try_into().unwrap()) > 0 { - self.zklend_dispatcher.read().withdraw_all(FELT_STRK_CONTRACT.try_into().unwrap()); - self.token_deposits.write(FELT_STRK_CONTRACT.try_into().unwrap(), 0); - } - if self.token_deposits.read(FELT_ETH_CONTRACT.try_into().unwrap()) > 0 { - self.zklend_dispatcher.read().withdraw_all(FELT_ETH_CONTRACT.try_into().unwrap()); - self.token_deposits.write(FELT_ETH_CONTRACT.try_into().unwrap(), 0); - } - } - - fn _require_supported_token( - ref self: ContractState, option_token: Option, - ) { - if let Option::Some(token) = option_token { - assert( - token == FELT_STRK_CONTRACT.try_into().unwrap() - || token == FELT_ETH_CONTRACT.try_into().unwrap(), - 'Unsupported token', - ); - } + fn premium(self: @ContractState) -> bool { + self.premium.read() } } } diff --git a/packages/snfoundry/contracts/tests/test_contract.cairo b/packages/snfoundry/contracts/tests/test_contract.cairo index c18d871..e5a30f0 100644 --- a/packages/snfoundry/contracts/tests/test_contract.cairo +++ b/packages/snfoundry/contracts/tests/test_contract.cairo @@ -1,4 +1,4 @@ -use contracts::your_contract::YourContract::{FELT_ETH_CONTRACT, FELT_STRK_CONTRACT}; +use contracts::your_contract::YourContract::FELT_STRK_CONTRACT; use contracts::your_contract::{IYourContractDispatcher, IYourContractDispatcherTrait}; use openzeppelin_testing::declare_and_deploy; use openzeppelin_token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; @@ -6,13 +6,13 @@ use openzeppelin_utils::serde::SerializedAppend; use snforge_std::{CheatSpan, cheat_caller_address}; use starknet::ContractAddress; -// Real wallet address deployed on Mainnet -const OWNER: ContractAddress = 0x00c853dC4D9141DC6192FeCc999cC7333348Ab4fDCEf97B760ECb63A7FDE1c0e +// Real wallet address deployed on Sepolia +const OWNER: ContractAddress = 0x02dA5254690b46B9C4059C25366D1778839BE63C142d899F0306fd5c312A5918 .try_into() .unwrap(); const STRK_TOKEN_CONTRACT_ADDRESS: ContractAddress = FELT_STRK_CONTRACT.try_into().unwrap(); -const ETH_TOKEN_CONTRACT_ADDRESS: ContractAddress = FELT_ETH_CONTRACT.try_into().unwrap(); + fn deploy_contract(name: ByteArray) -> ContractAddress { let mut calldata = array![]; calldata.append_serde(OWNER); @@ -30,25 +30,22 @@ fn test_set_greetings() { assert(current_greeting == expected_greeting, 'Should have the right message'); let new_greeting: ByteArray = "Learn Scaffold-Stark 2! :)"; - dispatcher - .set_greeting( - new_greeting.clone(), Option::None, Option::None, - ); // we dont transfer any fri/wei + dispatcher.set_greeting(new_greeting.clone(), Option::None); // we don't transfer any strk assert(dispatcher.greeting() == new_greeting, 'Should allow set new message'); } #[test] -#[fork("MAINNET_LATEST")] -fn test_transfer_eth() { - let user: ContractAddress = OWNER.try_into().unwrap(); +#[fork("SEPOLIA_LATEST")] +fn test_transfer() { + let user = OWNER; let your_contract_address = deploy_contract("YourContract"); let your_contract_dispatcher = IYourContractDispatcher { contract_address: your_contract_address, }; - let erc20_dispatcher = IERC20Dispatcher { contract_address: ETH_TOKEN_CONTRACT_ADDRESS }; + let erc20_dispatcher = IERC20Dispatcher { contract_address: STRK_TOKEN_CONTRACT_ADDRESS }; let amount_to_transfer = 500; - cheat_caller_address(ETH_TOKEN_CONTRACT_ADDRESS, user, CheatSpan::TargetCalls(1)); + cheat_caller_address(STRK_TOKEN_CONTRACT_ADDRESS, user, CheatSpan::TargetCalls(1)); erc20_dispatcher.approve(your_contract_address, amount_to_transfer); let approved_amount = erc20_dispatcher.allowance(user, your_contract_address); assert(approved_amount == amount_to_transfer, 'Not the right amount approved'); @@ -58,36 +55,7 @@ fn test_transfer_eth() { cheat_caller_address(your_contract_address, user, CheatSpan::TargetCalls(1)); your_contract_dispatcher .set_greeting( - new_greeting.clone(), - Option::Some(amount_to_transfer), - Option::Some(ETH_TOKEN_CONTRACT_ADDRESS), + new_greeting.clone(), Option::Some(amount_to_transfer), ); // we transfer 500 wei assert(your_contract_dispatcher.greeting() == new_greeting, 'Should allow set new message'); } - -#[test] -#[fork("MAINNET_LATEST")] -fn test_transfer_strk() { - let user: ContractAddress = OWNER.try_into().unwrap(); - let your_contract_address = deploy_contract("YourContract"); - - let your_contract_dispatcher = IYourContractDispatcher { - contract_address: your_contract_address, - }; - let erc20_dispatcher = IERC20Dispatcher { contract_address: STRK_TOKEN_CONTRACT_ADDRESS }; - let amount_to_transfer = 500; - cheat_caller_address(STRK_TOKEN_CONTRACT_ADDRESS, user, CheatSpan::TargetCalls(1)); - erc20_dispatcher.approve(your_contract_address, amount_to_transfer); - let approved_amount = erc20_dispatcher.allowance(user, your_contract_address); - assert(approved_amount == amount_to_transfer, 'Not the right amount approved'); - - let new_greeting: ByteArray = "Learn How to handle Some and None in Cairo"; - cheat_caller_address(your_contract_address, user, CheatSpan::TargetCalls(1)); - your_contract_dispatcher - .set_greeting( - new_greeting.clone(), - Option::Some(amount_to_transfer), - Option::Some(STRK_TOKEN_CONTRACT_ADDRESS), - ); // we transfer 500 fri - assert(your_contract_dispatcher.greeting() == new_greeting, 'Should allow set new message'); -} From 96e4ae463a197ec1133c9f391608324602b40c93 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Tue, 14 Oct 2025 10:04:28 +0700 Subject: [PATCH 04/12] fix: must download vStrk contract from Configure Contracts --- packages/nextjs/app/page.tsx | 56 +- .../contracts/configExternalContracts.ts | 409 +-------- packages/nextjs/utils/vesu/constants.ts | 9 - packages/nextjs/utils/vesu/vTokenAbi.ts | 780 ------------------ 4 files changed, 52 insertions(+), 1202 deletions(-) delete mode 100644 packages/nextjs/utils/vesu/constants.ts delete mode 100644 packages/nextjs/utils/vesu/vTokenAbi.ts diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 2084487..51cec20 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -5,11 +5,11 @@ import { useState } from "react"; import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; +import { useDeployedContractInfo } from "~~/hooks/scaffold-stark/useDeployedContractInfo"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork"; import { useAccount } from "@starknet-react/core"; import useScaffoldStrkBalance from "~~/hooks/scaffold-stark/useScaffoldStrkBalance"; -import { VSTRK_ADDRESS } from "~~/utils/vesu/constants"; const Home = () => { const [displayAmount, setDisplayAmount] = useState(""); @@ -19,6 +19,9 @@ const Home = () => { const { address: connectedAddress } = useAccount(); + // vSTRK contract info + const { data: vStrk } = useDeployedContractInfo("vStrk"); + const toHex = (v: unknown) => typeof v === "bigint" ? `0x${v.toString(16)}` : (v as string); @@ -49,7 +52,7 @@ const Home = () => { { contractName: "Strk", functionName: "approve", - args: [VSTRK_ADDRESS, amountWei], + args: [vStrk?.address, amountWei], }, { contractName: "vStrk", @@ -65,12 +68,14 @@ const Home = () => { eventName: "Deposit", fromBlock: 1540452n, // NOTE : For now keep this block number as it is. When running local mainnet fork, use this block number as the starting block number. For example: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_9 --fork-block 1540452` watch: true, + enabled: !!vStrk, }); const { data: withdrawEvents } = useScaffoldEventHistory({ contractName: "vStrk", eventName: "Withdraw", fromBlock: 1540452n, watch: true, + enabled: !!vStrk, }); return ( @@ -87,6 +92,41 @@ const Home = () => {
+
+

+ Instructions +

+
+
+ 1 +

+ Run mainnet fork:{" "} + + yarn chain --fork-network + https://starknet-mainnet.public.blastapi.io/rpc/v0_9 + +

+
+
+ 2 +

+ To deposit or withdraw a Vesu token, you will need to interact + with a "vToken", we will take vSTRK to interact. +

+
+
+ 3 +

+ Now let click to the "Configure Contracts" button on the bottom + left corner to download vStrk configures at address{" "} + + 0x0147ae3337b168ac9abe80a7214f0cb9e874b25c3db530a8e04beb98a134e07a + {" "} + and name vStrk +

+
+
+
{/* Contract Status removed for Vesu demo */}
@@ -98,6 +138,7 @@ const Home = () => { className="btn btn-primary btn-lg" onClick={() => redeemAll()} disabled={ + !vStrk || !connectedAddress || !vStrkBalance || (vStrkBalance as any) === 0n || @@ -107,13 +148,13 @@ const Home = () => { {isRedeeming ? ( ) : ( - "Redeem All" + "Withdraw All" )}
- Redeem all your vSTRK shares back to STRK. + Withdraw all your vSTRK shares back to STRK.
@@ -184,7 +225,12 @@ const Home = () => {
-
-

- Instructions -

-
-
- 1 -

- Run mainnet fork:{" "} - - yarn chain --fork-network - https://starknet-mainnet.public.blastapi.io/rpc/v0_9 - -

-
-
- 2 -

- To deposit or withdraw a Vesu token, you will need to interact - with a "vToken", we will take vSTRK to interact. -

-
-
- 3 -

- Now let click to the "Configure Contracts" button on the bottom - left corner to download vStrk configures at address{" "} - - 0x0147ae3337b168ac9abe80a7214f0cb9e874b25c3db530a8e04beb98a134e07a - {" "} - and name vStrk -

-
-
-
{/* Contract Status removed for Vesu demo */}
From 3de7a87773a40c80c9713183f306de9a13358e06 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Sat, 18 Oct 2025 17:50:37 +0700 Subject: [PATCH 08/12] docs: Replace zklend with Vesu --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ad56d42..7039700 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,13 @@ The tutorial is divided into the following steps: - At this point the user should be able to send STRK and ETH to the contract through our UI and see the events logged at the bottom. - [View changes from step-1 to step-2](https://github.com/Scaffold-Stark/basecamp/compare/step-1...step-2) -**Step 3: Full zklend Integration** ([branch: step-3](https://github.com/Scaffold-Stark/basecamp/tree/step-3)) +**Step 3: Full Vesu Integration** ([branch: step-3](https://github.com/Scaffold-Stark/basecamp/tree/step-3)) -- Updates [`YourContract.cairo`](https://github.com/Scaffold-Stark/basecamp/blob/step-3/packages/snfoundry/contracts/src/YourContract.cairo) with [zklend](https://app.zklend.com/markets) integration -- All the STRK and ETH deposits are now sent to zklend for yield farming -- Introduces development on mainnet fork. Can follow scaffold-stark [docs](https://scaffoldstark.com/docs/recipes/DevelopingOnFork) to run and interact with a local fork of Starknet mainnet. +- Introduces development on mainnet fork. Run mainnet fork: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_9`. Can follow scaffold-stark [docs](https://scaffoldstark.com/docs/recipes/DevelopingOnFork) to run and interact with a local fork of Starknet mainnet. +- To deposit or withdraw a Vesu token, you will need to interact with a "vToken", we will take vSTRK to interact +- Use `Configure Contracts` tool to to download Vesu vStrk configures at address `0x0147ae3337b168ac9abe80a7214f0cb9e874b25c3db530a8e04beb98a134e07a` and name vStrk - Minor `page.tsx` and `scaffold.config.ts` updates to support mainnetFork testing - Includes mainnet deployment steps -- Users can send STRK or ETH along with a greeting, these deposits will generate yield from first second onwards, owner can withdraw the yield anytime. User can connect with `burner wallet` to interact with the contract on Starknet mainnet fork. - [View changes from step-2 to step-3](https://github.com/Scaffold-Stark/basecamp/compare/step-2...step-3) Each step builds upon the previous one, introducing new concepts and features while maintaining a clean, production-ready codebase. From b88cb356acb16243982c82f43cf8394c74bda85e Mon Sep 17 00:00:00 2001 From: tu11aa Date: Sat, 18 Oct 2025 18:11:29 +0700 Subject: [PATCH 09/12] chore: revert deployed contract abi --- .../nextjs/contracts/deployedContracts.ts | 86 ++++++++++++++++++- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 7abef3b..e8353e3 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,7 +7,7 @@ const deployedContracts = { devnet: { YourContract: { address: - "0x3760a55e55c5d737d14e527c4c09c5b828f5476fd6f9b7148482ec4185afa17", + "0x3d0a8a77f45d5e0f52fc3f4734985ce57795caaaf23181eaa35aed377f01184", abi: [ { type: "impl", @@ -60,6 +60,20 @@ const deployedContracts = { }, ], }, + { + type: "enum", + name: "core::option::Option::", + variants: [ + { + name: "Some", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "None", + type: "()", + }, + ], + }, { type: "enum", name: "core::bool", @@ -98,9 +112,13 @@ const deployedContracts = { type: "core::byte_array::ByteArray", }, { - name: "amount_strk", + name: "option_amount", type: "core::option::Option::", }, + { + name: "option_token", + type: "core::option::Option::", + }, ], outputs: [], state_mutability: "external", @@ -123,6 +141,22 @@ const deployedContracts = { ], state_mutability: "view", }, + { + type: "function", + name: "token_deposits", + inputs: [ + { + name: "token", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, ], }, { @@ -252,6 +286,11 @@ const deployedContracts = { type: "core::option::Option::", kind: "data", }, + { + name: "token", + type: "core::option::Option::", + kind: "data", + }, ], }, { @@ -273,7 +312,7 @@ const deployedContracts = { }, ], classHash: - "0x21e2aa81952de7b6851d5e76ea1f70283373407b22bfb4d32fafa4c5e2c8f1d", + "0x73b00366d0117bee7ae7620469abc7ceefb8b78ff9257b77b3531a9c4411688", }, }, sepolia: { @@ -332,6 +371,20 @@ const deployedContracts = { }, ], }, + { + type: "enum", + name: "core::option::Option::", + variants: [ + { + name: "Some", + type: "core::starknet::contract_address::ContractAddress", + }, + { + name: "None", + type: "()", + }, + ], + }, { type: "enum", name: "core::bool", @@ -370,9 +423,13 @@ const deployedContracts = { type: "core::byte_array::ByteArray", }, { - name: "amount_strk", + name: "option_amount", type: "core::option::Option::", }, + { + name: "option_token", + type: "core::option::Option::", + }, ], outputs: [], state_mutability: "external", @@ -395,6 +452,22 @@ const deployedContracts = { ], state_mutability: "view", }, + { + type: "function", + name: "token_deposits", + inputs: [ + { + name: "token", + type: "core::starknet::contract_address::ContractAddress", + }, + ], + outputs: [ + { + type: "core::integer::u256", + }, + ], + state_mutability: "view", + }, ], }, { @@ -524,6 +597,11 @@ const deployedContracts = { type: "core::option::Option::", kind: "data", }, + { + name: "token", + type: "core::option::Option::", + kind: "data", + }, ], }, { From 522d81fe4a2f4df1c943a62a055c8b80688ba39e Mon Sep 17 00:00:00 2001 From: tu11aa Date: Sat, 18 Oct 2025 18:29:05 +0700 Subject: [PATCH 10/12] Vesu should be in another page --- packages/nextjs/app/page.tsx | 425 ++++++++++++-------- packages/nextjs/app/vesu/page.tsx | 272 +++++++++++++ packages/nextjs/components/Header.tsx | 7 + packages/nextjs/public/vesu-symbol-icon.svg | 87 ++++ 4 files changed, 626 insertions(+), 165 deletions(-) create mode 100644 packages/nextjs/app/vesu/page.tsx create mode 100644 packages/nextjs/public/vesu-symbol-icon.svg diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index 66d76b4..a783b2f 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -3,81 +3,118 @@ import { ConnectedAddress } from "~~/components/ConnectedAddress"; import { useState } from "react"; import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; +import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; +import { useBlockNumber } from "@starknet-react/core"; import { useDeployedContractInfo } from "~~/hooks/scaffold-stark/useDeployedContractInfo"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork"; -import { useAccount } from "@starknet-react/core"; -import useScaffoldStrkBalance from "~~/hooks/scaffold-stark/useScaffoldStrkBalance"; +import { CairoOption, CairoOptionVariant, BlockTag } from "starknet"; const Home = () => { + const [selectedToken, setSelectedToken] = useState<"ETH" | "STRK">("STRK"); + const [inputAmount, setInputAmount] = useState(0n); + const [greeting, setGreeting] = useState(""); const [displayAmount, setDisplayAmount] = useState(""); - const [amountWei, setAmountWei] = useState(0n); + const [isNoneOption, setIsNoneOption] = useState(true); const { targetNetwork } = useTargetNetwork(); - const { address: connectedAddress } = useAccount(); + const { data: YourContract } = useDeployedContractInfo("YourContract"); + const { data: EthContract } = useDeployedContractInfo("Eth"); + const { data: StrkContract } = useDeployedContractInfo("Strk"); - // vSTRK contract info - const { data: vStrk } = useDeployedContractInfo("vStrk"); - - const toHex = (v: unknown) => - typeof v === "bigint" ? `0x${v.toString(16)}` : (v as string); + const { data: currentGreeting } = useScaffoldReadContract({ + contractName: "YourContract", + functionName: "greeting", + }); - // Deposited amount = user's vSTRK balance (shares) - const { data: vStrkBalance } = useScaffoldReadContract({ - contractName: "vStrk", - functionName: "balance_of", - args: [connectedAddress], + const { data: premium } = useScaffoldReadContract({ + contractName: "YourContract", + functionName: "premium", }); - // Available STRK balance of user - const { value: availableStrk } = useScaffoldStrkBalance({ - address: connectedAddress || undefined, + const { data: ethBalance } = useScaffoldReadContract({ + contractName: "YourContract", + functionName: "token_deposits", + args: [EthContract?.address], }); - // Redeem (withdraw) all vSTRK shares to STRK - const { sendAsync: redeemAll, isPending: isRedeeming } = - useScaffoldWriteContract({ - contractName: "vStrk", - functionName: "redeem", - args: [vStrkBalance as any, connectedAddress, connectedAddress], - }); + const { data: strkBalance } = useScaffoldReadContract({ + contractName: "YourContract", + functionName: "token_deposits", + args: [StrkContract?.address], + }); - // STRK-only deposit flow: approve STRK to vSTRK, then deposit assets - const { sendAsync: depositStrk, isPending: isDepositing } = - useScaffoldMultiWriteContract({ - calls: [ - { - contractName: "Strk", - functionName: "approve", - args: [vStrk?.address, amountWei], - }, - { - contractName: "vStrk", - functionName: "deposit", - args: [amountWei, connectedAddress], - }, - ], - }); + const { data: lastBlock } = useBlockNumber({ + blockIdentifier: "pending" as BlockTag, + }); - // Event history for vSTRK Deposit and Withdraw - const { data: depositEvents } = useScaffoldEventHistory({ - contractName: "vStrk", - eventName: "Deposit", - fromBlock: 1540452n, // NOTE : For now keep this block number as it is. When running local mainnet fork, use this block number as the starting block number. For example: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_9 --fork-block 1540452` + const { data: events } = useScaffoldEventHistory({ + contractName: "YourContract", + eventName: "GreetingChanged", + fromBlock: lastBlock ? (lastBlock > 50n ? BigInt(lastBlock - 50) : 0n) : 0n, watch: true, - enabled: !!vStrk, }); - const { data: withdrawEvents } = useScaffoldEventHistory({ - contractName: "vStrk", - eventName: "Withdraw", - fromBlock: 1540452n, - watch: true, - enabled: !!vStrk, + + const noneOptionBigInt: CairoOption = new CairoOption( + CairoOptionVariant.None, + ); + + const noneOptionString: CairoOption = new CairoOption( + CairoOptionVariant.None, + ); + + const { sendAsync: setGreetingNoPayment } = useScaffoldWriteContract({ + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, noneOptionBigInt, noneOptionString], + }); + + const { sendAsync: withdrawAll } = useScaffoldWriteContract({ + contractName: "YourContract", + functionName: "withdraw", }); + const someOptionBigInt: CairoOption = new CairoOption( + CairoOptionVariant.Some, + inputAmount, + ); + + // Helper function to determine the token address option + const getTokenAddressOption = () => { + if (selectedToken === "ETH" && EthContract?.address) { + return new CairoOption(CairoOptionVariant.Some, EthContract.address); + } else if (selectedToken === "STRK" && StrkContract?.address) { + return new CairoOption(CairoOptionVariant.Some, StrkContract.address); + } else { + return noneOptionString; + } + }; + + const { sendAsync: setGreetingWithPayment } = useScaffoldMultiWriteContract({ + calls: [ + { + contractName: selectedToken === "STRK" ? "Strk" : "Eth", + functionName: "approve", + args: [YourContract?.address, someOptionBigInt.unwrap()], + }, + { + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, someOptionBigInt, getTokenAddressOption()], + }, + ], + }); + + const handleSetGreeting = async () => { + if (isNoneOption) { + await setGreetingNoPayment(); + } else { + await setGreetingWithPayment(); + } + }; + return (
@@ -93,7 +130,31 @@ const Home = () => {
- {/* Contract Status removed for Vesu demo */} +
+

+ Contract Status +

+
+
+

Current Greeting

+

+ {currentGreeting?.toString() ?? "No greeting set"} +

+
+ +
+

Premium Status

+
+
+ + {premium ? "Active" : "Inactive"} + +
+
+
+

@@ -101,36 +162,26 @@ const Home = () => {

- Withdraw all your vSTRK shares back to STRK. + This action will withdraw all deposited tokens back to the + contract owner.
- Deposited vSTRK (shares) + Available ETH - {vStrkBalance - ? (Number(vStrkBalance) / 10 ** 18).toFixed(6) + {ethBalance + ? (Number(ethBalance) / 10 ** 18).toFixed(6) : "0.000000"}{" "} - vSTRK + ETH
@@ -138,8 +189,8 @@ const Home = () => { Available STRK - {availableStrk - ? (Number(availableStrk) / 10 ** 18).toFixed(6) + {strkBalance + ? (Number(strkBalance) / 10 ** 18).toFixed(6) : "0.000000"}{" "} STRK @@ -148,120 +199,164 @@ const Home = () => {
-

Deposit

+

+ Set Greeting & Deposit +

+
+ +
+ + +
+
+
-
+ {/* Some Option */} + + + {/* None Option */} +
+
+
+ + No amount + +
+
+ No value +
+
+
+
+ + setGreeting(e.target.value)} + placeholder="Enter your greeting" + /> +

- vSTRK Activity + Transaction History

-
-
-

Deposits

-
- {depositEvents?.length ? ( - depositEvents.map((evt, idx) => ( -
-

- Owner: {toHex(evt.args.owner)} -

-

- Assets:{" "} - {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK - · Shares:{" "} - {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} - vSTRK -

-
- )) - ) : ( - No deposit events - )} -
-
-
-

Withdrawals

-
- {withdrawEvents?.length ? ( - withdrawEvents.map((evt, idx) => ( -
-

- Owner: {toHex(evt.args.owner)} -

-

- Assets:{" "} - {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK - · Shares:{" "} - {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} - vSTRK -

-
- )) - ) : ( - No withdraw events - )} +
+ {events?.map((event, index) => ( +
+

+ Set Greeting to {event.args.new_greeting} + {event.args.value.unwrap() > 0n && ( + + with{" "} + {(Number(event.args.value.unwrap()) / 10 ** 18).toFixed( + 6, + )} + {event.args.token.unwrap() === + BigInt(StrkContract?.address || "") + ? " STRK" + : " ETH"} + + )} +

-
+ ))}
diff --git a/packages/nextjs/app/vesu/page.tsx b/packages/nextjs/app/vesu/page.tsx new file mode 100644 index 0000000..66d76b4 --- /dev/null +++ b/packages/nextjs/app/vesu/page.tsx @@ -0,0 +1,272 @@ +"use client"; + +import { ConnectedAddress } from "~~/components/ConnectedAddress"; +import { useState } from "react"; +import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; +import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; +import { useScaffoldEventHistory } from "~~/hooks/scaffold-stark/useScaffoldEventHistory"; +import { useDeployedContractInfo } from "~~/hooks/scaffold-stark/useDeployedContractInfo"; +import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; +import { useTargetNetwork } from "~~/hooks/scaffold-stark/useTargetNetwork"; +import { useAccount } from "@starknet-react/core"; +import useScaffoldStrkBalance from "~~/hooks/scaffold-stark/useScaffoldStrkBalance"; + +const Home = () => { + const [displayAmount, setDisplayAmount] = useState(""); + const [amountWei, setAmountWei] = useState(0n); + + const { targetNetwork } = useTargetNetwork(); + + const { address: connectedAddress } = useAccount(); + + // vSTRK contract info + const { data: vStrk } = useDeployedContractInfo("vStrk"); + + const toHex = (v: unknown) => + typeof v === "bigint" ? `0x${v.toString(16)}` : (v as string); + + // Deposited amount = user's vSTRK balance (shares) + const { data: vStrkBalance } = useScaffoldReadContract({ + contractName: "vStrk", + functionName: "balance_of", + args: [connectedAddress], + }); + + // Available STRK balance of user + const { value: availableStrk } = useScaffoldStrkBalance({ + address: connectedAddress || undefined, + }); + + // Redeem (withdraw) all vSTRK shares to STRK + const { sendAsync: redeemAll, isPending: isRedeeming } = + useScaffoldWriteContract({ + contractName: "vStrk", + functionName: "redeem", + args: [vStrkBalance as any, connectedAddress, connectedAddress], + }); + + // STRK-only deposit flow: approve STRK to vSTRK, then deposit assets + const { sendAsync: depositStrk, isPending: isDepositing } = + useScaffoldMultiWriteContract({ + calls: [ + { + contractName: "Strk", + functionName: "approve", + args: [vStrk?.address, amountWei], + }, + { + contractName: "vStrk", + functionName: "deposit", + args: [amountWei, connectedAddress], + }, + ], + }); + + // Event history for vSTRK Deposit and Withdraw + const { data: depositEvents } = useScaffoldEventHistory({ + contractName: "vStrk", + eventName: "Deposit", + fromBlock: 1540452n, // NOTE : For now keep this block number as it is. When running local mainnet fork, use this block number as the starting block number. For example: `yarn chain --fork-network https://starknet-mainnet.public.blastapi.io/rpc/v0_9 --fork-block 1540452` + watch: true, + enabled: !!vStrk, + }); + const { data: withdrawEvents } = useScaffoldEventHistory({ + contractName: "vStrk", + eventName: "Withdraw", + fromBlock: 1540452n, + watch: true, + enabled: !!vStrk, + }); + + return ( +
+
+

+ + Scaffold-Stark Workshop + +
+ + {targetNetwork.name} + +
+

+ +
+ {/* Contract Status removed for Vesu demo */} +
+
+

+ Contract Management +

+ +
+
+
+ Withdraw all your vSTRK shares back to STRK. +
+
+
+ + Deposited vSTRK (shares) + + + {vStrkBalance + ? (Number(vStrkBalance) / 10 ** 18).toFixed(6) + : "0.000000"}{" "} + vSTRK + +
+
+ + Available STRK + + + {availableStrk + ? (Number(availableStrk) / 10 ** 18).toFixed(6) + : "0.000000"}{" "} + STRK + +
+
+
+
+
+

Deposit

+
+
+ +
+
+
+ { + const value = e.target.value; + setDisplayAmount(value); + if (value && value !== "") { + try { + const amountInWei = BigInt( + Math.floor(Number(value) * 10 ** 18), + ); + setAmountWei(amountInWei); + } catch (error) { + console.error("Invalid number input:", error); + setAmountWei(0n); + } + } else { + setAmountWei(0n); + } + }} + placeholder="Enter amount" + autoComplete="off" + /> +
+
+
+
+ +
+
+
+

+ vSTRK Activity +

+
+
+

Deposits

+
+ {depositEvents?.length ? ( + depositEvents.map((evt, idx) => ( +
+

+ Owner: {toHex(evt.args.owner)} +

+

+ Assets:{" "} + {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK + · Shares:{" "} + {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} + vSTRK +

+
+ )) + ) : ( + No deposit events + )} +
+
+
+

Withdrawals

+
+ {withdrawEvents?.length ? ( + withdrawEvents.map((evt, idx) => ( +
+

+ Owner: {toHex(evt.args.owner)} +

+

+ Assets:{" "} + {(Number(evt.args.assets) / 10 ** 18).toFixed(6)} STRK + · Shares:{" "} + {(Number(evt.args.shares) / 10 ** 18).toFixed(6)}{" "} + vSTRK +

+
+ )) + ) : ( + No withdraw events + )} +
+
+
+
+
+
+
+ ); +}; +export default Home; diff --git a/packages/nextjs/components/Header.tsx b/packages/nextjs/components/Header.tsx index 7c8c8c1..87a7d6f 100644 --- a/packages/nextjs/components/Header.tsx +++ b/packages/nextjs/components/Header.tsx @@ -30,6 +30,13 @@ export const menuLinks: HeaderMenuLink[] = [ href: "/debug", icon: , }, + { + label: "Vesu", + href: "/vesu", + icon: ( + Vesu + ), + }, ]; export const HeaderMenuLinks = () => { diff --git a/packages/nextjs/public/vesu-symbol-icon.svg b/packages/nextjs/public/vesu-symbol-icon.svg new file mode 100644 index 0000000..d909c31 --- /dev/null +++ b/packages/nextjs/public/vesu-symbol-icon.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 148f3b57c88e0b3d1009bd9317c16b17decaf991 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Sun, 19 Oct 2025 13:32:09 +0700 Subject: [PATCH 11/12] revert to get back multicall --- .../nextjs/contracts/deployedContracts.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index e8353e3..6923166 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -315,6 +315,92 @@ const deployedContracts = { "0x73b00366d0117bee7ae7620469abc7ceefb8b78ff9257b77b3531a9c4411688", }, }, + mainnet: { + Multicall: { + address: + "0x7ca5ccfeb2e4d6e13e9382d70042712f1f736c003f3a40243d9a397a7317251", + abi: [ + { + type: "impl", + name: "MulticallImpl", + interface_name: "contracts::multicall::IMulticall", + }, + { + type: "struct", + name: "core::array::Span::", + members: [ + { + name: "snapshot", + type: "@core::array::Array::", + }, + ], + }, + { + type: "struct", + name: "core::array::Span::", + members: [ + { + name: "snapshot", + type: "@core::array::Array::", + }, + ], + }, + { + type: "struct", + name: "core::array::Span::>", + members: [ + { + name: "snapshot", + type: "@core::array::Array::>", + }, + ], + }, + { + type: "interface", + name: "contracts::multicall::IMulticall", + items: [ + { + type: "function", + name: "call_contracts", + inputs: [ + { + name: "contracts", + type: "core::array::Span::", + }, + { + name: "entry_point_selectors", + type: "core::array::Span::", + }, + { + name: "calldata", + type: "core::array::Span::>", + }, + ], + outputs: [ + { + type: "core::array::Array::>", + }, + ], + state_mutability: "view", + }, + ], + }, + { + type: "constructor", + name: "constructor", + inputs: [], + }, + { + type: "event", + name: "contracts::multicall::Multicall::Event", + kind: "enum", + variants: [], + }, + ], + classHash: + "0x67be8d0979b1012f4222674cb81e3a0413e45e16897b8d7c650ae84ba4a3f23", + }, + }, sepolia: { YourContract: { address: From e62fed771e3e9d7dfc96b70f2c2e84e96abd4dc0 Mon Sep 17 00:00:00 2001 From: tu11aa Date: Sun, 19 Oct 2025 13:35:47 +0700 Subject: [PATCH 12/12] revert contract --- .../nextjs/contracts/deployedContracts.ts | 110 +++--------------- 1 file changed, 16 insertions(+), 94 deletions(-) diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts index 6923166..8e089af 100644 --- a/packages/nextjs/contracts/deployedContracts.ts +++ b/packages/nextjs/contracts/deployedContracts.ts @@ -7,12 +7,12 @@ const deployedContracts = { devnet: { YourContract: { address: - "0x3d0a8a77f45d5e0f52fc3f4734985ce57795caaaf23181eaa35aed377f01184", + "0x1a2542704c7588b9c5eb86c9a1b2391b93b77b67694268b74db51097031839d", abi: [ { type: "impl", name: "YourContractImpl", - interface_name: "contracts::your_contract::IYourContract", + interface_name: "contracts::YourContract::IYourContract", }, { type: "struct", @@ -60,20 +60,6 @@ const deployedContracts = { }, ], }, - { - type: "enum", - name: "core::option::Option::", - variants: [ - { - name: "Some", - type: "core::starknet::contract_address::ContractAddress", - }, - { - name: "None", - type: "()", - }, - ], - }, { type: "enum", name: "core::bool", @@ -90,7 +76,7 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::your_contract::IYourContract", + name: "contracts::YourContract::IYourContract", items: [ { type: "function", @@ -112,13 +98,9 @@ const deployedContracts = { type: "core::byte_array::ByteArray", }, { - name: "option_amount", + name: "amount_strk", type: "core::option::Option::", }, - { - name: "option_token", - type: "core::option::Option::", - }, ], outputs: [], state_mutability: "external", @@ -141,22 +123,6 @@ const deployedContracts = { ], state_mutability: "view", }, - { - type: "function", - name: "token_deposits", - inputs: [ - { - name: "token", - type: "core::starknet::contract_address::ContractAddress", - }, - ], - outputs: [ - { - type: "core::integer::u256", - }, - ], - state_mutability: "view", - }, ], }, { @@ -263,7 +229,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::your_contract::YourContract::GreetingChanged", + name: "contracts::YourContract::YourContract::GreetingChanged", kind: "struct", members: [ { @@ -286,16 +252,11 @@ const deployedContracts = { type: "core::option::Option::", kind: "data", }, - { - name: "token", - type: "core::option::Option::", - kind: "data", - }, ], }, { type: "event", - name: "contracts::your_contract::YourContract::Event", + name: "contracts::YourContract::YourContract::Event", kind: "enum", variants: [ { @@ -305,14 +266,14 @@ const deployedContracts = { }, { name: "GreetingChanged", - type: "contracts::your_contract::YourContract::GreetingChanged", + type: "contracts::YourContract::YourContract::GreetingChanged", kind: "nested", }, ], }, ], classHash: - "0x73b00366d0117bee7ae7620469abc7ceefb8b78ff9257b77b3531a9c4411688", + "0x5e4c766477764df946dcce9b0d2c865468882ac572c0d3767aeb98d23cbe74b", }, }, mainnet: { @@ -404,12 +365,12 @@ const deployedContracts = { sepolia: { YourContract: { address: - "0x6a5b250d1eeda1cdc9e98078d3dadbe1d2bacd7a4a44f55e9e250bfe18c4288", + "0x62eb9272c7523ee445d223bae15b5b44a79c3fdbb5216d3412534a47bcc5255", abi: [ { type: "impl", name: "YourContractImpl", - interface_name: "contracts::your_contract::IYourContract", + interface_name: "contracts::YourContract::IYourContract", }, { type: "struct", @@ -457,20 +418,6 @@ const deployedContracts = { }, ], }, - { - type: "enum", - name: "core::option::Option::", - variants: [ - { - name: "Some", - type: "core::starknet::contract_address::ContractAddress", - }, - { - name: "None", - type: "()", - }, - ], - }, { type: "enum", name: "core::bool", @@ -487,7 +434,7 @@ const deployedContracts = { }, { type: "interface", - name: "contracts::your_contract::IYourContract", + name: "contracts::YourContract::IYourContract", items: [ { type: "function", @@ -509,13 +456,9 @@ const deployedContracts = { type: "core::byte_array::ByteArray", }, { - name: "option_amount", + name: "amount_strk", type: "core::option::Option::", }, - { - name: "option_token", - type: "core::option::Option::", - }, ], outputs: [], state_mutability: "external", @@ -538,22 +481,6 @@ const deployedContracts = { ], state_mutability: "view", }, - { - type: "function", - name: "token_deposits", - inputs: [ - { - name: "token", - type: "core::starknet::contract_address::ContractAddress", - }, - ], - outputs: [ - { - type: "core::integer::u256", - }, - ], - state_mutability: "view", - }, ], }, { @@ -660,7 +587,7 @@ const deployedContracts = { }, { type: "event", - name: "contracts::your_contract::YourContract::GreetingChanged", + name: "contracts::YourContract::YourContract::GreetingChanged", kind: "struct", members: [ { @@ -683,16 +610,11 @@ const deployedContracts = { type: "core::option::Option::", kind: "data", }, - { - name: "token", - type: "core::option::Option::", - kind: "data", - }, ], }, { type: "event", - name: "contracts::your_contract::YourContract::Event", + name: "contracts::YourContract::YourContract::Event", kind: "enum", variants: [ { @@ -702,14 +624,14 @@ const deployedContracts = { }, { name: "GreetingChanged", - type: "contracts::your_contract::YourContract::GreetingChanged", + type: "contracts::YourContract::YourContract::GreetingChanged", kind: "nested", }, ], }, ], classHash: - "0x73b00366d0117bee7ae7620469abc7ceefb8b78ff9257b77b3531a9c4411688", + "0x5e4c766477764df946dcce9b0d2c865468882ac572c0d3767aeb98d23cbe74b", }, }, } as const;