> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trusset.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration

> Deployment sequence, configuration, and integration patterns for CommodityCustody.

This page covers how to deploy, configure, and integrate with the CommodityCustody contract. It assumes you have deployed the [Commodity Token suite](/licenses/commodities/integration) and have a functioning identity registry and at least one CommodityTokenUpgradeable instance.

## Prerequisites

Before deploying CommodityCustody, the following must be in place:

1. `IdentityRegistryUpgradeable` deployed and configured with KYC providers.
2. At least one `CommodityTokenUpgradeable` deployed via `CommodityTokenFactoryUpgradeable`.
3. USDC (or chosen settlement stablecoin) available on the target chain.
4. A `LiquidationRouter` deployed, or a placeholder address if liquidation is not yet needed.

## Compiler Configuration

The `batchSettleTrades` function takes 9 calldata array parameters plus `batchId`, which exceeds the EVM's 16-slot stack limit in the legacy compilation pipeline. The Solidity compiler must use `viaIR: true`.

```javascript theme={null}
// hardhat.config.js
module.exports = {
  solidity: {
    version: "0.8.24",
    settings: {
      optimizer: { enabled: true, runs: 200 },
      viaIR: true
    }
  }
};
```

Without this setting, compilation will fail with a stack-too-deep error.

## Deployment Sequence

<Steps>
  ### Deploy CommodityCustody

  Deploy the implementation contract, then deploy an ERC1967Proxy pointing to it and call `initialize`.

  ```javascript theme={null}
  const { ethers, upgrades } = require("hardhat");

  const CommodityCustody = await ethers.getContractFactory("CommodityCustody");

  const custody = await upgrades.deployProxy(
    CommodityCustody,
    [
      "0xADMIN_ADDRESS",            // admin (multi-sig recommended)
      "0xOPERATOR_ADDRESS",         // settlement operator (or 0x0 to default to admin)
      "0xLIQUIDATION_ROUTER",       // router contract address
      "0xUSDC_ADDRESS"              // USDC token address
    ],
    { kind: "uups" }
  );

  await custody.deployed();
  ```

  | Parameter            | Type    | Constraints            |
  | -------------------- | ------- | ---------------------- |
  | `_admin`             | address | Cannot be zero         |
  | `_operator`          | address | Zero defaults to admin |
  | `_liquidationRouter` | address | Cannot be zero         |
  | `_usdc`              | address | Cannot be zero         |

  ### Register Supported Tokens

  Register each token the orderbook will trade. Both commodity tokens and USDC are registered the same way.

  ```javascript theme={null}
  // Register commodity token
  await custody.addSupportedToken("0xCOMMODITY_TOKEN");

  // Register USDC
  await custody.addSupportedToken("0xUSDC_ADDRESS");
  ```

  ### Configure Commodity Token Compliance

  The custody contract must be authorized on each commodity token for deposits and withdrawals to succeed. The required configuration depends on the token's transfer restriction mode:

  ```javascript theme={null}
  const commodityToken = await ethers.getContractAt(
    "CommodityTokenUpgradeable", "0xCOMMODITY_TOKEN"
  );

  // WHITELIST mode: whitelist the custody contract
  await commodityToken.setWhitelist(custody.address, true);

  // BLACKLIST mode: ensure custody is not blacklisted (no action needed if clean)

  // KYC required: verify the custody contract address in the identity registry
  await identityRegistry.verifyIdentity(
    custody.address,
    keccak256("CUSTODY_CONTRACT"),
    investorType,
    softExpiry,
    hardExpiry
  );
  ```

  This step is the most common cause of failed deployments. If the commodity token's restriction mode changes after deployment, the custody contract must be re-authorized under the new mode.
</Steps>

## Deposit and Withdrawal

Users must deposit tokens into custody before they can place orders on the orderbook.

```javascript theme={null}
// Approve and deposit commodity tokens
await commodityToken.approve(custody.address, ethers.utils.parseEther("100"));
await custody.deposit(commodityToken.address, ethers.utils.parseEther("100"));

// Approve and deposit USDC
await usdc.approve(custody.address, ethers.utils.parseUnits("10000", 6));
await custody.deposit(usdc.address, ethers.utils.parseUnits("10000", 6));
```

There is no `checkTransferability` function on CommodityCustody. To pre-check whether a deposit or withdrawal will succeed, query the commodity token's compliance state directly:

```javascript theme={null}
// Check whitelist status
const isWhitelisted = await commodityToken.whitelist(userAddress);

// Check if account is frozen on the token
const isFrozen = await commodityToken.frozenAccounts(userAddress);

// Check if token is paused
const isPaused = await commodityToken.paused();

// Check KYC status (if kycRequired is true on the token)
const isVerified = await identityRegistry.isVerified(userAddress);
```

Withdrawals work similarly. The user can only withdraw their available (unlocked) balance, and the commodity token enforces compliance during the on-chain transfer:

```javascript theme={null}
const available = await custody.getAvailableBalance(userAddress, commodityToken.address);
await custody.withdraw(commodityToken.address, available);
```

## Trade Settlement Flow

The matching engine (operator) follows a lock-then-settle pattern. This is identical to the [Stock Orderbook](/licenses/stock-orderbook/integration) flow.

<Steps>
  ### Lock Balances

  When orders match off-chain, the operator locks both counterparties' balances.

  ```javascript theme={null}
  const lockId = ethers.utils.id("lock-001");

  // Lock maker's USDC (maker is buyer)
  await custody.lockBalance(maker, usdc.address, quoteAmount, lockId);

  // Lock taker's commodity tokens (taker is seller)
  await custody.lockBalance(taker, commodityToken.address, baseAmount, lockId);
  ```

  ### Settle Trade

  Atomically transfer locked balances between the counterparties. These are internal ledger movements - no on-chain token transfers occur.

  ```javascript theme={null}
  const settlementId = ethers.utils.id("trade-001");

  await custody.settleTrade(
    settlementId,
    maker,
    taker,
    commodityToken.address,  // base token
    usdc.address,             // quote token
    baseAmount,
    quoteAmount,
    true                      // makerIsBuyer
  );
  ```
</Steps>

For high-throughput scenarios, use `batchSettleTrades` to settle multiple trades in one transaction. Size batches based on your target chain's block gas limit. The gas guard stops processing if remaining gas drops below 80,000, so always check the `BatchSettled` event's `settledCount` against `totalSubmitted` and retry any remaining settlements.

## Liquidation Flows

Two paths exist for settling liquidated collateral received from a lending market.

### Path A: Internal Buyer

The buyer already has USDC in custody. Tokens move between internal balances and USDC is transferred on-chain to the router.

```javascript theme={null}
await custody.settleLiquidationWithBuyer(
  liquidationId,
  buyerAddress,
  tokenAmount,
  usdcAmount
);
```

Partial fills are supported. The liquidation remains open until the full token amount is matched. Check `getLiquidation(liquidationId)` to see the remaining amount.

### Path B: External Sale

The operator sells tokens through an external venue, then provides USDC proceeds. The commodity token enforces compliance during the on-chain transfer to the external buyer.

```javascript theme={null}
// Operator approves USDC to custody
await usdc.approve(custody.address, usdcReceived);

await custody.settleLiquidation(
  liquidationId,
  usdcReceived,
  externalBuyerAddress  // receives the commodity tokens
);
```

Both paths notify the lending market via `ILendingMarket.receiveLiquidationProceeds`. If the callback reverts, settlement still completes. Monitor `LiquidationSettled` and `LiquidationSoldToBuyer` events for reconciliation.

## Priority Trade Flow

For liquidating tokens already held in a user's custody balance (not received via the router):

```javascript theme={null}
// 1. Freeze user to prevent withdrawal front-running
await custody.freezeUser(liquidatedUser);

// 2. Lock the user's tokens
await custody.lockBalance(liquidatedUser, commodityToken.address, amount, lockId);

// 3. Settle with a buyer
await custody.settlePriorityTrade(
  settlementId,
  liquidatedUser,
  buyer,
  commodityToken.address,
  usdc.address,
  baseAmount,
  quoteAmount
);

// 4. Unfreeze the user
await custody.unfreezeUser(liquidatedUser);
```

On L1 Ethereum, front-running between these steps is possible. Deploy on an L2 or use a private mempool for liquidation transactions.

## Listening to Events

Index these events for your backend, matching engine, and reporting systems:

```typescript theme={null}
// Custody operations
custody.on("Deposited", (user, token, amount, newBalance) => { /* ... */ });
custody.on("Withdrawn", (user, token, amount) => { /* ... */ });

// Trade lifecycle
custody.on("BalanceLocked", (user, token, amount, lockId) => { /* ... */ });
custody.on("TradeSettled", (settlementId, maker, taker, baseToken, quoteToken, baseAmount, quoteAmount) => { /* ... */ });
custody.on("BatchSettled", (batchId, settledCount, totalSubmitted) => { /* ... */ });

// Liquidation
custody.on("LiquidationReceived", (liquidationId, token, amount, debtOwed, borrower, lendingMarket) => { /* ... */ });
custody.on("LiquidationSettled", (liquidationId, usdcReceived, tokenRecipient) => { /* ... */ });
custody.on("LiquidationSoldToBuyer", (liquidationId, buyer, tokenAmount, usdcAmount, fullyFilled) => { /* ... */ });

// Emergency controls
custody.on("UserFrozen", (user, operator) => { /* ... */ });
custody.on("WithdrawalsPaused", (operator) => { /* ... */ });

// CRITICAL: also monitor commodity token compliance changes
commodityToken.on("TransferRestrictionModeUpdated", (oldMode, newMode) => {
  // Re-verify custody contract authorization under the new mode
});
```

## API Integration

If you are using Trusset's API layer, custody balances and settlements are managed through the Stock Trading API groups (which serve both stock and commodity orderbooks). The API handles deposit orchestration, settlement submission, and balance queries without direct contract interaction.

For direct contract integration (self-hosted or custom deployment), use standard ethers.js or viem patterns with the contract ABIs included in the license package.
