From 2f1d9938645bed36b60bf27d29ab96f942b4f66b Mon Sep 17 00:00:00 2001 From: Kaan Kacar Date: Wed, 20 May 2026 20:28:22 +0300 Subject: [PATCH 1/2] Fix four content-drift items flagged in #21 - standards/SKILL.md: point dangling ../security/SKILL.md link at ../soroban/SKILL.md#part-3-security (security was merged into the soroban skill during the 7-skill restructure) - soroban/SKILL.md: normalize 12 deprecated env.register_contract(_wasm) call sites to env.register(X, ()); both old forms are #[deprecated] in soroban-sdk - soroban/SKILL.md: rename `stellar contract install` to `stellar contract upload` (install is now a deprecated alias in the current CLI) - dapp/SKILL.md + soroban/SKILL.md pitfalls: switch Freighter examples to the v3 API surface (getAddress / requestAccess, isConnected/isAllowed/signTransaction now return object shapes with { ..., error? }) --- skills/dapp/SKILL.md | 49 +++++++++++++++++++++------------------ skills/soroban/SKILL.md | 44 +++++++++++++++++------------------ skills/standards/SKILL.md | 2 +- 3 files changed, 50 insertions(+), 45 deletions(-) diff --git a/skills/dapp/SKILL.md b/skills/dapp/SKILL.md index 0e0d105..40ace7e 100644 --- a/skills/dapp/SKILL.md +++ b/skills/dapp/SKILL.md @@ -113,9 +113,8 @@ export const rpc = new StellarSdk.rpc.Server(config.rpcUrl); import { useState, useEffect, useCallback } from "react"; import { isConnected, - isAllowed, - setAllowed, - getPublicKey, + getAddress, + requestAccess, signTransaction, getNetwork, } from "@stellar/freighter-api"; @@ -130,34 +129,36 @@ export function useFreighter() { }, []); const checkConnection = async () => { - const freighterConnected = await isConnected(); - if (!freighterConnected) return; - - const allowed = await isAllowed(); - if (allowed) { - const pubKey = await getPublicKey(); - const net = await getNetwork(); - setConnected(true); - setAddress(pubKey); - setNetwork(net); - } + const { isConnected: installed, error } = await isConnected(); + if (error || !installed) return; + + // getAddress returns address: "" until the app has been granted access, + // so a non-empty address means we're already authorized. + const { address: addr } = await getAddress(); + if (!addr) return; + + const { network: net } = await getNetwork(); + setConnected(true); + setAddress(addr); + setNetwork(net); }; const connect = useCallback(async () => { - const freighterConnected = await isConnected(); - if (!freighterConnected) { + const { isConnected: installed, error } = await isConnected(); + if (error || !installed) { throw new Error("Freighter extension not installed"); } - await setAllowed(); - const pubKey = await getPublicKey(); - const net = await getNetwork(); + // requestAccess prompts the user and returns the granted address. + const { address: addr, error: accessError } = await requestAccess(); + if (accessError) throw new Error(accessError.message); + const { network: net } = await getNetwork(); setConnected(true); - setAddress(pubKey); + setAddress(addr); setNetwork(net); - return pubKey; + return addr; }, []); const disconnect = useCallback(() => { @@ -169,7 +170,11 @@ export function useFreighter() { const sign = useCallback( async (xdr: string, networkPassphrase: string) => { if (!connected) throw new Error("Wallet not connected"); - return signTransaction(xdr, { networkPassphrase }); + const { signedTxXdr, error } = await signTransaction(xdr, { + networkPassphrase, + }); + if (error) throw new Error(error.message); + return signedTxXdr; }, [connected] ); diff --git a/skills/soroban/SKILL.md b/skills/soroban/SKILL.md index 1054217..64b524e 100644 --- a/skills/soroban/SKILL.md +++ b/skills/soroban/SKILL.md @@ -507,7 +507,7 @@ use soroban_sdk::Env; #[test] fn test_increment() { let env = Env::default(); - let contract_id = env.register_contract(None, CounterContract); + let contract_id = env.register(CounterContract, ()); let client = CounterContractClient::new(&env, &contract_id); let admin = Address::generate(&env); @@ -524,7 +524,7 @@ fn test_transfer_with_auth() { let env = Env::default(); env.mock_all_auths(); // Auto-approve all auth requests - let contract_id = env.register_contract(None, TokenContract); + let contract_id = env.register(TokenContract, ()); let client = TokenContractClient::new(&env, &contract_id); let alice = Address::generate(&env); @@ -631,7 +631,7 @@ fn test_basic_functionality() { let env = Env::default(); // Register contract - let contract_id = env.register_contract(None, Contract); + let contract_id = env.register(Contract, ()); // Create typed client let client = ContractClient::new(&env, &contract_id); @@ -657,7 +657,7 @@ fn test_with_auth() { // Mock all authorizations automatically env.mock_all_auths(); - let contract_id = env.register_contract(None, TokenContract); + let contract_id = env.register(TokenContract, ()); let client = TokenContractClient::new(&env, &contract_id); let admin = Address::generate(&env); @@ -687,7 +687,7 @@ fn test_with_auth() { #[test] fn test_specific_auth() { let env = Env::default(); - let contract_id = env.register_contract(None, Contract); + let contract_id = env.register(Contract, ()); let client = ContractClient::new(&env, &contract_id); let user = Address::generate(&env); @@ -713,7 +713,7 @@ fn test_specific_auth() { #[test] fn test_time_based() { let env = Env::default(); - let contract_id = env.register_contract(None, VestingContract); + let contract_id = env.register(VestingContract, ()); let client = VestingContractClient::new(&env, &contract_id); let beneficiary = Address::generate(&env); @@ -762,7 +762,7 @@ fn test_ledger_manipulation() { #[test] fn test_events() { let env = Env::default(); - let contract_id = env.register_contract(None, Contract); + let contract_id = env.register(Contract, ()); let client = ContractClient::new(&env, &contract_id); client.do_something(); @@ -786,7 +786,7 @@ fn test_events() { #[test] fn test_storage_ttl() { let env = Env::default(); - let contract_id = env.register_contract(None, Contract); + let contract_id = env.register(Contract, ()); let client = ContractClient::new(&env, &contract_id); client.store_data(); @@ -809,8 +809,8 @@ fn test_cross_contract() { let env = Env::default(); // Register both contracts - let token_id = env.register_contract_wasm(None, token::WASM); - let vault_id = env.register_contract(None, VaultContract); + let token_id = env.register(token::WASM, ()); + let vault_id = env.register(VaultContract, ()); let token_client = token::Client::new(&env, &token_id); let vault_client = VaultContractClient::new(&env, &vault_id); @@ -921,8 +921,8 @@ stellar contract deploy \ --source my-testnet-key \ --network testnet -# Install contract code (separate from deployment) -stellar contract install \ +# Upload contract code (separate from deployment) +stellar contract upload \ --wasm target/wasm32-unknown-unknown/release/contract.wasm \ --source my-testnet-key \ --network testnet @@ -1131,7 +1131,7 @@ use soroban_sdk::{testutils::Address as _, Address, Env}; use crate::{Contract, ContractClient}; pub fn setup_contract(env: &Env) -> (Address, ContractClient) { - let contract_id = env.register_contract(None, Contract); + let contract_id = env.register(Contract, ()); let client = ContractClient::new(env, &contract_id); let admin = Address::generate(env); @@ -1274,7 +1274,7 @@ fn test_upgrade_compatibility() { env.mock_all_auths(); // Register both versions - let old_id = env.register_contract_wasm(None, deployed::WASM); + let old_id = env.register(deployed::WASM, ()); let new_id = env.register(NewContract, ()); let old_client = deployed::Client::new(&env, &old_id); @@ -2407,22 +2407,22 @@ const preparedTx = StellarSdk.rpc.assembleTransaction( **Solution**: ```typescript -import { isConnected, isAllowed } from "@stellar/freighter-api"; +import { isConnected, isAllowed, requestAccess } from "@stellar/freighter-api"; async function checkFreighter() { // Check if extension is installed - const connected = await isConnected(); - if (!connected) { + const { isConnected: installed, error } = await isConnected(); + if (error || !installed) { // Prompt user to install window.open("https://freighter.app", "_blank"); return; } - // Check if app is allowed - const allowed = await isAllowed(); - if (!allowed) { - // Need to request permission - await setAllowed(); + // Check if this app is already authorized + const { isAllowed: granted } = await isAllowed(); + if (!granted) { + // requestAccess prompts the user and returns { address, error } + await requestAccess(); } } ``` diff --git a/skills/standards/SKILL.md b/skills/standards/SKILL.md index a465360..08d4dcd 100644 --- a/skills/standards/SKILL.md +++ b/skills/standards/SKILL.md @@ -117,7 +117,7 @@ Use the CAP preamble status fields as the source of truth for implementation rea - Contract implementation details: [`../soroban/SKILL.md`](../soroban/SKILL.md) - Advanced architecture guidance: [`../soroban/SKILL.md`](../soroban/SKILL.md) - RPC and data access: [`../data/SKILL.md`](../data/SKILL.md) -- Security considerations: [`../security/SKILL.md`](../security/SKILL.md) +- Security considerations: [`../soroban/SKILL.md`](../soroban/SKILL.md#part-3-security) --- From 9abdab805d629104e0ed0fd5923c733de23fffbc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 17:48:30 +0000 Subject: [PATCH 2/2] docs: address PR review feedback on Freighter v3 snippets Agent-Logs-Url: https://github.com/stellar/stellar-dev-skill/sessions/9c753e1a-6068-4574-9159-8969aed852a0 Co-authored-by: kaankacar <103106776+kaankacar@users.noreply.github.com> --- skills/dapp/SKILL.md | 10 ++++++---- skills/soroban/SKILL.md | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/skills/dapp/SKILL.md b/skills/dapp/SKILL.md index 40ace7e..d67f712 100644 --- a/skills/dapp/SKILL.md +++ b/skills/dapp/SKILL.md @@ -134,10 +134,11 @@ export function useFreighter() { // getAddress returns address: "" until the app has been granted access, // so a non-empty address means we're already authorized. - const { address: addr } = await getAddress(); - if (!addr) return; + const { address: addr, error: addressError } = await getAddress(); + if (addressError || !addr) return; - const { network: net } = await getNetwork(); + const { network: net, error: networkError } = await getNetwork(); + if (networkError) return; setConnected(true); setAddress(addr); setNetwork(net); @@ -153,7 +154,8 @@ export function useFreighter() { const { address: addr, error: accessError } = await requestAccess(); if (accessError) throw new Error(accessError.message); - const { network: net } = await getNetwork(); + const { network: net, error: networkError } = await getNetwork(); + if (networkError) throw new Error(networkError.message); setConnected(true); setAddress(addr); setNetwork(net); diff --git a/skills/soroban/SKILL.md b/skills/soroban/SKILL.md index 64b524e..3c98cb8 100644 --- a/skills/soroban/SKILL.md +++ b/skills/soroban/SKILL.md @@ -2422,7 +2422,8 @@ async function checkFreighter() { const { isAllowed: granted } = await isAllowed(); if (!granted) { // requestAccess prompts the user and returns { address, error } - await requestAccess(); + const { error: accessError } = await requestAccess(); + if (accessError) throw new Error(accessError.message); } } ``` @@ -2442,7 +2443,8 @@ async function checkFreighter() { import { getNetwork } from "@stellar/freighter-api"; async function validateNetwork() { - const walletNetwork = await getNetwork(); + const { network: walletNetwork, error } = await getNetwork(); + if (error) throw new Error(error.message); const appNetwork = process.env.NEXT_PUBLIC_STELLAR_NETWORK; if (walletNetwork !== appNetwork) {