Onboarding
This guide is the operator-facing entry point for bridge facilitators integrating with Grunt. It focuses on how to set up your addresses, authenticate, discover auctions, submit offers, track status, and complete the bridge loan lifecycle.
Environments
Section titled “Environments”| Environment | Chains | Base URL |
|---|---|---|
| Developement | Ethereum Sepolia | https://bf.dev.gcp.3f.xyz |
| Production | Ethereum Mainnet | https://bf.3f.xyz |
Prerequisites
Section titled “Prerequisites”Before you begin, ensure you have:
- A funded wallet on the target network — you need gas for signatures, approvals, and any on-chain funding or redemption steps.
- Access to the required asset — your operational setup must be able to source the asset used by the Request contracts you intend to fund (for example, USDC).
- An approved bridge facilitator identity — 3F must approve the address your organization will use for onboarding and integration policy.
- An operational funding setup — your treasury, vault, or contract flow must support either signed pull offers or authorized push funding.
Identity and Address Model
Section titled “Identity and Address Model”Most BF integrations use two logical addresses:
- Bridge facilitator identity — your approved 3F identity, used for onboarding, authentication, and account-level policy.
- Operational funding address — the address that actually provides capital, receives PT/YT, and performs operational on-chain actions.
A simple setup can use the same address for both roles. More advanced setups often separate them so a multisig, vault, or contract-controlled address handles capital while another system manages day-to-day API access.
When to use separate addresses:
- Multisig or custody-controlled capital — your funding address is a cold storage or multisig wallet; a hot wallet manages API operations
- Contract-based vaults — your funding address is a smart contract that implements custom authorization or callback logic
- Operational resilience — you want the ability to rotate operator credentials without changing the on-chain funding address
When a single address suffices:
- Simplified operations — one address controls both identity and capital, reducing coordination overhead
- Direct control — your operational model does not require separate custody or approval layers
| Role | Controlled by | Purpose | Typical actions |
|---|---|---|---|
| BF identity | You | Approved integration identity | Onboarding, API key generation, signed admin/auth payloads |
| Operational funding address | You | Capital source and PT/YT holder | Submit or fund offers, approve assets, call mint(), redeem PT/YT |
| 3F authorizer | 3F | Reflects accepted push-funded offers on-chain | authorizeMinting() |
| Facility puller | 3F | Draws bridge capital into the strategy and repays it | pullFunds(), repay() |
| Request owner | 3F | Final lifecycle transitions | setRepaid() |
If you use a separate operational funding address, keep it stable. That is the address that must be ready to approve funds, receive PT/YT, and later redeem them after repayment.
This address can be set via POST /v1/facilitator/offer-address.
Step 1: Register Your Bridge Facilitator Identity
Section titled “Step 1: Register Your Bridge Facilitator Identity”Contact 3F and share the address that should be approved as your bridge facilitator identity. 3F uses this identity to:
- allow your organization to participate in bridge facilitator flows
- issue API credentials
- map a dedicated operational funding address if you use one
- coordinate wallet rotation or emergency access changes
Once approved, decide whether your BF identity and operational funding address will be the same or separate.
Step 2: Choose Your Auth and Funding Model
Section titled “Step 2: Choose Your Auth and Funding Model”Authentication models
Section titled “Authentication models”Grunt supports two operator-facing authentication models:
- EIP-712 signatures — used for onboarding and administrative auth. Signed offers and signed offer queries also use typed data.
- API key authentication — used for day-to-day offer operations when you want a persistent credential in your systems.
Administrative actions use short-lived signatures. Offer operations can use signatures or API keys, depending on the flow you choose.
Funding models
Section titled “Funding models”There are two ways your capital reaches a Request:
- Signed pull offers — you sign an offer off-chain and the Request later pulls funds from your operational funding address if the offer is selected.
- Authorized push funding — you authenticate with the API, 3F authorizes the accepted amount on-chain, and your operational funding address pushes funds by calling
mint().
Use signed pull offers when you want the Request to consume a typed offer directly. Use authorized push funding when you want an explicit accept-then-mint operational step.
Step 3: Generate Your API Key
Section titled “Step 3: Generate Your API Key”To generate an API key, sign a short-lived EIP-712 message and submit it through the API key generation flow.
This step maps to POST /v1/facilitator/generate-key. The path currently retains legacy naming, but this is the bridge facilitator API-key generation endpoint.
Typed-data shape:
{ "types": { "EIP712Domain": [ { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" } ], "GenerateFacilitatorApiKey": [ { "name": "facilitator", "type": "address" }, { "name": "deadline", "type": "uint256" } ] }, "primaryType": "GenerateFacilitatorApiKey", "domain": { "name": "grunt-api", "version": "1", "chainId": 1 }, "message": { "facilitator": "0xYourBridgeFacilitatorIdentity", "deadline": 1735689600 }}Key rules:
deadlineis the authentication expiry for this specific request.deadlinemust be Unix seconds, not milliseconds.deadlineshould be short-lived to reduce replay risk.deadlineis distinct from offerexpiration, which controls how long an offer remains valid for matching.
Store the resulting API key securely. Use it only for offer-management flows, and rotate it whenever your operating environment changes.
Step 4: Discover Auctions
Section titled “Step 4: Discover Auctions”Use the auction listing flow to find active Request contracts that need bridge capital.
In most integrations, this discovery step maps to GET /v1/auction.
Operationally, there are now three useful discovery modes:
GET /v1/auction— the default lightweight view for polling active opportunities.GET /v1/auction?scope=all— include terminal and historical auctions for reconciliation.GET /v1/auction?domain=true— include request-domain metadata needed for signed pull offers.
When domain=true is present, each auction may include:
{ "requestId": "0xRequestContractAddress", "eip712Domain": { "name": "Request Name", "version": "0.0.1", "chainId": 1 }}This response is meant to bridge discovery and signing:
requestIdis the Request contract you will ultimately bind the offer to.eip712Domain.name,version, andchainIdare the Request-domain values you should use in the EIP-712 payload.- the
verifyingContractis still the Request address itself, so userequestIdfor that field.
In practice, many BF operators keep the default GET /v1/auction polling loop for monitoring and only request domain=true when an operator or signing service is preparing an actual signed pull offer.
The API field is a convenience, not a new source of truth. If you need to cross-check or troubleshoot a signature mismatch, query eip712Domain() on the Request contract directly and treat the contract result as authoritative.
When reviewing an auction, confirm:
- the Request contract address
- the asset you must fund
- the total amount requested and the amount already filled
- the funding deadline
- the auction status
In practice, most BF operators keep two views:
- Active auctions — opportunities that can still be funded
- All auctions — historical and terminal requests for reconciliation or audit
Auction status lifecycle
Section titled “Auction status lifecycle”Auction statuses describe the off-chain RFQ and settlement workflow around a Request. They are API-facing operational states, not Request contract states.
graph LR
O[OPEN] --> SV[SOLVABLE]
SV --> SIP[SOLVING_IN_PROGRESS]
SIP --> DR[DEPOSIT_READY]
SIP --> SV
DR --> P[PROCESSING]
P --> PS[PARTIAL_SOLVED]
PS --> SV
P --> SUC[SUCCEEDED]
P -.-> F[FAILED]
SUC --> R[REPAID]
PS --> R
| Status | Meaning |
|---|---|
| OPEN | Auction was created by the engine from staged request metadata and is waiting until its deposit deadline. |
| SOLVABLE | Auction is ready for the solver to evaluate offers. Also used after insufficient liquidity, backoff, or recovery paths return work to the solver. |
| SOLVING_IN_PROGRESS | Solver has claimed the auction and is selecting offers. This is a leased in-progress state. |
| DEPOSIT_READY | Solver selected one or more offers and created accepted transaction rows. The relayer can now process them. |
| PROCESSING | Relayer has claimed the auction and is broadcasting or monitoring accepted transactions. |
| PARTIAL_SOLVED | Some execution completed, but the auction is not fully filled. The auction remains eligible for future solver passes. |
| SUCCEEDED | Auction target is filled, or the reduced target reached zero. Remaining submitted offers are marked NOT_ACCEPTED. |
| FAILED | Defined execution-complete failure state. Current production failure paths normally return the auction to PARTIAL_SOLVED so remaining work can be retried. |
| REPAID | Monitor marks a SUCCEEDED or PARTIAL_SOLVED auction repaid once the linked Request has is_repaid = true. |
Step 5: Submit Offers
Section titled “Step 5: Submit Offers”Mode A: Signed pull offers
Section titled “Mode A: Signed pull offers”Use this flow when you want Grunt to consume a typed offer directly from your operational funding address.
Both signed pull offers and authorized push offers start with an offer submission call, POST /v1/offer.
- Read the current minimum nonce for your funding address from the Request contract.
- Build an offer typed-data payload bound to that specific Request. In most API-led integrations, this means reading the auction row, taking
requestIdas theverifyingContract, and usingGET /v1/auction?domain=trueto populate the Request-domainname,version, andchainId. - Sign the offer from the address or contract authorization path that controls the funding address.
- Approve the Request contract as the asset spender for the amount you are willing to fund before the funding deadline.
- If selected, the Request consumes the offer, pulls funds, and mints PT/YT to your funding address.
Typed-data shape:
{ "types": { "EIP712Domain": [ { "name": "name", "type": "string" }, { "name": "version", "type": "string" }, { "name": "chainId", "type": "uint256" }, { "name": "verifyingContract", "type": "address" } ], "Offer": [ { "name": "maker", "type": "address" }, { "name": "amount", "type": "uint256" }, { "name": "expectedReturn", "type": "uint256" }, { "name": "nonce", "type": "uint256" }, { "name": "expiration", "type": "uint256" }, { "name": "useCallback", "type": "bool" } ] }, "primaryType": "Offer", "domain": { "name": "Request Name", "version": "0.0.1", "chainId": 1, "verifyingContract": "0xRequestContractAddress" }, "message": { "maker": "0xYourOperationalFundingAddress", "amount": "1000000000000", "expectedReturn": "100000000000", "nonce": 7, "expiration": 1735689600, "useCallback": false }}Field semantics:
nonce— replay protection and cancellation state. An offer is valid only if its nonce exceeds the Request’s stored minimum nonce for your funding address.expiration— Unix timestamp after which the offer is no longer valid for matching.expectedReturn— expected yield, denominated in the same asset as the principal. For example, if you lend 1,000,000 USDC and require a 1% return, setexpectedReturnto 10,000. Total repayment isamount + expectedReturn, or 1,010,000 in that example.useCallback— when set totrue, the Request callsonRequestConsumed()on your funding address before pulling funds. This enables contract-based funding addresses to move capital from internal vaults, set allowances, or execute preparatory logic atomically. Set tofalsefor EOA-based funding where funds are already approved and available.- The Request-domain
verifyingContractandchainIdbind the signature to a single Request contract on a specific chain.
Mode B: Authorized push funding
Section titled “Mode B: Authorized push funding”Use this flow when you want to submit an offer through the API and only move capital after 3F authorizes the accepted amount on-chain.
- Submit the offer using API authentication.
- Monitor status until the offer becomes
AWAITING_MINT. - From your operational funding address, approve the Request contract as the asset spender for the accepted amount.
- Call
mint()to transfer funds into the Request and receive PT/YT. - Keep the same operational funding address available for later redemption once the Request is repaid.
Illustrative API-managed offer shape:
{ "bridgeFacilitatorAddress": "0xYourBridgeFacilitatorIdentity", "fundingAddress": "0xYourOperationalFundingAddress", "amount": "1000000000000", "expectedReturn": "100000000000", "auctionId": "auction_01HXK...", "chainId": 1}Step 6: Track, Update, and Settle Offers
Section titled “Step 6: Track, Update, and Settle Offers”Once offers are live, your operating loop is straightforward:
- List or poll your offers by BF identity or funding address.
- Watch the offer status until it is accepted, awaiting mint, completed, or rejected.
- Update or cancel offers when your pricing or capacity changes.
- If a push-funded offer reaches
AWAITING_MINT, fund it promptly from the operational funding address. - After repayment is marked complete, redeem PT/YT from the same operational funding address that received them.
Offer listing maps to GET /v1/offer, and explicit offer withdrawal maps to POST /v1/offer/cancel.
Offer lifecycle
Section titled “Offer lifecycle”graph LR
S[SUBMITTED] --> A[ACCEPTED]
S --> C[CANCELLED]
S --> N[NOT_ACCEPTED]
A -->|Push funding| M[AWAITING_MINT]
M --> SUC[SUCCEEDED]
A -->|Signed pull funding| SUC
A --> F[FAILED]
M --> F
| Status | Meaning |
|---|---|
| SUBMITTED | Initial/default offer state. Only SUBMITTED and unexpired offers are selectable by the solver. |
| ACCEPTED | Solver selected the offer and created an accepted transaction for it. |
| AWAITING_MINT | Unsigned offer authorization confirmed on-chain; the system is waiting for the maker to mint. |
| CANCELLED | Offer was canceled and is no longer selectable. |
| SUCCEEDED | Offer execution completed successfully, either through signed offer consumption or maker mint after authorization. |
| FAILED | Offer execution failed, timed out, or failed validation or broadcast handling. |
| NOT_ACCEPTED | Offer remained submitted but was not selected before the auction closed, succeeded, or was repaid. |
Updating and cancelling outstanding offers
Section titled “Updating and cancelling outstanding offers”- Soft update — submit a new offer with better pricing or terms to replace your existing offer in the off-chain auction. No gas required; the new offer simply supersedes the old one for matching purposes.
- Soft cancel — withdraw your offer from consideration through the off-chain auction by submitting a cancellation request. No gas required, but valid only before the offer is selected.
- Hard cancel — increment your on-chain minimum nonce by sending a transaction to the Request contract. This invalidates all prior signed offers with certainty. Requires gas but provides finality independent of off-chain state.
Use soft updates and cancels for active position management. Reserve hard cancels for emergency revocation or when you need cryptographic certainty that old offers cannot be consumed.
Acceptance timeout
Section titled “Acceptance timeout”Off-chain acceptance is not final until funds arrive. If an accepted offer is not funded within the required window, 3F may fail the offer and select another bridge facilitator. Treat AWAITING_MINT as a prompt to fund, not as a guaranteed terminal state.
Common failure modes
Section titled “Common failure modes”| Failure | Typical cause | Practical fix |
|---|---|---|
| Signature is required | A signed flow was submitted without the required EIP-712 signature. | Provide a valid signature or switch to the API-key flow where supported. |
| Authentication signature expired | deadline was already in the past when the request was verified. |
Regenerate the payload with a fresh short-lived deadline. |
| Invalid request or chain binding | The typed data was signed for the wrong chain or Request contract. | Rebuild the payload from the correct Request domain and sign again. |
| Signature verification failed | The domain, message, or signer did not match what the system expected. | Recreate the canonical payload and re-sign from the correct authorization path. |
| Funding address mismatch | Your API credentials and operational funding address did not resolve to the same BF configuration. | Use the correct credentials or update the mapped operational funding address with 3F. |
| Funding transaction failed | Balance or allowance was insufficient when the Request attempted to transfer funds. | Recheck asset balance, approval, and the exact amount being funded. |
Sample Flow: End-to-End Example
Section titled “Sample Flow: End-to-End Example”The following illustrates a complete bridge facilitator cycle for a structured asset deployment.
Phase 1: Discovery
Section titled “Phase 1: Discovery”| Step | Action | Detail |
|---|---|---|
| 1 | Strategy opens deposits | 7-day window for a USDC-denominated money market fund (e.g., Bitwise) |
| 2 | Deposits close, auctions begin | Leverage points are auctioned; you discover opportunities via GET /v1/auction |
| 3 | You evaluate an opportunity | Request seeks 1,000,000 USDC at 10% annualized return |
Phase 2: Offer and Funding
Section titled “Phase 2: Offer and Funding”| Step | Action | Detail |
|---|---|---|
| 4 | You submit an offer | POST /v1/offer with amount: 1000000, expectedReturn: 10000 (~1% yield for the term; total repayment target 1,010,000) |
| 5 | Offer accepted | Status transitions to AWAITING_MINT for push funding, or proceeds through signed pull funding after acceptance |
| 6 | Funds transferred | Request calls pullFunds() or you call mint(); PT/YT minted to your funding address |
Phase 3: Deployment and Repayment
Section titled “Phase 3: Deployment and Repayment”| Step | Action | Detail |
|---|---|---|
| 7 | Strategy deploys capital | Funds deployed into target asset; begins accruing yield |
| 8 | Settlement completes | Timing depends on NAV cycle: standard delay if settled within deposit window, +1 day if after |
| 9 | Repayment marked | Request owner calls setRepaid() with principal + yield |
| 10 | You redeem PT/YT | Burn tokens to recover 1,010,000 USDC (principal + return) |
Extended Settlement
Section titled “Extended Settlement”If settlement exceeds the expected delay, repayment includes additional yield proportional to the extra time held. Your return reflects actual duration, preserving bridge facilitation economics.
For on-chain sequencing and role-level settlement detail, continue to Settlement. For PT/YT payoff mechanics, see PT/YT Tokens.