Skip to content

Commit c392873

Browse files
authored
Merge pull request #44 from MetaMask/feat/nonce-caveat-delegation-core2
Added Nonce Enforcer as Caveat in Delegation Core
2 parents 9c62033 + bdfa550 commit c392873

File tree

6 files changed

+528
-20
lines changed

6 files changed

+528
-20
lines changed

packages/delegation-core/src/caveats/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { createExactCalldataTerms } from './exactCalldata';
55
export { createNativeTokenStreamingTerms } from './nativeTokenStreaming';
66
export { createERC20StreamingTerms } from './erc20Streaming';
77
export { createERC20TokenPeriodTransferTerms } from './erc20TokenPeriodTransfer';
8+
export { createNonceTerms } from './nonce';
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { isHexString } from '@metamask/utils';
2+
import type { BytesLike } from '@metamask/utils';
3+
4+
import {
5+
bytesLikeToHex,
6+
defaultOptions,
7+
prepareResult,
8+
type EncodingOptions,
9+
type ResultValue,
10+
} from '../returns';
11+
import type { Hex } from '../types';
12+
13+
// char length of 32 byte hex string (including 0x prefix)
14+
const MAX_NONCE_STRING_LENGTH = 66;
15+
16+
/**
17+
* Terms for configuring a Nonce caveat.
18+
*/
19+
export type NonceTerms = {
20+
/** The nonce as BytesLike (0x-prefixed hex string or Uint8Array) to allow bulk revocation of delegations. */
21+
nonce: BytesLike;
22+
};
23+
24+
/**
25+
* Creates terms for a Nonce caveat that uses a nonce value for bulk revocation of delegations.
26+
*
27+
* @param terms - The terms for the Nonce caveat.
28+
* @param encodingOptions - The encoding options for the result.
29+
* @returns The terms as a 32-byte hex string.
30+
* @throws Error if the nonce is invalid.
31+
*/
32+
export function createNonceTerms(
33+
terms: NonceTerms,
34+
encodingOptions?: EncodingOptions<'hex'>,
35+
): Hex;
36+
export function createNonceTerms(
37+
terms: NonceTerms,
38+
encodingOptions: EncodingOptions<'bytes'>,
39+
): Uint8Array;
40+
/**
41+
* Creates terms for a Nonce caveat that uses a nonce value for bulk revocation of delegations.
42+
*
43+
* @param terms - The terms for the Nonce caveat.
44+
* @param encodingOptions - The encoding options for the result.
45+
* @returns The terms as a 32-byte padded value in the specified encoding format.
46+
* @throws Error if the nonce is invalid or empty.
47+
*/
48+
export function createNonceTerms(
49+
terms: NonceTerms,
50+
encodingOptions: EncodingOptions<ResultValue> = defaultOptions,
51+
): Hex | Uint8Array {
52+
const { nonce } = terms;
53+
54+
// Handle zero-length Uint8Array specifically
55+
if (nonce instanceof Uint8Array && nonce.length === 0) {
56+
throw new Error('Invalid nonce: Uint8Array must not be empty');
57+
}
58+
59+
// Validate that strings have 0x prefix (as required by BytesLike)
60+
if (typeof nonce === 'string' && !nonce.startsWith('0x')) {
61+
throw new Error('Invalid nonce: string must have 0x prefix');
62+
}
63+
64+
// Convert to hex string for consistent processing
65+
const hexNonce = bytesLikeToHex(nonce);
66+
67+
// Check for empty hex string (0x) first - more specific error
68+
if (hexNonce === '0x') {
69+
throw new Error('Invalid nonce: must not be empty');
70+
}
71+
72+
if (!isHexString(hexNonce)) {
73+
throw new Error('Invalid nonce: must be a valid BytesLike value');
74+
}
75+
76+
if (hexNonce.length > MAX_NONCE_STRING_LENGTH) {
77+
throw new Error('Invalid nonce: must be 32 bytes or less in length');
78+
}
79+
80+
// Remove '0x' prefix for padding, then add it back
81+
const nonceWithoutPrefix = hexNonce.slice(2);
82+
const paddedNonce = nonceWithoutPrefix.padStart(64, '0'); // 64 hex chars = 32 bytes
83+
const hexValue = `0x${paddedNonce}`;
84+
85+
return prepareResult(hexValue, encodingOptions);
86+
}

packages/delegation-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export {
1212
createNativeTokenStreamingTerms,
1313
createERC20StreamingTerms,
1414
createERC20TokenPeriodTransferTerms,
15+
createNonceTerms,
1516
} from './caveats';
1617

1718
export {

0 commit comments

Comments
 (0)