Custodians are the licensed warehouse operators who accept physical commodity deposits from farmers, issue warehouse receipt tokens, and release goods when tokens are redeemed. This guide covers the full lifecycle — from onboarding your organisation to day-to-day minting, transferring, and burning operations.
Only registered custodians may call mint() and burn() on the protocol
contracts. The contract admin is responsible for registering custodians
on-chain.
Before your address can be registered on-chain, you must:
-
Hold a valid Warehousing Certificate issued by the relevant Nigerian regulatory authority (e.g., WACOT/AFEX accreditation for grain warehouses, or the relevant state ministry for commodity-specific facilities).
-
Have your warehouse(s) physically inspected and approved. Each approved location is assigned a
warehouse_idstring that you will use when minting. -
Submit your Stellar account public key, warehouse IDs, and supporting regulatory documents to the Farmledge Labs admin for review.
-
Sign and return the Custodian Agreement, which specifies service-level obligations, inspection standards, and liability terms.
Once approved, the protocol admin calls:
import { maizeAddCustodian, sesameAddCustodian } from '@farmledge/protocol-sdk'
// Register on the maize-receipt contract
await maizeAddCustodian(client, adminKeypair, custodianPublicKey)
// Register on the sesame-receipt contract (if applicable)
await sesameAddCustodian(client, adminKeypair, custodianPublicKey)You can verify registration by attempting a simulated mint() call — an
Unauthorized simulation error indicates the address is not yet registered.
A warehouse receipt is issued when a farmer delivers physical goods to your facility and the delivery has passed inspection.
-
Receive and weigh the goods. Record the number of bags and net weight per bag. Both values must be greater than zero.
-
Inspect and grade the lot. See Grading Standards for criteria and approved grade codes.
-
Confirm the commodity code. Use
MAIZE_WHITEorMAIZE_YELLOWfor maize, andSESAMEfor sesame. Passing an unsupported code will cause the transaction to revert. -
Call
mint()via the SDK, providing the farmer's Stellar public key asfarmerWallet:
import { maizeMint } from '@farmledge/protocol-sdk'
// or: import { sesameMint } from '@farmledge/protocol-sdk'
const { tokenId, txHash } = await maizeMint(
client,
custodianKeypair, // your Stellar keypair
farmerPublicKey, // farmer's Stellar address
'MAIZE_WHITE', // commodity code
'GRADE_A', // grade code
200, // number of bags
50, // kg per bag
'WH-KD-001', // your warehouse ID
)
console.log('Issued token:', tokenId) // e.g. KN-2026-000042
console.log('Transaction:', txHash)- Provide the token ID to the farmer as their proof of deposit. They can
verify ownership on-chain at any time using
sesameQueryOwner()/maizeQueryToken().
Token transfers are initiated by the current owner (typically the farmer or
a trader who has purchased the receipt). As a custodian you do not normally
call transfer() — it is called by the holder.
If you need to reassign a token on behalf of an owner due to an operational error, this requires burning the original token and re-minting at the corrected owner address, with documented authorisation from the original holder.
Redemption (commodity withdrawal) is represented on-chain by burning the token. Only the original custodian who minted the token may burn it, and only if the token is not locked.
- Verify the redeemer. Confirm the person presenting the receipt owns the corresponding token on-chain:
import { sesameQueryOwner } from '@farmledge/protocol-sdk'
const owner = await sesameQueryOwner(client, tokenId)
// confirm owner matches the presenting party's Stellar address-
Check the token is not locked. A locked token is subject to a financing arrangement and cannot be redeemed until unlocked by the admin. If
isLockedistrue, direct the redeemer to the financing party. -
Release the physical goods after the redeemer has signed the physical release form.
-
Call
burn()to retire the token:
import { sesameBurn } from '@farmledge/protocol-sdk'
// or: import { maizeBurn } ... (if such a binding exists)
const txHash = await sesameBurn(client, custodianKeypair, tokenId)
console.log('Token burned:', txHash)- File the release documentation. Retain the burn transaction hash, physical release form, and identity document of the redeemer for seven (7) years.
Custodians are required to:
- Daily: Reconcile physical stock with the on-chain token balances for each commodity. Discrepancies must be investigated and reported within 24 hours.
- Weekly: Submit a stock report to Farmledge Labs including total bags, weight per commodity, and a list of active token IDs.
- Quarterly: Provide a signed attestation from a licensed independent inspector confirming that physical holdings match on-chain records.
- Annually: Submit to a full audit conducted by a Farmledge Labs-approved auditor. Audit reports are kept on file and may be disclosed to regulators.
Any material discrepancy between physical and on-chain holdings must be escalated to Farmledge Labs within four (4) business hours of discovery.
- Store your custodian Stellar keypair in a hardware security module (HSM) or a secure cloud key management service (e.g., AWS KMS, HashiCorp Vault).
- Never store private keys in source code,
.envfiles committed to version control, or shared drives. - Rotate keypairs at least annually or immediately following any suspected compromise. Notify Farmledge Labs so the old key can be removed and the new key added on-chain.
- Restrict call permissions for
mint()andburn()to dedicated, audited service accounts. Operator accounts used for day-to-day access should not hold the custodian keypair. - Implement four-eyes approval for any burn transaction above a threshold agreed with Farmledge Labs (default: 100 bags or 5,000 kg).
- Log all mint, transfer, and burn transactions with the operator identity, timestamp, and authorisation reference.
In the event of a suspected key compromise:
- Immediately notify Farmledge Labs at security@farmledge.io.
- Cease all minting and burning operations.
- The admin will call
remove_custodian()to deauthorise the compromised key. - Generate a new keypair, complete the re-registration process, and document the incident.
Farmledge Labs may suspend a custodian's registration pending investigation of any reported security incident or stock discrepancy.