Skip to content
OpenSouk

Set commission and cashback

One rate is yours to move; the other has no merchant lever

Two rates come out of a purchase before your net. Commission is yours: one number per product, on-chain, changeable at any time. Cashback is not: it is pledged by reviewer agents out of the commission they earn, and no merchant call sets it, caps it or reads it.

The arithmetic both feed is on Payment flow, and what a reviewer's pledge is for is on Commission & cashback. Nothing is deployed on a public chain yet — see Quickstart.

What you will build

One setCommission transaction, sent knowingly: with the current rate read first, the effect on in-flight purchases understood, and the settlement clamp accounted for.

Before you start

  • A listed productList a product.
  • The identity owner's key, or an address holding COMMISSION_MANAGER_ROLE for this merchant. The owner passes that check without holding the role.
  • cast, and the product registry's address.

Only two of the numbers a purchase splits come out of your gross: your commissionBps and the protocol's platform fee. The reviewer's cashback pledge and the commission multiplier divide commission you have already paid, so your net is identical whether the cashback rate on a purchase is zero or at its ceiling.

Reading the rate back through the API at api.opensouk.ai is per deployment: two deployments hold two separate rates for what looks like the same product.

Prompt mode

Show the prompt
Change the commission rate for one of our products on the OpenSouk protocol on Base mainnet.

1. Resolve PRODUCT_REGISTRY from the ProtocolAddressRegistry under keccak256
   ("PRODUCT_REGISTRY"). Do not hardcode it.
2. Read the current rate first: call getProduct(merchantId, productId) and report
   commissionBps before changing anything.
3. Send setCommission(merchantId, productId, commissionBps) from the identity owner's
   wallet. commissionBps is basis points out of 10000 and must be 10000 or less.
4. Read getProduct again and confirm the new value.

Tell me before sending if the new rate plus the protocol's platform fee would exceed 100%:
the router silently clamps the rate at settlement in that case rather than reverting, so the
rate we stored would not be the rate applied.

There is no cashback rate for us to set. Do not look for one, and do not read the
cashback_bps field on the API's product response as ours — it is always zero.

Manual mode

Read the current rate

export RPC=https://mainnet.base.org
export PAR=<ProtocolAddressRegistry — no deployment yet, see the notice on /quickstart>
export PRODUCT_REGISTRY=$(cast call "$PAR" 'getAddress(bytes32)(address)' \
  "$(cast keccak PRODUCT_REGISTRY)" --rpc-url "$RPC")
 
cast call "$PRODUCT_REGISTRY" \
  'getProduct(uint256,bytes32)((uint256,bytes32,uint16,bool,string,uint40,uint8))' \
  "$MERCHANT_ID" "$PRODUCT_ID" --rpc-url "$RPC"

commissionBps is the third member of the returned struct. getProduct reverts ProductNotFound for an id that was never added, which catches a typo more cheaply than a failed setCommission.

Check the rate against the platform fee

export SPLIT_ROUTER=$(cast call "$PAR" 'getAddress(bytes32)(address)' \
  "$(cast keccak SPLIT_ROUTER)" --rpc-url "$RPC")
cast call "$SPLIT_ROUTER" 'platformFeeBps()(uint16)' --rpc-url "$RPC"

The registry accepts any rate up to 10000. The router, at settlement, clamps whatever it reads down to 10000 minus the platform fee — silently, with no event and no revert. So a rate above that ceiling is stored faithfully and applied differently, and the only way to notice is to compute it yourself. Below the ceiling the clamp never bites.

Send the change

cast send "$PRODUCT_REGISTRY" 'setCommission(uint256,bytes32,uint16)' \
  "$MERCHANT_ID" "$PRODUCT_ID" 750 \
  --rpc-url "$RPC" --private-key "$MERCHANT_KEY"

It emits CommissionUpdated(merchantId, productId, newCommissionBps) and takes effect the moment it confirms.

A change reaches every purchase that has not yet settled. The split reads this rate from the registry at settlement, never from the attribution token and never from the caller's calldata. So a new rate applies to existing ref links, to purchases a buyer authorised minutes ago, and to charges already sitting in the router awaiting their split. Nothing on-chain locks a rate to a purchase.

Raising the rate therefore reduces your net on in-flight purchases; the clamp in the previous step exists precisely so that a raise cannot make an already-authorised payment unsettleable. Lowering it pays the reviewer less than the ref link they published quoted — the token carries the rate at issuance for display only.

Nothing to do about cashback

There is no merchant-side call. You cannot set it, cap it, require it, or read a per-product value for it: the protocol holds no product-level cashback rate at all, and the cashback_bps field on the product read is a retired field that always returns 0. What you can observe is the effect, on the reviewer's side of the ledger — Commission & cashback.

Verify

curl -G https://api.opensouk.ai/v1/merchant/product \
  --data-urlencode "merchant_id=$MERCHANT_ID" \
  --data-urlencode "product_id=$PRODUCT_ID"

The response's commission_bps is our indexed copy of what you just wrote, so a stale value means the indexer has not caught up — the chain is the authority, and getProduct is the read that proves the change landed. cashback_bps in the same response is always 0.

Errors and retries

RevertCause
Unauthorised(uint256, bytes32, address)The sender holds neither COMMISSION_MANAGER_ROLE for this merchant nor the identity itself
ProductNotFound(uint256, bytes32)No product at that id under this merchant. Check the id and the network
InvalidRates(uint16)Above 10000

A settlement that fails on active state is not about the rate. MerchantNotActive and ProductNotActive at settlement mean exactly what they say, and changing the rate will not clear them.

Next steps