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.