txflow-sdk 0.2.4 → 0.3.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/README.md +80 -3
- package/dist/client.d.ts +5 -5
- package/dist/client.js +5 -5
- package/dist/signing.d.ts +3 -3
- package/dist/types.d.ts +8 -3
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install txflow-sdk
|
|
|
12
12
|
|
|
13
13
|
TxFlow uses an **agent wallet pattern** with two distinct wallets:
|
|
14
14
|
|
|
15
|
-
- **User Wallet**: The main wallet that owns the funds. Required for authorization, withdrawals, and transfers.
|
|
15
|
+
- **User Wallet**: The main wallet that owns the funds. Required for authorization, withdrawals, and transfers. Can be any `ethers.AbstractSigner` (private key, MetaMask, Privy, Turnkey, etc.).
|
|
16
16
|
- **Agent Wallet**: A temporary wallet authorized by the user wallet. It only has **trading permissions** (place/cancel/modify orders, update leverage and margin mode). It cannot move funds.
|
|
17
17
|
|
|
18
18
|
The user wallet signs an `ApproveAgent` message to grant the agent wallet trading rights. After that, all trading operations use the agent wallet's key.
|
|
@@ -47,14 +47,22 @@ await client.withdraw(userWallet, { destination: "0x...", amount: "100" });
|
|
|
47
47
|
|
|
48
48
|
## Configuration
|
|
49
49
|
|
|
50
|
+
You can initialize the client with either a `privateKey` or a `signer`:
|
|
51
|
+
|
|
50
52
|
```typescript
|
|
53
|
+
// Option A: Private key (for bots/scripts)
|
|
51
54
|
const client = new TxFlowClient({
|
|
52
|
-
privateKey: "0x...", // Agent wallet private key (
|
|
55
|
+
privateKey: "0x...", // Agent wallet private key (trading only)
|
|
53
56
|
baseUrl: "https://testnet-api.txflow.net", // API base URL (optional)
|
|
54
57
|
isMainnet: true, // Source identifier for signing (optional, default: true)
|
|
55
58
|
vaultAddress: null, // Vault address if applicable (optional)
|
|
56
59
|
chainId: 1337, // L1 signing domain chain ID (optional)
|
|
57
60
|
});
|
|
61
|
+
|
|
62
|
+
// Option B: Any ethers.AbstractSigner (for browser wallets)
|
|
63
|
+
const client = new TxFlowClient({
|
|
64
|
+
signer: myAgentSigner, // Any ethers.AbstractSigner instance
|
|
65
|
+
});
|
|
58
66
|
```
|
|
59
67
|
|
|
60
68
|
### Mainnet Migration
|
|
@@ -73,6 +81,75 @@ const client = new TxFlowClient({
|
|
|
73
81
|
|
|
74
82
|
All signing logic, EIP-712 domains, and API calls adapt automatically based on the config.
|
|
75
83
|
|
|
84
|
+
## Browser Wallet Integration
|
|
85
|
+
|
|
86
|
+
The SDK accepts any `ethers.AbstractSigner` for user wallet operations (`approveAgent`, `withdraw`, `transferToken`, `sendToken`). This makes it compatible with MetaMask, Privy, Turnkey, and other wallet providers.
|
|
87
|
+
|
|
88
|
+
### MetaMask / Injected Wallet
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { TxFlowClient } from "txflow-sdk";
|
|
92
|
+
import { ethers } from "ethers";
|
|
93
|
+
|
|
94
|
+
// Connect to MetaMask
|
|
95
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
96
|
+
const userSigner = await provider.getSigner(); // ethers.JsonRpcSigner
|
|
97
|
+
|
|
98
|
+
// Generate a local agent wallet (trading only, no fund access)
|
|
99
|
+
const agentWallet = ethers.Wallet.createRandom();
|
|
100
|
+
// Persist agent key in localStorage so the user doesn't re-approve every session
|
|
101
|
+
localStorage.setItem("txflow_agent_key", agentWallet.privateKey);
|
|
102
|
+
|
|
103
|
+
const client = new TxFlowClient({
|
|
104
|
+
privateKey: agentWallet.privateKey,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// User's MetaMask signs the one-time agent authorization
|
|
108
|
+
await client.approveAgent(userSigner);
|
|
109
|
+
|
|
110
|
+
// All trading uses the local agent key (no MetaMask popups)
|
|
111
|
+
await client.placeOrder({ asset: 1, isBuy: true, price: "50000", size: "0.01" });
|
|
112
|
+
|
|
113
|
+
// Fund operations still go through MetaMask
|
|
114
|
+
await client.withdraw(userSigner, { destination: "0x...", amount: "100" });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Privy Embedded Wallet
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { TxFlowClient } from "txflow-sdk";
|
|
121
|
+
import { ethers } from "ethers";
|
|
122
|
+
import { usePrivy, useWallets } from "@privy-io/react-auth";
|
|
123
|
+
|
|
124
|
+
// Inside a React component
|
|
125
|
+
const { wallets } = useWallets();
|
|
126
|
+
const embeddedWallet = wallets.find((w) => w.walletClientType === "privy");
|
|
127
|
+
|
|
128
|
+
// Get an ethers signer from Privy
|
|
129
|
+
const privyProvider = await embeddedWallet.getEthersProvider();
|
|
130
|
+
const userSigner = await privyProvider.getSigner(); // ethers.JsonRpcSigner
|
|
131
|
+
|
|
132
|
+
// Generate a local agent wallet
|
|
133
|
+
const stored = localStorage.getItem("txflow_agent_key");
|
|
134
|
+
const agentWallet = stored
|
|
135
|
+
? new ethers.Wallet(stored)
|
|
136
|
+
: ethers.Wallet.createRandom();
|
|
137
|
+
localStorage.setItem("txflow_agent_key", agentWallet.privateKey);
|
|
138
|
+
|
|
139
|
+
const client = new TxFlowClient({
|
|
140
|
+
privateKey: agentWallet.privateKey,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Privy wallet signs the agent authorization (no browser extension needed)
|
|
144
|
+
await client.approveAgent(userSigner);
|
|
145
|
+
|
|
146
|
+
// Trading uses the local agent key (instant, no signing prompts)
|
|
147
|
+
await client.placeOrder({ asset: 1, isBuy: true, price: "50000", size: "0.01" });
|
|
148
|
+
|
|
149
|
+
// Fund operations go through Privy
|
|
150
|
+
await client.withdraw(userSigner, { destination: "0x...", amount: "100" });
|
|
151
|
+
```
|
|
152
|
+
|
|
76
153
|
## API Reference
|
|
77
154
|
|
|
78
155
|
### Trading (Agent Wallet)
|
|
@@ -144,7 +221,7 @@ await client.updateMarginMode({ asset: 1, isCross: true });
|
|
|
144
221
|
|
|
145
222
|
### User Actions (User Wallet)
|
|
146
223
|
|
|
147
|
-
These methods require the **user wallet** to be passed explicitly.
|
|
224
|
+
These methods require the **user wallet** to be passed explicitly. Any `ethers.AbstractSigner` is accepted (private key wallet, MetaMask signer, Privy signer, etc.). The agent wallet **cannot** perform these operations.
|
|
148
225
|
|
|
149
226
|
#### `approveAgent(userWallet, params?)`
|
|
150
227
|
|
package/dist/client.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class TxFlowClient {
|
|
|
7
7
|
private vaultAddress;
|
|
8
8
|
private chainId?;
|
|
9
9
|
constructor(config: TxFlowConfig);
|
|
10
|
-
|
|
10
|
+
getAddress(): Promise<string>;
|
|
11
11
|
private postExchange;
|
|
12
12
|
private postInfo;
|
|
13
13
|
private buildOrderWire;
|
|
@@ -18,10 +18,10 @@ export declare class TxFlowClient {
|
|
|
18
18
|
modifyOrder(params: ModifyOrderParams): Promise<ApiResponse>;
|
|
19
19
|
updateLeverage(params: UpdateLeverageParams): Promise<ApiResponse>;
|
|
20
20
|
updateMarginMode(params: UpdateMarginModeParams): Promise<ApiResponse>;
|
|
21
|
-
approveAgent(userWallet: ethers.
|
|
22
|
-
withdraw(userWallet: ethers.
|
|
23
|
-
transferToken(userWallet: ethers.
|
|
24
|
-
sendToken(userWallet: ethers.
|
|
21
|
+
approveAgent(userWallet: ethers.AbstractSigner, params?: Partial<ApproveAgentParams>): Promise<ApiResponse>;
|
|
22
|
+
withdraw(userWallet: ethers.AbstractSigner, params: WithdrawParams): Promise<ApiResponse>;
|
|
23
|
+
transferToken(userWallet: ethers.AbstractSigner, params: TransferTokenParams): Promise<ApiResponse>;
|
|
24
|
+
sendToken(userWallet: ethers.AbstractSigner, params: SendTokenParams): Promise<ApiResponse>;
|
|
25
25
|
buildPlaceOrder(params: PlaceOrderParams): Promise<SignedRequest>;
|
|
26
26
|
buildPlaceBatchOrders(orderParams: PlaceOrderParams[]): Promise<SignedRequest>;
|
|
27
27
|
buildCancelOrder(params: CancelOrderParams): Promise<SignedRequest>;
|
package/dist/client.js
CHANGED
|
@@ -8,14 +8,14 @@ export class TxFlowClient {
|
|
|
8
8
|
vaultAddress;
|
|
9
9
|
chainId;
|
|
10
10
|
constructor(config) {
|
|
11
|
-
this.wallet = new ethers.Wallet(config.privateKey);
|
|
11
|
+
this.wallet = config.signer ?? new ethers.Wallet(config.privateKey);
|
|
12
12
|
this.baseUrl = config.baseUrl ?? TESTNET_API_URL;
|
|
13
13
|
this.isMainnet = config.isMainnet ?? true;
|
|
14
14
|
this.vaultAddress = config.vaultAddress ?? null;
|
|
15
15
|
this.chainId = config.chainId;
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
return this.wallet.
|
|
17
|
+
async getAddress() {
|
|
18
|
+
return this.wallet.getAddress();
|
|
19
19
|
}
|
|
20
20
|
async postExchange(body) {
|
|
21
21
|
const resp = await fetch(`${this.baseUrl}/exchange`, {
|
|
@@ -131,7 +131,7 @@ export class TxFlowClient {
|
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
async approveAgent(userWallet, params) {
|
|
134
|
-
const agentAddress = params?.agentAddress ?? this.wallet.
|
|
134
|
+
const agentAddress = params?.agentAddress ?? await this.wallet.getAddress();
|
|
135
135
|
const agentName = params?.agentName ?? "TradeAgent";
|
|
136
136
|
const nonce = params?.nonce ?? Date.now();
|
|
137
137
|
const message = {
|
|
@@ -386,7 +386,7 @@ export class TxFlowClient {
|
|
|
386
386
|
const resp = await fetch(`${this.baseUrl}/request-fund`, {
|
|
387
387
|
method: "POST",
|
|
388
388
|
headers: { "Content-Type": "application/json" },
|
|
389
|
-
body: JSON.stringify({ address: address ?? this.wallet.
|
|
389
|
+
body: JSON.stringify({ address: address ?? await this.wallet.getAddress() }),
|
|
390
390
|
});
|
|
391
391
|
return resp.json();
|
|
392
392
|
}
|
package/dist/signing.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ethers } from "ethers";
|
|
2
2
|
import type { Signature } from "./types.js";
|
|
3
3
|
export declare function actionHash(action: unknown, vaultAddress: string | null, nonce: number): string;
|
|
4
|
-
export declare function signL1Action(wallet: ethers.
|
|
4
|
+
export declare function signL1Action(wallet: ethers.AbstractSigner, action: unknown, vaultAddress: string | null, nonce: number, isMainnet: boolean, chainId?: number): Promise<Signature>;
|
|
5
5
|
export declare function generateNonce(): number;
|
|
6
|
-
export declare function createSign(wallet: ethers.
|
|
6
|
+
export declare function createSign(wallet: ethers.AbstractSigner, action: unknown, isMainnet: boolean, vaultAddress?: string | null, chainId?: number): Promise<{
|
|
7
7
|
signature: Signature;
|
|
8
8
|
nonce: number;
|
|
9
9
|
}>;
|
|
10
|
-
export declare function signUserAction(wallet: ethers.
|
|
10
|
+
export declare function signUserAction(wallet: ethers.AbstractSigner, domain: ethers.TypedDataDomain, types: Record<string, ethers.TypedDataField[]>, message: Record<string, unknown>): Promise<Signature>;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
export
|
|
2
|
-
privateKey: string;
|
|
1
|
+
export type TxFlowConfig = {
|
|
3
2
|
baseUrl?: string;
|
|
4
3
|
isMainnet?: boolean;
|
|
5
4
|
vaultAddress?: string | null;
|
|
6
5
|
chainId?: number;
|
|
7
|
-
}
|
|
6
|
+
} & ({
|
|
7
|
+
privateKey: string;
|
|
8
|
+
signer?: never;
|
|
9
|
+
} | {
|
|
10
|
+
signer: import("ethers").AbstractSigner;
|
|
11
|
+
privateKey?: never;
|
|
12
|
+
});
|
|
8
13
|
export interface OrderWire {
|
|
9
14
|
a: number;
|
|
10
15
|
b: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "txflow-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TypeScript SDK for TxFlow perpetual DEX with EIP-712 signing and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
"futures"
|
|
37
37
|
],
|
|
38
38
|
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://gitlab.com/andy-vibecoding/txflow-sdk.git"
|
|
42
|
+
},
|
|
39
43
|
"dependencies": {
|
|
40
44
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
41
45
|
"@msgpack/msgpack": "^3.0.0-beta2",
|