Skip to main content
This page describes Path B — deploying and operating custom QRC-compatible contracts without the managed Token Management API. Path B works through the existing transaction endpoints (POST /v1/transactions with operation CONTRACT_CALL or RAW) and reuses Qustody’s approval and post-quantum signing pipeline.
Path B is powerful and unforgiving. There are no typed mint/burn/role validations — every byte of calldata you submit is yours to verify. Test on Quantum Chain testnet, verify the deployed bytecode against your source, and gate the deployment with a strict approval policy.

End-to-end flow

Step 1 — Write a QRC-compatible Solidity contract

Use any standard Solidity workflow. The QVM is bytecode- and opcode-compatible with the EVM (Berlin/London), so existing Solidity that does not rely on ecrecover will compile and run unmodified. If you need in-contract signature verification, call the post-quantum precompile at 0x0b — see QVM vs EVM.

Step 2 — Compile

Any standard toolchain works (solc, Foundry’s forge build, Hardhat, etc.). Produce two artifacts: the ABI (JSON) and the deployment bytecode (hex string).

Step 3 — Build the deployment transaction

Construct a Qustody transaction request with the deployment bytecode as the data payload and an empty to address. Use a vault account that holds enough native currency for gas.
POST /v1/transactions
Content-Type: application/json
Idempotency-Key: deploy-mytoken-2026-04-27

{
  "operationType": "CONTRACT_CALL",
  "from": { "type": "vaultAccountId", "vaultAccountId": "vault_123" },
  "to": null,
  "data": "0x60806040…",
  "value": "0",
  "feeStrategy": "MEDIUM"
}

Step 4 — Approval

Qustody evaluates the configured approval policy. For deployments, configure REQUIRE_APPROVAL with a multi-approver quorum.

Step 5 — Post-quantum signing

Once approved, the transaction enters PENDING_SIGNATURE. Either:
  • The configured signer signs automatically (gRPC or remote modes), or
  • You fetch the signing payload, sign externally, and submit the signature back:
GET  /v1/transactions/{id}/signing_payload
POST /v1/transactions/{id}/signature
See external signing for the full flow.

Step 6 — Broadcast and confirmation

Qustody broadcasts the signed transaction and walks it through BROADCASTING → CONFIRMING → COMPLETED. The receipt.contractAddress field on the transaction contains the deployed contract address.

Step 7 — Encode function calls

For every subsequent contract call, ABI-encode the call data client-side and submit a CONTRACT_CALL transaction:
POST /v1/transactions

{
  "operationType": "CONTRACT_CALL",
  "from": { "type": "vaultAccountId", "vaultAccountId": "vault_123" },
  "to": "0x9a8e5e21f0c27d2c5c14b6e9bd8e4a0f9c9b4d12",
  "data": "0xa9059cbb000000000000000000000000…",
  "value": "0",
  "feeStrategy": "MEDIUM"
}
Use any ABI library (ethers.js, web3.py, go-ethereum/accounts/abi) to produce the data payload.

Step 8 — Track transaction status

Poll GET /v1/transactions/{id} or subscribe to transaction.status_changed, transaction.completed, transaction.failed webhooks.

Step 9 — Verify contract state

Query state through Quantum Chain RPC (e.g. eth_call) or via your own indexer. Qustody does not currently expose a generic contract-state read endpoint for custom contracts.

Step 10 — Security warnings

  • Bytecode you submit is bytecode you bear. Audit your contract before mainnet.
  • ecrecover is removed from the QVM. Any inherited Solidity that uses it will revert on call. See QVM vs EVM.
  • tx.origin is still available but inadvisable for authorization decisions.
  • Use Idempotency-Key on every write request. Network retries are otherwise unsafe.
  • Treat upgrades as deployments. A privileged-upgrade transaction is its own privileged operation.