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.