Skip to content
This repository was archived by the owner on Mar 11, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
26b53e6
simplify estimateFillOrderV2 api
royvardhan Feb 22, 2026
d9dd0fc
update placeOrder to receive a signed txn and broadcast
royvardhan Feb 22, 2026
72a63ce
allow same chain swaps and add fx strategy
royvardhan Feb 25, 2026
ca59533
filler constructs cNGN price
royvardhan Feb 25, 2026
86b5e23
yeild CANCELLATION_COMPLETE
royvardhan Feb 25, 2026
18d86e7
get the cancel calldata signed from the user
royvardhan Feb 25, 2026
e99b6db
nit
royvardhan Feb 25, 2026
c761352
set account code before simulating user op
royvardhan Feb 26, 2026
b052fcd
set code cache at init
royvardhan Feb 26, 2026
1bac304
add price policy to fx strategy
royvardhan Feb 26, 2026
9603ed1
remove enum
royvardhan Feb 26, 2026
8a8de6f
update sdk to execute partial fills
royvardhan Feb 27, 2026
e678ed5
allow partial fills in fx swap
royvardhan Feb 27, 2026
0f24df3
send approvals in batch txn
royvardhan Feb 27, 2026
e9d35ec
add partial fill rules in fx, docs and cleanup
royvardhan Feb 27, 2026
f02032a
create Tron chain
royvardhan Feb 27, 2026
31a88ff
hardcode nonce
royvardhan Feb 27, 2026
df4f18b
update IChain and use it in event monitor
royvardhan Feb 28, 2026
ea1d180
use IEvmChain
royvardhan Feb 28, 2026
aa77b33
refactor broadcastTransaction
royvardhan Feb 28, 2026
e88c4fd
single end-to-end executor
royvardhan Feb 28, 2026
de7c631
decompose IntentsV2 into smaller parts
royvardhan Feb 28, 2026
467382d
nit
royvardhan Feb 28, 2026
bea1b6a
resolve pr comments
royvardhan Mar 2, 2026
906ef75
hardcode 0 nonce for simulation
royvardhan Mar 2, 2026
93e0d09
log error
royvardhan Mar 2, 2026
52c4142
fallback should use not hardcode any token
royvardhan Mar 2, 2026
f0058a0
yield partial fill details
royvardhan Mar 2, 2026
92b0043
accept graffitti
royvardhan Mar 2, 2026
1d0d87d
nit
royvardhan Mar 2, 2026
b450e49
simplify validateAndSortBids
royvardhan Mar 2, 2026
3f8c06f
yield filled
royvardhan Mar 2, 2026
0593ec3
support multi-token output orders in BidManager.validateAndSortBids
royvardhan Mar 2, 2026
9f0710f
fallback to trace call if recorded slots return undefined
royvardhan Mar 2, 2026
c40b834
refresh fee token cache and some nits
royvardhan Mar 2, 2026
56d9072
exit computing order usd value if any token pricing fails
royvardhan Mar 2, 2026
eb93f37
Update BidManager.ts
royvardhan Mar 2, 2026
1192791
generalize fx strategy
seunlanlege Mar 2, 2026
58052a6
use types from binance/wallet
royvardhan Mar 3, 2026
64bc67a
add quote and cancel from dest
royvardhan Mar 3, 2026
1c12f43
[indexer]: index partial fills
royvardhan Mar 3, 2026
e79707e
nits
seunlanlege Mar 3, 2026
59f1c86
use strategy derived order value for confirmation policy
royvardhan Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"node": ">=22",
"pnpm": ">=7"
},
"packageManager": "pnpm@9.15.0+sha256.09a8fe31a34fda706354680619f4002f4ccef6dadff93240d24ef6c831f0fd28",
"packageManager": "pnpm@10.30.3",
"dependencies": {
"jest": "^29.7.0",
"ts-node": "^10.9.2"
Expand Down
8 changes: 0 additions & 8 deletions packages/filler-v2/filler-config-example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ substratePrivateKey = ""
# Hyperbridge WebSocket URL
hyperbridgeWsUrl = ""

# ERC-4337 EntryPoint contract address
entryPointAddress = ""

# Address of the deployed SolverAccount.sol contract
# The filler's EOA will delegate to this contract via EIP-7702
# This enables the filler to participate in solver selection mode
solverAccountContractAddress = ""

# ERC-4337 bundler URL for UserOperation gas estimation
bundlerUrl = ""

Expand Down
1 change: 1 addition & 0 deletions packages/filler-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"test:services": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/services.test.ts",
"test:filler": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/filler.test.ts",
"test:watch": "vitest",
"test:delegation": "vitest --watch=false --maxConcurrency=1 --testTimeout=1000000 src/tests/delegation.test.ts",
"lint": "biome lint .",
"lint:fix": "biome lint --write .",
"format": "prettier --write \"src/**/*.ts\"",
Expand Down
9 changes: 4 additions & 5 deletions packages/filler-v2/src/bin/filler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ program
substratePrivateKey: config.filler.substratePrivateKey,
hyperbridgeWsUrl: config.filler.hyperbridgeWsUrl,
entryPointAddress: config.filler.entryPointAddress,
solverAccountContractAddress: config.filler.solverAccountContractAddress,
dataDir: config.filler.dataDir,
bundlerUrl: config.filler.bundlerUrl,
rebalancing: config.rebalancing,
Expand Down Expand Up @@ -310,15 +309,15 @@ program
)

// Handle graceful shutdown
process.on("SIGINT", () => {
process.on("SIGINT", async () => {
logger.warn("Shutting down intent filler (SIGINT)...")
intentFiller.stop()
await intentFiller.stop()
process.exit(0)
})

process.on("SIGTERM", () => {
process.on("SIGTERM", async () => {
logger.warn("Shutting down intent filler (SIGTERM)...")
intentFiller.stop()
await intentFiller.stop()
process.exit(0)
})

Expand Down
12 changes: 12 additions & 0 deletions packages/filler-v2/src/config/abis/Entrypoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const ENTRYPOINT_ABI = [
{
inputs: [
{ name: "sender", type: "address" },
{ name: "key", type: "uint192" },
],
name: "getNonce",
outputs: [{ name: "nonce", type: "uint256" }],
stateMutability: "view",
type: "function",
},
] as const
85 changes: 85 additions & 0 deletions packages/filler-v2/src/config/abis/IntentGatewayV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,54 @@ export const INTENT_GATEWAY_V2_ABI = [
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
stateMutability: "view",
},
{
type: "function",
name: "_destinationProtocolFees",
inputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view",
},
{
type: "function",
name: "_filled",
inputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view",
},
{
type: "function",
name: "_instances",
inputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view",
},
{
type: "function",
name: "_nonce",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view",
},
{
type: "function",
name: "_orders",
inputs: [
{ name: "", type: "bytes32", internalType: "bytes32" },
{ name: "", type: "address", internalType: "address" },
],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view",
},
{
type: "function",
name: "_partialFills",
inputs: [
{ name: "", type: "bytes32", internalType: "bytes32" },
{ name: "", type: "bytes32", internalType: "bytes32" },
],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view",
},
{
type: "function",
name: "calculateCommitmentSlotHash",
Expand Down Expand Up @@ -822,6 +870,35 @@ export const INTENT_GATEWAY_V2_ABI = [
],
anonymous: false,
},
{
type: "event",
name: "PartialFill",
inputs: [
{ name: "commitment", type: "bytes32", indexed: true, internalType: "bytes32" },
{ name: "filler", type: "address", indexed: false, internalType: "address" },
{
name: "outputs",
type: "tuple[]",
indexed: false,
internalType: "struct TokenInfo[]",
components: [
{ name: "token", type: "bytes32", internalType: "bytes32" },
{ name: "amount", type: "uint256", internalType: "uint256" },
],
},
{
name: "inputs",
type: "tuple[]",
indexed: false,
internalType: "struct TokenInfo[]",
components: [
{ name: "token", type: "bytes32", internalType: "bytes32" },
{ name: "amount", type: "uint256", internalType: "uint256" },
],
},
],
anonymous: false,
},
{ type: "error", name: "Cancelled", inputs: [] },
{ type: "error", name: "ECDSAInvalidSignature", inputs: [] },
{
Expand All @@ -840,6 +917,14 @@ export const INTENT_GATEWAY_V2_ABI = [
{ type: "error", name: "InvalidInput", inputs: [] },
{ type: "error", name: "InvalidShortString", inputs: [] },
{ type: "error", name: "NotExpired", inputs: [] },
{
type: "error",
name: "SafeCastOverflowedUintDowncast",
inputs: [
{ name: "bits", type: "uint8", internalType: "uint8" },
{ name: "value", type: "uint256", internalType: "uint256" },
],
},
{
type: "error",
name: "SafeERC20FailedOperation",
Expand Down
76 changes: 76 additions & 0 deletions packages/filler-v2/src/config/interpolated-curve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ export interface CurveConfig {
points: CurvePoint[]
}

/**
* A coordinate point on a price curve
* @property amount - The input threshold (e.g., USD amount)
* @property priceUsd - The cNGN price in USD at this threshold
*/
export interface PriceCurvePoint {
amount: string
priceUsd: string
}

/**
* Configuration for a price curve
*/
export interface PriceCurveConfig {
points: PriceCurvePoint[]
}

interface ParsedPoint {
amount: number
value: number
Expand Down Expand Up @@ -129,3 +146,62 @@ export class FillerBpsPolicy {
return BigInt(this.curve.getValue(orderValueUsd))
}
}

/**
* Manages cNGN prices (in USD) based on order value.
* Uses piecewise linear interpolation between configured USD thresholds.
*/
export class FillerPricePolicy {
private points: { amount: Decimal; priceUsd: Decimal }[]

constructor(config: PriceCurveConfig) {
if (!config.points || config.points.length < 1) {
throw new Error("Filler price policy: must have at least 1 point to define a curve")
}

this.points = config.points
.map((p) => ({
amount: new Decimal(p.amount),
priceUsd: new Decimal(p.priceUsd),
}))
.sort((a, b) => a.amount.comparedTo(b.amount))

for (const point of this.points) {
if (!point.amount.isFinite() || point.amount.isNegative()) {
throw new Error("Filler price policy: invalid amount")
}
if (!point.priceUsd.isFinite() || !point.priceUsd.isPositive()) {
throw new Error("Filler price policy: price must be a positive number")
}
}
}

getPrice(orderValueUsd: Decimal): Decimal {
const amount = orderValueUsd

// Below minimum configured amount, use the first point
if (amount.lte(this.points[0].amount)) {
return this.points[0].priceUsd
}

// Above maximum configured amount, use the last point
const lastPoint = this.points[this.points.length - 1]
if (amount.gte(lastPoint.amount)) {
return lastPoint.priceUsd
}

// Piecewise linear interpolation between surrounding points
for (let i = 0; i < this.points.length - 1; i++) {
const p1 = this.points[i]
const p2 = this.points[i + 1]

if (amount.gte(p1.amount) && amount.lte(p2.amount)) {
const t = amount.minus(p1.amount).div(p2.amount.minus(p1.amount))
return p1.priceUsd.plus(t.mul(p2.priceUsd.minus(p1.priceUsd)))
}
}

// Fallback (should not be reached due to earlier checks)
return lastPoint.priceUsd
}
}
Loading
Loading