@agether/sdk 1.6.0 → 1.6.2
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/cli.d.ts +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +397 -4
- package/dist/clients/AgentIdentityClient.d.ts +188 -0
- package/dist/clients/AgentIdentityClient.d.ts.map +1 -0
- package/dist/clients/AgentIdentityClient.js +333 -0
- package/dist/clients/AgetherClient.d.ts +63 -0
- package/dist/clients/AgetherClient.d.ts.map +1 -0
- package/dist/clients/AgetherClient.js +171 -0
- package/dist/clients/MorphoClient.d.ts +287 -0
- package/dist/clients/MorphoClient.d.ts.map +1 -0
- package/dist/clients/MorphoClient.js +951 -0
- package/dist/clients/ScoringClient.d.ts +89 -0
- package/dist/clients/ScoringClient.d.ts.map +1 -0
- package/dist/clients/ScoringClient.js +93 -0
- package/dist/clients/X402Client.d.ts +130 -0
- package/dist/clients/X402Client.d.ts.map +1 -0
- package/dist/clients/X402Client.js +301 -0
- package/dist/index.d.mts +142 -1
- package/dist/index.d.ts +142 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +397 -4
- package/dist/index.mjs +397 -4
- package/dist/types/index.d.ts +121 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +43 -0
- package/dist/utils/abis.d.ts +18 -0
- package/dist/utils/abis.d.ts.map +1 -0
- package/dist/utils/abis.js +93 -0
- package/dist/utils/config.d.ts +34 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +115 -0
- package/dist/utils/format.d.ts +44 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +75 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -696,6 +696,179 @@ var MorphoClient = class {
|
|
|
696
696
|
};
|
|
697
697
|
}
|
|
698
698
|
// ════════════════════════════════════════════════════════
|
|
699
|
+
// Balance & Borrowing Capacity
|
|
700
|
+
// ════════════════════════════════════════════════════════
|
|
701
|
+
/**
|
|
702
|
+
* Get the USDC balance of the AgentAccount.
|
|
703
|
+
* @returns USDC balance in raw units (6 decimals)
|
|
704
|
+
*/
|
|
705
|
+
async getUsdcBalance() {
|
|
706
|
+
const acctAddr = await this.getAccountAddress();
|
|
707
|
+
const usdc = new Contract2(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
708
|
+
return usdc.balanceOf(acctAddr);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Calculate the maximum additional USDC that can be borrowed
|
|
712
|
+
* given the agent's current collateral and debt across all markets.
|
|
713
|
+
*
|
|
714
|
+
* For each market with collateral deposited:
|
|
715
|
+
* maxBorrow = (collateralValue * LLTV) - currentDebt
|
|
716
|
+
*
|
|
717
|
+
* Uses the Morpho oracle to price collateral → loan token.
|
|
718
|
+
*
|
|
719
|
+
* @returns Maximum additional USDC borrowable (6 decimals)
|
|
720
|
+
*/
|
|
721
|
+
async getMaxBorrowable() {
|
|
722
|
+
const acctAddr = await this.getAccountAddress();
|
|
723
|
+
const markets = await this.getMarkets();
|
|
724
|
+
let totalAdditional = 0n;
|
|
725
|
+
const byMarket = [];
|
|
726
|
+
for (const m of markets) {
|
|
727
|
+
if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
|
|
728
|
+
try {
|
|
729
|
+
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
730
|
+
if (pos.collateral === 0n) continue;
|
|
731
|
+
const mktState = await this.morphoBlue.market(m.uniqueKey);
|
|
732
|
+
const totalBorrowShares = BigInt(mktState.totalBorrowShares);
|
|
733
|
+
const totalBorrowAssets = BigInt(mktState.totalBorrowAssets);
|
|
734
|
+
const currentDebt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
|
|
735
|
+
let collateralValueInLoan;
|
|
736
|
+
try {
|
|
737
|
+
const oracleContract = new Contract2(m.oracle, [
|
|
738
|
+
"function price() view returns (uint256)"
|
|
739
|
+
], this.provider);
|
|
740
|
+
const oraclePrice = await oracleContract.price();
|
|
741
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
742
|
+
collateralValueInLoan = BigInt(pos.collateral) * oraclePrice / ORACLE_PRICE_SCALE;
|
|
743
|
+
} catch {
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
const maxBorrowTotal = collateralValueInLoan * m.lltv / 10n ** 18n;
|
|
747
|
+
const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
|
|
748
|
+
totalAdditional += maxAdditional;
|
|
749
|
+
byMarket.push({
|
|
750
|
+
collateralToken: m.collateralAsset.symbol,
|
|
751
|
+
maxAdditional,
|
|
752
|
+
currentDebt,
|
|
753
|
+
collateralValue: collateralValueInLoan
|
|
754
|
+
});
|
|
755
|
+
} catch {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return { total: totalAdditional, byMarket };
|
|
760
|
+
}
|
|
761
|
+
// ════════════════════════════════════════════════════════
|
|
762
|
+
// Market Rates & Yield Estimation
|
|
763
|
+
// ════════════════════════════════════════════════════════
|
|
764
|
+
/**
|
|
765
|
+
* Fetch current supply/borrow APY for a collateral market from Morpho GraphQL API.
|
|
766
|
+
*
|
|
767
|
+
* Note: On Morpho Blue, collateral does NOT earn yield directly. Supply APY
|
|
768
|
+
* is what lenders earn; borrow APY is what borrowers pay.
|
|
769
|
+
*/
|
|
770
|
+
async getMarketRates(collateralSymbolOrAddress) {
|
|
771
|
+
const chainId = this.config.chainId;
|
|
772
|
+
const usdcAddr = this.config.contracts.usdc.toLowerCase();
|
|
773
|
+
let collateralFilter = "";
|
|
774
|
+
if (collateralSymbolOrAddress) {
|
|
775
|
+
const colInfo = BASE_COLLATERALS[collateralSymbolOrAddress];
|
|
776
|
+
const colAddr = (colInfo?.address ?? collateralSymbolOrAddress).toLowerCase();
|
|
777
|
+
collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
|
|
778
|
+
}
|
|
779
|
+
const query = `{
|
|
780
|
+
markets(
|
|
781
|
+
first: 50
|
|
782
|
+
orderBy: SupplyAssetsUsd
|
|
783
|
+
orderDirection: Desc
|
|
784
|
+
where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"]${collateralFilter} }
|
|
785
|
+
) {
|
|
786
|
+
items {
|
|
787
|
+
uniqueKey
|
|
788
|
+
lltv
|
|
789
|
+
loanAsset { address symbol decimals }
|
|
790
|
+
collateralAsset { address symbol decimals }
|
|
791
|
+
state {
|
|
792
|
+
borrowAssets
|
|
793
|
+
supplyAssets
|
|
794
|
+
utilization
|
|
795
|
+
supplyApy
|
|
796
|
+
borrowApy
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}`;
|
|
801
|
+
try {
|
|
802
|
+
const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
803
|
+
const items = resp.data?.data?.markets?.items ?? [];
|
|
804
|
+
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers2.ZeroAddress).map((m) => ({
|
|
805
|
+
collateralToken: m.collateralAsset.symbol,
|
|
806
|
+
loanToken: m.loanAsset.symbol,
|
|
807
|
+
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
808
|
+
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
809
|
+
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
810
|
+
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 1e6 : 0,
|
|
811
|
+
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 1e6 : 0,
|
|
812
|
+
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
813
|
+
marketId: m.uniqueKey
|
|
814
|
+
}));
|
|
815
|
+
} catch {
|
|
816
|
+
return [];
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Estimate theoretical yield for a given collateral amount over a period.
|
|
821
|
+
*
|
|
822
|
+
* ⚠️ IMPORTANT: On Morpho Blue, collateral does NOT earn yield directly.
|
|
823
|
+
* This estimates what the collateral WOULD earn if it were instead supplied
|
|
824
|
+
* as a lender (not used as collateral). This is a theoretical upper bound
|
|
825
|
+
* useful for setting spending caps.
|
|
826
|
+
*
|
|
827
|
+
* @param collateralSymbol - e.g. 'WETH'
|
|
828
|
+
* @param amount - collateral amount in human-readable (e.g. '1.5')
|
|
829
|
+
* @param periodDays - estimation period in days (default: 1)
|
|
830
|
+
* @param ethPriceUsd - ETH price in USD for value conversion (if not provided, uses oracle)
|
|
831
|
+
* @returns Estimated yield in USD for the period
|
|
832
|
+
*/
|
|
833
|
+
async getYieldEstimate(collateralSymbol, amount, periodDays = 1, ethPriceUsd) {
|
|
834
|
+
const colInfo = BASE_COLLATERALS[collateralSymbol];
|
|
835
|
+
if (!colInfo) throw new AgetherError(`Unknown collateral: ${collateralSymbol}`, "UNKNOWN_COLLATERAL");
|
|
836
|
+
const rates = await this.getMarketRates(collateralSymbol);
|
|
837
|
+
if (rates.length === 0) {
|
|
838
|
+
throw new AgetherError(`No market found for ${collateralSymbol}`, "MARKET_NOT_FOUND");
|
|
839
|
+
}
|
|
840
|
+
const market = rates[0];
|
|
841
|
+
const supplyApy = market.supplyApy;
|
|
842
|
+
let collateralValueUsd;
|
|
843
|
+
if (ethPriceUsd) {
|
|
844
|
+
collateralValueUsd = parseFloat(amount) * ethPriceUsd;
|
|
845
|
+
} else {
|
|
846
|
+
try {
|
|
847
|
+
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
848
|
+
const oracleContract = new Contract2(params.oracle, [
|
|
849
|
+
"function price() view returns (uint256)"
|
|
850
|
+
], this.provider);
|
|
851
|
+
const oraclePrice = await oracleContract.price();
|
|
852
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
853
|
+
const amountWei = ethers2.parseUnits(amount, colInfo.decimals);
|
|
854
|
+
const valueInUsdc = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
|
|
855
|
+
collateralValueUsd = Number(valueInUsdc) / 1e6;
|
|
856
|
+
} catch {
|
|
857
|
+
throw new AgetherError("Cannot determine collateral value. Provide ethPriceUsd.", "PRICE_UNAVAILABLE");
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const estimatedYieldUsd = collateralValueUsd * supplyApy * (periodDays / 365);
|
|
861
|
+
return {
|
|
862
|
+
collateralToken: collateralSymbol,
|
|
863
|
+
amount,
|
|
864
|
+
periodDays,
|
|
865
|
+
theoreticalSupplyApy: supplyApy,
|
|
866
|
+
estimatedYieldUsd,
|
|
867
|
+
collateralValueUsd,
|
|
868
|
+
disclaimer: "Collateral on Morpho Blue does NOT earn yield directly. This estimates what it WOULD earn if supplied as a lender instead. Use as a theoretical spending cap."
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
// ════════════════════════════════════════════════════════
|
|
699
872
|
// Lending Operations (all via AgentAccount.executeBatch)
|
|
700
873
|
// ════════════════════════════════════════════════════════
|
|
701
874
|
/**
|
|
@@ -827,7 +1000,6 @@ var MorphoClient = class {
|
|
|
827
1000
|
*/
|
|
828
1001
|
async repay(usdcAmount, tokenSymbol, marketParams) {
|
|
829
1002
|
const acctAddr = await this.getAccountAddress();
|
|
830
|
-
const amount = ethers2.parseUnits(usdcAmount, 6);
|
|
831
1003
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
832
1004
|
const usdcAddr = this.config.contracts.usdc;
|
|
833
1005
|
let params;
|
|
@@ -839,14 +1011,60 @@ var MorphoClient = class {
|
|
|
839
1011
|
const { params: p } = await this._findActiveMarket();
|
|
840
1012
|
params = p;
|
|
841
1013
|
}
|
|
1014
|
+
let repayAssets;
|
|
1015
|
+
let repayShares;
|
|
1016
|
+
let approveAmount;
|
|
1017
|
+
if (usdcAmount === "all") {
|
|
1018
|
+
const markets = await this.getMarkets();
|
|
1019
|
+
const mkt = markets.find(
|
|
1020
|
+
(m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase()
|
|
1021
|
+
);
|
|
1022
|
+
if (mkt) {
|
|
1023
|
+
const pos = await this.morphoBlue.position(mkt.uniqueKey, acctAddr);
|
|
1024
|
+
repayShares = BigInt(pos.borrowShares);
|
|
1025
|
+
repayAssets = 0n;
|
|
1026
|
+
const onChainMkt = await this.morphoBlue.market(mkt.uniqueKey);
|
|
1027
|
+
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
1028
|
+
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
1029
|
+
const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
1030
|
+
approveAmount = estimated > 0n ? estimated : ethers2.parseUnits("1", 6);
|
|
1031
|
+
} else {
|
|
1032
|
+
repayAssets = ethers2.parseUnits("999999", 6);
|
|
1033
|
+
repayShares = 0n;
|
|
1034
|
+
approveAmount = repayAssets;
|
|
1035
|
+
}
|
|
1036
|
+
} else {
|
|
1037
|
+
repayAssets = ethers2.parseUnits(usdcAmount, 6);
|
|
1038
|
+
repayShares = 0n;
|
|
1039
|
+
approveAmount = repayAssets;
|
|
1040
|
+
try {
|
|
1041
|
+
const markets = await this.getMarkets();
|
|
1042
|
+
const mkt = markets.find(
|
|
1043
|
+
(m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase()
|
|
1044
|
+
);
|
|
1045
|
+
if (mkt) {
|
|
1046
|
+
const pos = await this.morphoBlue.position(mkt.uniqueKey, acctAddr);
|
|
1047
|
+
const onChainMkt = await this.morphoBlue.market(mkt.uniqueKey);
|
|
1048
|
+
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
1049
|
+
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
1050
|
+
const currentDebt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
|
|
1051
|
+
if (repayAssets >= currentDebt && BigInt(pos.borrowShares) > 0n) {
|
|
1052
|
+
repayShares = BigInt(pos.borrowShares);
|
|
1053
|
+
repayAssets = 0n;
|
|
1054
|
+
approveAmount = currentDebt + 10n;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
} catch {
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
842
1060
|
const targets = [usdcAddr, morphoAddr];
|
|
843
1061
|
const values = [0n, 0n];
|
|
844
1062
|
const datas = [
|
|
845
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr,
|
|
1063
|
+
erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
|
|
846
1064
|
morphoIface.encodeFunctionData("repay", [
|
|
847
1065
|
this._toTuple(params),
|
|
848
|
-
|
|
849
|
-
|
|
1066
|
+
repayAssets,
|
|
1067
|
+
repayShares,
|
|
850
1068
|
acctAddr,
|
|
851
1069
|
"0x"
|
|
852
1070
|
])
|
|
@@ -1043,6 +1261,9 @@ var X402Client = class {
|
|
|
1043
1261
|
const client = new x402Client();
|
|
1044
1262
|
registerExactEvmScheme(client, { signer });
|
|
1045
1263
|
this.paidFetch = wrapFetchWithPayment(fetch, client);
|
|
1264
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1265
|
+
const dailyLimit = config.dailySpendLimitUsdc ? BigInt(Math.round(parseFloat(config.dailySpendLimitUsdc) * 1e6)) : 0n;
|
|
1266
|
+
this._spendingTracker = { date: today, totalBorrowed: 0n, dailyLimit };
|
|
1046
1267
|
}
|
|
1047
1268
|
async get(url, opts) {
|
|
1048
1269
|
return this.request(url, { ...opts, method: "GET" });
|
|
@@ -1058,6 +1279,82 @@ var X402Client = class {
|
|
|
1058
1279
|
getAddress() {
|
|
1059
1280
|
return this.address;
|
|
1060
1281
|
}
|
|
1282
|
+
/** Get the current spending tracker state */
|
|
1283
|
+
getSpendingTracker() {
|
|
1284
|
+
this._resetTrackerIfNewDay();
|
|
1285
|
+
return { ...this._spendingTracker };
|
|
1286
|
+
}
|
|
1287
|
+
/** Get remaining daily spending allowance in USDC (human-readable) */
|
|
1288
|
+
getRemainingDailyAllowance() {
|
|
1289
|
+
this._resetTrackerIfNewDay();
|
|
1290
|
+
if (this._spendingTracker.dailyLimit === 0n) return "unlimited";
|
|
1291
|
+
const remaining = this._spendingTracker.dailyLimit - this._spendingTracker.totalBorrowed;
|
|
1292
|
+
return (Number(remaining > 0n ? remaining : 0n) / 1e6).toFixed(2);
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Pay with auto-draw: Make an x402 request with automatic Morpho borrowing.
|
|
1296
|
+
*
|
|
1297
|
+
* Flow:
|
|
1298
|
+
* 1. Check USDC balance on AgentAccount
|
|
1299
|
+
* 2. Probe the URL to discover payment amount (if 402)
|
|
1300
|
+
* 3. If insufficient USDC, calculate deficit
|
|
1301
|
+
* 4. Check spending limit
|
|
1302
|
+
* 5. Borrow from Morpho via MorphoClient
|
|
1303
|
+
* 6. Proceed with x402 payment
|
|
1304
|
+
*/
|
|
1305
|
+
async payWithAutoDraw(url, opts) {
|
|
1306
|
+
const { morphoClient, ...fetchOpts } = opts || {};
|
|
1307
|
+
if (!this.config.autoDraw || !morphoClient) {
|
|
1308
|
+
return this.request(url, fetchOpts);
|
|
1309
|
+
}
|
|
1310
|
+
try {
|
|
1311
|
+
const usdcBalance = await morphoClient.getUsdcBalance();
|
|
1312
|
+
console.log(` [auto-draw] AgentAccount USDC balance: ${(Number(usdcBalance) / 1e6).toFixed(2)}`);
|
|
1313
|
+
const paymentAmount = await this._probePaymentAmount(url, fetchOpts);
|
|
1314
|
+
if (paymentAmount !== null) {
|
|
1315
|
+
console.log(` [auto-draw] Payment required: ${(Number(paymentAmount) / 1e6).toFixed(6)} USDC`);
|
|
1316
|
+
const bufferStr = this.config.autoDrawBuffer || "0.5";
|
|
1317
|
+
const buffer = BigInt(Math.round(parseFloat(bufferStr) * 1e6));
|
|
1318
|
+
const needed = paymentAmount + buffer;
|
|
1319
|
+
if (usdcBalance < needed) {
|
|
1320
|
+
const deficit = needed - usdcBalance;
|
|
1321
|
+
console.log(` [auto-draw] Insufficient balance. Need to borrow ${(Number(deficit) / 1e6).toFixed(2)} USDC`);
|
|
1322
|
+
const limitCheck = await this._checkSpendingLimit(deficit, morphoClient);
|
|
1323
|
+
if (!limitCheck.allowed) {
|
|
1324
|
+
return {
|
|
1325
|
+
success: false,
|
|
1326
|
+
error: `Auto-draw blocked: ${limitCheck.reason}`
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
const maxBorrowable = await morphoClient.getMaxBorrowable();
|
|
1330
|
+
if (maxBorrowable.total < deficit) {
|
|
1331
|
+
return {
|
|
1332
|
+
success: false,
|
|
1333
|
+
error: `Auto-draw failed: insufficient collateral. Need ${(Number(deficit) / 1e6).toFixed(2)} USDC but can only borrow ${(Number(maxBorrowable.total) / 1e6).toFixed(2)} USDC more.`
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
const borrowAmount = (Number(deficit) / 1e6).toFixed(6);
|
|
1337
|
+
console.log(` [auto-draw] Borrowing ${borrowAmount} USDC from Morpho...`);
|
|
1338
|
+
const borrowResult = await morphoClient.borrow(borrowAmount);
|
|
1339
|
+
console.log(` [auto-draw] Borrow tx: ${borrowResult.tx}`);
|
|
1340
|
+
this._trackSpending(deficit);
|
|
1341
|
+
const result = await this.request(url, fetchOpts);
|
|
1342
|
+
return {
|
|
1343
|
+
...result,
|
|
1344
|
+
autoDrawInfo: {
|
|
1345
|
+
borrowed: borrowAmount,
|
|
1346
|
+
borrowTx: borrowResult.tx,
|
|
1347
|
+
reason: `USDC balance insufficient (had ${(Number(usdcBalance) / 1e6).toFixed(2)}, needed ${(Number(needed) / 1e6).toFixed(2)})`
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return this.request(url, fetchOpts);
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
console.log(` [auto-draw] Auto-draw check failed: ${error instanceof Error ? error.message : String(error)}. Proceeding with normal request.`);
|
|
1355
|
+
return this.request(url, fetchOpts);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1061
1358
|
// ──────────── Core request — @x402/fetch handles 402 automatically ────────────
|
|
1062
1359
|
async request(url, options) {
|
|
1063
1360
|
try {
|
|
@@ -1107,6 +1404,102 @@ var X402Client = class {
|
|
|
1107
1404
|
};
|
|
1108
1405
|
}
|
|
1109
1406
|
}
|
|
1407
|
+
// ──────────── Auto-Draw Helpers ────────────
|
|
1408
|
+
/**
|
|
1409
|
+
* Probe a URL to discover payment requirements without paying.
|
|
1410
|
+
* Makes a request and parses the 402 PAYMENT-REQUIRED header.
|
|
1411
|
+
* @returns Payment amount in raw USDC units (6 decimals), or null if not a 402.
|
|
1412
|
+
*/
|
|
1413
|
+
async _probePaymentAmount(url, options) {
|
|
1414
|
+
try {
|
|
1415
|
+
const response = await fetch(url, {
|
|
1416
|
+
...options,
|
|
1417
|
+
headers: {
|
|
1418
|
+
...options?.headers,
|
|
1419
|
+
"X-Agent-Id": this.config.agentId || ""
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
if (response.status !== 402) return null;
|
|
1423
|
+
const paymentHeader = response.headers.get("X-PAYMENT") || response.headers.get("PAYMENT-REQUIRED");
|
|
1424
|
+
if (!paymentHeader) return null;
|
|
1425
|
+
try {
|
|
1426
|
+
const decoded = JSON.parse(Buffer.from(paymentHeader, "base64").toString("utf-8"));
|
|
1427
|
+
const requirements = Array.isArray(decoded) ? decoded : decoded.accepts || [decoded];
|
|
1428
|
+
if (requirements.length > 0) {
|
|
1429
|
+
const amount = requirements[0].maxAmountRequired || requirements[0].amount;
|
|
1430
|
+
if (amount) {
|
|
1431
|
+
return BigInt(amount);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
} catch {
|
|
1435
|
+
}
|
|
1436
|
+
return null;
|
|
1437
|
+
} catch {
|
|
1438
|
+
return null;
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
/** Reset spending tracker if it's a new day */
|
|
1442
|
+
_resetTrackerIfNewDay() {
|
|
1443
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1444
|
+
if (this._spendingTracker.date !== today) {
|
|
1445
|
+
this._spendingTracker = {
|
|
1446
|
+
date: today,
|
|
1447
|
+
totalBorrowed: 0n,
|
|
1448
|
+
dailyLimit: this._spendingTracker.dailyLimit
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
/** Track a new spending amount */
|
|
1453
|
+
_trackSpending(amount) {
|
|
1454
|
+
this._resetTrackerIfNewDay();
|
|
1455
|
+
this._spendingTracker.totalBorrowed += amount;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Check if a borrow amount is within spending limits.
|
|
1459
|
+
* Considers both fixed daily limits and yield-limited spending.
|
|
1460
|
+
*/
|
|
1461
|
+
async _checkSpendingLimit(amount, morphoClient) {
|
|
1462
|
+
this._resetTrackerIfNewDay();
|
|
1463
|
+
if (this.config.yieldLimitedSpending) {
|
|
1464
|
+
try {
|
|
1465
|
+
const status = await morphoClient.getStatus();
|
|
1466
|
+
let totalDailyYieldUsdc = 0;
|
|
1467
|
+
for (const pos of status.positions) {
|
|
1468
|
+
if (parseFloat(pos.collateral) > 0) {
|
|
1469
|
+
try {
|
|
1470
|
+
const estimate = await morphoClient.getYieldEstimate(
|
|
1471
|
+
pos.collateralToken,
|
|
1472
|
+
pos.collateral,
|
|
1473
|
+
1
|
|
1474
|
+
// 1 day
|
|
1475
|
+
);
|
|
1476
|
+
totalDailyYieldUsdc += estimate.estimatedYieldUsd;
|
|
1477
|
+
} catch {
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
const yieldLimit = BigInt(Math.round(totalDailyYieldUsdc * 1e6));
|
|
1482
|
+
const newTotal = this._spendingTracker.totalBorrowed + amount;
|
|
1483
|
+
if (yieldLimit > 0n && newTotal > yieldLimit) {
|
|
1484
|
+
return {
|
|
1485
|
+
allowed: false,
|
|
1486
|
+
reason: `Yield-limited spending exceeded. Daily yield cap: $${(Number(yieldLimit) / 1e6).toFixed(2)}, already spent: $${(Number(this._spendingTracker.totalBorrowed) / 1e6).toFixed(2)}, requested: $${(Number(amount) / 1e6).toFixed(2)}`
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
} catch {
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
if (this._spendingTracker.dailyLimit > 0n) {
|
|
1493
|
+
const newTotal = this._spendingTracker.totalBorrowed + amount;
|
|
1494
|
+
if (newTotal > this._spendingTracker.dailyLimit) {
|
|
1495
|
+
return {
|
|
1496
|
+
allowed: false,
|
|
1497
|
+
reason: `Daily spending limit exceeded. Limit: $${(Number(this._spendingTracker.dailyLimit) / 1e6).toFixed(2)}, already spent: $${(Number(this._spendingTracker.totalBorrowed) / 1e6).toFixed(2)}, requested: $${(Number(amount) / 1e6).toFixed(2)}`
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
return { allowed: true };
|
|
1502
|
+
}
|
|
1110
1503
|
};
|
|
1111
1504
|
|
|
1112
1505
|
// src/clients/ScoringClient.ts
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agether SDK Types
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Agent registers via ERC-8004 → gets agentId
|
|
6
|
+
* - AccountFactory creates AgentAccount (KYA-gated smart wallet) per agent
|
|
7
|
+
* - AgentReputation: oracle-based credit scoring
|
|
8
|
+
* - Morpho Blue: direct overcollateralized lending (agents interact directly)
|
|
9
|
+
* - x402: HTTP payment protocol for scoring API
|
|
10
|
+
*/
|
|
11
|
+
export declare enum ChainId {
|
|
12
|
+
Ethereum = 1,
|
|
13
|
+
Base = 8453,
|
|
14
|
+
BaseSepolia = 84532,
|
|
15
|
+
Sepolia = 11155111,
|
|
16
|
+
Hardhat = 31337
|
|
17
|
+
}
|
|
18
|
+
/** Morpho Blue MarketParams struct */
|
|
19
|
+
export interface MorphoMarketParams {
|
|
20
|
+
loanToken: string;
|
|
21
|
+
collateralToken: string;
|
|
22
|
+
oracle: string;
|
|
23
|
+
irm: string;
|
|
24
|
+
lltv: bigint;
|
|
25
|
+
}
|
|
26
|
+
/** Morpho Blue on-chain position for an account */
|
|
27
|
+
export interface MorphoPosition {
|
|
28
|
+
supplyShares: bigint;
|
|
29
|
+
borrowShares: bigint;
|
|
30
|
+
collateral: bigint;
|
|
31
|
+
}
|
|
32
|
+
/** Morpho market info (from GraphQL API or on-chain) */
|
|
33
|
+
export interface MorphoMarketInfo {
|
|
34
|
+
uniqueKey: string;
|
|
35
|
+
loanAsset: {
|
|
36
|
+
address: string;
|
|
37
|
+
symbol: string;
|
|
38
|
+
decimals: number;
|
|
39
|
+
};
|
|
40
|
+
collateralAsset: {
|
|
41
|
+
address: string;
|
|
42
|
+
symbol: string;
|
|
43
|
+
decimals: number;
|
|
44
|
+
};
|
|
45
|
+
oracle: string;
|
|
46
|
+
irm: string;
|
|
47
|
+
lltv: bigint;
|
|
48
|
+
totalSupplyAssets: bigint;
|
|
49
|
+
totalBorrowAssets: bigint;
|
|
50
|
+
utilization: number;
|
|
51
|
+
}
|
|
52
|
+
/** On-chain score attestation from AgentReputation contract */
|
|
53
|
+
export interface ScoreAttestation {
|
|
54
|
+
score: bigint;
|
|
55
|
+
timestamp: bigint;
|
|
56
|
+
signer: string;
|
|
57
|
+
}
|
|
58
|
+
/** Score result from backend scoring API */
|
|
59
|
+
export interface ScoreResult {
|
|
60
|
+
agentId: string;
|
|
61
|
+
score: number;
|
|
62
|
+
timestamp: number;
|
|
63
|
+
breakdown: {
|
|
64
|
+
kyaBonus: number;
|
|
65
|
+
accountBonus: number;
|
|
66
|
+
balanceBonus: number;
|
|
67
|
+
historyBonus: number;
|
|
68
|
+
baseScore: number;
|
|
69
|
+
};
|
|
70
|
+
txHash?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface TransactionResult {
|
|
73
|
+
txHash: string;
|
|
74
|
+
blockNumber: number;
|
|
75
|
+
status: 'success' | 'failed';
|
|
76
|
+
gasUsed: bigint;
|
|
77
|
+
}
|
|
78
|
+
export interface X402PaymentRequest {
|
|
79
|
+
service: string;
|
|
80
|
+
amount: bigint;
|
|
81
|
+
asset: string;
|
|
82
|
+
chain: ChainId;
|
|
83
|
+
recipient: string;
|
|
84
|
+
}
|
|
85
|
+
export interface X402PaymentResult {
|
|
86
|
+
paymentId: string;
|
|
87
|
+
txHash: string;
|
|
88
|
+
amount: bigint;
|
|
89
|
+
chain: ChainId;
|
|
90
|
+
status: 'pending' | 'confirmed' | 'failed';
|
|
91
|
+
}
|
|
92
|
+
export interface AgetherConfig {
|
|
93
|
+
chainId: ChainId;
|
|
94
|
+
rpcUrl: string;
|
|
95
|
+
contracts: ContractAddresses;
|
|
96
|
+
scoringEndpoint?: string;
|
|
97
|
+
kyaEndpoint?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface ContractAddresses {
|
|
100
|
+
accountFactory: string;
|
|
101
|
+
validationRegistry: string;
|
|
102
|
+
agentReputation: string;
|
|
103
|
+
usdc: string;
|
|
104
|
+
identityRegistry: string;
|
|
105
|
+
morphoBlue: string;
|
|
106
|
+
}
|
|
107
|
+
export declare class AgetherError extends Error {
|
|
108
|
+
code: string;
|
|
109
|
+
details?: Record<string, unknown> | undefined;
|
|
110
|
+
constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
|
|
111
|
+
}
|
|
112
|
+
export declare class InsufficientBalanceError extends AgetherError {
|
|
113
|
+
constructor(available: bigint, required: bigint);
|
|
114
|
+
}
|
|
115
|
+
export declare class ScoringRejectedError extends AgetherError {
|
|
116
|
+
constructor(riskScore: number, reason?: string);
|
|
117
|
+
}
|
|
118
|
+
export declare class AgentNotApprovedError extends AgetherError {
|
|
119
|
+
constructor(agentId: bigint);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agether SDK Types
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Agent registers via ERC-8004 → gets agentId
|
|
6
|
+
* - AccountFactory creates AgentAccount (KYA-gated smart wallet) per agent
|
|
7
|
+
* - AgentReputation: oracle-based credit scoring
|
|
8
|
+
* - Morpho Blue: direct overcollateralized lending (agents interact directly)
|
|
9
|
+
* - x402: HTTP payment protocol for scoring API
|
|
10
|
+
*/
|
|
11
|
+
// ============ Enums ============
|
|
12
|
+
export var ChainId;
|
|
13
|
+
(function (ChainId) {
|
|
14
|
+
ChainId[ChainId["Ethereum"] = 1] = "Ethereum";
|
|
15
|
+
ChainId[ChainId["Base"] = 8453] = "Base";
|
|
16
|
+
ChainId[ChainId["BaseSepolia"] = 84532] = "BaseSepolia";
|
|
17
|
+
ChainId[ChainId["Sepolia"] = 11155111] = "Sepolia";
|
|
18
|
+
ChainId[ChainId["Hardhat"] = 31337] = "Hardhat";
|
|
19
|
+
})(ChainId || (ChainId = {}));
|
|
20
|
+
// ============ Error Types ============
|
|
21
|
+
export class AgetherError extends Error {
|
|
22
|
+
constructor(message, code, details) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.details = details;
|
|
26
|
+
this.name = 'AgetherError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class InsufficientBalanceError extends AgetherError {
|
|
30
|
+
constructor(available, required) {
|
|
31
|
+
super(`Insufficient balance: available ${available}, required ${required}`, 'INSUFFICIENT_BALANCE', { available: available.toString(), required: required.toString() });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class ScoringRejectedError extends AgetherError {
|
|
35
|
+
constructor(riskScore, reason) {
|
|
36
|
+
super(`Scoring rejected: risk score ${riskScore}${reason ? `, ${reason}` : ''}`, 'SCORING_REJECTED', { riskScore, reason });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class AgentNotApprovedError extends AgetherError {
|
|
40
|
+
constructor(agentId) {
|
|
41
|
+
super(`Agent ${agentId} is not KYA-approved. Submit code for validation first.`, 'AGENT_NOT_APPROVED', { agentId: agentId.toString() });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract ABIs (minimal for SDK)
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - AccountFactory + AgentAccount (KYA-gated smart wallets)
|
|
6
|
+
* - AgentReputation (oracle-based credit scores)
|
|
7
|
+
* - ValidationRegistry (KYA code validation)
|
|
8
|
+
* - ERC-8004 IdentityRegistry
|
|
9
|
+
* - Morpho Blue (direct overcollateralized lending)
|
|
10
|
+
*/
|
|
11
|
+
export declare const IDENTITY_REGISTRY_ABI: string[];
|
|
12
|
+
export declare const ACCOUNT_FACTORY_ABI: string[];
|
|
13
|
+
export declare const AGENT_ACCOUNT_ABI: string[];
|
|
14
|
+
export declare const AGENT_REPUTATION_ABI: string[];
|
|
15
|
+
export declare const VALIDATION_REGISTRY_ABI: string[];
|
|
16
|
+
export declare const MORPHO_BLUE_ABI: string[];
|
|
17
|
+
export declare const ERC20_ABI: string[];
|
|
18
|
+
//# sourceMappingURL=abis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abis.d.ts","sourceRoot":"","sources":["../../src/utils/abis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,eAAO,MAAM,qBAAqB,UAOjC,CAAC;AAIF,eAAO,MAAM,mBAAmB,UAQ/B,CAAC;AAIF,eAAO,MAAM,iBAAiB,UAc7B,CAAC;AAIF,eAAO,MAAM,oBAAoB,UAShC,CAAC;AAIF,eAAO,MAAM,uBAAuB,UAKnC,CAAC;AAIF,eAAO,MAAM,eAAe,UAiB3B,CAAC;AAIF,eAAO,MAAM,SAAS,UASrB,CAAC"}
|