For the complete documentation index, see llms.txt. This page is also available as Markdown.

Shares

The kpkShares ERC-20 token — pro-rata fund ownership with a request-based mint/burn model.

Shares represent proportional ownership of the fund. When users subscribe, new shares are minted to reflect their contribution. When they redeem, those shares are burned. At any point, a holder's share balance corresponds to their fraction of the fund's total Net Asset Value (NAV).

The kpkShares contract

Each fund's shares are an instance of kpkShares — an ERC-20 token (18 decimals) that also serves as the onchain interface for subscriptions and redemptions. It is built on OpenZeppelin's upgradeable contracts:

  • ERC20Upgradeable — standard token behaviour (transfer, approve, balanceOf, totalSupply, …).

  • AccessControlUpgradeable — the DEFAULT_ADMIN_ROLE / OPERATOR permission model (see Roles and operators).

  • UUPSUpgradeable — the contract is a proxy. Each fund gets its own implementation (deployed by the factory), so upgrading one fund never affects another.

Request-based, not ERC-4626

While inspired by ERC-4626 tokenized vaults, kpkShares does not expose direct deposit/withdraw. Every inflow and outflow goes through an operator-approved request, an approach closer to ERC-7540 (asynchronous vaults). Concretely:

  1. A user submits a request (requestSubscription / requestRedemption). Their assets — or shares — are moved into escrow inside the kpkShares contract while the request is PENDING.

  2. An operator settles a batch of requests at a share price, minting or burning accordingly.

This lets the fund batch requests, control execution, and manage inflows and outflows from a risk and liquidity perspective. See Subscriptions and Redemptions for the full lifecycle.

Share price and decimals

The price of a share is the total NAV divided by the circulating supply. Share prices are expressed in normalized USD units with 8 decimals; the share token itself uses 18 decimals. NAV is computed onchain by the NAV Calculator; the price used to settle a batch of requests is submitted by the operator and stored per asset as the last settled price.

The contract exposes pure conversion helpers (both take a sharesPrice in 8-decimal USD):

// shares = (assetAmount * 10^18 * 1e8) / (sharesPrice * 10^assetDecimals)
function assetsToShares(uint256 assetAmount, uint256 sharesPrice, address subscriptionAsset)
    external view returns (uint256);

// assets = (shares * sharesPrice * 10^assetDecimals) / (1e8 * 10^18)
function sharesToAssets(uint256 shares, uint256 sharesPrice, address redemptionAsset)
    external view returns (uint256);

For computing minimums with the last settled price, prefer previewSubscription / previewRedemption — see Calculate share price.

Approved assets

A fund can accept more than one asset. Each approved asset is described by:

The base asset set at deployment is automatically flagged isFeeModuleAsset = true. Operators manage the asset list with updateAsset (see Roles and operators); integrators read it with getApprovedAssets / getApprovedAsset / isApprovedAsset (see List approved assets).

Last updated