txflow-sdk 0.2.4 → 0.3.1

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 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 (required, trading only)
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. The user wallet is the main wallet that owns the funds and has full account control. The agent wallet **cannot** perform these operations.
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
- get address(): string;
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.Wallet, params?: Partial<ApproveAgentParams>): Promise<ApiResponse>;
22
- withdraw(userWallet: ethers.Wallet, params: WithdrawParams): Promise<ApiResponse>;
23
- transferToken(userWallet: ethers.Wallet, params: TransferTokenParams): Promise<ApiResponse>;
24
- sendToken(userWallet: ethers.Wallet, params: SendTokenParams): Promise<ApiResponse>;
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
- get address() {
18
- return this.wallet.address;
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.address;
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.address }),
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.Wallet, action: unknown, vaultAddress: string | null, nonce: number, isMainnet: boolean, chainId?: number): Promise<Signature>;
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.Wallet, action: unknown, isMainnet: boolean, vaultAddress?: string | null, chainId?: number): Promise<{
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.Wallet, domain: ethers.TypedDataDomain, types: Record<string, ethers.TypedDataField[]>, message: Record<string, unknown>): Promise<Signature>;
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 interface TxFlowConfig {
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.2.4",
3
+ "version": "0.3.1",
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",