Skip to main content

Audited Contract Registry

Audited contract bytecode, ABI, and verification sources ship as the public npm package @upsideos/evm-rwa-artifacts. Any client can install the package and check that an on-chain contract matches the audited code. The ABIs and verification sources also ship as the upsideos_evm_rwa_artifacts Ruby gem.

The first published release is EVM Security Token v5 (evm/comakery_security_token_v5/2026-09-17-quantstamp), pinned to source commit 45b32eaeea1d96f1f64ef0d74796a5a80ec154ce (tag v2025-10-16). Quantstamp audited this version. The audit report is available on request.

Install

npm install @upsideos/evm-rwa-artifacts

Package layout

ExportContents
@upsideos/evm-rwa-artifacts/v5v5 artifacts (abi, bytecode)
@upsideos/evm-rwa-artifacts/v5/manifest.jsonRelease record and hashes
@upsideos/evm-rwa-artifacts/v5/artifacts/<Name>.jsonABI, creation code, runtime code, immutable slots
@upsideos/evm-rwa-artifacts/v5/abis/<Name>.jsonPer-contract ABI
@upsideos/evm-rwa-artifacts/v5/verification-source-codes.jsonsolc standard-json input
@upsideos/evm-rwa-artifacts/v5.1v5.1 artifacts
@upsideos/evm-rwa-artifacts/recallable-paymentRecallable Payment artifacts

Root of trust: an exact npm version (or git commit) plus the sha512 integrity in your lockfile. Public npm releases also carry Sigstore provenance from the publish workflow in upsideos/contract-artifacts.

Ruby

gem 'upsideos_evm_rwa_artifacts'

The gem carries the ABIs, the release manifests, and the verification sources, built from the same audited commit as the npm package. It ships no bytecode and no tooling, because a Ruby consumer reads contracts and verifies them but does not deploy them.

require 'upsideos_evm_rwa_artifacts'

UpsideosEvmRwaArtifacts.abi('v5', 'TransferRules')
UpsideosEvmRwaArtifacts.merged_abi('v5', 'RestrictedLockupToken')
UpsideosEvmRwaArtifacts.verification_source_codes_path('v5')
UpsideosEvmRwaArtifacts.commit('v5')

RubyGems trusted publishing signs each release to the workflow run that built it, the same OIDC model npm uses.

Manifest

The envelope is the same for EVM, Solana, and Sui. Only the build object and the per-artifact code fields change. This release uses build.kind = solc-standard-json.

runtimeCode.immutableReferences is required. Constructor-set immutables (for example ERC2771Context.trustedForwarder) make each deployment's eth_getCode output different. The verifier zeros those ranges before it hashes.

callSurfaces holds the merged ABI. The token forwards unknown selectors into its extensions, so a client that talks to the token address needs the union of the token and extension ABIs, not the token ABI alone.

Verify a deployment on a block explorer

Explorer verification is tied to a deployed address, so it happens after deployment. @upsideos/evm-explorer-verify submits the published bundle with the right compiler version and constructor arguments:

npx evm-verify-explorer --release v5 --contract AccessControl \
--address 0x... --chain-id 84532 --api-key "$EXPLORER_API_KEY"

It also exports submitSourceVerification and checkVerificationStatus for callers that run verification from a queue worker.

Client check without a compiler

const manifest = require('@upsideos/evm-rwa-artifacts/v5/manifest.json')

async function check(rpcUrl, address, name) {
const expected = manifest.artifacts.find(a => a.name === name)
const body = await fetch(rpcUrl, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'eth_getCode',
params: [address, 'latest'],
}),
}).then(r => r.json())
const hex = body.result.slice(2)
const bytes = new Uint8Array(hex.length / 2)
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16)
}
for (const ranges of Object.values(expected.runtimeCode.immutableReferences || {})) {
for (const { start, length } of ranges) {
bytes.fill(0, start, start + length)
}
}
const digest = await crypto.subtle.digest('SHA-256', bytes)
const actual = [...new Uint8Array(digest)]
.map(b => b.toString(16).padStart(2, '0'))
.join('')
return actual === expected.runtimeCode.sha256
}

Client check with a compiler

  1. Load verification-source-codes.json.
  2. Check its canonical SHA-256 against build.standardJson.sha256.
  3. Compile with solcLongVersion from the bundle (0.8.28+commit.7893614a for v5).
  4. Compare creation bytecode to artifacts/<Name>.json.

This is the full trustless path. It does not need the contracts git repository because the bundle inlines every source (metadata.useLiteralContent: true).

Creation-code path

Fetch the deployment transaction. The input prefix must match creationCode. The suffix is the ABI-encoded constructor arguments. Decode it with the published ABI.

Solana and Sui

The manifest schema already accepts solana-verifiable-build and sui-move. Adapters for those families are not in this release.