stellarskills 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/fees/SKILL.md ADDED
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: stellarskills-fees
3
+ description: Stellar transaction fees, base fee, surge pricing, resource fees (Soroban), and fee bumps.
4
+ ---
5
+
6
+ # STELLARSKILLS — Fees
7
+
8
+ > Stellar transaction fees, base fee, surge pricing, resource fees (Soroban), and fee bumps.
9
+
10
+ ---
11
+
12
+ ## The Fee Philosophy
13
+
14
+ Stellar is designed to be inexpensive. Fees exist primarily as a spam deterrent, not as a major source of revenue or yield for validators.
15
+
16
+ On Stellar:
17
+ - **Base Fee**: Applies to classic operations (payments, trustlines, etc.)
18
+ - **Resource Fee**: Applies to Soroban smart contracts (CPU, memory, ledger I/O)
19
+ - **Refunds**: You specify a maximum fee, but you are only charged the minimum necessary to be included in the ledger. The rest is refunded.
20
+
21
+ ---
22
+
23
+ ## Classic Fees (Base Fee)
24
+
25
+ Every transaction specifies a `fee` (in **stroops**, where 1 XLM = 10,000,000 stroops). This is the **maximum total fee** you are willing to pay for the transaction.
26
+
27
+ ### Minimum Fee Calculation
28
+ The minimum fee for a classic transaction is:
29
+ ```
30
+ min_fee = base_fee × number_of_operations
31
+ ```
32
+
33
+ - **Default base fee**: 100 stroops (0.00001 XLM)
34
+ - Transaction with 1 operation: min fee = 100 stroops
35
+ - Transaction with 10 operations: min fee = 1000 stroops
36
+
37
+ ```javascript
38
+ import { TransactionBuilder, BASE_FEE } from "@stellar/stellar-sdk";
39
+
40
+ // BASE_FEE constant is 100
41
+ const tx = new TransactionBuilder(account, {
42
+ fee: BASE_FEE, // 100 stroops per operation
43
+ // ...
44
+ });
45
+ ```
46
+
47
+ ### Surge Pricing (Fee Market)
48
+ If the network is congested (more than 1000 operations per ledger), surge pricing activates. Transactions with higher base fees are prioritized.
49
+
50
+ **Crucial detail**: You only pay the *lowest* fee required to make it into the ledger, up to your specified maximum. If you set your fee to 10,000 stroops, but the clearing price is 500 stroops, you only pay 500.
51
+
52
+ ### Dynamic Fee Estimation
53
+ Always fetch current fee stats before building a transaction in production to avoid stalled transactions:
54
+
55
+ ```javascript
56
+ const server = new Horizon.Server("https://horizon.stellar.org");
57
+ const feeStats = await server.feeStats();
58
+
59
+ // Use the 99th percentile for high priority, or 50th for normal
60
+ const priorityFee = feeStats.fee_charged.p99;
61
+ const normalFee = feeStats.fee_charged.p50;
62
+
63
+ const tx = new TransactionBuilder(account, {
64
+ fee: priorityFee.toString(),
65
+ // ...
66
+ });
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Soroban Resource Fees
72
+
73
+ Soroban smart contracts charge for the exact resources they consume:
74
+ 1. CPU instructions
75
+ 2. Memory (RAM)
76
+ 3. Ledger reads/writes (I/O)
77
+ 4. Transaction size (bytes)
78
+ 5. Events emitted
79
+
80
+ ### How to calculate
81
+ You never calculate this manually. You must use `simulateTransaction` on the Soroban RPC.
82
+
83
+ ```javascript
84
+ // 1. Build raw tx with a placeholder fee
85
+ const tx = new TransactionBuilder(account, { fee: "100" })
86
+ .addOperation(contract.call("my_func"))
87
+ .build();
88
+
89
+ // 2. Simulate
90
+ const sim = await sorobanServer.simulateTransaction(tx);
91
+
92
+ // 3. Assemble (applies footprint and calculated resource fee)
93
+ const preparedTx = SorobanRpc.assembleTransaction(tx, sim);
94
+
95
+ // preparedTx now has the correct fee and resources attached
96
+ ```
97
+
98
+ ### Extending Soroban Budgets
99
+ If simulation fails because it hits the default resource limits, you can manually increase the budget (if the network max allows it):
100
+
101
+ *(Note: Most dApps should optimize their contracts rather than increasing limits, as limits protect network throughput).*
102
+
103
+ ---
104
+
105
+ ## Fee Bump Transactions
106
+
107
+ A fee bump transaction allows Account A to pay the fee for Account B's transaction *after* Account B has already signed it.
108
+
109
+ **Use cases:**
110
+ - Rescuing a stuck transaction (one submitted with too low a fee during a surge).
111
+ - Sponsoring fees for users (dApp pays the gas so the user doesn't need XLM).
112
+
113
+ ### Creating a Fee Bump
114
+ ```javascript
115
+ import { FeeBumpTransaction, TransactionBuilder, Networks } from "@stellar/stellar-sdk";
116
+
117
+ // 1. You receive an inner transaction signed by the user (it might be stuck)
118
+ // const innerTx = ...
119
+
120
+ // 2. Wrap it in a FeeBump
121
+ const feeBump = TransactionBuilder.buildFeeBumpTransaction(
122
+ sponsorKeypair, // Account paying the higher fee
123
+ "5000", // New max base fee per operation (in stroops)
124
+ innerTx, // The original signed transaction
125
+ Networks.MAINNET
126
+ );
127
+
128
+ // 3. Sponsor signs
129
+ feeBump.sign(sponsorKeypair);
130
+
131
+ // 4. Submit
132
+ await server.submitTransaction(feeBump);
133
+ ```
134
+
135
+ **Important**: The inner transaction's sequence number and signatures remain valid. Only the fee payer changes.
136
+
137
+ ---
138
+
139
+ ## Common Errors
140
+
141
+ | Error | Meaning | Fix |
142
+ |-------|---------|-----|
143
+ | `tx_insufficient_fee` | The network is surging and your fee is too low | Fetch `feeStats` and submit with higher fee, or use Fee Bump |
144
+ | `op_underfunded` | Account doesn't have enough XLM to cover fee + min balance | Add more XLM. Remember minimum balance requirements! |
145
+ | Soroban simulation `wasm_vm_error` | Contract exceeded resource budget (often CPU) | Optimize contract logic or reduce storage reads/writes |
146
+
147
+ ---
148
+
149
+ *raw.githubusercontent.com/ggoldani/stellarskills/main/fees — MIT License*
@@ -0,0 +1,169 @@
1
+ ---
2
+ name: stellarskills-frontend
3
+ description: Connecting web apps to Stellar. Stellar Wallets Kit, Freighter API, signing Soroban transactions, and secure SEP-10 Web3 Auth.
4
+ ---
5
+
6
+ # STELLARSKILLS — Frontend Integration
7
+
8
+ > Connecting web apps to Stellar. Stellar Wallets Kit, Freighter API, signing Soroban transactions, and secure SEP-10 Web3 Auth.
9
+
10
+ ---
11
+
12
+ ## 1. Connecting Wallets (The Modern Standard)
13
+
14
+ To build a professional dApp with high UX, you must support multiple wallets (Freighter, Albedo, xBull, Lobstr, and WalletConnect) simultaneously. **Do not write custom logic for each extension.**
15
+
16
+ Instead, use **Stellar Wallets Kit** (`@creit.tech/stellar-wallets-kit`), the standard "RainbowKit equivalent" for Stellar.
17
+
18
+ ```bash
19
+ npm install @creit.tech/stellar-wallets-kit
20
+ ```
21
+
22
+ ### Initializing the Kit & Showing the Modal
23
+
24
+ ```javascript
25
+ import {
26
+ StellarWalletsKit,
27
+ WalletNetwork,
28
+ allowAllModules,
29
+ FREIGHTER_ID
30
+ } from '@creit.tech/stellar-wallets-kit';
31
+
32
+ // 1. Initialize the kit globally in your React Context or state manager
33
+ const kit = new StellarWalletsKit({
34
+ network: WalletNetwork.TESTNET,
35
+ selectedWalletId: FREIGHTER_ID,
36
+ modules: allowAllModules(),
37
+ });
38
+
39
+ // 2. Open the beautiful native UI modal to let user choose their wallet
40
+ await kit.openModal({
41
+ onWalletSelected: async (option) => {
42
+ kit.setWallet(option.id);
43
+ const publicKey = await kit.getPublicKey();
44
+ console.log(`Connected with ${option.name}: ${publicKey}`);
45
+ }
46
+ });
47
+ ```
48
+
49
+ ---
50
+
51
+ ## 2. Signing Transactions (Wallets Kit)
52
+
53
+ Once connected, you can sign XDR transactions agnostically. The kit handles the extension pop-up whether the user is on Freighter or Albedo.
54
+
55
+ ```javascript
56
+ import { TransactionBuilder, Networks, BASE_FEE, Operation } from "@stellar/stellar-sdk";
57
+
58
+ // 1. Build the transaction (Requires fetching account sequence from Horizon)
59
+ const tx = new TransactionBuilder(account, { fee: BASE_FEE, networkPassphrase: Networks.TESTNET })
60
+ .addOperation(Operation.payment({ destination: "GBB...", asset: Asset.native(), amount: "10" }))
61
+ .setTimeout(30)
62
+ .build();
63
+
64
+ // 2. Sign via Wallets Kit
65
+ const { signedXDR } = await kit.signTx({
66
+ xdr: tx.toXDR(),
67
+ publicKeys: [userPublicKey],
68
+ network: WalletNetwork.TESTNET
69
+ });
70
+
71
+ // 3. Reconstruct and submit to Horizon/RPC
72
+ const signedTx = TransactionBuilder.fromXDR(signedXDR, Networks.TESTNET);
73
+ await horizonServer.submitTransaction(signedTx);
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 3. Low-Level Integration: Freighter API
79
+
80
+ If you absolutely must build a low-level, Freighter-only integration without UI wrappers, use `@stellar/freighter-api`.
81
+
82
+ ```bash
83
+ npm install @stellar/freighter-api
84
+ ```
85
+
86
+ ```javascript
87
+ import { isConnected, requestAccess, signTransaction } from "@stellar/freighter-api";
88
+
89
+ // Connect
90
+ if (await isConnected()) {
91
+ const address = await requestAccess();
92
+ }
93
+
94
+ // Sign
95
+ const signedTxXdr = await signTransaction(tx.toXDR(), { network: "TESTNET" });
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 4. Signing Transactions (Soroban Smart Contracts)
101
+
102
+ When calling a Soroban smart contract, you cannot simply sign the operation. You must **simulate** the transaction first to fetch the correct resource footprint and fee, assemble it, and *then* request the user's signature.
103
+
104
+ ```javascript
105
+ import { TransactionBuilder, Networks, BASE_FEE, Contract } from "@stellar/stellar-sdk";
106
+ import { SorobanRpc } from "@stellar/stellar-sdk";
107
+
108
+ const contract = new Contract(contractId);
109
+
110
+ // 1. Build initial tx with default limits
111
+ let tx = new TransactionBuilder(account, { fee: BASE_FEE, networkPassphrase: Networks.TESTNET })
112
+ .addOperation(contract.call("deposit", ...))
113
+ .setTimeout(30)
114
+ .build();
115
+
116
+ // 2. Simulate via RPC to calculate the exact footprint and CPU fee
117
+ const sim = await rpcServer.simulateTransaction(tx);
118
+ if (SorobanRpc.Api.isSimulationError(sim)) throw sim.error;
119
+
120
+ // 3. Assemble transaction with the correct simulated footprint
121
+ tx = SorobanRpc.assembleTransaction(tx, sim);
122
+
123
+ // 4. Request user signature via Wallets Kit or Freighter API
124
+ const { signedXDR } = await kit.signTx({ xdr: tx.toXDR(), publicKeys: [userPublicKey] });
125
+
126
+ // 5. Submit to RPC and poll
127
+ const signedTx = TransactionBuilder.fromXDR(signedXDR, Networks.TESTNET);
128
+ const sendResponse = await rpcServer.sendTransaction(signedTx);
129
+ ```
130
+
131
+ ---
132
+
133
+ ## 5. SEP-10 Web3 Auth (Security Warning)
134
+
135
+ If your app has a backend and needs to securely authenticate the user via Web3, implement the **SEP-10** standard.
136
+
137
+ ### ⚠️ SECURITY RULE: Never store JWTs in LocalStorage
138
+ Do not store the returned `auth_token` in `localStorage` or `sessionStorage`. This makes your frontend highly vulnerable to XSS (Cross-Site Scripting) attacks. The backend must set the JWT inside an `HttpOnly`, `Secure`, and `SameSite=Strict` (or `Lax`) cookie. Ensure all `fetch` calls to your protected API include `credentials: "include"`.
139
+
140
+ ### Frontend Implementation
141
+ ```javascript
142
+ // 1. Fetch SEP-10 challenge from your backend
143
+ const challengeResponse = await fetch("/api/auth/challenge?account=" + userPublicKey);
144
+ const { transaction, network_passphrase } = await challengeResponse.json();
145
+
146
+ // 2. Request user to sign the challenge transaction via wallet
147
+ const { signedXDR } = await kit.signTx({
148
+ xdr: transaction,
149
+ publicKeys: [userPublicKey],
150
+ network: WalletNetwork.TESTNET
151
+ });
152
+
153
+ // 3. Send signed challenge back to backend
154
+ // The backend verifies the signature. It MUST NOT return the token in the JSON body.
155
+ // Instead, the backend sets the HttpOnly cookie in the response headers.
156
+ await fetch("/api/auth/token", {
157
+ method: "POST",
158
+ body: JSON.stringify({ transaction: signedXDR }),
159
+ headers: { "Content-Type": "application/json" }
160
+ });
161
+
162
+ // 4. Subsequent authenticated requests
163
+ // The browser will automatically attach the HttpOnly cookie
164
+ const userProfile = await fetch("/api/me", { credentials: "include" });
165
+ ```
166
+
167
+ ---
168
+
169
+ *raw.githubusercontent.com/ggoldani/stellarskills/main/frontend — MIT License*