# How to Deploy and Use Ink! Smart Contracts on the 3DPass Blockchain

> Deploy Ink smart contracts to the 3DPass blockchain. Learn to compile Rust, upload WebAssembly, and instantiate your contract using the Substrate contracts pallet. Get started today.

- Repository: [3Dpass/3dp](https://github.com/3dpass/3dp)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Deploying Ink! smart contracts on the 3DPass blockchain involves compiling Rust code into a WebAssembly blob using `cargo contract`, uploading the binary via the `contracts_uploadCode` RPC to the chain's storage, and instantiating the contract through the `contracts_instantiate` dispatchable, all orchestrated by the native Substrate contracts pallet configured in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs).**

The 3DPass blockchain (repository `3dpass/3DP`) provides native support for **Ink! smart contracts** through its integrated Substrate contracts pallet. This allows developers to write **WebAssembly (Wasm)**-based smart contracts in Rust and deploy them to the 3DPass network, leveraging the security and performance of the underlying Ledger of Things infrastructure.

## The Contracts Pallet Architecture

The 3DPass node ships with the native Substrate **contracts pallet**, which supports Ink!—the Rust-based eDSL for writing WebAssembly smart contracts. According to the repository's [`README.md`](https://github.com/3dpass/3dp/blob/main/README.md) (lines 186-188), the node explicitly supports "native Substrate Smart contract trait using **ink**".

The pallet is declared as a dependency in [`runtime/Cargo.toml`](https://github.com/3dpass/3dp/blob/main/runtime/Cargo.toml) (lines 127-129) from the Parity Substrate repository:

```toml
pallet-contracts = { git = "https://github.com/paritytech/substrate", default-features = false }

```

The runtime configuration resides in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs), where the `pallet_contracts::Config` implementation (lines 78-81) wires the contracts pallet into the 3DPass runtime. This configuration includes the **weight schedule**, **maximum code size limits** (lines 130-132), and the **call filter** security whitelist (lines 84-91).

## Three-Stage Deployment Process

Deploying an Ink! smart contract to 3DPass follows a standardized three-stage pipeline that mirrors standard Substrate contract workflows:

### 1. Compile to WebAssembly

Your Ink! source code is compiled into a Wasm blob using `cargo contract`. No 3DPass-specific compilation flags are required—the output is a standard WASM contract that the contracts pallet understands. The build process produces a `.contract` bundle containing both the Wasm binary and the contract metadata.

### 2. Upload Code to Chain Storage

The compiled Wasm blob is stored in the chain's global storage via the **pallet-contracts** dispatchable. In [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs), the configuration defines the maximum code size at lines 130-132. This upload step is executed through the `contracts_uploadCode` RPC call or the `cargo contract upload` CLI command.

### 3. Instantiate the Contract

Once stored, the contract is instantiated via the `contracts_instantiate` dispatchable. This creates a new contract address and initializes the contract storage using your chosen constructor. The runtime validates this instantiation against the **CallFilter** configured at lines 84-91 of [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs), which defaults to `Nothing` (blocking runtime calls from contracts for security).

## Step-by-Step Deployment Guide

Follow these steps to deploy an Ink! contract to a local 3DPass node:

### Prerequisites

Ensure you have the Rust nightly toolchain and the Ink! CLI installed. The repository's [`README.md`](https://github.com/3dpass/3dp/blob/main/README.md) (lines 28-39) documents the required Rust toolchain configuration for building the 3DPass node.

### 1. Build Your Contract

Compile your Ink! smart contract to WebAssembly:

```bash
cargo contract build --release

```

This generates `target/ink/<contract_name>.contract`, which bundles the Wasm binary and JSON metadata.

### 2. Start a Local 3DPass Node

Launch a development node with the contracts pallet enabled:

```bash
cargo run --release -- --dev

```

The node exposes the WebSocket endpoint `ws://127.0.0.1:9944` for RPC interactions.

### 3. Upload the Contract Code

Upload the compiled Wasm blob to the chain's storage using Alice's development account:

```bash
cargo contract upload \
    --suri //Alice \
    --url ws://127.0.0.1:9944 \
    target/ink/my_contract.contract

```

This submits a `contracts_uploadCode` extrinsic that stores the code on-chain and returns a `codeHash`.

### 4. Instantiate the Contract

Deploy an instance of the contract using a specific constructor:

```bash
cargo contract instantiate \
    --suri //Alice \
    --url ws://127.0.0.1:9944 \
    --constructor new \
    --args 42 \
    --endowment 1_000_000_000_000 \
    --gas-limit 500_000

```

This executes the `contracts_instantiate` RPC, creates the contract address, and initializes storage.

## Runtime Configuration and Security

The 3DPass runtime enforces strict security boundaries for contract execution through the `CallFilter` type defined at lines 84-91 of [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs). By default, this is set to `Nothing`, meaning Ink! contracts **cannot dispatch calls to other runtime pallets**. This sandboxing prevents malicious contracts from manipulating core runtime functions.

To expose specific runtime functions to your contracts (such as calling into the balances or assets pallets), you must modify the `CallFilter` implementation:

```rust
// In runtime/src/lib.rs
type CallFilter = frame_support::traits::Everything; // Allow all (development only)
// OR
type CallFilter = frame_support::traits::EverythingExcept<SomeSpecificCalls>; // Custom filter

```

After modifying the filter, recompile the runtime with `cargo build --release` and restart your node.

## Interacting with Deployed Contracts

Once instantiated, interact with your contract using the Polkadot-JS API or the contracts CLI.

### Query and Transact via JavaScript

Use `@polkadot/api` and `@polkadot/api-contract` to interact with your deployed contract:

```javascript
import { ApiPromise, WsProvider } from '@polkadot/api';
import { ContractPromise } from '@polkadot/api-contract';
import abi from './my_contract.json'; // Generated by cargo contract

async function interact() {
  const provider = new WsProvider('ws://127.0.0.1:9944');
  const api = await ApiPromise.create({ provider });
  
  // Replace with your contract address from instantiation
  const contract = new ContractPromise(api, abi, '5F...contractAddress');
  
  // Read-only query
  const { output } = await contract.query.getValue(
    '5F...aliceAddress', // Caller
    { value: 0, gasLimit: -1 }
  );
  console.log('Stored value:', output?.toString());
  
  // Mutable transaction
  const tx = await contract.tx.setValue(
    { value: 0, gasLimit: -1 },
    100 // New value
  );
  await tx.signAndSend('5F...aliceAddress');
}
interact();

```

### CLI Interaction

Call contract messages directly from the command line:

```bash
cargo contract call \
    --suri //Alice \
    --url ws://127.0.0.1:9944 \
    --contract <CONTRACT_ADDRESS> \
    --message get_value \
    --gas-limit 500_000

```

## Summary

- **The 3DPass blockchain** supports Ink! smart contracts through the native Substrate contracts pallet configured in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) (lines 78-81).
- **Deployment requires three steps**: compile with `cargo contract build`, upload via `contracts_uploadCode`, and instantiate via `contracts_instantiate`.
- **Security defaults are strict**: the `CallFilter` (lines 84-91) defaults to `Nothing`, blocking runtime calls from contracts unless explicitly whitelisted.
- **Size and weight limits** are enforced through the `Schedule` and `MaxCodeLen` configurations (lines 130-132) in the runtime.
- **Interaction is standard Substrate**: use Polkadot-JS UI, `cargo contract` CLI, or the JavaScript API to call contract messages.

## Frequently Asked Questions

### What Ink! version does 3DPass support?

The 3DPass runtime uses the standard `pallet-contracts` from the Parity Substrate repository (declared in [`runtime/Cargo.toml`](https://github.com/3dpass/3dp/blob/main/runtime/Cargo.toml) lines 127-129), which supports the latest stable Ink! language features. For specific version compatibility, check the Substrate commit referenced in the repository's `Cargo.lock` file, though standard Ink! 4.x and 5.x contracts compile and deploy without modification.

### Why does my contract instantiation fail with "CallFiltered" errors?

The 3DPass runtime configures `CallFilter = Nothing` at lines 84-91 of [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) by default. This prevents contracts from calling into other runtime pallets as a security measure. If your contract logic requires dispatching calls to runtime functions (such as the Balances pallet), you must modify the `CallFilter` type to explicitly allow those calls and recompile the runtime.

### How large can my Ink! contract be on 3DPass?

The maximum code size is defined in [`runtime/src/lib.rs`](https://github.com/3dpass/3dp/blob/main/runtime/src/lib.rs) at lines 130-132 through the `MaxCodeLen` configuration parameter. If your compiled Wasm blob exceeds this limit, the `contracts_uploadCode` transaction will fail. Optimize your contract using `cargo contract build --release` or split logic across multiple contracts to stay within the permitted size.

### Can I deploy the same contract code multiple times?

Yes. After uploading the Wasm blob once via `contracts_uploadCode`, you can instantiate multiple independent contract instances using the same `codeHash` but different constructor arguments and endowments. Each instantiation creates a unique contract address with isolated storage, allowing you to deploy multiple copies of the same logic without re-uploading the binary.