Skip to main content

Import

import {
  createFinancingClient,
  initializeFromShyConfig,
  assertFinancingManifest,
  FINANCING_MANIFEST_CONTRACT_VERSION   // "shycontracts-v1"
} from 'shyware/sdk/web/contractsClient.js'
contractsClient.js re-exports from financingClient.js under these aliases.

Initialization

const client = await initializeFromShyConfig(shyconfig)
Requires contract_version: "shycontracts-v1" and a financing block with return_basis, remittance_source_mode, funding_mode, and transfer_layer: "shywire".

Return basis modes

return_basisDescription
project_profitRemittances are a share of reported project profit
customer_revenueRemittances are matched to incoming customer revenue
eligible_incomeRemittances are matched to a defined income category
The return basis determines how buildFinancingRemittance validates the matchedAmount field and which remittance_source_mode is valid.

Funding modes

funding_modeDescription
single_lenderOne capital provider per contract
staggered_waitlistInvestors join sequentially as tranches are filled
shared_financingMultiple investors share a single contract with defined allocations

Contract lifecycle

1. Register contract

const { txJson, contractId, contractHash } = await client.buildRegisterFinancingContract({
  borrowerCommitment,
  offchainTerms: {
    financeType: 'revenue_share',
    totalAmount: 500000,
    revShareBps: 1500,       // 15%
    termMonths: 24,
    goalAmount: 400000       // only relevant if goal_gated: true
  },
  tranches: [
    {
      classId: 'senior',
      investorCommitment: investorCommitment1,
      allocationBps: 7000,   // 70%
      seniority: 1,
      status: 'active'
    },
    {
      classId: 'junior',
      investorCommitment: investorCommitment2,
      allocationBps: 3000,
      seniority: 2,
      status: 'active'
    }
  ]
})
// → TxType 7
// contractHash = H(offchainTerms + financeType + ...)
// contractId   = H(contractHash : timestamp : randomHex(16))
// List 1: (assetId, disbursementAmount, contractHash) — no counterparty identity
// List 2: borrowerCommitment — no contract terms
contractHash is the on-chain commitment to the off-chain terms. An auditor with the off-chain terms can verify that contractHash matches the on-chain record while observers learn only that a financing event of the committed amount occurred.

2. Activate contract (goal-gated)

Required when goal_gated: true. Signals that the fundraising goal has been met and disbursement should proceed.
await client.buildActivateFinancingContract({
  contractId,
  goalEvidence: 'evidence-doc-ref-123'
})
// → TxType 9
// goalEvidenceHash = H(goalEvidence)

3. Submit remittance

const { txJson, transferId, nullifier } = await client.buildFinancingRemittance({
  contractId,
  payerCommitment,
  matchedAmount: 12500,
  sourceRef: 'invoice-2024-03',
  incomeCategory: 'customer_revenue'
})
// → TxType 8
// transferId = H(transferNonce)
// nullifier  = H(payerCommit : contractId : sourceRef)
// List 1: (contractHash, remittanceAmount) — no payer identity
// List 2: payerCommitment — no contract terms
Observers see aggregate remittance volume per contract identifier but cannot identify the paying entity. The HSM-backed tally attestation covers total disbursed and total remitted per contract.

ZK extension

The ZK nullifier (Claim 11) applies to the remittance flow:
// With ZK prover initialized:
const nullifier = zkClient.computeNullifier(walletSecret, contractId)
// nullifier = MiMC(walletSecret, contractId)
// Prevents a single wallet from submitting duplicate remittance records
// for the same contract without revealing the wallet address on-chain

Secondary-market stake transfers

Contract stake positions can be transferred between investors via the shywire rail:
// Transfer stake position (routed through shywire TxTypeTransfer=4)
const wireClient = await initializeFromShyConfig(wireShyconfig)
await wireClient.buildTransfer({
  assetId: contractId,
  senderCommitment,
  recipientCommitment,
  amount: allocationBps
})
Remittances (operator → lender disbursements) are out-of-band and are not routed through shywire.