Skip to content

Commit b13204a

Browse files
authored
[simplex,sdk]: support signing with MPC Vault (#707)
1 parent bdafcc8 commit b13204a

40 files changed

+1550
-397
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@
1010
[submodule "sdk/packages/core/lib/forge-std"]
1111
path = sdk/packages/core/lib/forge-std
1212
url = https://github.com/foundry-rs/forge-std
13+
[submodule "sdk/packages/simplex/proto/mpcvaultapis"]
14+
path = sdk/packages/simplex/proto/mpcvaultapis
15+
url = https://github.com/mpcvault/mpcvaultapis.git

sdk/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
packages/core/
33
packages/indexer/
44

5+
# Generated by pnpm build in @hyperbridge/simplex (protoc); never bake host output into the image
6+
packages/simplex/src/proto/
7+
58
# Version Control
69
.git/
710
.github/

sdk/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ packages/indexer/docker/mainnet/
2525
packages/simplex/src/filler-config.toml
2626
packages/simplex/src/simplex-config.toml
2727
packages/simplex/.simplex-data
28+
packages/simplex/src/proto
29+
packages/simplex/.protoc-ci
2830

2931

3032
# Compiled Java class files

sdk/package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"release": "pnpm build && pnpm --filter=\"*\" publish --no-git-checks"
1616
},
1717
"devDependencies": {
18-
"@typescript-eslint/eslint-plugin": "^8.25.0",
18+
"@typescript-eslint/eslint-plugin": "^8.25.0",
1919
"@typescript-eslint/parser": "^8.25.0",
2020
"eslint": "^9.21.0",
2121
"eslint-config-prettier": "^10.0.2",
@@ -54,7 +54,15 @@
5454
]
5555
},
5656
"pnpm": {
57-
"onlyBuiltDependencies": ["better-sqlite3", "bufferutil", "utf-8-validate", "esbuild"]
57+
"onlyBuiltDependencies": [
58+
"better-sqlite3",
59+
"bufferutil",
60+
"utf-8-validate",
61+
"esbuild"
62+
],
63+
"overrides": {
64+
"viem": "2.47.6"
65+
}
5866
},
5967
"engines": {
6068
"node": ">=22",

sdk/packages/sdk/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
"tronweb": "^6.2.0",
7878
"ts-pattern": "^5.6.2",
7979
"unstorage": "^1.17.2",
80-
"viem": "^2.34.0"
80+
"viem": "2.47.6"
8181
},
8282
"devDependencies": {
8383
"@biomejs/biome": "^1.9.4",
@@ -122,8 +122,7 @@
122122
"@polkadot/x-randomvalues": "^13.5.6",
123123
"@polkadot/x-textdecoder": "^13.5.6",
124124
"@polkadot/x-textencoder": "^13.5.6",
125-
"@polkadot/x-ws": "^13.5.6",
126-
"typescript": "^5.9.3"
125+
"@polkadot/x-ws": "^13.5.6"
127126
},
128127
"peerDependencies": {
129128
"vite": "^5.0.0 || ^6.0.0"

sdk/packages/sdk/src/protocols/intents/BidManager.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { encodeFunctionData, decodeFunctionData, concat, keccak256, parseEventLogs } from "viem"
2-
import { privateKeyToAccount } from "viem/accounts"
32
import { ABI as IntentGatewayV2ABI } from "@/abis/IntentGatewayV2"
43
import { ADDRESS_ZERO, bytes32ToBytes20, hexToString, retryPromise } from "@/utils"
54
import type {
@@ -59,7 +58,7 @@ export class BidManager {
5958
const {
6059
order,
6160
solverAccount,
62-
solverPrivateKey,
61+
solverSigner,
6362
nonce,
6463
entryPointAddress,
6564
callGasLimit,
@@ -92,12 +91,10 @@ export class BidManager {
9291
const userOpHash = this.crypto.computeUserOpHash(userOp, entryPointAddress, chainId)
9392
const sessionKey = order.session
9493

95-
const messageHash = keccak256(concat([userOpHash, order.id as HexString, sessionKey as import("viem").Hex]))
94+
const messageHash = keccak256(concat([userOpHash, order.id as HexString, sessionKey as HexString]))
95+
const solverSignature = await solverSigner.signMessage(messageHash, Number(chainId))
9696

97-
const solverAccount_ = privateKeyToAccount(solverPrivateKey as import("viem").Hex)
98-
const solverSignature = await solverAccount_.signMessage({ message: { raw: messageHash } })
99-
100-
const signature = concat([order.id as HexString, solverSignature as import("viem").Hex]) as HexString
97+
const signature = concat([order.id as HexString, solverSignature as HexString]) as HexString
10198

10299
return { ...userOp, signature }
103100
}

sdk/packages/sdk/src/types/index.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import type { ConsolaInstance } from "consola"
22
import type { GraphQLClient } from "graphql-request"
33
import type { ContractFunctionArgs, Hex, Log, PublicClient, TransactionReceipt } from "viem"
4+
import type { Account } from "viem/accounts"
5+
6+
/** Re-export: use this type when wiring a viem `Account` next to `SigningAccount` so you stay aligned with the SDK’s viem resolution. */
7+
export type { Account as ViemAccount } from "viem/accounts"
48
import type HandlerV1 from "@/abis/handler"
59
import type { IChain } from "@/chain"
610
import { Struct, Vector, Bytes, u8 } from "scale-ts"
@@ -1177,11 +1181,19 @@ export interface PackedUserOperation {
11771181
signature: HexString
11781182
}
11791183

1184+
export interface SigningAccount {
1185+
/** Signs a bid message hash for a given chain. Returns a 65-byte ECDSA signature. */
1186+
signMessage: (messageHash: HexString, chainId: number) => Promise<HexString>
1187+
/** Signs a raw 32-byte hash, returning split signature components for EIP-7702 etc. */
1188+
signRawHash: (hash: HexString) => Promise<{ r: HexString; s: HexString; yParity: number }>
1189+
}
1190+
11801191
export interface SubmitBidOptions {
11811192
order: Order
11821193
fillOptions: FillOptions
11831194
solverAccount: HexString
1184-
solverPrivateKey: HexString
1195+
/** Canonical signer used for bid message signing and raw-hash operations. */
1196+
solverSigner: SigningAccount
11851197
nonce: bigint
11861198
entryPointAddress: HexString
11871199
// Estimated gas for executing fillOrder calldata
@@ -1356,7 +1368,13 @@ export type IntentOrderStatusUpdate =
13561368
remainingAssets?: TokenInfo[]
13571369
error: string
13581370
}
1359-
| { status: "FAILED"; commitment?: HexString; totalFilledAssets?: TokenInfo[]; remainingAssets?: TokenInfo[]; error: string }
1371+
| {
1372+
status: "FAILED"
1373+
commitment?: HexString
1374+
totalFilledAssets?: TokenInfo[]
1375+
remainingAssets?: TokenInfo[]
1376+
error: string
1377+
}
13601378

13611379
/** Result of selecting a bid and submitting to the bundler */
13621380
export interface SelectBidResult {

sdk/packages/simplex/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Hyperbridge Intent FillerV2
1+
# Hyperbridge Simplex
22

3-
A high-performance intent filler for the Hyperbridge IntentGatewayV2 protocol. This package provides both a library interface and a CLI binary for running an intent filler that monitors and fills cross-chain orders.
3+
Canonical documentation for Simplex lives in the Hyperbridge docs:
44

55
## Installation
66

sdk/packages/simplex/filler-config-example.toml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,22 @@
44

55
# Filler configuration
66
[simplex]
7-
privateKey = "" # Replace with your actual EVM private key (not required if all chains are watchOnly)
7+
# Choose ONE signer mode via [simplex.signer]:
8+
# 1) Private key signer:
9+
# [simplex.signer]
10+
# type = "privateKey"
11+
# privateKey = "0x..." # Not required if all chains are watchOnly
12+
#
13+
# 2) MPCVault signer:
14+
# [simplex.signer]
15+
# type = "mpcVault"
16+
# [simplex.signer.mpcVault]
17+
# apiToken = ""
18+
# vaultUuid = ""
19+
# accountAddress = "0x0000000000000000000000000000000000000000"
20+
# callbackClientSignerPublicKey = "ssh-ed25519 AAAA..."
21+
# grpcTarget = "api.mpcvault.com:443" # optional; default when omitted
22+
823
maxConcurrentOrders = 5
924

1025
# ===== Solver Selection Mode Configuration =====
@@ -75,7 +90,7 @@ triggerPercentage = 0.5
7590

7691
# Strategy configuration
7792
# You can configure multiple strategies
78-
# All strategies use the simplex.privateKey from above
93+
# All strategies use the configured simplex signer (privateKey or mpcVault)
7994
[[strategies]]
8095
type = "basic"
8196
# Filler BPS (basis points) curve based on order value

sdk/packages/simplex/package.json

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,21 @@
1919
"dist"
2020
],
2121
"scripts": {
22-
"build": "tsup",
22+
"codegen": "bash ./scripts/build.sh --codegen-only",
23+
"build": "bash ./scripts/build.sh",
2324
"prepublishOnly": "npm run build",
24-
"test": "vitest --watch=false --maxConcurrency=1",
25-
"test:services": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/services.test.ts",
26-
"test:filler": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/basic.testnet.test.ts",
27-
"test:basic": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/basic.testnet.test.ts",
28-
"test:fx": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/fx.mainnet.test.ts",
29-
"test:watch": "vitest",
30-
"lint": "biome lint .",
31-
"lint:fix": "biome lint --write .",
32-
"format": "prettier --write \"src/**/*.ts\"",
33-
"cli": "NODE_NO_WARNINGS=1 tsx src/bin/simplex.ts",
34-
"cli:dev": "nodemon --watch src --ext ts --exec tsx src/bin/simplex.ts"
25+
"test": "pnpm run codegen && vitest --watch=false --maxConcurrency=1",
26+
"test:filler": "pnpm run codegen && vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/basic.testnet.test.ts",
27+
"test:basic": "pnpm run codegen && vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/basic.testnet.test.ts",
28+
"test:fx": "pnpm run codegen && vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/strategies/fx.mainnet.test.ts",
29+
"test:mpcvault": "pnpm run codegen && vitest --watch=false --maxConcurrency=1 --testTimeout=120000 src/tests/wallet/mpcvault.integration.test.ts",
30+
"test:watch": "pnpm run codegen && vitest",
31+
"lint": "pnpm run codegen && biome lint src/bin src/config src/core src/services src/strategies src/tests src/index.ts",
32+
"lint:fix": "pnpm run codegen && biome lint --write src/bin src/config src/core src/services src/strategies src/tests src/index.ts",
33+
"format": "pnpm run codegen && prettier --write \"src/**/*.ts\"",
34+
"cli": "pnpm run codegen && NODE_NO_WARNINGS=1 tsx src/bin/simplex.ts",
35+
"cli:dev": "pnpm run codegen && nodemon --watch src --ext ts --exec tsx src/bin/simplex.ts",
36+
"proto:generate": "./scripts/generate-proto.sh"
3537
},
3638
"devDependencies": {
3739
"@biomejs/biome": "^1.9.4",
@@ -40,6 +42,7 @@
4042
"@vitest/coverage-v8": "^3.0.7",
4143
"nodemon": "^3.1.0",
4244
"tronweb": "^6.2.0",
45+
"ts-proto": "^2.6.1",
4346
"tsup": "^8.4.0",
4447
"tsx": "^4.16.2",
4548
"typescript": "^5.7.3",
@@ -57,6 +60,8 @@
5760
"@binance/wallet": "^16.0.0",
5861
"@circle-fin/adapter-viem-v2": "1.4.0",
5962
"@circle-fin/bridge-kit": "1.5.0",
63+
"@bufbuild/protobuf": "^2.2.3",
64+
"@grpc/grpc-js": "^1.12.5",
6065
"@hyperbridge/sdk": "workspace:*",
6166
"@polkadot/api": "latest",
6267
"@polkadot/util": "latest",
@@ -77,7 +82,7 @@
7782
"pino-pretty": "^11.3.0",
7883
"scale-ts": "^1.6.1",
7984
"toml": "^3.0.0",
80-
"viem": "^2.34.0"
85+
"viem": "2.47.6"
8186
},
8287
"resolutions": {
8388
"@polkadot/api": "^16.4.6",

0 commit comments

Comments
 (0)