@agether/sdk 1.7.0 → 1.9.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 +107 -0
- package/dist/cli.js +164 -30
- package/dist/index.d.mts +120 -11
- package/dist/index.d.ts +120 -11
- package/dist/index.js +164 -30
- package/dist/index.mjs +165 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,6 +106,90 @@ await vault.withdraw(parseUnits('5000', 6));
|
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
|
+
## 🔐 Signing Modes
|
|
110
|
+
|
|
111
|
+
Both `MorphoClient` (ethers) and `X402Client` (viem) support two mutually exclusive signing modes: **private key** (SDK-managed wallet) and **external signer/wallet** (custody-agnostic).
|
|
112
|
+
|
|
113
|
+
### MorphoClient — Private Key
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { MorphoClient } from '@agether/sdk';
|
|
117
|
+
|
|
118
|
+
const client = new MorphoClient({
|
|
119
|
+
privateKey: process.env.AGENT_PRIVATE_KEY!,
|
|
120
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
121
|
+
agentId: '42',
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### MorphoClient — External Signer (ethers.AbstractSigner)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { MorphoClient, AgetherSigner } from '@agether/sdk';
|
|
129
|
+
|
|
130
|
+
// Any ethers.AbstractSigner works:
|
|
131
|
+
// - ethers.Wallet
|
|
132
|
+
// - Privy embedded wallet signer
|
|
133
|
+
// - Bankr custodial signer
|
|
134
|
+
// - Turnkey / MPC wallet signer
|
|
135
|
+
// - MetaMask via BrowserProvider.getSigner()
|
|
136
|
+
const signer: AgetherSigner = getSignerFromCustodyProvider();
|
|
137
|
+
|
|
138
|
+
const client = new MorphoClient({
|
|
139
|
+
signer,
|
|
140
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
141
|
+
agentId: '42',
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// All operations work identically regardless of signing mode
|
|
145
|
+
const status = await client.getStatus();
|
|
146
|
+
await client.supplyCollateral('WETH', '0.1');
|
|
147
|
+
await client.borrow('100');
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
> **Note:** When using an external signer, the SDK treats it as immutable — it will never
|
|
151
|
+
> recreate or reconnect the signer. Nonce management is the caller's responsibility.
|
|
152
|
+
|
|
153
|
+
### X402Client — Private Key
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { X402Client } from '@agether/sdk';
|
|
157
|
+
|
|
158
|
+
const client = new X402Client({
|
|
159
|
+
privateKey: process.env.AGENT_PRIVATE_KEY!,
|
|
160
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
161
|
+
backendUrl: 'https://api.agether.ai',
|
|
162
|
+
agentId: '42',
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### X402Client — viem WalletClient (Privy, Turnkey, etc.)
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { X402Client, AgetherViemWallet } from '@agether/sdk';
|
|
170
|
+
|
|
171
|
+
// Any viem WalletClient with an attached account works:
|
|
172
|
+
// - Privy embedded wallet → createWalletClient(...)
|
|
173
|
+
// - Turnkey signer → turnkeyToViemAccount(...)
|
|
174
|
+
// - MetaMask → createWalletClient({ transport: custom(window.ethereum) })
|
|
175
|
+
const walletClient: AgetherViemWallet = privyWalletClient;
|
|
176
|
+
|
|
177
|
+
const client = new X402Client({
|
|
178
|
+
walletClient,
|
|
179
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
180
|
+
backendUrl: 'https://api.agether.ai',
|
|
181
|
+
agentId: '42',
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// All x402 operations work identically regardless of signing mode
|
|
185
|
+
const result = await client.get('https://paid-api.example.com/data');
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
> **Note:** The `walletClient` must have an `account` property set (i.e. created with
|
|
189
|
+
> `createWalletClient({ account: ... })`). The SDK will never recreate or reconnect the client.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
109
193
|
## 📚 API Reference
|
|
110
194
|
|
|
111
195
|
### AgetherClient
|
|
@@ -215,6 +299,29 @@ Client for ERC-8004 agent identity management via ag0 SDK.
|
|
|
215
299
|
|
|
216
300
|
---
|
|
217
301
|
|
|
302
|
+
## 🔒 KYA (Know Your Agent) Gate
|
|
303
|
+
|
|
304
|
+
The protocol includes an optional **KYA code verification gate**. When enabled, agents must have their code approved by a validator in the `ValidationRegistry` before they can call `execute()` or `executeBatch()` on their `AgentAccount`.
|
|
305
|
+
|
|
306
|
+
**When is it active?**
|
|
307
|
+
- If the `AccountFactory` was deployed with a non-zero `validationRegistry` address, KYA is **enabled**
|
|
308
|
+
- If `validationRegistry = address(0)`, KYA is **disabled** — agents can transact immediately after registration
|
|
309
|
+
|
|
310
|
+
**Checking from the SDK:**
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const kyaRequired = await client.isKyaRequired();
|
|
314
|
+
if (kyaRequired) {
|
|
315
|
+
console.log('KYA gate is active — agent code must be approved before executing');
|
|
316
|
+
} else {
|
|
317
|
+
console.log('KYA gate is disabled — agents can execute immediately');
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
The `register()` method also returns `kyaRequired: boolean` so consumers know the state at registration time.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
218
325
|
## 📝 Types
|
|
219
326
|
|
|
220
327
|
### CreditStatus
|
package/dist/cli.js
CHANGED
|
@@ -66,7 +66,10 @@ var init_abis = __esm({
|
|
|
66
66
|
"function totalAccounts() view returns (uint256)",
|
|
67
67
|
"function getAgentId(address account) view returns (uint256)",
|
|
68
68
|
"function createAccount(uint256 agentId) returns (address account)",
|
|
69
|
-
"
|
|
69
|
+
"function validationRegistry() view returns (address)",
|
|
70
|
+
"function setValidationRegistry(address newRegistry)",
|
|
71
|
+
"event AccountCreated(uint256 indexed agentId, address indexed account, address indexed owner)",
|
|
72
|
+
"event ValidationRegistryUpdated(address indexed oldRegistry, address indexed newRegistry)"
|
|
70
73
|
];
|
|
71
74
|
AGENT_ACCOUNT_ABI = [
|
|
72
75
|
"function agentId() view returns (uint256)",
|
|
@@ -228,14 +231,44 @@ var init_MorphoClient = __esm({
|
|
|
228
231
|
this.config = defaultCfg;
|
|
229
232
|
this.agentId = config.agentId;
|
|
230
233
|
this._rpcUrl = config.rpcUrl || defaultCfg.rpcUrl;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
if ("signer" in config && config.signer) {
|
|
235
|
+
this._useExternalSigner = true;
|
|
236
|
+
const signerProvider = config.signer.provider;
|
|
237
|
+
if (signerProvider) {
|
|
238
|
+
this.provider = signerProvider;
|
|
239
|
+
this._signer = config.signer;
|
|
240
|
+
} else {
|
|
241
|
+
this.provider = new import_ethers.ethers.JsonRpcProvider(this._rpcUrl);
|
|
242
|
+
this._signer = config.signer.connect(this.provider);
|
|
243
|
+
}
|
|
244
|
+
if ("address" in config.signer && typeof config.signer.address === "string") {
|
|
245
|
+
this._eoaAddress = config.signer.address;
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
this._privateKey = config.privateKey;
|
|
249
|
+
this._useExternalSigner = false;
|
|
250
|
+
this.provider = new import_ethers.ethers.JsonRpcProvider(this._rpcUrl);
|
|
251
|
+
const wallet = new import_ethers.ethers.Wallet(this._privateKey, this.provider);
|
|
252
|
+
this._signer = wallet;
|
|
253
|
+
this._eoaAddress = wallet.address;
|
|
254
|
+
}
|
|
234
255
|
const addrs = { ...defaultCfg.contracts, ...config.contracts };
|
|
235
|
-
this.accountFactory = new import_ethers.Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this.
|
|
256
|
+
this.accountFactory = new import_ethers.Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
236
257
|
this.morphoBlue = new import_ethers.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
237
|
-
this.agentReputation = new import_ethers.Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this.
|
|
238
|
-
this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this.
|
|
258
|
+
this.agentReputation = new import_ethers.Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
|
|
259
|
+
this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
|
|
260
|
+
}
|
|
261
|
+
// ════════════════════════════════════════════════════════
|
|
262
|
+
// KYA Gate Check
|
|
263
|
+
// ════════════════════════════════════════════════════════
|
|
264
|
+
/**
|
|
265
|
+
* Check whether the KYA (Know Your Agent) code verification gate is active.
|
|
266
|
+
* When validationRegistry is address(0), KYA is disabled — agents can use
|
|
267
|
+
* execute/executeBatch without prior code approval.
|
|
268
|
+
*/
|
|
269
|
+
async isKyaRequired() {
|
|
270
|
+
const registryAddr = await this.accountFactory.validationRegistry();
|
|
271
|
+
return registryAddr !== import_ethers.ethers.ZeroAddress;
|
|
239
272
|
}
|
|
240
273
|
// ════════════════════════════════════════════════════════
|
|
241
274
|
// Account Management
|
|
@@ -255,8 +288,35 @@ var init_MorphoClient = __esm({
|
|
|
255
288
|
if (!this.agentId) throw new AgetherError("agentId not set", "NO_AGENT_ID");
|
|
256
289
|
return this.agentId;
|
|
257
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Get the EOA wallet address (synchronous, best-effort).
|
|
293
|
+
*
|
|
294
|
+
* For the `privateKey` path this always works. For the `signer` path
|
|
295
|
+
* it works if the signer exposes `.address` synchronously (e.g. ethers.Wallet).
|
|
296
|
+
* If the address has not been resolved yet, throws — call `getSignerAddress()` first.
|
|
297
|
+
*/
|
|
258
298
|
getWalletAddress() {
|
|
259
|
-
return this.
|
|
299
|
+
if (this._eoaAddress) return this._eoaAddress;
|
|
300
|
+
const signer = this._signer;
|
|
301
|
+
if (signer.address && typeof signer.address === "string") {
|
|
302
|
+
const addr = signer.address;
|
|
303
|
+
this._eoaAddress = addr;
|
|
304
|
+
return addr;
|
|
305
|
+
}
|
|
306
|
+
throw new AgetherError(
|
|
307
|
+
"EOA address not yet resolved. Call getSignerAddress() (async) first, or use a signer that exposes .address synchronously.",
|
|
308
|
+
"ADDRESS_NOT_RESOLVED"
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Resolve the EOA signer address (async, works with all signer types).
|
|
313
|
+
* Result is cached after the first call.
|
|
314
|
+
*/
|
|
315
|
+
async getSignerAddress() {
|
|
316
|
+
if (!this._eoaAddress) {
|
|
317
|
+
this._eoaAddress = await this._signer.getAddress();
|
|
318
|
+
}
|
|
319
|
+
return this._eoaAddress;
|
|
260
320
|
}
|
|
261
321
|
/** Mint a new ERC-8004 identity and return the agentId. */
|
|
262
322
|
async _mintNewIdentity() {
|
|
@@ -283,13 +343,14 @@ var init_MorphoClient = __esm({
|
|
|
283
343
|
* If already registered, returns existing state.
|
|
284
344
|
*/
|
|
285
345
|
async register(_name) {
|
|
286
|
-
const eoaAddr = this.
|
|
346
|
+
const eoaAddr = await this.getSignerAddress();
|
|
287
347
|
if (this.agentId) {
|
|
288
348
|
const exists = await this.accountFactory.accountExists(BigInt(this.agentId));
|
|
289
349
|
if (exists) {
|
|
290
350
|
const acct = await this.accountFactory.getAccount(BigInt(this.agentId));
|
|
291
351
|
this._accountAddress = acct;
|
|
292
|
-
|
|
352
|
+
const kyaRequired2 = await this.isKyaRequired();
|
|
353
|
+
return { agentId: this.agentId, address: eoaAddr, agentAccount: acct, alreadyRegistered: true, kyaRequired: kyaRequired2 };
|
|
293
354
|
}
|
|
294
355
|
}
|
|
295
356
|
let agentId;
|
|
@@ -314,17 +375,19 @@ var init_MorphoClient = __esm({
|
|
|
314
375
|
}
|
|
315
376
|
const acctAddr = await this.accountFactory.getAccount(agentId);
|
|
316
377
|
this._accountAddress = acctAddr;
|
|
378
|
+
const kyaRequired = await this.isKyaRequired();
|
|
317
379
|
return {
|
|
318
380
|
agentId: this.agentId,
|
|
319
381
|
address: eoaAddr,
|
|
320
382
|
agentAccount: acctAddr,
|
|
321
383
|
alreadyRegistered: acctExists,
|
|
384
|
+
kyaRequired,
|
|
322
385
|
tx: txHash
|
|
323
386
|
};
|
|
324
387
|
}
|
|
325
388
|
/** Get ETH / USDC / collateral balances for EOA and AgentAccount. */
|
|
326
389
|
async getBalances() {
|
|
327
|
-
const eoaAddr = this.
|
|
390
|
+
const eoaAddr = await this.getSignerAddress();
|
|
328
391
|
const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
329
392
|
const ethBal = await this.provider.getBalance(eoaAddr);
|
|
330
393
|
const usdcBal = await usdc.balanceOf(eoaAddr);
|
|
@@ -372,7 +435,7 @@ var init_MorphoClient = __esm({
|
|
|
372
435
|
/** Transfer USDC from EOA to AgentAccount. */
|
|
373
436
|
async fundAccount(usdcAmount) {
|
|
374
437
|
const acctAddr = await this.getAccountAddress();
|
|
375
|
-
const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.
|
|
438
|
+
const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this._signer);
|
|
376
439
|
const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
|
|
377
440
|
const tx = await usdc.transfer(acctAddr, amount);
|
|
378
441
|
const receipt = await tx.wait();
|
|
@@ -720,7 +783,7 @@ var init_MorphoClient = __esm({
|
|
|
720
783
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
721
784
|
const weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
|
|
722
785
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
723
|
-
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.
|
|
786
|
+
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this._signer);
|
|
724
787
|
const transferTx = await colToken.transfer(acctAddr, weiAmount);
|
|
725
788
|
await transferTx.wait();
|
|
726
789
|
this._refreshSigner();
|
|
@@ -797,7 +860,7 @@ var init_MorphoClient = __esm({
|
|
|
797
860
|
const colWei = import_ethers.ethers.parseUnits(collateralAmount, colInfo.decimals);
|
|
798
861
|
const borrowWei = import_ethers.ethers.parseUnits(borrowUsdcAmount, 6);
|
|
799
862
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
800
|
-
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.
|
|
863
|
+
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this._signer);
|
|
801
864
|
const transferTx = await colToken.transfer(acctAddr, colWei);
|
|
802
865
|
await transferTx.wait();
|
|
803
866
|
this._refreshSigner();
|
|
@@ -927,7 +990,7 @@ var init_MorphoClient = __esm({
|
|
|
927
990
|
if (!colInfo) throw new AgetherError(`Unknown collateral: ${tokenSymbol}`, "UNKNOWN_COLLATERAL");
|
|
928
991
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
929
992
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
930
|
-
const dest = receiver || this.
|
|
993
|
+
const dest = receiver || await this.getSignerAddress();
|
|
931
994
|
let weiAmount;
|
|
932
995
|
if (amount === "all") {
|
|
933
996
|
const markets = await this.getMarkets();
|
|
@@ -985,7 +1048,7 @@ var init_MorphoClient = __esm({
|
|
|
985
1048
|
throw new AgetherError("Provide agentId or address", "INVALID_TARGET");
|
|
986
1049
|
}
|
|
987
1050
|
const weiAmount = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
|
|
988
|
-
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this.
|
|
1051
|
+
const colToken = new import_ethers.Contract(colInfo.address, ERC20_ABI, this._signer);
|
|
989
1052
|
const tx = await colToken.transfer(targetAddr, weiAmount);
|
|
990
1053
|
const receipt = await tx.wait();
|
|
991
1054
|
this._refreshSigner();
|
|
@@ -1017,24 +1080,41 @@ var init_MorphoClient = __esm({
|
|
|
1017
1080
|
// Internal Helpers
|
|
1018
1081
|
// ════════════════════════════════════════════════════════
|
|
1019
1082
|
/**
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1083
|
+
* Refresh the signer and re-bind contract instances.
|
|
1084
|
+
*
|
|
1085
|
+
* For the **privateKey** path: recreates provider + wallet so the next tx
|
|
1086
|
+
* fetches a fresh nonce from chain. Anvil (and some RPC providers) return a
|
|
1087
|
+
* stale `eth_getTransactionCount` right after a block is mined, causing
|
|
1088
|
+
* "nonce too low" on the follow-up tx.
|
|
1089
|
+
*
|
|
1090
|
+
* For the **external signer** path: the signer is immutable and owned by the
|
|
1091
|
+
* caller (e.g. custody provider). We only re-bind contract instances to
|
|
1092
|
+
* ensure they reference the current signer. Nonce management is the caller's
|
|
1093
|
+
* responsibility.
|
|
1023
1094
|
*/
|
|
1024
1095
|
_refreshSigner() {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1096
|
+
if (this._useExternalSigner) {
|
|
1097
|
+
const addrs = this.config.contracts;
|
|
1098
|
+
this.accountFactory = new import_ethers.Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
1099
|
+
this.agentReputation = new import_ethers.Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
|
|
1100
|
+
this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
|
|
1101
|
+
} else {
|
|
1102
|
+
this.provider = new import_ethers.ethers.JsonRpcProvider(this._rpcUrl);
|
|
1103
|
+
const wallet = new import_ethers.ethers.Wallet(this._privateKey, this.provider);
|
|
1104
|
+
this._signer = wallet;
|
|
1105
|
+
this._eoaAddress = wallet.address;
|
|
1106
|
+
const addrs = this.config.contracts;
|
|
1107
|
+
this.accountFactory = new import_ethers.Contract(addrs.accountFactory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
1108
|
+
this.agentReputation = new import_ethers.Contract(addrs.agentReputation, AGENT_REPUTATION_ABI, this._signer);
|
|
1109
|
+
this.identityRegistry = new import_ethers.Contract(addrs.identityRegistry, IDENTITY_REGISTRY_ABI, this._signer);
|
|
1110
|
+
}
|
|
1031
1111
|
}
|
|
1032
1112
|
/**
|
|
1033
1113
|
* Execute a single call via AgentAccount.execute.
|
|
1034
1114
|
*/
|
|
1035
1115
|
async exec(target, data, value = 0n) {
|
|
1036
1116
|
const acctAddr = await this.getAccountAddress();
|
|
1037
|
-
const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this.
|
|
1117
|
+
const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this._signer);
|
|
1038
1118
|
let gasLimit;
|
|
1039
1119
|
try {
|
|
1040
1120
|
const estimate = await account.execute.estimateGas(target, value, data);
|
|
@@ -1052,7 +1132,7 @@ var init_MorphoClient = __esm({
|
|
|
1052
1132
|
*/
|
|
1053
1133
|
async batch(targets, values, datas) {
|
|
1054
1134
|
const acctAddr = await this.getAccountAddress();
|
|
1055
|
-
const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this.
|
|
1135
|
+
const account = new import_ethers.Contract(acctAddr, AGENT_ACCOUNT_ABI, this._signer);
|
|
1056
1136
|
let gasLimit;
|
|
1057
1137
|
try {
|
|
1058
1138
|
const estimate = await account.executeBatch.estimateGas(targets, values, datas);
|
|
@@ -1116,9 +1196,63 @@ var init_X402Client = __esm({
|
|
|
1116
1196
|
X402Client = class {
|
|
1117
1197
|
constructor(config) {
|
|
1118
1198
|
this.config = config;
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1199
|
+
let baseSigner;
|
|
1200
|
+
if ("walletClient" in config && config.walletClient) {
|
|
1201
|
+
const wc = config.walletClient;
|
|
1202
|
+
const account = wc.account;
|
|
1203
|
+
if (!account) {
|
|
1204
|
+
throw new Error(
|
|
1205
|
+
"X402Client: walletClient must have an attached account. Pass an account when creating the WalletClient or use privateKey mode instead."
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
this.address = account.address;
|
|
1209
|
+
baseSigner = {
|
|
1210
|
+
address: account.address,
|
|
1211
|
+
signTypedData: (msg) => wc.signTypedData({
|
|
1212
|
+
account,
|
|
1213
|
+
domain: msg.domain,
|
|
1214
|
+
types: msg.types,
|
|
1215
|
+
primaryType: msg.primaryType,
|
|
1216
|
+
message: msg.message
|
|
1217
|
+
})
|
|
1218
|
+
};
|
|
1219
|
+
} else if ("privateKey" in config && config.privateKey) {
|
|
1220
|
+
const privateKey = config.privateKey.startsWith("0x") ? config.privateKey : `0x${config.privateKey}`;
|
|
1221
|
+
const account = (0, import_accounts.privateKeyToAccount)(privateKey);
|
|
1222
|
+
this.address = account.address;
|
|
1223
|
+
baseSigner = account;
|
|
1224
|
+
} else {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"X402Client: provide either privateKey or walletClient in config."
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
let signer;
|
|
1230
|
+
if (config.accountAddress) {
|
|
1231
|
+
const accountAddr = config.accountAddress;
|
|
1232
|
+
const inner = baseSigner;
|
|
1233
|
+
signer = (0, import_accounts.toAccount)({
|
|
1234
|
+
address: accountAddr,
|
|
1235
|
+
async signMessage({ message }) {
|
|
1236
|
+
if ("signMessage" in inner && typeof inner.signMessage === "function") {
|
|
1237
|
+
return inner.signMessage({ message });
|
|
1238
|
+
}
|
|
1239
|
+
throw new Error("signMessage not supported by underlying signer");
|
|
1240
|
+
},
|
|
1241
|
+
async signTransaction(tx) {
|
|
1242
|
+
if ("signTransaction" in inner && typeof inner.signTransaction === "function") {
|
|
1243
|
+
return inner.signTransaction(tx);
|
|
1244
|
+
}
|
|
1245
|
+
throw new Error("signTransaction not supported by underlying signer");
|
|
1246
|
+
},
|
|
1247
|
+
async signTypedData(typedData) {
|
|
1248
|
+
const sig = await inner.signTypedData(typedData);
|
|
1249
|
+
return `${sig}00`;
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
this.address = accountAddr;
|
|
1253
|
+
} else {
|
|
1254
|
+
signer = baseSigner;
|
|
1255
|
+
}
|
|
1122
1256
|
const client = new import_client.x402Client();
|
|
1123
1257
|
(0, import_client2.registerExactEvmScheme)(client, { signer });
|
|
1124
1258
|
this.paidFetch = (0, import_fetch.wrapFetchWithPayment)(fetch, client);
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Signer } from 'ethers';
|
|
1
|
+
import { Signer, ethers } from 'ethers';
|
|
2
|
+
import { WalletClient } from 'viem';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Agether SDK Types
|
|
@@ -186,10 +187,20 @@ declare class AgetherClient {
|
|
|
186
187
|
* - supplyCollateral: [ERC20.approve, Morpho.supplyCollateral]
|
|
187
188
|
*
|
|
188
189
|
* Market discovery via Morpho GraphQL API (https://api.morpho.org/graphql)
|
|
190
|
+
*
|
|
191
|
+
* Supports two signing modes:
|
|
192
|
+
* - `privateKey`: SDK manages wallet lifecycle (existing behavior)
|
|
193
|
+
* - `signer`: external signer (Bankr, Privy, Turnkey, MetaMask, etc.)
|
|
189
194
|
*/
|
|
190
195
|
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Convenience type alias for any ethers-compatible signer.
|
|
198
|
+
* Use this when declaring variables or parameters that accept
|
|
199
|
+
* ethers.Wallet, Privy signer, Bankr signer, Turnkey signer, etc.
|
|
200
|
+
*/
|
|
201
|
+
type AgetherSigner = ethers.AbstractSigner;
|
|
202
|
+
/** Base configuration fields shared by both signing modes. */
|
|
203
|
+
interface MorphoClientBaseConfig {
|
|
193
204
|
rpcUrl: string;
|
|
194
205
|
agentId?: string;
|
|
195
206
|
chainId?: ChainId;
|
|
@@ -201,6 +212,44 @@ interface MorphoClientConfig {
|
|
|
201
212
|
identityRegistry: string;
|
|
202
213
|
}>;
|
|
203
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* MorphoClient configuration.
|
|
217
|
+
*
|
|
218
|
+
* Provide **either** `privateKey` (SDK manages wallet) **or** `signer`
|
|
219
|
+
* (external custody provider). The two fields are mutually exclusive.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* // Private key (existing behavior — fully backward compatible):
|
|
224
|
+
* new MorphoClient({ privateKey: '0x...', rpcUrl, agentId: '42' })
|
|
225
|
+
*
|
|
226
|
+
* // External signer (Bankr, Privy, Turnkey, MetaMask, etc.):
|
|
227
|
+
* new MorphoClient({ signer: privySigner, rpcUrl, agentId: '42' })
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
type MorphoClientConfig = MorphoClientBaseConfig & ({
|
|
231
|
+
/** Raw private key hex string. SDK creates an ethers.Wallet internally. */
|
|
232
|
+
privateKey: string;
|
|
233
|
+
signer?: never;
|
|
234
|
+
} | {
|
|
235
|
+
/**
|
|
236
|
+
* Any `ethers.AbstractSigner` instance for transaction signing.
|
|
237
|
+
*
|
|
238
|
+
* Accepts:
|
|
239
|
+
* - `ethers.Wallet` (local key)
|
|
240
|
+
* - Privy embedded wallet signer
|
|
241
|
+
* - Bankr custodial signer
|
|
242
|
+
* - Turnkey / MPC wallet signer
|
|
243
|
+
* - Hardware wallet adapter (Ledger, Trezor)
|
|
244
|
+
* - MetaMask `BrowserProvider.getSigner()`
|
|
245
|
+
* - Any object implementing `ethers.AbstractSigner`
|
|
246
|
+
*
|
|
247
|
+
* The signer is treated as **immutable** by the SDK — it will never be
|
|
248
|
+
* recreated or reconnected. Nonce management is the caller's responsibility.
|
|
249
|
+
*/
|
|
250
|
+
signer: ethers.AbstractSigner;
|
|
251
|
+
privateKey?: never;
|
|
252
|
+
});
|
|
204
253
|
interface BalancesResult {
|
|
205
254
|
agentId: string;
|
|
206
255
|
address: string;
|
|
@@ -219,6 +268,8 @@ interface RegisterResult {
|
|
|
219
268
|
address: string;
|
|
220
269
|
agentAccount: string;
|
|
221
270
|
alreadyRegistered: boolean;
|
|
271
|
+
/** Whether the KYA (code verification) gate is active on this factory */
|
|
272
|
+
kyaRequired: boolean;
|
|
222
273
|
tx?: string;
|
|
223
274
|
}
|
|
224
275
|
interface PositionResult {
|
|
@@ -272,12 +323,14 @@ interface FundResult {
|
|
|
272
323
|
agentAccount: string;
|
|
273
324
|
}
|
|
274
325
|
declare class MorphoClient {
|
|
275
|
-
private
|
|
326
|
+
private _signer;
|
|
276
327
|
private provider;
|
|
277
328
|
private config;
|
|
278
329
|
private agentId;
|
|
279
330
|
private _rpcUrl;
|
|
280
|
-
private _privateKey
|
|
331
|
+
private _privateKey?;
|
|
332
|
+
private _useExternalSigner;
|
|
333
|
+
private _eoaAddress?;
|
|
281
334
|
private accountFactory;
|
|
282
335
|
private morphoBlue;
|
|
283
336
|
private agentReputation;
|
|
@@ -287,10 +340,28 @@ declare class MorphoClient {
|
|
|
287
340
|
private _discoveredMarkets?;
|
|
288
341
|
private _discoveredAt;
|
|
289
342
|
constructor(config: MorphoClientConfig);
|
|
343
|
+
/**
|
|
344
|
+
* Check whether the KYA (Know Your Agent) code verification gate is active.
|
|
345
|
+
* When validationRegistry is address(0), KYA is disabled — agents can use
|
|
346
|
+
* execute/executeBatch without prior code approval.
|
|
347
|
+
*/
|
|
348
|
+
isKyaRequired(): Promise<boolean>;
|
|
290
349
|
/** Resolve the AgentAccount address (cached). */
|
|
291
350
|
getAccountAddress(): Promise<string>;
|
|
292
351
|
getAgentId(): string;
|
|
352
|
+
/**
|
|
353
|
+
* Get the EOA wallet address (synchronous, best-effort).
|
|
354
|
+
*
|
|
355
|
+
* For the `privateKey` path this always works. For the `signer` path
|
|
356
|
+
* it works if the signer exposes `.address` synchronously (e.g. ethers.Wallet).
|
|
357
|
+
* If the address has not been resolved yet, throws — call `getSignerAddress()` first.
|
|
358
|
+
*/
|
|
293
359
|
getWalletAddress(): string;
|
|
360
|
+
/**
|
|
361
|
+
* Resolve the EOA signer address (async, works with all signer types).
|
|
362
|
+
* Result is cached after the first call.
|
|
363
|
+
*/
|
|
364
|
+
getSignerAddress(): Promise<string>;
|
|
294
365
|
/** Mint a new ERC-8004 identity and return the agentId. */
|
|
295
366
|
private _mintNewIdentity;
|
|
296
367
|
/**
|
|
@@ -450,9 +521,17 @@ declare class MorphoClient {
|
|
|
450
521
|
age: bigint;
|
|
451
522
|
}>;
|
|
452
523
|
/**
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
524
|
+
* Refresh the signer and re-bind contract instances.
|
|
525
|
+
*
|
|
526
|
+
* For the **privateKey** path: recreates provider + wallet so the next tx
|
|
527
|
+
* fetches a fresh nonce from chain. Anvil (and some RPC providers) return a
|
|
528
|
+
* stale `eth_getTransactionCount` right after a block is mined, causing
|
|
529
|
+
* "nonce too low" on the follow-up tx.
|
|
530
|
+
*
|
|
531
|
+
* For the **external signer** path: the signer is immutable and owned by the
|
|
532
|
+
* caller (e.g. custody provider). We only re-bind contract instances to
|
|
533
|
+
* ensure they reference the current signer. Nonce management is the caller's
|
|
534
|
+
* responsibility.
|
|
456
535
|
*/
|
|
457
536
|
private _refreshSigner;
|
|
458
537
|
/**
|
|
@@ -491,8 +570,15 @@ declare class MorphoClient {
|
|
|
491
570
|
*
|
|
492
571
|
* Chain support: Base (8453), Base Sepolia (84532), Ethereum (1).
|
|
493
572
|
*/
|
|
494
|
-
|
|
495
|
-
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Convenience type alias for any viem-compatible WalletClient.
|
|
576
|
+
* Use this when declaring variables or parameters that accept
|
|
577
|
+
* viem WalletClient instances from Privy, Turnkey, MetaMask, etc.
|
|
578
|
+
*/
|
|
579
|
+
type AgetherViemWallet = WalletClient;
|
|
580
|
+
/** Base configuration fields shared by both signing modes. */
|
|
581
|
+
interface X402BaseConfig {
|
|
496
582
|
rpcUrl: string;
|
|
497
583
|
backendUrl: string;
|
|
498
584
|
agentId?: string;
|
|
@@ -519,6 +605,29 @@ interface X402Config {
|
|
|
519
605
|
*/
|
|
520
606
|
autoDrawBuffer?: string;
|
|
521
607
|
}
|
|
608
|
+
/** Config with SDK-managed private key (existing behavior). */
|
|
609
|
+
interface X402PrivateKeyConfig extends X402BaseConfig {
|
|
610
|
+
/** Raw hex private key (with or without '0x' prefix). SDK creates the wallet internally. */
|
|
611
|
+
privateKey: string;
|
|
612
|
+
walletClient?: never;
|
|
613
|
+
}
|
|
614
|
+
/** Config with caller-provided viem WalletClient (custody-agnostic). */
|
|
615
|
+
interface X402WalletClientConfig extends X402BaseConfig {
|
|
616
|
+
/**
|
|
617
|
+
* A viem WalletClient with an attached account (e.g. from Privy, Turnkey, MetaMask).
|
|
618
|
+
* The client **must** have an `account` property set. The SDK will use it for
|
|
619
|
+
* EIP-712 typed-data signing and will never recreate or reconnect the client.
|
|
620
|
+
*/
|
|
621
|
+
walletClient: WalletClient;
|
|
622
|
+
privateKey?: never;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* X402Client configuration.
|
|
626
|
+
*
|
|
627
|
+
* Provide **either** `privateKey` (SDK manages wallet) **or** `walletClient`
|
|
628
|
+
* (external custody provider). The two fields are mutually exclusive.
|
|
629
|
+
*/
|
|
630
|
+
type X402Config = X402PrivateKeyConfig | X402WalletClientConfig;
|
|
522
631
|
interface X402Response<T = unknown> {
|
|
523
632
|
success: boolean;
|
|
524
633
|
data?: T;
|
|
@@ -954,4 +1063,4 @@ declare function getDefaultConfig(chainId: ChainId): AgetherConfig;
|
|
|
954
1063
|
*/
|
|
955
1064
|
declare function createConfig(chainId: ChainId, options?: Partial<AgetherConfig>): AgetherConfig;
|
|
956
1065
|
|
|
957
|
-
export { ACCOUNT_FACTORY_ABI, AGENT_ACCOUNT_ABI, AGENT_REPUTATION_ABI, AgentIdentityClient, type AgentIdentityClientOptions, AgentNotApprovedError, AgetherClient, type AgetherClientOptions, type AgetherConfig, AgetherError, type BalancesResult, type BorrowResult, ChainId, type ContractAddresses, type DepositAndBorrowResult, type DepositResult, ERC20_ABI, type FundResult, IDENTITY_REGISTRY_ABI, InsufficientBalanceError, MORPHO_BLUE_ABI, MorphoClient, type MorphoClientConfig, type MorphoMarketInfo, type MorphoMarketParams, type MorphoPosition, type PaymentRequirements, type PositionResult, type RegisterResult, type RepayResult, type ScoreAttestation, type ScoreResult, ScoringClient, type ScoringClientConfig, ScoringRejectedError, type SpendingTracker, type StatusResult, type TransactionResult, VALIDATION_REGISTRY_ABI, type WithdrawResult, X402Client, type X402Config, type X402PaymentRequest, type X402PaymentResult, type X402Response, bpsToRate, createConfig, formatAPR, formatAddress, formatHealthFactor, formatPercent, formatTimestamp, formatUSD, formatUnits, getDefaultConfig, parseUnits, rateToBps };
|
|
1066
|
+
export { ACCOUNT_FACTORY_ABI, AGENT_ACCOUNT_ABI, AGENT_REPUTATION_ABI, AgentIdentityClient, type AgentIdentityClientOptions, AgentNotApprovedError, AgetherClient, type AgetherClientOptions, type AgetherConfig, AgetherError, type AgetherSigner, type AgetherViemWallet, type BalancesResult, type BorrowResult, ChainId, type ContractAddresses, type DepositAndBorrowResult, type DepositResult, ERC20_ABI, type FundResult, IDENTITY_REGISTRY_ABI, InsufficientBalanceError, MORPHO_BLUE_ABI, MorphoClient, type MorphoClientConfig, type MorphoMarketInfo, type MorphoMarketParams, type MorphoPosition, type PaymentRequirements, type PositionResult, type RegisterResult, type RepayResult, type ScoreAttestation, type ScoreResult, ScoringClient, type ScoringClientConfig, ScoringRejectedError, type SpendingTracker, type StatusResult, type TransactionResult, VALIDATION_REGISTRY_ABI, type WithdrawResult, X402Client, type X402Config, type X402PaymentRequest, type X402PaymentResult, type X402Response, bpsToRate, createConfig, formatAPR, formatAddress, formatHealthFactor, formatPercent, formatTimestamp, formatUSD, formatUnits, getDefaultConfig, parseUnits, rateToBps };
|