> For the complete documentation index, see [llms.txt](https://docs.baas.sh/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.baas.sh/baas-sdk/blockchain/smart-contracts.md).

# Smart contracts

Call your registered smart contracts from your app. Read data, send transactions, simulate, and estimate gas. No ABI files to import, no low-level library to wire up.

## Build a call

Every contract call follows the same shape: pick the contract, the address, the function, optionally the arguments, then finish with the action you want.

```ts
baas.contract('ERC20')          // 1. which contract class
  .address('0x1234…')           // 2. which deployment
  .function('totalSupply')      // 3. which function
  .params()                     // 4. its arguments (optional if none)
  .read<string>();              // 5. the action
```

The `.params()` step is optional when the function takes no arguments. Each step's autocomplete only suggests the next valid method, so the chain is always built in the right order.

## Read data

Use `read<T>()` to call view and pure functions.

```ts
// No arguments
const supply = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('totalSupply')
  .read<string>();

// With arguments
const balance = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('balanceOf')
  .params('0xabc…')
  .read<string>();
```

Type the result with a generic for type safety: `read<string>()`, `read<boolean>()`, `read<bigint>()`, and so on.

{% hint style="warning" %}
**Numbers come back as strings.** Numeric types like `uint256` are returned as decimal strings (JSON has no native big-number type). Type those with `<string>` and convert with `BigInt(value)` if you need arithmetic.
{% endhint %}

If a function returns different data depending on who's calling it (for example an access check that reads `msg.sender`), use `.simulate({ from })` instead of `.read()`. It lets you tell BaaS which address to use for the call.

## Send transactions

Use `sendTransaction(opts?)` to call functions that change on-chain state. It returns a `BaasTransaction` with the transaction hash and a `wait()` method to await confirmation.

```ts
import { Units } from '@baas/sdk';

// Simple write
const tx = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('mint')
  .params(1000)
  .sendTransaction();
//  → { hash: '0x…', wait }

// Payable function
const tx = await baas
  .contract('Vault')
  .address('0x5678…')
  .function('deposit')
  .sendTransaction({ value: Units.fromEth(0.001) }); // 0.001 ETH (or raw wei: '1000000000000000')

// External wallet — pass the same EIP-1193 provider used at sign-in
const tx = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('mint')
  .params(1000)
  .sendTransaction({ signer: window.ethereum });
```

`value` is denominated in **wei** (the smallest unit of ETH; `1 ETH = 10¹⁸ wei`). `Units.fromEth(0.001)` converts a human amount for you; a raw wei `string` or `bigint` works too. See [Unit conversion](/baas-sdk/blockchain/units.md).

### Preview before paying gas

The recommended pattern for any write is **simulate → send → wait**. Simulating first catches reverts before the wallet popup, so users only see a prompt when the call is going to succeed.

```ts
const step = baas
  .contract('ERC20').address('0x1234…')
  .function('mint').params(1000);

await step.simulate({ from: session.address }); // catches reverts
const tx = await step.sendTransaction({ signer }); // opens wallet
return tx.wait(); // resolves on-chain
```

Reuse the `step` builder between `simulate` and `sendTransaction` so the call is built once.

## Estimate gas

`estimateGas(opts?)` returns the number of gas units estimated for a call, as a `bigint`.

```ts
const gas = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('mint')
  .params(1000)
  .estimateGas();
//  → 21000n (gas units)
```

Gas is a unit count, not a cost in wei. Multiply by the chain's `gasPrice` to get the wei cost.

## Validation errors that guide you

If a step is invalid (unknown contract class, wrong address, function not in the ABI, wrong argument types), BaaS returns a `BaasApiError` carrying `.level` (the step that failed) and `.validOptions` (what was expected at that step). You can use these to show users helpful suggestions.

```ts
try {
  await baas.contract('ERC20x').address('0x…').function('mint').params(1000).read();
} catch (err) {
  if (err instanceof BaasApiError && err.level === 'contract') {
    console.log('Did you mean:', err.validOptions);
    // → ['ERC20', 'ERC721', 'MyToken']
  }
}
```

The `.level` is one of `'contract'`, `'address'`, `'function'`, or `'params'`. See [Error handling](/baas-sdk/resources/error-handling.md#smart-contract-validation-errors) for the full table and the safe `if (err.level)` check that covers non-cascade cases (reverts, network failures, user cancellations).

### Disambiguating overloaded functions

A contract may declare multiple functions with the same name but different signatures (Solidity overloads, e.g. `mint(uint256)` and `mint(address, uint256)`). When the number of arguments differs, the server resolves the right overload from your arguments automatically. You don't need to do anything special for this case.

When two overloads take the **same number of arguments** but differ on a scalar type that JavaScript can't distinguish (e.g. `value(uint8)` vs `value(uint256)` both called with `100`), the server returns a `params_ambiguous` cascade error. Wrap the conflicting argument with `Typed.*` to pick a side:

```ts
import { Typed } from '@baas/sdk';

// Ambiguous: both value(uint8) and value(uint256) accept a JS number.
await baas.contract('Counter').address('0x…').function('value').params(100).read();
// → BaasApiError(code: 'params_ambiguous', validOptions: ['value(uint256)', 'value(uint8)'])

// Disambiguated via Typed:
await baas.contract('Counter').address('0x…').function('value').params(Typed.uint8(100)).read();
```

Available helpers: `Typed.uint8`…`Typed.uint256` (32 widths), `Typed.int8`…`Typed.int256`, `Typed.bytes1`…`Typed.bytes32`, `Typed.address`, `Typed.bool`, `Typed.bytes`, `Typed.string`. Aliases: `Typed.uint` (= `uint256`) and `Typed.int` (= `int256`).

## Types

```ts
type ContractStep   = { address(addr: string): AddressStep };
type AddressStep    = { function(name: string): FunctionStep };
type FunctionStep   = TerminalStep & { params(...args: readonly unknown[]): TerminalStep };
type TerminalStep   = {
  read<T = unknown>(): Promise<T>;
  sendTransaction(opts?: SendOptions): Promise<BaasTransaction>;
  simulate<T = unknown>(opts?: SimulateOptions): Promise<T>;
  estimateGas(opts?: EstimateGasOptions): Promise<bigint>;
};

type SendOptions        = { value?: string | bigint; signer?: EIP1193Provider };
type SimulateOptions    = { value?: string | bigint; from?: string };
type EstimateGasOptions = { value?: string | bigint; from?: string };
```

## Next

* [Wallet operations](/baas-sdk/blockchain/wallet.md) — send transactions, sign messages, and read balances directly on the user's wallet.
* [Error handling](/baas-sdk/resources/error-handling.md) — the full error hierarchy and the cascade reference.
* [API reference](/baas-sdk/resources/api-reference.md) — every method and signature in one place.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.baas.sh/baas-sdk/blockchain/smart-contracts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
