@owney/sdk 0.7.21-beta.5 → 0.7.21-beta.6
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 +7 -7
- package/dist/index.cjs +85 -42
- package/dist/index.d.cts +11 -7
- package/dist/index.d.ts +11 -7
- package/dist/index.js +85 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ const sdk = new OwneySDK({ apiKey: "your-owney-api-key" });
|
|
|
19
19
|
// Connect with an EIP-1193 wallet provider
|
|
20
20
|
await sdk.connect(provider);
|
|
21
21
|
|
|
22
|
-
// Activate agents on Base (
|
|
22
|
+
// Activate agents on Base (creates and initializes provider wallets as needed)
|
|
23
23
|
await sdk.activateAgent(8453);
|
|
24
24
|
|
|
25
25
|
// Get balances across all agents
|
|
@@ -32,10 +32,10 @@ const balances = await sdk.getBalances();
|
|
|
32
32
|
|
|
33
33
|
Create a new SDK instance.
|
|
34
34
|
|
|
35
|
-
| Param
|
|
36
|
-
|
|
|
37
|
-
| `config.apiKey`
|
|
38
|
-
| `config.zyfaiRpcUrls`
|
|
35
|
+
| Param | Type | Description |
|
|
36
|
+
| --------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `config.apiKey` | `string` | Your Owney API key, used to authenticate with the routing API and fetch agent-specific keys |
|
|
38
|
+
| `config.zyfaiRpcUrls` | `{ 8453?: string; 42161?: string }` (optional) | Per-chain RPC URL overrides used by Zyfai SDK network calls |
|
|
39
39
|
|
|
40
40
|
```typescript
|
|
41
41
|
import { OwneySDK } from "@owney/sdk";
|
|
@@ -108,7 +108,7 @@ if (chainId) {
|
|
|
108
108
|
|
|
109
109
|
### `activateAgent(chainId, agentId?)`
|
|
110
110
|
|
|
111
|
-
Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted.
|
|
111
|
+
Activate the user's smart wallet for the specified agents, or all chain-compatible agents if omitted. Activation performs each provider's required setup before deposits are allowed. For Yieldseeker, this creates the user and agent when needed and calls the agent `/deploy` endpoint before any funding transfer. Saves the chainId for use by all subsequent SDK calls.
|
|
112
112
|
|
|
113
113
|
| Param | Type | Description |
|
|
114
114
|
| --------- | ---------------------- | ----------------------------------------------------------------------------- |
|
|
@@ -125,7 +125,7 @@ await sdk.activateAgent(42161);
|
|
|
125
125
|
|
|
126
126
|
### `deposit(options)`
|
|
127
127
|
|
|
128
|
-
Deposit funds into a specific agent, or split equally across all agents if `agentId` is omitted. Validates that the asset is supported by the target agent(s) on the active chain, and per-agent minimum deposit amounts (defined per chain+asset on `agent.supportedAssets[].assets[].minDepositAmount`) are taken into account.
|
|
128
|
+
Deposit funds into a specific agent, or split equally across all agents if `agentId` is omitted. Validates that the asset is supported by the target agent(s) on the active chain, and per-agent minimum deposit amounts (defined per chain+asset on `agent.supportedAssets[].assets[].minDepositAmount`) are taken into account. Custom `depositCallback` implementations run once per final valid agent. The default Permit2 flow signs one recipient-bound batch authorization for every agent share.
|
|
129
129
|
|
|
130
130
|
| Param | Type | Description |
|
|
131
131
|
| ------------------------- | -------------------- | --------------------------------------------------------------- |
|
package/dist/index.cjs
CHANGED
|
@@ -2235,7 +2235,12 @@ async function postSponsorBatchTransfer(input) {
|
|
|
2235
2235
|
// src/lib/permit2.ts
|
|
2236
2236
|
var import_viem3 = require("viem");
|
|
2237
2237
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2238
|
-
|
|
2238
|
+
function permit2ApprovalAmount(requiredAmount) {
|
|
2239
|
+
if (requiredAmount <= 0n) {
|
|
2240
|
+
throw new Error("Permit2 approval requires a positive deposit amount");
|
|
2241
|
+
}
|
|
2242
|
+
return requiredAmount;
|
|
2243
|
+
}
|
|
2239
2244
|
var ERC20_ALLOWANCE_ABI = [
|
|
2240
2245
|
{
|
|
2241
2246
|
type: "function",
|
|
@@ -2985,7 +2990,7 @@ function depositDestination(context, movement) {
|
|
|
2985
2990
|
if (receipt && minted) return { protocol: "Vault", pool: receipt.name || receipt.symbol, tokenSymbol: context.asset };
|
|
2986
2991
|
return void 0;
|
|
2987
2992
|
}
|
|
2988
|
-
function movementEntry(movement, wallet, agent, asset, ownerAddress, destination) {
|
|
2993
|
+
function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses, destination) {
|
|
2989
2994
|
const from = movement.fromAddress.toLowerCase();
|
|
2990
2995
|
const to = movement.toAddress.toLowerCase();
|
|
2991
2996
|
const owner = ownerAddress.toLowerCase();
|
|
@@ -2995,7 +3000,7 @@ function movementEntry(movement, wallet, agent, asset, ownerAddress, destination
|
|
|
2995
3000
|
return void 0;
|
|
2996
3001
|
}
|
|
2997
3002
|
let action;
|
|
2998
|
-
if (
|
|
3003
|
+
if (to === agentWallet && !vaultAddresses.has(from)) {
|
|
2999
3004
|
action = "Top up";
|
|
3000
3005
|
} else if (from === agentWallet && to === owner) {
|
|
3001
3006
|
action = "Withdraw";
|
|
@@ -3045,6 +3050,7 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
3045
3050
|
context.agent,
|
|
3046
3051
|
context.asset,
|
|
3047
3052
|
options.ownerAddress,
|
|
3053
|
+
options.vaultAddresses,
|
|
3048
3054
|
depositDestination(context, movement)
|
|
3049
3055
|
)
|
|
3050
3056
|
),
|
|
@@ -3125,6 +3131,7 @@ var OWNEY_AGENT_NAME = "owney";
|
|
|
3125
3131
|
var YIELDSEEKER_USERNAME_PREFIX = "owney_";
|
|
3126
3132
|
var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
|
|
3127
3133
|
var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
|
|
3134
|
+
var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
|
|
3128
3135
|
function generateYieldseekerUsername() {
|
|
3129
3136
|
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3130
3137
|
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
@@ -3186,6 +3193,8 @@ var YieldseekerAgent = class {
|
|
|
3186
3193
|
agentContexts = /* @__PURE__ */ new Map();
|
|
3187
3194
|
users = /* @__PURE__ */ new Map();
|
|
3188
3195
|
pendingAgents = /* @__PURE__ */ new Map();
|
|
3196
|
+
yieldOptions = /* @__PURE__ */ new Map();
|
|
3197
|
+
pendingYieldOptions = /* @__PURE__ */ new Map();
|
|
3189
3198
|
constructor(owneyApiKey, options = {}) {
|
|
3190
3199
|
this.api = new YieldseekerApiClient(
|
|
3191
3200
|
owneyApiKey,
|
|
@@ -3252,7 +3261,6 @@ var YieldseekerAgent = class {
|
|
|
3252
3261
|
chainId
|
|
3253
3262
|
});
|
|
3254
3263
|
}
|
|
3255
|
-
await this.deployAfterFunding(state, chainId, context);
|
|
3256
3264
|
} finally {
|
|
3257
3265
|
await this.refreshSnapshotAfterMovement(
|
|
3258
3266
|
state,
|
|
@@ -3404,9 +3412,20 @@ var YieldseekerAgent = class {
|
|
|
3404
3412
|
historic: true,
|
|
3405
3413
|
actions: true
|
|
3406
3414
|
});
|
|
3415
|
+
const catalog = await Promise.all(
|
|
3416
|
+
[...new Set(contexts.map((context) => context.asset))].map(
|
|
3417
|
+
(contextAsset) => this.loadYieldOptions(contextAsset)
|
|
3418
|
+
)
|
|
3419
|
+
);
|
|
3420
|
+
const vaultAddresses = new Set(
|
|
3421
|
+
catalog.flat().filter(
|
|
3422
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem6.isAddress)(yieldOption.address)
|
|
3423
|
+
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
3424
|
+
);
|
|
3407
3425
|
return mapYieldseekerHistory(contexts, {
|
|
3408
3426
|
limit: options?.limit ?? 10,
|
|
3409
3427
|
ownerAddress: state.walletAddress,
|
|
3428
|
+
vaultAddresses,
|
|
3410
3429
|
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
3411
3430
|
...options?.toDate ? { toDate: options.toDate } : {}
|
|
3412
3431
|
});
|
|
@@ -3425,18 +3444,32 @@ var YieldseekerAgent = class {
|
|
|
3425
3444
|
const assets = requested ? [requested] : ["USDC", "WETH"];
|
|
3426
3445
|
const values = await Promise.all(
|
|
3427
3446
|
assets.map(async (asset) => {
|
|
3428
|
-
|
|
3429
|
-
const response = await this.api.request(
|
|
3430
|
-
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3431
|
-
);
|
|
3432
|
-
if (!Array.isArray(response?.yieldOptions)) {
|
|
3433
|
-
throw this.invalidResponse("yield options");
|
|
3434
|
-
}
|
|
3435
|
-
return { asset, yieldOptions: response.yieldOptions };
|
|
3447
|
+
return { asset, yieldOptions: await this.loadYieldOptions(asset) };
|
|
3436
3448
|
})
|
|
3437
3449
|
);
|
|
3438
3450
|
return mapYieldseekerAgentApy(values, days);
|
|
3439
3451
|
}
|
|
3452
|
+
async loadYieldOptions(asset) {
|
|
3453
|
+
const cached = this.yieldOptions.get(asset);
|
|
3454
|
+
if (cached && cached.expiresAt > Date.now()) return cached.value;
|
|
3455
|
+
const pending = this.pendingYieldOptions.get(asset);
|
|
3456
|
+
if (pending) return pending;
|
|
3457
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3458
|
+
const request = this.api.request(
|
|
3459
|
+
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3460
|
+
).then((response) => {
|
|
3461
|
+
if (!Array.isArray(response?.yieldOptions)) {
|
|
3462
|
+
throw this.invalidResponse("yield options");
|
|
3463
|
+
}
|
|
3464
|
+
this.yieldOptions.set(asset, {
|
|
3465
|
+
expiresAt: Date.now() + YIELDSEEKER_YIELD_OPTIONS_CACHE_MS,
|
|
3466
|
+
value: response.yieldOptions
|
|
3467
|
+
});
|
|
3468
|
+
return response.yieldOptions;
|
|
3469
|
+
}).finally(() => this.pendingYieldOptions.delete(asset));
|
|
3470
|
+
this.pendingYieldOptions.set(asset, request);
|
|
3471
|
+
return request;
|
|
3472
|
+
}
|
|
3440
3473
|
userKey(state, chainId) {
|
|
3441
3474
|
return `${state.walletAddress.toLowerCase()}:${chainId}`;
|
|
3442
3475
|
}
|
|
@@ -3515,8 +3548,9 @@ var YieldseekerAgent = class {
|
|
|
3515
3548
|
const pending = this.pendingAgents.get(key2);
|
|
3516
3549
|
if (pending) return pending;
|
|
3517
3550
|
const request = this.resolveAgent(state, chainId, asset, true).then(
|
|
3518
|
-
(context) => {
|
|
3551
|
+
async (context) => {
|
|
3519
3552
|
if (!context) throw this.invalidResponse("agent creation");
|
|
3553
|
+
await this.deployAgent(state, chainId, context);
|
|
3520
3554
|
this.agentContexts.set(key2, context);
|
|
3521
3555
|
return context;
|
|
3522
3556
|
}
|
|
@@ -3661,24 +3695,21 @@ var YieldseekerAgent = class {
|
|
|
3661
3695
|
...actions?.actions ? { actions: actions.actions } : {}
|
|
3662
3696
|
};
|
|
3663
3697
|
}
|
|
3664
|
-
async
|
|
3698
|
+
async deployAgent(state, chainId, context) {
|
|
3665
3699
|
if (context.wallet.initializedDate != null) return;
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
console.warn(
|
|
3678
|
-
"[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
|
|
3679
|
-
error
|
|
3680
|
-
);
|
|
3700
|
+
const walletAddress = context.wallet.walletAddress.toLowerCase();
|
|
3701
|
+
const deployed = await this.walletRequest(
|
|
3702
|
+
state,
|
|
3703
|
+
chainId,
|
|
3704
|
+
this.agentPath(context, "deploy"),
|
|
3705
|
+
{ method: "POST", body: {} }
|
|
3706
|
+
);
|
|
3707
|
+
if (!deployed?.agentWallet || !(0, import_viem6.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
3708
|
+
throw this.invalidResponse("agent deployment", {
|
|
3709
|
+
reason: "Deploy did not return the expected Agent Wallet."
|
|
3710
|
+
});
|
|
3681
3711
|
}
|
|
3712
|
+
context.wallet = deployed.agentWallet;
|
|
3682
3713
|
}
|
|
3683
3714
|
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
3684
3715
|
try {
|
|
@@ -5246,7 +5277,14 @@ var OwneySDK = class {
|
|
|
5246
5277
|
} catch (error) {
|
|
5247
5278
|
if (!(error instanceof OwneyError) || error.code !== "PERMIT2_APPROVAL_REQUIRED")
|
|
5248
5279
|
throw error;
|
|
5249
|
-
|
|
5280
|
+
const requiredAmount = transfers.reduce(
|
|
5281
|
+
(sum, transfer) => sum + BigInt(transfer.amount),
|
|
5282
|
+
0n
|
|
5283
|
+
);
|
|
5284
|
+
await this.approvePermit2(
|
|
5285
|
+
asset,
|
|
5286
|
+
requiredAmount
|
|
5287
|
+
);
|
|
5250
5288
|
return batchTransfer(cid, transfers);
|
|
5251
5289
|
}
|
|
5252
5290
|
}
|
|
@@ -5333,7 +5371,10 @@ var OwneySDK = class {
|
|
|
5333
5371
|
console.warn(
|
|
5334
5372
|
"[owney-sdk] First token deposit: sending one-time Permit2 approval..."
|
|
5335
5373
|
);
|
|
5336
|
-
await this.approvePermit2(
|
|
5374
|
+
await this.approvePermit2(
|
|
5375
|
+
asset,
|
|
5376
|
+
BigInt(amount)
|
|
5377
|
+
);
|
|
5337
5378
|
continue;
|
|
5338
5379
|
}
|
|
5339
5380
|
if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
|
|
@@ -5986,14 +6027,15 @@ var OwneySDK = class {
|
|
|
5986
6027
|
return pending;
|
|
5987
6028
|
}
|
|
5988
6029
|
/**
|
|
5989
|
-
*
|
|
5990
|
-
*
|
|
5991
|
-
*
|
|
5992
|
-
*
|
|
5993
|
-
*
|
|
6030
|
+
* User-paid approval of Permit2 on the selected token for the active chain.
|
|
6031
|
+
* Approves exactly the pending deposit amount. Another approval is required
|
|
6032
|
+
* for a later deposit once this allowance has been consumed. Resolves after
|
|
6033
|
+
* one confirmation so the subsequent deposit attempt sees the new allowance.
|
|
6034
|
+
*
|
|
6035
|
+
* @param requiredAmount Raw base-unit amount the pending deposit must cover.
|
|
5994
6036
|
* @returns the approval transaction hash.
|
|
5995
6037
|
*/
|
|
5996
|
-
async approvePermit2(asset = "WETH") {
|
|
6038
|
+
async approvePermit2(asset = "WETH", requiredAmount = 0n) {
|
|
5997
6039
|
const state = this.requireState();
|
|
5998
6040
|
const chainId = this.requireChainId();
|
|
5999
6041
|
this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
|
|
@@ -6005,6 +6047,11 @@ var OwneySDK = class {
|
|
|
6005
6047
|
);
|
|
6006
6048
|
}
|
|
6007
6049
|
const provider = this.requireConnectedProvider();
|
|
6050
|
+
const publicClient = (0, import_viem11.createPublicClient)({
|
|
6051
|
+
chain: VIEM_CHAIN2[chainId],
|
|
6052
|
+
transport: (0, import_viem11.custom)(provider)
|
|
6053
|
+
});
|
|
6054
|
+
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
6008
6055
|
const wallet = (0, import_viem11.createWalletClient)({
|
|
6009
6056
|
account: state.walletAddress,
|
|
6010
6057
|
chain: VIEM_CHAIN2[chainId],
|
|
@@ -6014,14 +6061,10 @@ var OwneySDK = class {
|
|
|
6014
6061
|
address: token,
|
|
6015
6062
|
abi: ERC20_ALLOWANCE_ABI,
|
|
6016
6063
|
functionName: "approve",
|
|
6017
|
-
args: [PERMIT2_ADDRESS,
|
|
6064
|
+
args: [PERMIT2_ADDRESS, approvalAmount],
|
|
6018
6065
|
account: state.walletAddress,
|
|
6019
6066
|
chain: VIEM_CHAIN2[chainId]
|
|
6020
6067
|
});
|
|
6021
|
-
const publicClient = (0, import_viem11.createPublicClient)({
|
|
6022
|
-
chain: VIEM_CHAIN2[chainId],
|
|
6023
|
-
transport: (0, import_viem11.custom)(provider)
|
|
6024
|
-
});
|
|
6025
6068
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
6026
6069
|
hash,
|
|
6027
6070
|
confirmations: 1
|
package/dist/index.d.cts
CHANGED
|
@@ -719,14 +719,15 @@ declare class OwneySDK {
|
|
|
719
719
|
*/
|
|
720
720
|
ensureAutoSelectProtocols(asset: "USDC" | "WETH", agentId?: AgentId): Promise<boolean>;
|
|
721
721
|
/**
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
722
|
+
* User-paid approval of Permit2 on the selected token for the active chain.
|
|
723
|
+
* Approves exactly the pending deposit amount. Another approval is required
|
|
724
|
+
* for a later deposit once this allowance has been consumed. Resolves after
|
|
725
|
+
* one confirmation so the subsequent deposit attempt sees the new allowance.
|
|
726
|
+
*
|
|
727
|
+
* @param requiredAmount Raw base-unit amount the pending deposit must cover.
|
|
727
728
|
* @returns the approval transaction hash.
|
|
728
729
|
*/
|
|
729
|
-
approvePermit2(asset?: OwneySupportedTokens): Promise<`0x${string}`>;
|
|
730
|
+
approvePermit2(asset?: OwneySupportedTokens, requiredAmount?: bigint): Promise<`0x${string}`>;
|
|
730
731
|
/**
|
|
731
732
|
* Get the agent's average APY performance over a time period. Does not require a wallet connection.
|
|
732
733
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
|
@@ -797,6 +798,8 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
797
798
|
private readonly agentContexts;
|
|
798
799
|
private readonly users;
|
|
799
800
|
private readonly pendingAgents;
|
|
801
|
+
private readonly yieldOptions;
|
|
802
|
+
private readonly pendingYieldOptions;
|
|
800
803
|
constructor(owneyApiKey: string, options?: YieldseekerAgentOptions);
|
|
801
804
|
disconnect(): Promise<void>;
|
|
802
805
|
activateAgent(state: ConnectionState, chainId: number, asset?: OwneySupportedTokens): Promise<void>;
|
|
@@ -808,6 +811,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
808
811
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
809
812
|
getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
|
|
810
813
|
getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
|
|
814
|
+
private loadYieldOptions;
|
|
811
815
|
private userKey;
|
|
812
816
|
private contextKey;
|
|
813
817
|
private resolveUser;
|
|
@@ -817,7 +821,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
817
821
|
private resolveAgent;
|
|
818
822
|
private loadPortfolio;
|
|
819
823
|
private loadPortfolioContext;
|
|
820
|
-
private
|
|
824
|
+
private deployAgent;
|
|
821
825
|
private refreshSnapshotAfterMovement;
|
|
822
826
|
private agentPath;
|
|
823
827
|
private walletRequest;
|
package/dist/index.d.ts
CHANGED
|
@@ -719,14 +719,15 @@ declare class OwneySDK {
|
|
|
719
719
|
*/
|
|
720
720
|
ensureAutoSelectProtocols(asset: "USDC" | "WETH", agentId?: AgentId): Promise<boolean>;
|
|
721
721
|
/**
|
|
722
|
-
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
722
|
+
* User-paid approval of Permit2 on the selected token for the active chain.
|
|
723
|
+
* Approves exactly the pending deposit amount. Another approval is required
|
|
724
|
+
* for a later deposit once this allowance has been consumed. Resolves after
|
|
725
|
+
* one confirmation so the subsequent deposit attempt sees the new allowance.
|
|
726
|
+
*
|
|
727
|
+
* @param requiredAmount Raw base-unit amount the pending deposit must cover.
|
|
727
728
|
* @returns the approval transaction hash.
|
|
728
729
|
*/
|
|
729
|
-
approvePermit2(asset?: OwneySupportedTokens): Promise<`0x${string}`>;
|
|
730
|
+
approvePermit2(asset?: OwneySupportedTokens, requiredAmount?: bigint): Promise<`0x${string}`>;
|
|
730
731
|
/**
|
|
731
732
|
* Get the agent's average APY performance over a time period. Does not require a wallet connection.
|
|
732
733
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
|
@@ -797,6 +798,8 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
797
798
|
private readonly agentContexts;
|
|
798
799
|
private readonly users;
|
|
799
800
|
private readonly pendingAgents;
|
|
801
|
+
private readonly yieldOptions;
|
|
802
|
+
private readonly pendingYieldOptions;
|
|
800
803
|
constructor(owneyApiKey: string, options?: YieldseekerAgentOptions);
|
|
801
804
|
disconnect(): Promise<void>;
|
|
802
805
|
activateAgent(state: ConnectionState, chainId: number, asset?: OwneySupportedTokens): Promise<void>;
|
|
@@ -808,6 +811,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
808
811
|
getHistory(state: ConnectionState, chainId: number, options?: HistoryFilters): Promise<OwneyAgentHistory>;
|
|
809
812
|
getUserProfile(state: ConnectionState, chainId: number): Promise<AgentUserProfile>;
|
|
810
813
|
getAgentApy(days: DailyApyDays, options?: AgentApyOptions): Promise<AgentApy>;
|
|
814
|
+
private loadYieldOptions;
|
|
811
815
|
private userKey;
|
|
812
816
|
private contextKey;
|
|
813
817
|
private resolveUser;
|
|
@@ -817,7 +821,7 @@ declare class YieldseekerAgent implements IAgent {
|
|
|
817
821
|
private resolveAgent;
|
|
818
822
|
private loadPortfolio;
|
|
819
823
|
private loadPortfolioContext;
|
|
820
|
-
private
|
|
824
|
+
private deployAgent;
|
|
821
825
|
private refreshSnapshotAfterMovement;
|
|
822
826
|
private agentPath;
|
|
823
827
|
private walletRequest;
|
package/dist/index.js
CHANGED
|
@@ -2209,7 +2209,12 @@ async function postSponsorBatchTransfer(input) {
|
|
|
2209
2209
|
// src/lib/permit2.ts
|
|
2210
2210
|
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2211
2211
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2212
|
-
|
|
2212
|
+
function permit2ApprovalAmount(requiredAmount) {
|
|
2213
|
+
if (requiredAmount <= 0n) {
|
|
2214
|
+
throw new Error("Permit2 approval requires a positive deposit amount");
|
|
2215
|
+
}
|
|
2216
|
+
return requiredAmount;
|
|
2217
|
+
}
|
|
2213
2218
|
var ERC20_ALLOWANCE_ABI = [
|
|
2214
2219
|
{
|
|
2215
2220
|
type: "function",
|
|
@@ -2964,7 +2969,7 @@ function depositDestination(context, movement) {
|
|
|
2964
2969
|
if (receipt && minted) return { protocol: "Vault", pool: receipt.name || receipt.symbol, tokenSymbol: context.asset };
|
|
2965
2970
|
return void 0;
|
|
2966
2971
|
}
|
|
2967
|
-
function movementEntry(movement, wallet, agent, asset, ownerAddress, destination) {
|
|
2972
|
+
function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses, destination) {
|
|
2968
2973
|
const from = movement.fromAddress.toLowerCase();
|
|
2969
2974
|
const to = movement.toAddress.toLowerCase();
|
|
2970
2975
|
const owner = ownerAddress.toLowerCase();
|
|
@@ -2974,7 +2979,7 @@ function movementEntry(movement, wallet, agent, asset, ownerAddress, destination
|
|
|
2974
2979
|
return void 0;
|
|
2975
2980
|
}
|
|
2976
2981
|
let action;
|
|
2977
|
-
if (
|
|
2982
|
+
if (to === agentWallet && !vaultAddresses.has(from)) {
|
|
2978
2983
|
action = "Top up";
|
|
2979
2984
|
} else if (from === agentWallet && to === owner) {
|
|
2980
2985
|
action = "Withdraw";
|
|
@@ -3024,6 +3029,7 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
3024
3029
|
context.agent,
|
|
3025
3030
|
context.asset,
|
|
3026
3031
|
options.ownerAddress,
|
|
3032
|
+
options.vaultAddresses,
|
|
3027
3033
|
depositDestination(context, movement)
|
|
3028
3034
|
)
|
|
3029
3035
|
),
|
|
@@ -3104,6 +3110,7 @@ var OWNEY_AGENT_NAME = "owney";
|
|
|
3104
3110
|
var YIELDSEEKER_USERNAME_PREFIX = "owney_";
|
|
3105
3111
|
var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
|
|
3106
3112
|
var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
|
|
3113
|
+
var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
|
|
3107
3114
|
function generateYieldseekerUsername() {
|
|
3108
3115
|
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3109
3116
|
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
@@ -3165,6 +3172,8 @@ var YieldseekerAgent = class {
|
|
|
3165
3172
|
agentContexts = /* @__PURE__ */ new Map();
|
|
3166
3173
|
users = /* @__PURE__ */ new Map();
|
|
3167
3174
|
pendingAgents = /* @__PURE__ */ new Map();
|
|
3175
|
+
yieldOptions = /* @__PURE__ */ new Map();
|
|
3176
|
+
pendingYieldOptions = /* @__PURE__ */ new Map();
|
|
3168
3177
|
constructor(owneyApiKey, options = {}) {
|
|
3169
3178
|
this.api = new YieldseekerApiClient(
|
|
3170
3179
|
owneyApiKey,
|
|
@@ -3231,7 +3240,6 @@ var YieldseekerAgent = class {
|
|
|
3231
3240
|
chainId
|
|
3232
3241
|
});
|
|
3233
3242
|
}
|
|
3234
|
-
await this.deployAfterFunding(state, chainId, context);
|
|
3235
3243
|
} finally {
|
|
3236
3244
|
await this.refreshSnapshotAfterMovement(
|
|
3237
3245
|
state,
|
|
@@ -3383,9 +3391,20 @@ var YieldseekerAgent = class {
|
|
|
3383
3391
|
historic: true,
|
|
3384
3392
|
actions: true
|
|
3385
3393
|
});
|
|
3394
|
+
const catalog = await Promise.all(
|
|
3395
|
+
[...new Set(contexts.map((context) => context.asset))].map(
|
|
3396
|
+
(contextAsset) => this.loadYieldOptions(contextAsset)
|
|
3397
|
+
)
|
|
3398
|
+
);
|
|
3399
|
+
const vaultAddresses = new Set(
|
|
3400
|
+
catalog.flat().filter(
|
|
3401
|
+
(yieldOption) => yieldOption.chainId === chainId && isAddress2(yieldOption.address)
|
|
3402
|
+
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
3403
|
+
);
|
|
3386
3404
|
return mapYieldseekerHistory(contexts, {
|
|
3387
3405
|
limit: options?.limit ?? 10,
|
|
3388
3406
|
ownerAddress: state.walletAddress,
|
|
3407
|
+
vaultAddresses,
|
|
3389
3408
|
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
3390
3409
|
...options?.toDate ? { toDate: options.toDate } : {}
|
|
3391
3410
|
});
|
|
@@ -3404,18 +3423,32 @@ var YieldseekerAgent = class {
|
|
|
3404
3423
|
const assets = requested ? [requested] : ["USDC", "WETH"];
|
|
3405
3424
|
const values = await Promise.all(
|
|
3406
3425
|
assets.map(async (asset) => {
|
|
3407
|
-
|
|
3408
|
-
const response = await this.api.request(
|
|
3409
|
-
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3410
|
-
);
|
|
3411
|
-
if (!Array.isArray(response?.yieldOptions)) {
|
|
3412
|
-
throw this.invalidResponse("yield options");
|
|
3413
|
-
}
|
|
3414
|
-
return { asset, yieldOptions: response.yieldOptions };
|
|
3426
|
+
return { asset, yieldOptions: await this.loadYieldOptions(asset) };
|
|
3415
3427
|
})
|
|
3416
3428
|
);
|
|
3417
3429
|
return mapYieldseekerAgentApy(values, days);
|
|
3418
3430
|
}
|
|
3431
|
+
async loadYieldOptions(asset) {
|
|
3432
|
+
const cached = this.yieldOptions.get(asset);
|
|
3433
|
+
if (cached && cached.expiresAt > Date.now()) return cached.value;
|
|
3434
|
+
const pending = this.pendingYieldOptions.get(asset);
|
|
3435
|
+
if (pending) return pending;
|
|
3436
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3437
|
+
const request = this.api.request(
|
|
3438
|
+
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3439
|
+
).then((response) => {
|
|
3440
|
+
if (!Array.isArray(response?.yieldOptions)) {
|
|
3441
|
+
throw this.invalidResponse("yield options");
|
|
3442
|
+
}
|
|
3443
|
+
this.yieldOptions.set(asset, {
|
|
3444
|
+
expiresAt: Date.now() + YIELDSEEKER_YIELD_OPTIONS_CACHE_MS,
|
|
3445
|
+
value: response.yieldOptions
|
|
3446
|
+
});
|
|
3447
|
+
return response.yieldOptions;
|
|
3448
|
+
}).finally(() => this.pendingYieldOptions.delete(asset));
|
|
3449
|
+
this.pendingYieldOptions.set(asset, request);
|
|
3450
|
+
return request;
|
|
3451
|
+
}
|
|
3419
3452
|
userKey(state, chainId) {
|
|
3420
3453
|
return `${state.walletAddress.toLowerCase()}:${chainId}`;
|
|
3421
3454
|
}
|
|
@@ -3494,8 +3527,9 @@ var YieldseekerAgent = class {
|
|
|
3494
3527
|
const pending = this.pendingAgents.get(key2);
|
|
3495
3528
|
if (pending) return pending;
|
|
3496
3529
|
const request = this.resolveAgent(state, chainId, asset, true).then(
|
|
3497
|
-
(context) => {
|
|
3530
|
+
async (context) => {
|
|
3498
3531
|
if (!context) throw this.invalidResponse("agent creation");
|
|
3532
|
+
await this.deployAgent(state, chainId, context);
|
|
3499
3533
|
this.agentContexts.set(key2, context);
|
|
3500
3534
|
return context;
|
|
3501
3535
|
}
|
|
@@ -3640,24 +3674,21 @@ var YieldseekerAgent = class {
|
|
|
3640
3674
|
...actions?.actions ? { actions: actions.actions } : {}
|
|
3641
3675
|
};
|
|
3642
3676
|
}
|
|
3643
|
-
async
|
|
3677
|
+
async deployAgent(state, chainId, context) {
|
|
3644
3678
|
if (context.wallet.initializedDate != null) return;
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
console.warn(
|
|
3657
|
-
"[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
|
|
3658
|
-
error
|
|
3659
|
-
);
|
|
3679
|
+
const walletAddress = context.wallet.walletAddress.toLowerCase();
|
|
3680
|
+
const deployed = await this.walletRequest(
|
|
3681
|
+
state,
|
|
3682
|
+
chainId,
|
|
3683
|
+
this.agentPath(context, "deploy"),
|
|
3684
|
+
{ method: "POST", body: {} }
|
|
3685
|
+
);
|
|
3686
|
+
if (!deployed?.agentWallet || !isAddress2(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
3687
|
+
throw this.invalidResponse("agent deployment", {
|
|
3688
|
+
reason: "Deploy did not return the expected Agent Wallet."
|
|
3689
|
+
});
|
|
3660
3690
|
}
|
|
3691
|
+
context.wallet = deployed.agentWallet;
|
|
3661
3692
|
}
|
|
3662
3693
|
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
3663
3694
|
try {
|
|
@@ -5233,7 +5264,14 @@ var OwneySDK = class {
|
|
|
5233
5264
|
} catch (error) {
|
|
5234
5265
|
if (!(error instanceof OwneyError) || error.code !== "PERMIT2_APPROVAL_REQUIRED")
|
|
5235
5266
|
throw error;
|
|
5236
|
-
|
|
5267
|
+
const requiredAmount = transfers.reduce(
|
|
5268
|
+
(sum, transfer) => sum + BigInt(transfer.amount),
|
|
5269
|
+
0n
|
|
5270
|
+
);
|
|
5271
|
+
await this.approvePermit2(
|
|
5272
|
+
asset,
|
|
5273
|
+
requiredAmount
|
|
5274
|
+
);
|
|
5237
5275
|
return batchTransfer(cid, transfers);
|
|
5238
5276
|
}
|
|
5239
5277
|
}
|
|
@@ -5320,7 +5358,10 @@ var OwneySDK = class {
|
|
|
5320
5358
|
console.warn(
|
|
5321
5359
|
"[owney-sdk] First token deposit: sending one-time Permit2 approval..."
|
|
5322
5360
|
);
|
|
5323
|
-
await this.approvePermit2(
|
|
5361
|
+
await this.approvePermit2(
|
|
5362
|
+
asset,
|
|
5363
|
+
BigInt(amount)
|
|
5364
|
+
);
|
|
5324
5365
|
continue;
|
|
5325
5366
|
}
|
|
5326
5367
|
if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
|
|
@@ -5973,14 +6014,15 @@ var OwneySDK = class {
|
|
|
5973
6014
|
return pending;
|
|
5974
6015
|
}
|
|
5975
6016
|
/**
|
|
5976
|
-
*
|
|
5977
|
-
*
|
|
5978
|
-
*
|
|
5979
|
-
*
|
|
5980
|
-
*
|
|
6017
|
+
* User-paid approval of Permit2 on the selected token for the active chain.
|
|
6018
|
+
* Approves exactly the pending deposit amount. Another approval is required
|
|
6019
|
+
* for a later deposit once this allowance has been consumed. Resolves after
|
|
6020
|
+
* one confirmation so the subsequent deposit attempt sees the new allowance.
|
|
6021
|
+
*
|
|
6022
|
+
* @param requiredAmount Raw base-unit amount the pending deposit must cover.
|
|
5981
6023
|
* @returns the approval transaction hash.
|
|
5982
6024
|
*/
|
|
5983
|
-
async approvePermit2(asset = "WETH") {
|
|
6025
|
+
async approvePermit2(asset = "WETH", requiredAmount = 0n) {
|
|
5984
6026
|
const state = this.requireState();
|
|
5985
6027
|
const chainId = this.requireChainId();
|
|
5986
6028
|
this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
|
|
@@ -5992,6 +6034,11 @@ var OwneySDK = class {
|
|
|
5992
6034
|
);
|
|
5993
6035
|
}
|
|
5994
6036
|
const provider = this.requireConnectedProvider();
|
|
6037
|
+
const publicClient = createPublicClient4({
|
|
6038
|
+
chain: VIEM_CHAIN2[chainId],
|
|
6039
|
+
transport: custom3(provider)
|
|
6040
|
+
});
|
|
6041
|
+
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
5995
6042
|
const wallet = createWalletClient3({
|
|
5996
6043
|
account: state.walletAddress,
|
|
5997
6044
|
chain: VIEM_CHAIN2[chainId],
|
|
@@ -6001,14 +6048,10 @@ var OwneySDK = class {
|
|
|
6001
6048
|
address: token,
|
|
6002
6049
|
abi: ERC20_ALLOWANCE_ABI,
|
|
6003
6050
|
functionName: "approve",
|
|
6004
|
-
args: [PERMIT2_ADDRESS,
|
|
6051
|
+
args: [PERMIT2_ADDRESS, approvalAmount],
|
|
6005
6052
|
account: state.walletAddress,
|
|
6006
6053
|
chain: VIEM_CHAIN2[chainId]
|
|
6007
6054
|
});
|
|
6008
|
-
const publicClient = createPublicClient4({
|
|
6009
|
-
chain: VIEM_CHAIN2[chainId],
|
|
6010
|
-
transport: custom3(provider)
|
|
6011
|
-
});
|
|
6012
6055
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
6013
6056
|
hash,
|
|
6014
6057
|
confirmations: 1
|