Skip to content

Commit dc8e560

Browse files
authored
feat: predicate sdk & cli support (#8224)
1 parent 19b4f3e commit dc8e560

39 files changed

Lines changed: 3780 additions & 229 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@hyperlane-xyz/cli': minor
3+
---
4+
5+
Added CLI support for Predicate attestations in warp send command.
6+
7+
CLI Changes:
8+
- Added `--predicate-api-key` option to `warp send` for automatic attestation fetching from Predicate API
9+
- Added `--attestation` option to `warp send` for using pre-obtained attestations (JSON string)
10+
- Detected PredicateRouterWrapper address and sent to Predicate API for correct attestation target
11+
- Added E2E tests for warp send with Predicate attestations
12+
- Added example YAML configs for Predicate warp routes
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@hyperlane-xyz/sdk': major
3+
---
4+
5+
Added Predicate integration for compliance-gated warp route transfers
6+
7+
- Added `PredicateWrapperConfigSchema` for configuring predicate wrapper deployment
8+
- Added `PredicateApiClient` for fetching attestations from Predicate API
9+
- Added `PredicateWrapperDeployer` for deploying and configuring PredicateRouterWrapper contracts
10+
- Integrated predicate wrapper deployment into warp route deployment flow
11+
- Supported aggregation hooks with predicate wrapper (wrapper executes first)
12+
- Always aggregated predicate wrapper with mailbox default hook to ensure gas quoting works correctly
13+
- Detected PredicateRouterWrapper recursively inside nested aggregation hooks
14+
15+
Example configuration:
16+
```yaml
17+
ethereum:
18+
type: collateral
19+
token: '0x...'
20+
predicateWrapper:
21+
predicateRegistry: '0xe15a8Ca5BD8464283818088c1760d8f23B6a216E'
22+
policyId: 'x-your-policy-id'
23+
```

.github/workflows/test-cli-e2e.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ jobs:
4444
test:
4545
- core-deploy
4646
- warp-deploy-1
47+
- warp-deploy-predicate
4748
- warp-apply-simple-updates
49+
- warp-apply-predicate-updates
4850
- warp-check-1
4951
- warp-send
5052
steps:
@@ -90,6 +92,7 @@ jobs:
9092
- warp-apply-hook-updates
9193
- warp-apply-ism-updates
9294
- warp-apply-ownership-updates
95+
- warp-apply-predicate-updates
9396
- warp-apply-rebalancing-config
9497
- warp-apply-simple-updates
9598
- warp-apply-submitters
@@ -102,6 +105,7 @@ jobs:
102105
- warp-bridge-2
103106
- warp-deploy-1
104107
- warp-deploy-2
108+
- warp-deploy-predicate
105109
- warp-deploy-remote-routers
106110
# check
107111
- warp-check-1
@@ -115,6 +119,7 @@ jobs:
115119
- warp-read
116120
- warp-rebalancer
117121
- warp-send
122+
- warp-send-predicate
118123
# xerc20
119124
- xerc20
120125
steps:

solidity/soldeer.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ version = "4.9.3"
2828
git = "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable.git"
2929
rev = "3d4c0d5741b131c231e558d7a6213392ab3672a5"
3030

31+
[[dependencies]]
32+
name = "@predicate-contracts"
33+
version = "2.2.2"
34+
git = "https://github.com/predicatelabs/predicate-contracts.git"
35+
rev = "v2.2.2"
36+
3137
[[dependencies]]
3238
name = "forge-std"
3339
version = "1.9.2"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
base:
2+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
3+
mailbox: '0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D'
4+
hook:
5+
type: predicateHook
6+
address: '0x9995F95aaA827347Bc2AAbF862dF75Ead6E8b97a'
7+
interchainSecurityModule: '0x0000000000000000000000000000000000000000'
8+
remoteRouters:
9+
'1':
10+
address: '0x0000000000000000000000005f72c2d341884ddf0f8a18155d8172f56ae1eeec'
11+
name: USD Coin
12+
symbol: USDC
13+
decimals: 6
14+
isNft: false
15+
contractVersion: 10.1.5
16+
type: collateral
17+
token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
18+
allowedRebalancers: []
19+
allowedRebalancingBridges: {}
20+
proxyAdmin:
21+
address: '0x475bB419502213fdb44d89ad94A1234fA3d7B2f9'
22+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
23+
destinationGas:
24+
'1': '64000'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
base:
2+
type: collateral
3+
token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
4+
mailbox: '0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D'
5+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
6+
predicateWrapper:
7+
predicateRegistry: '0xe15a8Ca5BD8464283818088c1760d8f23B6a216E'
8+
policyId: 'x-managed-policy-157b68744498ccac3201a806ef6036ac'
9+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
10+
11+
ethereum:
12+
type: synthetic
13+
mailbox: '0xc005dc82818d67AF737725bD4bf75435d065D239'
14+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
tokens:
2+
- chainName: base
3+
standard: EvmHypCollateral
4+
decimals: 6
5+
symbol: USDC
6+
name: USD Coin
7+
addressOrDenom: '0x659CAFbe5A0A5B8357192E7C280Fd1f77C28Bd9C'
8+
collateralAddressOrDenom: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
9+
connections:
10+
- token: 'ethereum|ethereum|0x5f72C2D341884Ddf0F8A18155d8172f56Ae1eEEc'
11+
12+
- chainName: ethereum
13+
standard: EvmHypSynthetic
14+
decimals: 6
15+
symbol: USDC
16+
name: USD Coin
17+
addressOrDenom: '0x5f72C2D341884Ddf0F8A18155d8172f56Ae1eEEc'
18+
connections:
19+
- token: 'ethereum|base|0x659CAFbe5A0A5B8357192E7C280Fd1f77C28Bd9C'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
ethereum:
2+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
3+
mailbox: '0xc005dc82818d67AF737725bD4bf75435d065D239'
4+
hook: '0x0000000000000000000000000000000000000000'
5+
interchainSecurityModule: '0x0000000000000000000000000000000000000000'
6+
remoteRouters:
7+
'8453':
8+
address: '0x000000000000000000000000659cafbe5a0a5b8357192e7c280fd1f77c28bd9c'
9+
name: USD Coin
10+
symbol: USDC
11+
decimals: 6
12+
isNft: false
13+
contractVersion: 10.1.5
14+
type: synthetic
15+
proxyAdmin:
16+
address: '0x0fbF624e7FD62e01f83862AFdc6a33A6338dB857'
17+
owner: '0x380ad2e410688e0153125d01a6af9c4C27F7F0eC'
18+
destinationGas:
19+
'8453': '68000'

typescript/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"types": "./dist/src/index.d.ts",
2626
"scripts": {
2727
"hyperlane": "node ./dist/cli.js",
28-
"build": "pnpm version:update && tsc",
28+
"build": "pnpm version:update && NODE_OPTIONS='--max-old-space-size=4096' tsc",
2929
"bundle": "rm -rf ./bundle && ncc build ./dist/cli.js -o bundle && node ../../scripts/ncc.post-bundle.mjs",
3030
"dev": "pnpm version:update && tsc --watch",
3131
"clean": "rm -rf ./dist && rm -rf ./bundle",

typescript/cli/src/commands/warp.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ const send: CommandModuleWithWriteContext<
349349
recipient?: string;
350350
chains?: string[];
351351
skipValidation?: boolean;
352+
predicateApiKey?: string;
353+
predicateApiUrl?: string;
354+
attestation?: string;
352355
sourceToken?: string;
353356
destinationToken?: string;
354357
feeQuotingUrl?: string;
@@ -380,6 +383,23 @@ const send: CommandModuleWithWriteContext<
380383
description: 'Skip transfer validation (e.g., collateral checks)',
381384
default: false,
382385
},
386+
'predicate-api-key': {
387+
type: 'string',
388+
description: 'Predicate API key for fetching attestations automatically',
389+
default: process.env.PREDICATE_API_KEY,
390+
conflicts: 'attestation',
391+
},
392+
'predicate-api-url': {
393+
type: 'string',
394+
description:
395+
'Predicate API base URL (overrides default; useful for testing)',
396+
default: process.env.PREDICATE_API_URL,
397+
implies: 'predicate-api-key',
398+
},
399+
attestation: {
400+
type: 'string',
401+
description: 'Pre-obtained Predicate attestation (JSON string)',
402+
},
383403
'source-token': {
384404
type: 'string',
385405
description:
@@ -408,12 +428,17 @@ const send: CommandModuleWithWriteContext<
408428
timeout,
409429
quick,
410430
relay,
431+
symbol: _symbol,
432+
warp: _warp,
411433
warpRouteId,
412434
amount,
413435
recipient,
414436
roundTrip,
415437
chains: chainsArg,
416438
skipValidation,
439+
predicateApiKey,
440+
predicateApiUrl,
441+
attestation,
417442
sourceToken,
418443
destinationToken,
419444
feeQuotingUrl,
@@ -495,6 +520,9 @@ const send: CommandModuleWithWriteContext<
495520
skipWaitForDelivery: quick,
496521
selfRelay: relay,
497522
skipValidation,
523+
predicateApiKey,
524+
predicateApiUrl,
525+
attestation,
498526
sourceToken,
499527
destinationToken,
500528
feeQuotingUrl,

0 commit comments

Comments
 (0)