Partner integration
Approved partners receive one public partnerCode, build and broadcast V4 purchases independently, and reconcile attribution from public chain events. WF calculates the commercial payout offchain.
Integration model
A partner applies through the WF partner page and completes Web2 review. Approval creates a Partner record and one non-zero bytes32 partnerCode. The code is a public attribution label, not an API key, signature, or permission to move funds.
WF does not require a Partner Order API, transaction-hash callback, webhook, WF relayer, or partner-owned broadcaster. The default path is a normal wallet transaction sent by the user through any Polygon RPC. EIP-712 is only needed when another address submits the transaction and pays Gas for the user.
| Boundary | Responsibility | Authority |
|---|---|---|
| Partner application | Business, compliance, payout details | WF Web2 approval |
| Partner client | Game UI, purchaseData, order id and direct wallet transaction; optional delegated submission | Partner infrastructure |
| UnifiedLedger V4 | Funds, nonce, signature, attribution and replay checks | Polygon contract state |
| WF Indexer | Event projection and reorg handling | Derived from chain events |
| WF settlement | Web2 rate, statement and manual payout | Audited commercial ledger |
1. Apply and receive a partnerCode
Submit the partner application at /partners. After approval, the Partner Console shows the partnerCode, effective block, current commercial rate, payout details, attributed purchases, statements, and payment status.
Only purchases confirmed at or after the effective block are eligible. A paused or terminated Partner keeps its historical records but does not earn commission from later purchases. A partnerCode must be treated as public and may be embedded in a website or application.
- No Partner API key or private channel credential is issued.
- No pre-created WF order is required before the chain transaction.
- No wallet-to-partner binding is required for the transaction submitter.
- Using an unknown, inactive, or zero partnerCode does not block a valid purchase; it creates no Partner payable.
2. Build the V4 purchase
Load /v1/protocol/manifest from the public Indexer and reject a deploymentId or chainId mismatch. Read the game and round, encode game-specific purchaseData, read purchaseNonces(owner), and use quotePurchase for the exact amount. The game reads the round allocation snapshot from Treasury automatically.
Generate a locally unique localOrderId and derive wfOrderId from chainId, ledger, partnerCode, owner, nonce, and the local order id. The formula is public and can be implemented with any Web3 library; the WF SDK is optional. Reusing a wfOrderId is rejected onchain.
import { buildPartnerWfOrderId, buildPurchaseRequestV4 } from "@wf-protocol/contract-sdk";
const wfOrderId = buildPartnerWfOrderId({
chainId: 137, ledger, partnerCode, localOrderId, owner, nonce,
});
const request = buildPurchaseRequestV4({
owner, game, beneficiary: owner, amount, purchaseData,
wfOrderId, partnerCode, nonce, deadline,
});Purchase request fields
Both transaction modes use the same PurchaseRequestV4 fields. In the default direct path they are calldata in the transaction signed by the owner wallet. In delegated mode they are additionally covered by an EIP-712 signature whose domain is UnifiedLedger version 4, the active chain, and the active ledger.
| Field | Type | Rule |
|---|---|---|
| owner / beneficiary / game | address | Payer, ticket owner, and active game |
| amount | uint256 | Six-decimal USD ledger amount |
| purchaseDataHash | bytes32 | keccak256 of exact game purchaseData |
| wfOrderId / partnerCode | bytes32 | Both zero or both non-zero; order id cannot be reused |
| nonce / deadline | uint256 / uint48 | Current owner nonce and signature expiry |
3. Sign and broadcast
The default path calls executePurchaseV4 from the owner wallet. This is a normal transaction: the user pays Gas and no EIP-712 signature is requested. For optional delegated submission, the owner signs PurchaseRequestV4 and any broadcaster calls executePurchaseWithAuthorizationV4 and pays Gas.
Simulate against the active ledger immediately before requesting the signature or sending the transaction. Do not retry an ambiguous write until isWfOrderUsed(owner, partnerCode, wfOrderId), purchaseNonces(owner), and the transaction receipt have been checked. Order reuse is rejected within the same owner and partnerCode; usedWfOrderIds only reports historical use across all owners.
await walletClient.writeContract({
account: owner,
address: ledger, abi: unifiedLedgerV4Abi,
functionName: "executePurchaseV4",
args: [request, purchaseData],
});4. Confirm from public events
PurchaseExecutedV4 is the authoritative attribution record. A partner may scan Polygon directly or query /v1/protocol/purchases/v4 and /v1/protocol/purchases/by-wf-order/:wfOrderId?owner=0x...&partnerCode=0x.... Unscoped queries return 409 when more than one purchase matches. WF does not require the partner to submit a txHash.
Store chainId, blockNumber, txHash, logIndex, receiptId, wfOrderId, partnerCode, owner, game, amount, allocationVersion, partnerBps, and purchaseDataHash. Treat data as pending until the configured finality threshold; chain reorgs, cancelled rounds, and refunds can reverse commission eligibility.
5. Reconcile commission
partnerBps in PurchaseExecutedV4 is the total onchain Partner commission pool read automatically from the round Treasury snapshot. It is not supplied or signed by the Partner and is not the individual Partner's commercial rate. WF selects the approved Web2 rate version effective at the purchase block and uses it to split that pool between Partner payable and platform operations.
For example, a 100 USD purchase with a 5% onchain Partner pool creates 5 USD of eligible pool. If the Partner's Web2 share is 30%, the Partner payable is 1.5 USD and 3.5 USD remains platform operations. Statements are generated by WF and paid manually after review; no automatic Partner payout contract is part of this flow.
- Unknown, zero, not-yet-effective, paused, or terminated codes receive no Partner payable.
- The Partner Console rate and statements are private commercial data; chain purchases and partnerCode attribution are public.
- Every statement line must trace back to a canonical PurchaseExecutedV4 event and any later refund or cancellation event.
Contract publication and trust model
Core contracts that hold, account for, route, or settle user funds should have verified source on PolygonScan before production Partner onboarding. Public verification lets an integrator reproduce calldata, decode errors and events, inspect proxy implementations and roles, and compare deployed bytecode with the documented release.
The full engineering monorepo may remain private during testing and audit. After the audit and deployment freeze, publish the core Solidity source under an explicit license. Operational services do not need to be open-source for a third party to broadcast transactions, but their behavior and trust boundary must be documented.
| Artifact | Publication rule |
|---|---|
| Proxy and implementation addresses | Public, versioned, linked from the active manifest |
| Core Solidity source and compiler settings | Verify on PolygonScan before production onboarding |
| ABI, EIP-712 types, events and custom errors | Public and pinned to deploymentId |
| Upgrade admin, roles, Safe and timelock | Public with current holders and delay rules |
| SDK and integration examples | Public, versioned, reproducible |
| Private keys, RPC secrets and security runbooks | Never publish |
Production acceptance checklist
- Partner approval has a non-zero partnerCode, effective block, payout details, and versioned Web2 rate.
- Client pins chainId, deploymentId, ledger address, and ABI from one release; delegated mode also pins the EIP-712 domain.
- A direct wallet purchase works without the WF SDK and does not request an EIP-712 signature.
- Direct and delegated purchases both emit the expected PurchaseExecutedV4 attribution.
- Duplicate wfOrderId, stale nonce, expired signature, changed purchaseData, and rounds without a Treasury allocation snapshot are rejected.
- Indexer reorg, cancellation, refund, statement, and manual-payment reconciliation are tested end to end.
- Core deployed contracts are source-verified and all upgrade and emergency authorities are disclosed.