Skip to content

Commit d588c2e

Browse files
author
azeth-sync[bot]
committed
v0.2.23: sync from monorepo 2026-07-02
1 parent 316679d commit d588c2e

30 files changed

Lines changed: 3082 additions & 58 deletions

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azeth/sdk",
3-
"version": "0.2.22",
3+
"version": "0.2.23",
44
"type": "module",
55
"description": "TypeScript SDK for the Azeth trust infrastructure — smart accounts, x402 payments, reputation, and service discovery",
66
"license": "MIT",
@@ -38,7 +38,7 @@
3838
"test:mutation": "npx stryker run"
3939
},
4040
"dependencies": {
41-
"@azeth/common": "^0.2.22",
41+
"@azeth/common": "^0.2.23",
4242
"@x402/core": "^2.14.0",
4343
"@x402/extensions": "^2.14.0",
4444
"@xmtp/agent-sdk": "^2.2.0",

src/account/create.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ export interface CreateAccountResult {
4444
account: `0x${string}`;
4545
tokenId: bigint;
4646
txHash: `0x${string}`;
47+
/** How the creation transaction was funded:
48+
* 'gasless-relay' — the Azeth server relay sponsored gas (createAccountWithSignature);
49+
* 'direct' — the owner EOA paid gas with a direct factory transaction
50+
* (fallback when the relay is unreachable or rate-limited). */
51+
creationPath?: 'gasless-relay' | 'direct';
4752
}
4853

4954
/** Deploy a new Azeth smart account via the AzethFactory v11 (one-call setup).
@@ -135,7 +140,7 @@ export async function createAccount(
135140
})) as `0x${string}`;
136141
}
137142

138-
return { account, tokenId, txHash };
143+
return { account, tokenId, txHash, creationPath: 'direct' };
139144
}
140145

141146
/** Compute the deterministic address for an account without deploying */

src/account/gasless.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export async function submitToRelay(
143143
account: body.data.account,
144144
tokenId: BigInt(body.data.tokenId),
145145
txHash: body.data.txHash,
146+
creationPath: 'gasless-relay',
146147
};
147148
}
148149

src/account/transfer.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ async function preflightCheck(
5252
addresses: AzethContractAddresses,
5353
smartAccount: `0x${string}`,
5454
params: TransferParams,
55+
guardianCosignAvailable?: boolean,
5556
): Promise<void> {
5657
const guardianAddress = requireAddress(addresses, 'guardianModule');
5758

@@ -70,6 +71,38 @@ async function preflightCheck(
7071

7172
if (reason === 0) return; // OK
7273

74+
// Guardian-satisfiable requirements: when the client will attach a guardian
75+
// co-signature (explicit auto-sign key or self-guardian), these are not
76+
// blocking — the dual signature validates at the guardian tier on-chain.
77+
if (guardianCosignAvailable) {
78+
if (reason === 5 || reason === 6) return; // ORACLE_STALE / GUARDIAN_REQUIRED → co-sign satisfies
79+
if (reason === 2 || reason === 3) {
80+
// Limits exceeded at the OWNER tier — check against the higher GUARDIAN tier.
81+
const guardrails = await publicClient.readContract({
82+
address: guardianAddress,
83+
abi: GuardianModuleAbi,
84+
functionName: 'getGuardrails',
85+
args: [smartAccount],
86+
}) as { guardianMaxTxAmountUSD: bigint; guardianDailySpendLimitUSD: bigint };
87+
if (reason === 2 && details.usdValue <= guardrails.guardianMaxTxAmountUSD) return;
88+
if (reason === 3 && details.dailySpentUSD + details.usdValue <= guardrails.guardianDailySpendLimitUSD) return;
89+
// Exceeds even the guardian tier — fall through to the descriptive error below,
90+
// with the guardian-tier limit in the details for an actionable message.
91+
throw new AzethError(
92+
reason === 2
93+
? `Transfer of ${formatUSD(details.usdValue)} exceeds even the guardian-tier per-transaction limit of ${formatUSD(guardrails.guardianMaxTxAmountUSD)}`
94+
: `Transfer of ${formatUSD(details.usdValue)} would exceed even the guardian-tier daily limit of ${formatUSD(guardrails.guardianDailySpendLimitUSD)} (spent today: ${formatUSD(details.dailySpentUSD)})`,
95+
'GUARDIAN_REJECTED',
96+
{
97+
reason: VALIDATION_REASON_NAMES[reason] ?? 'UNKNOWN',
98+
usdValue: formatUSD(details.usdValue),
99+
guardianMaxTxAmountUSD: formatUSD(guardrails.guardianMaxTxAmountUSD),
100+
guardianDailySpendLimitUSD: formatUSD(guardrails.guardianDailySpendLimitUSD),
101+
},
102+
);
103+
}
104+
}
105+
73106
const reasonName = VALIDATION_REASON_NAMES[reason] ?? 'UNKNOWN';
74107

75108
const errorDetails: Record<string, unknown> = {
@@ -124,6 +157,7 @@ export async function transfer(
124157
params: TransferParams,
125158
publicClient?: PublicClient<Transport, Chain>,
126159
addresses?: AzethContractAddresses,
160+
guardianCosignAvailable?: boolean,
127161
): Promise<TransferResult> {
128162
// M-12 fix (Audit #8): Block negative amounts (bigint can go negative).
129163
// AUDIT-FIX: Also reject zero-amount transfers — they waste gas on a no-op.
@@ -134,7 +168,7 @@ export async function transfer(
134168
// Pre-flight guardrail check: catch spending limit / whitelist failures early
135169
// with descriptive errors instead of opaque "AA24 signature error".
136170
if (publicClient && addresses) {
137-
await preflightCheck(publicClient, addresses, smartAccount, params);
171+
await preflightCheck(publicClient, addresses, smartAccount, params, guardianCosignAvailable);
138172
}
139173

140174
let txHash: `0x${string}`;

0 commit comments

Comments
 (0)