@owney/sdk 0.4.5 → 0.5.0-beta.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/dist/index.cjs +175 -2
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +179 -2
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -933,6 +933,130 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
933
933
|
return out;
|
|
934
934
|
}
|
|
935
935
|
|
|
936
|
+
// src/client.ts
|
|
937
|
+
var import_viem3 = require("viem");
|
|
938
|
+
var import_chains = require("viem/chains");
|
|
939
|
+
|
|
940
|
+
// src/lib/transfer-auth.ts
|
|
941
|
+
var import_viem2 = require("viem");
|
|
942
|
+
var ERC20_META_ABI = [
|
|
943
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
944
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
945
|
+
];
|
|
946
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
947
|
+
return {
|
|
948
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
949
|
+
types: {
|
|
950
|
+
TransferWithAuthorization: [
|
|
951
|
+
{ name: "from", type: "address" },
|
|
952
|
+
{ name: "to", type: "address" },
|
|
953
|
+
{ name: "value", type: "uint256" },
|
|
954
|
+
{ name: "validAfter", type: "uint256" },
|
|
955
|
+
{ name: "validBefore", type: "uint256" },
|
|
956
|
+
{ name: "nonce", type: "bytes32" }
|
|
957
|
+
]
|
|
958
|
+
},
|
|
959
|
+
primaryType: "TransferWithAuthorization",
|
|
960
|
+
message: input.message
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
async function readTokenMeta(publicClient, token) {
|
|
964
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
965
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
966
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
967
|
+
]);
|
|
968
|
+
return { tokenName, tokenVersion };
|
|
969
|
+
}
|
|
970
|
+
function randomAuthNonce() {
|
|
971
|
+
const bytes = new Uint8Array(32);
|
|
972
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
973
|
+
return (0, import_viem2.bytesToHex)(bytes);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// src/lib/sponsor-client.ts
|
|
977
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
978
|
+
async function postSponsorTransferAuth(input) {
|
|
979
|
+
const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
980
|
+
let res;
|
|
981
|
+
try {
|
|
982
|
+
res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
983
|
+
method: "POST",
|
|
984
|
+
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
985
|
+
body: JSON.stringify(input.body)
|
|
986
|
+
});
|
|
987
|
+
} catch (networkError) {
|
|
988
|
+
throw new OwneyError(
|
|
989
|
+
"SPONSOR_REQUEST_FAILED",
|
|
990
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
991
|
+
{ cause: String(networkError) }
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
const text = await res.text();
|
|
995
|
+
let parsed = null;
|
|
996
|
+
try {
|
|
997
|
+
parsed = JSON.parse(text);
|
|
998
|
+
} catch {
|
|
999
|
+
}
|
|
1000
|
+
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
1001
|
+
throw new OwneyError(
|
|
1002
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1003
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
1004
|
+
{ statusCode: res.status, responseBody: text.slice(0, 500) }
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
return parsed.data;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// src/lib/sponsored-deposit.ts
|
|
1011
|
+
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
1012
|
+
function makeSponsoredDepositCallback(deps) {
|
|
1013
|
+
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
1014
|
+
return async (smartWallet, chainId, amount) => {
|
|
1015
|
+
const cid = chainId;
|
|
1016
|
+
const token = deps.tokenAddressByChain[cid];
|
|
1017
|
+
if (!token) {
|
|
1018
|
+
throw new OwneyError(
|
|
1019
|
+
"CHAIN_UNSUPPORTED",
|
|
1020
|
+
`No sponsored token configured for chain ${chainId}`
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
const pub = deps.getPublicClient(cid);
|
|
1024
|
+
const wallet = deps.getWalletClient(cid);
|
|
1025
|
+
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
1026
|
+
const validAfter = 0n;
|
|
1027
|
+
const validBefore = BigInt(Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS);
|
|
1028
|
+
const nonce = randomAuthNonce();
|
|
1029
|
+
const typedData = buildTransferWithAuthorizationTypedData({
|
|
1030
|
+
token,
|
|
1031
|
+
chainId: cid,
|
|
1032
|
+
tokenName,
|
|
1033
|
+
tokenVersion,
|
|
1034
|
+
message: { from: deps.ownerAddress, to: smartWallet, value: BigInt(amount), validAfter, validBefore, nonce }
|
|
1035
|
+
});
|
|
1036
|
+
const authSignature = await wallet.signTypedData(
|
|
1037
|
+
{ account: deps.ownerAddress, ...typedData }
|
|
1038
|
+
);
|
|
1039
|
+
const result = await post({
|
|
1040
|
+
baseUrl: deps.baseUrl,
|
|
1041
|
+
apiKey: deps.apiKey,
|
|
1042
|
+
body: {
|
|
1043
|
+
chainId: cid,
|
|
1044
|
+
token,
|
|
1045
|
+
from: deps.ownerAddress,
|
|
1046
|
+
to: smartWallet,
|
|
1047
|
+
value: amount,
|
|
1048
|
+
validAfter: validAfter.toString(),
|
|
1049
|
+
validBefore: validBefore.toString(),
|
|
1050
|
+
nonce,
|
|
1051
|
+
authSignature,
|
|
1052
|
+
tokenName,
|
|
1053
|
+
tokenVersion
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
return result.txHash;
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
|
|
936
1060
|
// src/client.ts
|
|
937
1061
|
function encodeMultiAgentCursor(map) {
|
|
938
1062
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -954,6 +1078,11 @@ function decodeMultiAgentCursor(token) {
|
|
|
954
1078
|
}
|
|
955
1079
|
return parsed;
|
|
956
1080
|
}
|
|
1081
|
+
var SPONSORED_USDC_BY_CHAIN = {
|
|
1082
|
+
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1083
|
+
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1084
|
+
};
|
|
1085
|
+
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
|
|
957
1086
|
var OwneySDK = class {
|
|
958
1087
|
agents = /* @__PURE__ */ new Map();
|
|
959
1088
|
activeAgents = /* @__PURE__ */ new Set();
|
|
@@ -966,6 +1095,7 @@ var OwneySDK = class {
|
|
|
966
1095
|
state = null;
|
|
967
1096
|
apiKey;
|
|
968
1097
|
zyfaiRpcUrls;
|
|
1098
|
+
cachedSponsoredCallback = null;
|
|
969
1099
|
initializingAgentsPromise = null;
|
|
970
1100
|
constructor(config) {
|
|
971
1101
|
this.apiKey = config.apiKey;
|
|
@@ -989,6 +1119,7 @@ var OwneySDK = class {
|
|
|
989
1119
|
);
|
|
990
1120
|
}
|
|
991
1121
|
this.state = { provider, walletAddress, chainId: null };
|
|
1122
|
+
this.cachedSponsoredCallback = null;
|
|
992
1123
|
}
|
|
993
1124
|
/**
|
|
994
1125
|
* Disconnect from all agents and clear connection state.
|
|
@@ -1001,6 +1132,7 @@ var OwneySDK = class {
|
|
|
1001
1132
|
this.activeAgents.clear();
|
|
1002
1133
|
this.disabledAgents.clear();
|
|
1003
1134
|
this.state = null;
|
|
1135
|
+
this.cachedSponsoredCallback = null;
|
|
1004
1136
|
}
|
|
1005
1137
|
isAgentDisabled(agentId) {
|
|
1006
1138
|
return this.disabledAgents.has(agentId);
|
|
@@ -1034,6 +1166,46 @@ var OwneySDK = class {
|
|
|
1034
1166
|
}
|
|
1035
1167
|
return chainId;
|
|
1036
1168
|
}
|
|
1169
|
+
requireConnectedProvider() {
|
|
1170
|
+
if (!this.state?.provider) {
|
|
1171
|
+
throw new OwneyError(
|
|
1172
|
+
"NOT_CONNECTED",
|
|
1173
|
+
"connect(provider) must be called before deposit",
|
|
1174
|
+
{}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
return this.state.provider;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
|
|
1181
|
+
* used when the caller omits `depositCallback`. Wraps the connected EIP-1193
|
|
1182
|
+
* provider with viem `custom(provider)` to read token meta and sign the
|
|
1183
|
+
* `TransferWithAuthorization`, then POSTs to the sponsor API.
|
|
1184
|
+
*/
|
|
1185
|
+
getDefaultSponsoredCallback() {
|
|
1186
|
+
if (this.cachedSponsoredCallback)
|
|
1187
|
+
return this.cachedSponsoredCallback;
|
|
1188
|
+
const provider = this.requireConnectedProvider();
|
|
1189
|
+
const owner = this.state.walletAddress;
|
|
1190
|
+
this.cachedSponsoredCallback = makeSponsoredDepositCallback({
|
|
1191
|
+
apiKey: this.apiKey,
|
|
1192
|
+
ownerAddress: owner,
|
|
1193
|
+
tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
|
|
1194
|
+
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1195
|
+
// PublicClient/WalletClient param types — structurally identical at
|
|
1196
|
+
// runtime, but the two share a name TS treats as unrelated.
|
|
1197
|
+
getPublicClient: (cid) => (0, import_viem3.createPublicClient)({
|
|
1198
|
+
chain: VIEM_CHAIN[cid],
|
|
1199
|
+
transport: (0, import_viem3.custom)(provider)
|
|
1200
|
+
}),
|
|
1201
|
+
getWalletClient: (cid) => (0, import_viem3.createWalletClient)({
|
|
1202
|
+
account: owner,
|
|
1203
|
+
chain: VIEM_CHAIN[cid],
|
|
1204
|
+
transport: (0, import_viem3.custom)(provider)
|
|
1205
|
+
})
|
|
1206
|
+
});
|
|
1207
|
+
return this.cachedSponsoredCallback;
|
|
1208
|
+
}
|
|
1037
1209
|
getAgent(agentId) {
|
|
1038
1210
|
const agent = this.agents.get(agentId);
|
|
1039
1211
|
if (!agent) {
|
|
@@ -1187,6 +1359,7 @@ var OwneySDK = class {
|
|
|
1187
1359
|
}
|
|
1188
1360
|
const state = this.requireState();
|
|
1189
1361
|
const chainId = this.requireChainId();
|
|
1362
|
+
const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
|
|
1190
1363
|
if (agentId) {
|
|
1191
1364
|
if (this.isAgentDisabled(agentId)) {
|
|
1192
1365
|
throw new OwneyError(
|
|
@@ -1201,7 +1374,7 @@ var OwneySDK = class {
|
|
|
1201
1374
|
return withFailureReporting(
|
|
1202
1375
|
this.apiKey,
|
|
1203
1376
|
agent.id,
|
|
1204
|
-
() => agent.deposit(state, chainId, amount,
|
|
1377
|
+
() => agent.deposit(state, chainId, amount, effectiveCallback)
|
|
1205
1378
|
);
|
|
1206
1379
|
}
|
|
1207
1380
|
const totalAmount = BigInt(amount);
|
|
@@ -1235,7 +1408,7 @@ var OwneySDK = class {
|
|
|
1235
1408
|
agentResults[agent.id] = await withFailureReporting(
|
|
1236
1409
|
this.apiKey,
|
|
1237
1410
|
agent.id,
|
|
1238
|
-
() => agent.deposit(state, chainId, agentAmount,
|
|
1411
|
+
() => agent.deposit(state, chainId, agentAmount, effectiveCallback)
|
|
1239
1412
|
);
|
|
1240
1413
|
}
|
|
1241
1414
|
return { agentResults };
|
package/dist/index.d.cts
CHANGED
|
@@ -99,7 +99,7 @@ type AgentsApyOptions = {
|
|
|
99
99
|
type DepositOptions = {
|
|
100
100
|
amount: string;
|
|
101
101
|
asset: Asset;
|
|
102
|
-
depositCallback
|
|
102
|
+
depositCallback?: DepositCallback;
|
|
103
103
|
agentId?: AgentId;
|
|
104
104
|
};
|
|
105
105
|
|
|
@@ -235,6 +235,7 @@ declare class OwneySDK {
|
|
|
235
235
|
private state;
|
|
236
236
|
private apiKey;
|
|
237
237
|
private zyfaiRpcUrls?;
|
|
238
|
+
private cachedSponsoredCallback;
|
|
238
239
|
private initializingAgentsPromise;
|
|
239
240
|
constructor(config: OwneySDKConfig);
|
|
240
241
|
/**
|
|
@@ -261,6 +262,14 @@ declare class OwneySDK {
|
|
|
261
262
|
getActiveChainId(): number | null;
|
|
262
263
|
private requireState;
|
|
263
264
|
private requireChainId;
|
|
265
|
+
private requireConnectedProvider;
|
|
266
|
+
/**
|
|
267
|
+
* Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
|
|
268
|
+
* used when the caller omits `depositCallback`. Wraps the connected EIP-1193
|
|
269
|
+
* provider with viem `custom(provider)` to read token meta and sign the
|
|
270
|
+
* `TransferWithAuthorization`, then POSTs to the sponsor API.
|
|
271
|
+
*/
|
|
272
|
+
private getDefaultSponsoredCallback;
|
|
264
273
|
private getAgent;
|
|
265
274
|
private getActiveAgents;
|
|
266
275
|
private ensureAgentsInitialized;
|
|
@@ -388,7 +397,7 @@ declare class OwneySDK {
|
|
|
388
397
|
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
389
398
|
}
|
|
390
399
|
|
|
391
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
400
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
392
401
|
declare class OwneyError extends Error {
|
|
393
402
|
readonly code: OwneyErrorCode;
|
|
394
403
|
readonly details?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -99,7 +99,7 @@ type AgentsApyOptions = {
|
|
|
99
99
|
type DepositOptions = {
|
|
100
100
|
amount: string;
|
|
101
101
|
asset: Asset;
|
|
102
|
-
depositCallback
|
|
102
|
+
depositCallback?: DepositCallback;
|
|
103
103
|
agentId?: AgentId;
|
|
104
104
|
};
|
|
105
105
|
|
|
@@ -235,6 +235,7 @@ declare class OwneySDK {
|
|
|
235
235
|
private state;
|
|
236
236
|
private apiKey;
|
|
237
237
|
private zyfaiRpcUrls?;
|
|
238
|
+
private cachedSponsoredCallback;
|
|
238
239
|
private initializingAgentsPromise;
|
|
239
240
|
constructor(config: OwneySDKConfig);
|
|
240
241
|
/**
|
|
@@ -261,6 +262,14 @@ declare class OwneySDK {
|
|
|
261
262
|
getActiveChainId(): number | null;
|
|
262
263
|
private requireState;
|
|
263
264
|
private requireChainId;
|
|
265
|
+
private requireConnectedProvider;
|
|
266
|
+
/**
|
|
267
|
+
* Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
|
|
268
|
+
* used when the caller omits `depositCallback`. Wraps the connected EIP-1193
|
|
269
|
+
* provider with viem `custom(provider)` to read token meta and sign the
|
|
270
|
+
* `TransferWithAuthorization`, then POSTs to the sponsor API.
|
|
271
|
+
*/
|
|
272
|
+
private getDefaultSponsoredCallback;
|
|
264
273
|
private getAgent;
|
|
265
274
|
private getActiveAgents;
|
|
266
275
|
private ensureAgentsInitialized;
|
|
@@ -388,7 +397,7 @@ declare class OwneySDK {
|
|
|
388
397
|
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
389
398
|
}
|
|
390
399
|
|
|
391
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
400
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "SPONSOR_REQUEST_FAILED" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
392
401
|
declare class OwneyError extends Error {
|
|
393
402
|
readonly code: OwneyErrorCode;
|
|
394
403
|
readonly details?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -902,6 +902,134 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
902
902
|
return out;
|
|
903
903
|
}
|
|
904
904
|
|
|
905
|
+
// src/client.ts
|
|
906
|
+
import {
|
|
907
|
+
createPublicClient,
|
|
908
|
+
createWalletClient,
|
|
909
|
+
custom
|
|
910
|
+
} from "viem";
|
|
911
|
+
import { base, arbitrum } from "viem/chains";
|
|
912
|
+
|
|
913
|
+
// src/lib/transfer-auth.ts
|
|
914
|
+
import { bytesToHex } from "viem";
|
|
915
|
+
var ERC20_META_ABI = [
|
|
916
|
+
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
917
|
+
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
918
|
+
];
|
|
919
|
+
function buildTransferWithAuthorizationTypedData(input) {
|
|
920
|
+
return {
|
|
921
|
+
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
922
|
+
types: {
|
|
923
|
+
TransferWithAuthorization: [
|
|
924
|
+
{ name: "from", type: "address" },
|
|
925
|
+
{ name: "to", type: "address" },
|
|
926
|
+
{ name: "value", type: "uint256" },
|
|
927
|
+
{ name: "validAfter", type: "uint256" },
|
|
928
|
+
{ name: "validBefore", type: "uint256" },
|
|
929
|
+
{ name: "nonce", type: "bytes32" }
|
|
930
|
+
]
|
|
931
|
+
},
|
|
932
|
+
primaryType: "TransferWithAuthorization",
|
|
933
|
+
message: input.message
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
async function readTokenMeta(publicClient, token) {
|
|
937
|
+
const [tokenName, tokenVersion] = await Promise.all([
|
|
938
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
939
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
940
|
+
]);
|
|
941
|
+
return { tokenName, tokenVersion };
|
|
942
|
+
}
|
|
943
|
+
function randomAuthNonce() {
|
|
944
|
+
const bytes = new Uint8Array(32);
|
|
945
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
946
|
+
return bytesToHex(bytes);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// src/lib/sponsor-client.ts
|
|
950
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
951
|
+
async function postSponsorTransferAuth(input) {
|
|
952
|
+
const base2 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
953
|
+
let res;
|
|
954
|
+
try {
|
|
955
|
+
res = await fetch(`${base2}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
956
|
+
method: "POST",
|
|
957
|
+
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
958
|
+
body: JSON.stringify(input.body)
|
|
959
|
+
});
|
|
960
|
+
} catch (networkError) {
|
|
961
|
+
throw new OwneyError(
|
|
962
|
+
"SPONSOR_REQUEST_FAILED",
|
|
963
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
964
|
+
{ cause: String(networkError) }
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
const text = await res.text();
|
|
968
|
+
let parsed = null;
|
|
969
|
+
try {
|
|
970
|
+
parsed = JSON.parse(text);
|
|
971
|
+
} catch {
|
|
972
|
+
}
|
|
973
|
+
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
974
|
+
throw new OwneyError(
|
|
975
|
+
"SPONSOR_REQUEST_FAILED",
|
|
976
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
977
|
+
{ statusCode: res.status, responseBody: text.slice(0, 500) }
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
return parsed.data;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// src/lib/sponsored-deposit.ts
|
|
984
|
+
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
985
|
+
function makeSponsoredDepositCallback(deps) {
|
|
986
|
+
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
987
|
+
return async (smartWallet, chainId, amount) => {
|
|
988
|
+
const cid = chainId;
|
|
989
|
+
const token = deps.tokenAddressByChain[cid];
|
|
990
|
+
if (!token) {
|
|
991
|
+
throw new OwneyError(
|
|
992
|
+
"CHAIN_UNSUPPORTED",
|
|
993
|
+
`No sponsored token configured for chain ${chainId}`
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
const pub = deps.getPublicClient(cid);
|
|
997
|
+
const wallet = deps.getWalletClient(cid);
|
|
998
|
+
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
999
|
+
const validAfter = 0n;
|
|
1000
|
+
const validBefore = BigInt(Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS);
|
|
1001
|
+
const nonce = randomAuthNonce();
|
|
1002
|
+
const typedData = buildTransferWithAuthorizationTypedData({
|
|
1003
|
+
token,
|
|
1004
|
+
chainId: cid,
|
|
1005
|
+
tokenName,
|
|
1006
|
+
tokenVersion,
|
|
1007
|
+
message: { from: deps.ownerAddress, to: smartWallet, value: BigInt(amount), validAfter, validBefore, nonce }
|
|
1008
|
+
});
|
|
1009
|
+
const authSignature = await wallet.signTypedData(
|
|
1010
|
+
{ account: deps.ownerAddress, ...typedData }
|
|
1011
|
+
);
|
|
1012
|
+
const result = await post({
|
|
1013
|
+
baseUrl: deps.baseUrl,
|
|
1014
|
+
apiKey: deps.apiKey,
|
|
1015
|
+
body: {
|
|
1016
|
+
chainId: cid,
|
|
1017
|
+
token,
|
|
1018
|
+
from: deps.ownerAddress,
|
|
1019
|
+
to: smartWallet,
|
|
1020
|
+
value: amount,
|
|
1021
|
+
validAfter: validAfter.toString(),
|
|
1022
|
+
validBefore: validBefore.toString(),
|
|
1023
|
+
nonce,
|
|
1024
|
+
authSignature,
|
|
1025
|
+
tokenName,
|
|
1026
|
+
tokenVersion
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
return result.txHash;
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
905
1033
|
// src/client.ts
|
|
906
1034
|
function encodeMultiAgentCursor(map) {
|
|
907
1035
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -923,6 +1051,11 @@ function decodeMultiAgentCursor(token) {
|
|
|
923
1051
|
}
|
|
924
1052
|
return parsed;
|
|
925
1053
|
}
|
|
1054
|
+
var SPONSORED_USDC_BY_CHAIN = {
|
|
1055
|
+
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1056
|
+
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1057
|
+
};
|
|
1058
|
+
var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
|
|
926
1059
|
var OwneySDK = class {
|
|
927
1060
|
agents = /* @__PURE__ */ new Map();
|
|
928
1061
|
activeAgents = /* @__PURE__ */ new Set();
|
|
@@ -935,6 +1068,7 @@ var OwneySDK = class {
|
|
|
935
1068
|
state = null;
|
|
936
1069
|
apiKey;
|
|
937
1070
|
zyfaiRpcUrls;
|
|
1071
|
+
cachedSponsoredCallback = null;
|
|
938
1072
|
initializingAgentsPromise = null;
|
|
939
1073
|
constructor(config) {
|
|
940
1074
|
this.apiKey = config.apiKey;
|
|
@@ -958,6 +1092,7 @@ var OwneySDK = class {
|
|
|
958
1092
|
);
|
|
959
1093
|
}
|
|
960
1094
|
this.state = { provider, walletAddress, chainId: null };
|
|
1095
|
+
this.cachedSponsoredCallback = null;
|
|
961
1096
|
}
|
|
962
1097
|
/**
|
|
963
1098
|
* Disconnect from all agents and clear connection state.
|
|
@@ -970,6 +1105,7 @@ var OwneySDK = class {
|
|
|
970
1105
|
this.activeAgents.clear();
|
|
971
1106
|
this.disabledAgents.clear();
|
|
972
1107
|
this.state = null;
|
|
1108
|
+
this.cachedSponsoredCallback = null;
|
|
973
1109
|
}
|
|
974
1110
|
isAgentDisabled(agentId) {
|
|
975
1111
|
return this.disabledAgents.has(agentId);
|
|
@@ -1003,6 +1139,46 @@ var OwneySDK = class {
|
|
|
1003
1139
|
}
|
|
1004
1140
|
return chainId;
|
|
1005
1141
|
}
|
|
1142
|
+
requireConnectedProvider() {
|
|
1143
|
+
if (!this.state?.provider) {
|
|
1144
|
+
throw new OwneyError(
|
|
1145
|
+
"NOT_CONNECTED",
|
|
1146
|
+
"connect(provider) must be called before deposit",
|
|
1147
|
+
{}
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
return this.state.provider;
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
|
|
1154
|
+
* used when the caller omits `depositCallback`. Wraps the connected EIP-1193
|
|
1155
|
+
* provider with viem `custom(provider)` to read token meta and sign the
|
|
1156
|
+
* `TransferWithAuthorization`, then POSTs to the sponsor API.
|
|
1157
|
+
*/
|
|
1158
|
+
getDefaultSponsoredCallback() {
|
|
1159
|
+
if (this.cachedSponsoredCallback)
|
|
1160
|
+
return this.cachedSponsoredCallback;
|
|
1161
|
+
const provider = this.requireConnectedProvider();
|
|
1162
|
+
const owner = this.state.walletAddress;
|
|
1163
|
+
this.cachedSponsoredCallback = makeSponsoredDepositCallback({
|
|
1164
|
+
apiKey: this.apiKey,
|
|
1165
|
+
ownerAddress: owner,
|
|
1166
|
+
tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
|
|
1167
|
+
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1168
|
+
// PublicClient/WalletClient param types — structurally identical at
|
|
1169
|
+
// runtime, but the two share a name TS treats as unrelated.
|
|
1170
|
+
getPublicClient: (cid) => createPublicClient({
|
|
1171
|
+
chain: VIEM_CHAIN[cid],
|
|
1172
|
+
transport: custom(provider)
|
|
1173
|
+
}),
|
|
1174
|
+
getWalletClient: (cid) => createWalletClient({
|
|
1175
|
+
account: owner,
|
|
1176
|
+
chain: VIEM_CHAIN[cid],
|
|
1177
|
+
transport: custom(provider)
|
|
1178
|
+
})
|
|
1179
|
+
});
|
|
1180
|
+
return this.cachedSponsoredCallback;
|
|
1181
|
+
}
|
|
1006
1182
|
getAgent(agentId) {
|
|
1007
1183
|
const agent = this.agents.get(agentId);
|
|
1008
1184
|
if (!agent) {
|
|
@@ -1156,6 +1332,7 @@ var OwneySDK = class {
|
|
|
1156
1332
|
}
|
|
1157
1333
|
const state = this.requireState();
|
|
1158
1334
|
const chainId = this.requireChainId();
|
|
1335
|
+
const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
|
|
1159
1336
|
if (agentId) {
|
|
1160
1337
|
if (this.isAgentDisabled(agentId)) {
|
|
1161
1338
|
throw new OwneyError(
|
|
@@ -1170,7 +1347,7 @@ var OwneySDK = class {
|
|
|
1170
1347
|
return withFailureReporting(
|
|
1171
1348
|
this.apiKey,
|
|
1172
1349
|
agent.id,
|
|
1173
|
-
() => agent.deposit(state, chainId, amount,
|
|
1350
|
+
() => agent.deposit(state, chainId, amount, effectiveCallback)
|
|
1174
1351
|
);
|
|
1175
1352
|
}
|
|
1176
1353
|
const totalAmount = BigInt(amount);
|
|
@@ -1204,7 +1381,7 @@ var OwneySDK = class {
|
|
|
1204
1381
|
agentResults[agent.id] = await withFailureReporting(
|
|
1205
1382
|
this.apiKey,
|
|
1206
1383
|
agent.id,
|
|
1207
|
-
() => agent.deposit(state, chainId, agentAmount,
|
|
1384
|
+
() => agent.deposit(state, chainId, agentAmount, effectiveCallback)
|
|
1208
1385
|
);
|
|
1209
1386
|
}
|
|
1210
1387
|
return { agentResults };
|
package/package.json
CHANGED