z0gcode 0.2.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/.env.example +41 -0
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/bin/z0g.mjs +1052 -0
- package/contracts/Z0gSession.json +424 -0
- package/contracts/Z0gSession.sol +106 -0
- package/package.json +60 -0
- package/skills/0g/CHAIN.md +229 -0
- package/skills/0g/COMPUTE.md +296 -0
- package/skills/0g/NETWORK_CONFIG.md +163 -0
- package/skills/0g/SECURITY.md +174 -0
- package/skills/0g/STORAGE.md +167 -0
- package/skills/0g/TESTING.md +263 -0
- package/src/agent.mjs +434 -0
- package/src/anchor.mjs +65 -0
- package/src/checkpoints.mjs +64 -0
- package/src/client.mjs +134 -0
- package/src/commands.mjs +93 -0
- package/src/config.mjs +74 -0
- package/src/context.mjs +55 -0
- package/src/crypto.mjs +47 -0
- package/src/env.mjs +47 -0
- package/src/goal.mjs +45 -0
- package/src/inft.mjs +79 -0
- package/src/mcp-server.mjs +38 -0
- package/src/mcp.mjs +91 -0
- package/src/media.mjs +52 -0
- package/src/models-info.mjs +97 -0
- package/src/plan.mjs +21 -0
- package/src/prompt.mjs +149 -0
- package/src/provenance.mjs +46 -0
- package/src/sessions.mjs +168 -0
- package/src/settings.mjs +37 -0
- package/src/skills.mjs +43 -0
- package/src/tools.mjs +481 -0
- package/src/ui.mjs +798 -0
- package/src/user-skills.mjs +111 -0
- package/src/worktree.mjs +61 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Chain Patterns
|
|
2
|
+
|
|
3
|
+
EVM patterns, deployment configurations, and best practices for 0G Chain.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
0G Chain is an EVM-compatible Layer 1 blockchain. It supports standard Solidity smart contracts with
|
|
8
|
+
a critical requirement: **all contracts must be compiled with `evmVersion: "cancun"`**.
|
|
9
|
+
|
|
10
|
+
## Hardhat Configuration
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
// hardhat.config.ts
|
|
14
|
+
import { HardhatUserConfig } from 'hardhat/config';
|
|
15
|
+
import '@nomicfoundation/hardhat-toolbox';
|
|
16
|
+
import 'dotenv/config';
|
|
17
|
+
|
|
18
|
+
const config: HardhatUserConfig = {
|
|
19
|
+
solidity: {
|
|
20
|
+
version: '0.8.24',
|
|
21
|
+
settings: {
|
|
22
|
+
optimizer: { enabled: true, runs: 200 },
|
|
23
|
+
evmVersion: 'cancun', // REQUIRED for 0G Chain
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
networks: {
|
|
27
|
+
'0g-testnet': {
|
|
28
|
+
url: 'https://evmrpc-testnet.0g.ai',
|
|
29
|
+
chainId: 16602,
|
|
30
|
+
accounts: [process.env.PRIVATE_KEY!],
|
|
31
|
+
},
|
|
32
|
+
'0g-mainnet': {
|
|
33
|
+
url: 'https://evmrpc.0g.ai',
|
|
34
|
+
chainId: 16661,
|
|
35
|
+
accounts: [process.env.PRIVATE_KEY!],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default config;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Foundry Configuration
|
|
44
|
+
|
|
45
|
+
```toml
|
|
46
|
+
# foundry.toml
|
|
47
|
+
[profile.default]
|
|
48
|
+
src = "src"
|
|
49
|
+
out = "out"
|
|
50
|
+
libs = ["lib"]
|
|
51
|
+
evm_version = "cancun" # REQUIRED for 0G Chain
|
|
52
|
+
solc_version = "0.8.24"
|
|
53
|
+
optimizer = true
|
|
54
|
+
optimizer_runs = 200
|
|
55
|
+
|
|
56
|
+
[rpc_endpoints]
|
|
57
|
+
0g_testnet = "https://evmrpc-testnet.0g.ai"
|
|
58
|
+
0g_mainnet = "https://evmrpc.0g.ai"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Contract Deployment
|
|
62
|
+
|
|
63
|
+
### With Hardhat
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// scripts/deploy.ts
|
|
67
|
+
import { ethers } from 'hardhat';
|
|
68
|
+
|
|
69
|
+
async function main() {
|
|
70
|
+
const [deployer] = await ethers.getSigners();
|
|
71
|
+
console.log('Deploying with:', deployer.address);
|
|
72
|
+
|
|
73
|
+
const Contract = await ethers.getContractFactory('MyContract');
|
|
74
|
+
const contract = await Contract.deploy(/* constructor args */);
|
|
75
|
+
await contract.waitForDeployment();
|
|
76
|
+
|
|
77
|
+
const address = await contract.getAddress();
|
|
78
|
+
console.log('Deployed to:', address);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
main().catch(console.error);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx hardhat run scripts/deploy.ts --network 0g-testnet
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### With Foundry
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
forge create src/MyContract.sol:MyContract \
|
|
92
|
+
--rpc-url https://evmrpc-testnet.0g.ai \
|
|
93
|
+
--private-key $PRIVATE_KEY \
|
|
94
|
+
--constructor-args "arg1" "arg2"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### With ethers v6 (Direct)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { ethers, ContractFactory } from 'ethers';
|
|
101
|
+
import 'dotenv/config';
|
|
102
|
+
|
|
103
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
104
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
105
|
+
|
|
106
|
+
// ABI and bytecode from compilation output
|
|
107
|
+
const factory = new ContractFactory(abi, bytecode, wallet);
|
|
108
|
+
const contract = await factory.deploy(/* constructor args */);
|
|
109
|
+
await contract.waitForDeployment();
|
|
110
|
+
|
|
111
|
+
console.log('Deployed to:', await contract.getAddress());
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Contract Interaction
|
|
115
|
+
|
|
116
|
+
### Read (View Functions)
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { ethers } from 'ethers';
|
|
120
|
+
|
|
121
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
122
|
+
const contract = new ethers.Contract(contractAddress, abi, provider);
|
|
123
|
+
|
|
124
|
+
// Read-only calls (no gas)
|
|
125
|
+
const value = await contract.getValue();
|
|
126
|
+
const balance = await contract.balanceOf(address);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Write (State-Changing Functions)
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
133
|
+
const contract = new ethers.Contract(contractAddress, abi, wallet);
|
|
134
|
+
|
|
135
|
+
// State-changing calls (costs gas)
|
|
136
|
+
const tx = await contract.setValue(42);
|
|
137
|
+
const receipt = await tx.wait();
|
|
138
|
+
console.log('Tx hash:', receipt.hash);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Events
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Listen for events
|
|
145
|
+
contract.on('Transfer', (from, to, amount) => {
|
|
146
|
+
console.log(`Transfer: ${from} → ${to}: ${amount}`);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Query past events
|
|
150
|
+
const filter = contract.filters.Transfer(null, myAddress);
|
|
151
|
+
const events = await contract.queryFilter(filter, fromBlock, toBlock);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## ethers v6 Migration Notes
|
|
155
|
+
|
|
156
|
+
0G Chain examples use ethers v6 exclusively. Key differences from v5:
|
|
157
|
+
|
|
158
|
+
| v5 (DO NOT USE) | v6 (CORRECT) |
|
|
159
|
+
| ---------------------------------- | ------------------------------ |
|
|
160
|
+
| `ethers.providers.JsonRpcProvider` | `ethers.JsonRpcProvider` |
|
|
161
|
+
| `ethers.utils.parseEther` | `ethers.parseEther` |
|
|
162
|
+
| `ethers.utils.formatEther` | `ethers.formatEther` |
|
|
163
|
+
| `contract.deployed()` | `contract.waitForDeployment()` |
|
|
164
|
+
| `contract.address` | `await contract.getAddress()` |
|
|
165
|
+
| `BigNumber.from()` | Native `BigInt` |
|
|
166
|
+
| `ethers.utils.keccak256` | `ethers.keccak256` |
|
|
167
|
+
|
|
168
|
+
## Gas Estimation
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const gasEstimate = await contract.setValue.estimateGas(42);
|
|
172
|
+
console.log('Estimated gas:', gasEstimate.toString());
|
|
173
|
+
|
|
174
|
+
// With manual gas limit
|
|
175
|
+
const tx = await contract.setValue(42, {
|
|
176
|
+
gasLimit: (gasEstimate * 120n) / 100n, // 20% buffer
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Verification
|
|
181
|
+
|
|
182
|
+
### Hardhat Verify
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npx hardhat verify --network 0g-testnet <CONTRACT_ADDRESS> "arg1" "arg2"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Foundry Verify
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
forge verify-contract <CONTRACT_ADDRESS> src/MyContract.sol:MyContract \
|
|
192
|
+
--chain-id 16602 \
|
|
193
|
+
--verifier-url https://chainscan-galileo.0g.ai/api
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Critical Rules
|
|
197
|
+
|
|
198
|
+
### ALWAYS
|
|
199
|
+
|
|
200
|
+
- Use `evmVersion: "cancun"` in compiler settings
|
|
201
|
+
- Use ethers v6 syntax (NOT v5)
|
|
202
|
+
- Load private keys from environment variables
|
|
203
|
+
- Wait for transaction confirmation (`tx.wait()`)
|
|
204
|
+
- Test on testnet before mainnet deployment
|
|
205
|
+
|
|
206
|
+
### NEVER
|
|
207
|
+
|
|
208
|
+
- Use `evmVersion` other than `"cancun"` for 0G Chain
|
|
209
|
+
- Use ethers v5 patterns (`ethers.providers`, `ethers.utils`, etc.)
|
|
210
|
+
- Hardcode private keys in source files
|
|
211
|
+
- Deploy to mainnet without testnet validation
|
|
212
|
+
|
|
213
|
+
## Common Errors
|
|
214
|
+
|
|
215
|
+
| Error | Cause | Fix |
|
|
216
|
+
| --------------------- | -------------------- | ------------------------------- |
|
|
217
|
+
| `invalid opcode` | Wrong evmVersion | Set `evmVersion: "cancun"` |
|
|
218
|
+
| `execution reverted` | Contract logic error | Check require/revert conditions |
|
|
219
|
+
| `insufficient funds` | Wallet empty | Fund from faucet (testnet) |
|
|
220
|
+
| `nonce too low` | Pending tx | Wait or manually set nonce |
|
|
221
|
+
| `cannot estimate gas` | Function will revert | Check function parameters |
|
|
222
|
+
|
|
223
|
+
## References
|
|
224
|
+
|
|
225
|
+
- [0G Chain Docs](https://docs.0g.ai/build-with-0g/0g-chain)
|
|
226
|
+
- [Hardhat Documentation](https://hardhat.org/docs)
|
|
227
|
+
- [Foundry Documentation](https://book.getfoundry.sh)
|
|
228
|
+
- [ethers v6 Migration](https://docs.ethers.org/v6/migrating/)
|
|
229
|
+
- See also: [NETWORK_CONFIG.md](./NETWORK_CONFIG.md), [SECURITY.md](./SECURITY.md)
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# Compute Patterns
|
|
2
|
+
|
|
3
|
+
Architecture, broker lifecycle, processResponse() deep-dive, and best practices for 0G decentralized
|
|
4
|
+
compute.
|
|
5
|
+
|
|
6
|
+
## Architecture Overview
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
┌────────────────────────────────────┐
|
|
10
|
+
│ Your Application │
|
|
11
|
+
├────────────────────────────────────┤
|
|
12
|
+
│ 0G Serving Broker SDK │
|
|
13
|
+
│ (@0glabs/0g-serving-broker) │
|
|
14
|
+
├────────────────────────────────────┤
|
|
15
|
+
│ Provider Network │
|
|
16
|
+
│ (TEE-verified GPU nodes) │
|
|
17
|
+
├────────────────────────────────────┤
|
|
18
|
+
│ 0G Chain │
|
|
19
|
+
│ (Settlement & verification) │
|
|
20
|
+
└────────────────────────────────────┘
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Service Types
|
|
24
|
+
|
|
25
|
+
| Type | Endpoint Path | Models | Use Case |
|
|
26
|
+
| ---------------- | ----------------------- | ----------------------------------- | ------------------- |
|
|
27
|
+
| `chatbot` | `/chat/completions` | DeepSeek V3.1, Qwen, Gemma, GPT-OSS | Conversational AI |
|
|
28
|
+
| `text-to-image` | `/images/generations` | Flux Turbo | Image generation |
|
|
29
|
+
| `speech-to-text` | `/audio/transcriptions` | Whisper Large V3 | Audio transcription |
|
|
30
|
+
|
|
31
|
+
## Broker Lifecycle
|
|
32
|
+
|
|
33
|
+
### 1. Initialize Broker
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { ethers } from 'ethers';
|
|
37
|
+
import { createZGComputeNetworkBroker } from '@0glabs/0g-serving-broker';
|
|
38
|
+
|
|
39
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
40
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
41
|
+
const broker = await createZGComputeNetworkBroker(wallet);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Discover Providers
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const services = await broker.inference.listService();
|
|
48
|
+
|
|
49
|
+
// Services are returned as tuple arrays:
|
|
50
|
+
// [0] = providerAddress, [1] = serviceType, [2] = url,
|
|
51
|
+
// [6] = model, [10] = teeVerified
|
|
52
|
+
const chatbotServices = services.filter((s: any) => s[1] === 'chatbot');
|
|
53
|
+
const imageServices = services.filter((s: any) => s[1] === 'text-to-image');
|
|
54
|
+
const speechServices = services.filter((s: any) => s[1] === 'speech-to-text');
|
|
55
|
+
|
|
56
|
+
// Access provider info: s[0] = address, s[6] = model, s[10] = TEE verified
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Fund Account
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Deposit to main account
|
|
63
|
+
await broker.ledger.depositFund(10);
|
|
64
|
+
|
|
65
|
+
// Transfer to provider sub-account
|
|
66
|
+
await broker.ledger.transferFund(providerAddress, 'inference', ethers.parseEther('5'));
|
|
67
|
+
|
|
68
|
+
// Acknowledge provider (one-time per provider)
|
|
69
|
+
await broker.inference.acknowledgeProviderSigner(providerAddress);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 4. Get Service Metadata
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 5. Generate Auth Headers
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// For chatbot (no body needed)
|
|
82
|
+
const headers = await broker.inference.getRequestHeaders(providerAddress);
|
|
83
|
+
|
|
84
|
+
// For text-to-image (body MUST be included for signing)
|
|
85
|
+
const headers = await broker.inference.getRequestHeaders(
|
|
86
|
+
providerAddress,
|
|
87
|
+
JSON.stringify(requestBody),
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 6. Make Request & Process Response
|
|
92
|
+
|
|
93
|
+
See the processResponse() section below — this is the most critical step.
|
|
94
|
+
|
|
95
|
+
## processResponse() Deep-Dive
|
|
96
|
+
|
|
97
|
+
**This is the most important function in the 0G Compute SDK.** It MUST be called after every
|
|
98
|
+
inference request for fee settlement and response verification.
|
|
99
|
+
|
|
100
|
+
### Signature
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
await broker.inference.processResponse(
|
|
104
|
+
providerAddress, // string — provider's Ethereum address
|
|
105
|
+
chatID, // string | undefined — response identifier
|
|
106
|
+
usageData, // string | undefined — JSON-stringified usage stats
|
|
107
|
+
);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Parameter Order is CRITICAL
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
processResponse(providerAddress, chatID, usageData)
|
|
114
|
+
↑ FIRST ↑ SECOND ↑ THIRD
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Getting the order wrong will cause silent fee miscalculation.
|
|
118
|
+
|
|
119
|
+
### ChatID Extraction Rules
|
|
120
|
+
|
|
121
|
+
| Service Type | Primary Source | Fallback |
|
|
122
|
+
| ----------------------- | ------------------------------------ | ------------------------------- |
|
|
123
|
+
| Chatbot (non-streaming) | `response.headers.get("ZG-Res-Key")` | `data.id` from response body |
|
|
124
|
+
| Chatbot (streaming) | `response.headers.get("ZG-Res-Key")` | `message.id` from stream chunks |
|
|
125
|
+
| Text-to-Image | `response.headers.get("ZG-Res-Key")` | None |
|
|
126
|
+
| Speech-to-Text | `response.headers.get("ZG-Res-Key")` | None |
|
|
127
|
+
|
|
128
|
+
**ALWAYS check headers first, body as fallback (chatbot only):**
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
|
|
132
|
+
if (!chatID) {
|
|
133
|
+
chatID = data.id; // Fallback for chatbot only
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Usage Data by Service Type
|
|
138
|
+
|
|
139
|
+
| Service Type | Usage Data Required | Format |
|
|
140
|
+
| -------------- | ------------------- | ---------------------------- |
|
|
141
|
+
| Chatbot | Yes | `JSON.stringify(data.usage)` |
|
|
142
|
+
| Text-to-Image | No | Omit or pass `undefined` |
|
|
143
|
+
| Speech-to-Text | Yes (if available) | `JSON.stringify(data.usage)` |
|
|
144
|
+
|
|
145
|
+
### Complete Examples
|
|
146
|
+
|
|
147
|
+
#### Chatbot processResponse
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const data = await response.json();
|
|
151
|
+
let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
|
|
152
|
+
if (!chatID) chatID = data.id;
|
|
153
|
+
|
|
154
|
+
await broker.inference.processResponse(providerAddress, chatID, JSON.stringify(data.usage));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Text-to-Image processResponse
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
|
|
161
|
+
|
|
162
|
+
if (chatID) {
|
|
163
|
+
await broker.inference.processResponse(providerAddress, chatID);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Speech-to-Text processResponse
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const data = await response.json();
|
|
171
|
+
const chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
|
|
172
|
+
|
|
173
|
+
await broker.inference.processResponse(
|
|
174
|
+
providerAddress,
|
|
175
|
+
chatID,
|
|
176
|
+
data.usage ? JSON.stringify(data.usage) : undefined,
|
|
177
|
+
);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Streaming Pattern
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
const response = await fetch(`${endpoint}/chat/completions`, {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
186
|
+
body: JSON.stringify({ messages, model, stream: true }),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
let chatID = response.headers.get('ZG-Res-Key') || response.headers.get('zg-res-key');
|
|
190
|
+
let usage = null;
|
|
191
|
+
let streamChatID = null;
|
|
192
|
+
|
|
193
|
+
const decoder = new TextDecoder();
|
|
194
|
+
const reader = response.body!.getReader();
|
|
195
|
+
let rawBody = '';
|
|
196
|
+
|
|
197
|
+
while (true) {
|
|
198
|
+
const { done, value } = await reader.read();
|
|
199
|
+
if (done) break;
|
|
200
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
201
|
+
rawBody += chunk;
|
|
202
|
+
process.stdout.write(chunk); // Real-time output
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Parse stream for chatID fallback and usage
|
|
206
|
+
for (const line of rawBody.split('\n')) {
|
|
207
|
+
const trimmed = line.trim();
|
|
208
|
+
if (!trimmed || trimmed === 'data: [DONE]') continue;
|
|
209
|
+
try {
|
|
210
|
+
const jsonStr = trimmed.startsWith('data:') ? trimmed.slice(5).trim() : trimmed;
|
|
211
|
+
const message = JSON.parse(jsonStr);
|
|
212
|
+
if (!streamChatID && message.id) streamChatID = message.id;
|
|
213
|
+
if (message.usage) usage = message.usage;
|
|
214
|
+
} catch {}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const finalChatID = chatID || streamChatID;
|
|
218
|
+
await broker.inference.processResponse(providerAddress, finalChatID, JSON.stringify(usage || {}));
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Account Structure
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
Your Wallet
|
|
225
|
+
↓ deposit
|
|
226
|
+
Main Account
|
|
227
|
+
↓ transfer-fund
|
|
228
|
+
Provider Sub-Accounts (one per provider)
|
|
229
|
+
↓ service usage (auto-deducted)
|
|
230
|
+
↓ retrieve-fund (24h lock)
|
|
231
|
+
Main Account
|
|
232
|
+
↓ refund
|
|
233
|
+
Your Wallet
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## TEE Verification
|
|
237
|
+
|
|
238
|
+
Trusted Execution Environment verification ensures provider integrity:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
const services = await broker.inference.listService();
|
|
242
|
+
// Tuple: [0]=providerAddress, [1]=serviceType, [10]=teeVerified
|
|
243
|
+
for (const service of services) {
|
|
244
|
+
if (service[0] === targetProvider) {
|
|
245
|
+
console.log('TEE verified:', service[10]);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## CLI Commands Reference
|
|
251
|
+
|
|
252
|
+
| Action | Command |
|
|
253
|
+
| -------------------- | ----------------------------------------------------------------- |
|
|
254
|
+
| Setup network | `0g-compute-cli setup-network` |
|
|
255
|
+
| Login | `0g-compute-cli login` |
|
|
256
|
+
| Deposit | `0g-compute-cli deposit --amount 10` |
|
|
257
|
+
| Check balance | `0g-compute-cli get-account` |
|
|
258
|
+
| Transfer to provider | `0g-compute-cli transfer-fund --provider <ADDR> --amount 5` |
|
|
259
|
+
| Acknowledge provider | `0g-compute-cli inference acknowledge-provider --provider <ADDR>` |
|
|
260
|
+
| List providers | `0g-compute-cli inference list-providers` |
|
|
261
|
+
| Start local proxy | `0g-compute-cli inference serve --provider <ADDR>` |
|
|
262
|
+
| Get API secret | `0g-compute-cli inference get-secret --provider <ADDR>` |
|
|
263
|
+
|
|
264
|
+
## Critical Rules
|
|
265
|
+
|
|
266
|
+
### ALWAYS
|
|
267
|
+
|
|
268
|
+
- Call `processResponse()` after EVERY inference request
|
|
269
|
+
- Use correct parameter order: `(providerAddress, chatID, usageData)`
|
|
270
|
+
- Extract ChatID from `ZG-Res-Key` header first, body as fallback
|
|
271
|
+
- Acknowledge provider before first use
|
|
272
|
+
- Check balance before making requests
|
|
273
|
+
|
|
274
|
+
### NEVER
|
|
275
|
+
|
|
276
|
+
- Skip `processResponse()` — causes fee settlement failure
|
|
277
|
+
- Reverse the parameter order of `processResponse()`
|
|
278
|
+
- Hardcode private keys
|
|
279
|
+
- Use ethers v5 syntax (use v6)
|
|
280
|
+
- Skip provider acknowledgment
|
|
281
|
+
|
|
282
|
+
## Common Errors
|
|
283
|
+
|
|
284
|
+
| Error | Cause | Fix |
|
|
285
|
+
| --------------------------- | -------------------------------- | ---------------------------------------------- |
|
|
286
|
+
| `Insufficient balance` | Sub-account empty | Transfer funds: `broker.ledger.transferFund()` |
|
|
287
|
+
| `Provider not acknowledged` | First-time use | `broker.inference.acknowledgeProviderSigner()` |
|
|
288
|
+
| `Invalid request headers` | Stale auth | Re-call `getRequestHeaders()` |
|
|
289
|
+
| `Fee verification failed` | Wrong `processResponse()` params | Check param order and chatID source |
|
|
290
|
+
| `Connection refused` | Wrong RPC URL | Verify RPC_URL in .env |
|
|
291
|
+
|
|
292
|
+
## References
|
|
293
|
+
|
|
294
|
+
- [0G Compute SDK Docs](https://docs.0g.ai/build-with-0g/compute-network/sdk)
|
|
295
|
+
- [0G Serving Broker](https://github.com/0gfoundation/0g-serving-broker)
|
|
296
|
+
- See also: [NETWORK_CONFIG.md](./NETWORK_CONFIG.md), [SECURITY.md](./SECURITY.md)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Network Configuration
|
|
2
|
+
|
|
3
|
+
Single source of truth for all 0G network endpoints, chain IDs, SDK versions, and environment setup.
|
|
4
|
+
|
|
5
|
+
## Network Environments
|
|
6
|
+
|
|
7
|
+
### Testnet (Galileo — Recommended for Development)
|
|
8
|
+
|
|
9
|
+
| Parameter | Value |
|
|
10
|
+
| --------------- | --------------------------------------------- |
|
|
11
|
+
| Network Name | 0G-Galileo-Testnet |
|
|
12
|
+
| RPC Endpoint | `https://evmrpc-testnet.0g.ai` |
|
|
13
|
+
| Chain ID | `16602` |
|
|
14
|
+
| Currency Symbol | 0G |
|
|
15
|
+
| Block Explorer | `https://chainscan-galileo.0g.ai` |
|
|
16
|
+
| Storage RPC | `https://storagerpc-testnet.0g.ai` |
|
|
17
|
+
| Storage Indexer | `https://indexer-storage-testnet-turbo.0g.ai` |
|
|
18
|
+
|
|
19
|
+
### Mainnet (Aristotle)
|
|
20
|
+
|
|
21
|
+
| Parameter | Value |
|
|
22
|
+
| --------------- | ------------------------------------- |
|
|
23
|
+
| Network Name | 0G Mainnet |
|
|
24
|
+
| RPC Endpoint | `https://evmrpc.0g.ai` |
|
|
25
|
+
| Chain ID | `16661` |
|
|
26
|
+
| Currency Symbol | 0G |
|
|
27
|
+
| Block Explorer | `https://chainscan.0g.ai` |
|
|
28
|
+
| Storage RPC | `https://storagerpc.0g.ai` |
|
|
29
|
+
| Storage Indexer | `https://indexer-storage-turbo.0g.ai` |
|
|
30
|
+
|
|
31
|
+
## SDK Versions
|
|
32
|
+
|
|
33
|
+
| Package | Version | Purpose |
|
|
34
|
+
| --------------------------- | --------- | ------------------------------------------- |
|
|
35
|
+
| `@0glabs/0g-ts-sdk` | `^0.3.3` | Storage operations (upload, download) |
|
|
36
|
+
| `@0glabs/0g-serving-broker` | `^0.6.5` | Compute operations (inference, fine-tuning) |
|
|
37
|
+
| `ethers` | `^6.13.0` | Chain interaction (MUST be v6, NOT v5) |
|
|
38
|
+
| `dotenv` | `^16.4.0` | Environment variable management |
|
|
39
|
+
|
|
40
|
+
## Environment Variables Template
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# .env — NEVER commit this file
|
|
44
|
+
|
|
45
|
+
# Network Configuration
|
|
46
|
+
RPC_URL=https://evmrpc-testnet.0g.ai
|
|
47
|
+
CHAIN_ID=16602
|
|
48
|
+
|
|
49
|
+
# Wallet (NEVER hardcode in source files)
|
|
50
|
+
PRIVATE_KEY=your_private_key_here
|
|
51
|
+
|
|
52
|
+
# Storage Endpoints
|
|
53
|
+
STORAGE_INDEXER=https://indexer-storage-testnet-turbo.0g.ai
|
|
54
|
+
|
|
55
|
+
# Compute
|
|
56
|
+
PROVIDER_ADDRESS=your_provider_address
|
|
57
|
+
|
|
58
|
+
# Optional
|
|
59
|
+
OUTPUT_DIR=./output
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## SDK Initialization Patterns
|
|
63
|
+
|
|
64
|
+
### ethers v6 Provider (Chain)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { ethers } from 'ethers';
|
|
68
|
+
import 'dotenv/config';
|
|
69
|
+
|
|
70
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
71
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Storage Client
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { ZgFile, Indexer } from '@0glabs/0g-ts-sdk';
|
|
78
|
+
import { ethers } from 'ethers';
|
|
79
|
+
|
|
80
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
81
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
82
|
+
const indexer = new Indexer(process.env.STORAGE_INDEXER!);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Compute Broker
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { ethers } from 'ethers';
|
|
89
|
+
import { createZGComputeNetworkBroker } from '@0glabs/0g-serving-broker';
|
|
90
|
+
|
|
91
|
+
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
|
|
92
|
+
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
|
|
93
|
+
const broker = await createZGComputeNetworkBroker(wallet);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Browser Environment (Compute)
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { BrowserProvider } from 'ethers';
|
|
100
|
+
import { createZGComputeNetworkBroker } from '@0glabs/0g-serving-broker';
|
|
101
|
+
|
|
102
|
+
if (typeof window.ethereum === 'undefined') {
|
|
103
|
+
throw new Error('Please install MetaMask');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const provider = new BrowserProvider(window.ethereum);
|
|
107
|
+
const signer = await provider.getSigner();
|
|
108
|
+
const broker = await createZGComputeNetworkBroker(signer);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Browser Polyfills
|
|
112
|
+
|
|
113
|
+
When using 0G SDKs in browser environments:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pnpm add -D vite-plugin-node-polyfills
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// vite.config.js
|
|
121
|
+
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
|
122
|
+
|
|
123
|
+
export default {
|
|
124
|
+
plugins: [
|
|
125
|
+
nodePolyfills({
|
|
126
|
+
include: ['crypto', 'stream', 'util', 'buffer', 'process'],
|
|
127
|
+
globals: { Buffer: true, global: true, process: true },
|
|
128
|
+
}),
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Network Selection Helper
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
type Network = 'testnet' | 'mainnet';
|
|
137
|
+
|
|
138
|
+
function getNetworkConfig(network: Network) {
|
|
139
|
+
const configs = {
|
|
140
|
+
testnet: {
|
|
141
|
+
rpcUrl: 'https://evmrpc-testnet.0g.ai',
|
|
142
|
+
chainId: 16602,
|
|
143
|
+
storageRpc: 'https://storagerpc-testnet.0g.ai',
|
|
144
|
+
storageIndexer: 'https://indexer-storage-testnet-turbo.0g.ai',
|
|
145
|
+
explorer: 'https://chainscan-galileo.0g.ai',
|
|
146
|
+
},
|
|
147
|
+
mainnet: {
|
|
148
|
+
rpcUrl: 'https://evmrpc.0g.ai',
|
|
149
|
+
chainId: 16661,
|
|
150
|
+
storageRpc: 'https://storagerpc.0g.ai',
|
|
151
|
+
storageIndexer: 'https://indexer-storage-turbo.0g.ai',
|
|
152
|
+
explorer: 'https://chainscan.0g.ai',
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
return configs[network];
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## References
|
|
160
|
+
|
|
161
|
+
- [0G Testnet Info](https://docs.0g.ai/run-a-node/testnet-information)
|
|
162
|
+
- [0G Storage SDK](https://docs.0g.ai/build-with-0g/storage-network/sdk)
|
|
163
|
+
- [0G Compute SDK](https://docs.0g.ai/build-with-0g/compute-network/sdk)
|