Skip to main content

Overview

The getContractState method retrieves the raw key-value storage state of a NEAR smart contract. This is useful for inspecting contract storage directly without calling view functions.

Method Signature

client.getContractState(args: GetContractStateArgs)
  : Promise<GetContractStateResult>
Source: packages/near-api-ts/universal/src/client/methods/contract/getContractState.ts:31

Parameters

contractAccountId
string
required
The account ID of the contract whose state to retrieve
atMomentOf
BlockReference
Block reference to query the contract state at a specific point in time. Can be:
  • { blockId: string } - Block hash
  • { blockHeight: number } - Block height
  • { finality: 'optimistic' | 'final' } - Finality level
keyPrefix
string
Filter results to only include keys starting with this prefix. The prefix is encoded as UTF-8 bytes.
includeProof
boolean
Whether to include a merkle proof of the state. Useful for verification purposes.
policies
object
transport
PartialTransportPolicy
Transport-level policies for the request
options
object
signal
AbortSignal
AbortSignal for canceling the request

Response

blockHash
string
required
Hash of the block at which the state was queried
blockHeight
number
required
Height of the block at which the state was queried
contractAccountId
string
required
The account ID of the contract (echoed from request)
contractState
StateRecord[]
required
Array of key-value pairs representing the contract’s storage state.
key
string
required
Base64-encoded storage key
value
string
required
Base64-encoded storage value
proof
string[]
Merkle proof for the state (only present if includeProof was true)

Implementation Details

The method makes an RPC call with the following structure:
// Source: packages/near-api-ts/universal/src/client/methods/contract/getContractState.ts:38-49
await sendRequest({
  method: 'query',
  params: {
    request_type: 'view_state',
    account_id: args.contractAccountId,
    prefix_base64: base64KeyPrefix,
    include_proof: args.includeProof,
    ...toNativeBlockReference(args.atMomentOf),
  },
  transportPolicy: args.policies?.transport,
  signal: args.options?.signal,
});

Examples

Get All Contract State

import { createClient, mainnet } from '@near-js/client';

const client = createClient({ network: mainnet });

const state = await client.getContractState({
  contractAccountId: 'example.near',
});

console.log('Contract state at block:', state.blockHeight);
console.log('Number of storage entries:', state.contractState.length);

for (const { key, value } of state.contractState) {
  const decodedKey = Buffer.from(key, 'base64').toString();
  const decodedValue = Buffer.from(value, 'base64').toString();
  console.log(`${decodedKey}: ${decodedValue}`);
}

Get State with Key Prefix

const state = await client.getContractState({
  contractAccountId: 'nft.example.near',
  keyPrefix: 'token:', // Only get keys starting with "token:"
});

console.log('Found', state.contractState.length, 'token entries');

Get Historical State

// Query state at a specific block height
const historicalState = await client.getContractState({
  contractAccountId: 'example.near',
  atMomentOf: {
    blockHeight: 123456789,
  },
});

console.log('State at block', historicalState.blockHeight);

Get State with Proof

const stateWithProof = await client.getContractState({
  contractAccountId: 'example.near',
  includeProof: true,
});

if (stateWithProof.proof) {
  console.log('Merkle proof:', stateWithProof.proof);
  // Use proof for verification
}

Decode Storage Values

import { base64 } from '@scure/base';

const state = await client.getContractState({
  contractAccountId: 'ft.example.near',
  keyPrefix: 'accounts:',
});

for (const { key, value } of state.contractState) {
  const keyBytes = base64.decode(key);
  const valueBytes = base64.decode(value);
  
  // Decode key (assuming UTF-8 string)
  const accountId = new TextDecoder().decode(keyBytes);
  
  // Decode value (assuming JSON)
  const accountData = JSON.parse(new TextDecoder().decode(valueBytes));
  
  console.log(`${accountId}:`, accountData);
}

With Abort Signal

const controller = new AbortController();

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10000);

try {
  const state = await client.getContractState({
    contractAccountId: 'large-contract.near',
    options: {
      signal: controller.signal,
    },
  });
  console.log('Retrieved state:', state.contractState.length, 'entries');
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request was aborted');
  }
}

Use Cases

Debugging Contract Storage

Inspect raw storage to debug contract issues:
const state = await client.getContractState({
  contractAccountId: 'debug.near',
});

// Find all storage keys
const keys = state.contractState.map(({ key }) => 
  Buffer.from(key, 'base64').toString('utf8')
);

console.log('Storage keys:', keys);

Exporting Contract Data

Export all contract data for backup or analysis:
const state = await client.getContractState({
  contractAccountId: 'backup.near',
});

const exportData = state.contractState.map(({ key, value }) => ({
  key: Buffer.from(key, 'base64').toString('hex'),
  value: Buffer.from(value, 'base64').toString('hex'),
  blockHeight: state.blockHeight,
}));

await fs.writeFile('contract-state.json', JSON.stringify(exportData, null, 2));

Notes

  • Storage keys and values are always base64-encoded in the response
  • Large contracts may have many storage entries; consider using keyPrefix to filter
  • The method queries RPC nodes, not the blockchain directly
  • Historical state is available depending on RPC node archival capabilities
  • Storage layout depends on the contract implementation