> 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 to read data, send transactions, simulate, and estimate gas.

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, no amount conversion to write.

These examples assume you are signed in and have selected an enabled network. Register the contract and its deployment in your BaaS project first. Replace the shortened example addresses with full deployment and wallet addresses.

Use a trusted API and contract registry. Before a write, show the intended action and amount in your UI.

## 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. registered contract name
  .address('0x1234…')           // 2. which deployment
  .function('totalSupply')      // 3. which function
  .params()                     // 4. its arguments (optional if none)
  .read();                      // 5. the action
```

The `.params()` step is optional when the function takes no arguments.

For amounts with a configured unit, pass `SmartUnits('1.5')` inside `.params(...)`; BaaS handles the conversion. See [Smart units](/baas-sdk/blockchain/smart-units.md).

## Read data

Use `read<T>()` to call view and pure functions. It resolves to the function's **outputs array**, in ABI order. A single output comes back as a one-element array, so destructure it to name your values.

When BaaS knows an output's decimals, that slot holds a `UnitFormattedValue`: display `formatted`, compute with `raw`. On an ERC-20, that's `totalSupply`, `balanceOf`, and `allowance`.

```ts
import type { UnitFormattedValue } from '@baas.sh/sdk';

// An amount, no arguments
const [supply] = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('totalSupply')
  .read<[UnitFormattedValue]>();
console.log(supply.formatted); // → '1000000.0'

// An amount, with arguments
const [balance] = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('balanceOf')
  .params('0xabc…')
  .read<[UnitFormattedValue]>();
console.log(`${balance.formatted} tokens`); // → '1.5 tokens'

// Any other output: an address, a string, a flag
const [owner] = await baas
  .contract('Vault')
  .address('0x5678…')
  .function('owner')
  .read<[string]>();
```

Type `T` as a tuple, one slot per output: `read<[string, string]>()` for two outputs, `read<[string[]]>()` for one output that is a list. A function with no outputs resolves to `[]`.

An integer output without a unit arrives as a decimal string, since JSON has no big-number type. Keep it as `string` in the tuple, and use `BigInt(value)` when you need arithmetic. If it is an amount, [declare a unit](/baas-console/contracts/units/custom-units.md) for it, and it arrives formatted from then on. See [When to use raw values](/baas-sdk/blockchain/smart-units.md#when-to-use-raw-values).

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()`: you tell BaaS which address to use, and get back the same outputs array.

## Send transactions

Use `sendTransaction(opts?)` to change on-chain state. It returns a transaction hash and `wait()` to await confirmation. For passkey wallets, [activate the wallet](/baas-sdk/blockchain/wallet.md#activate-a-smart-wallet-on-a-chain) on the selected network first. Fund the wallet for the transfer and any fees.

```ts
import { SmartUnits } from '@baas.sh/sdk';

// Simple write: 1.5 tokens, converted to base units by BaaS
const tx = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('transfer')
  .params('0xabc…', SmartUnits('1.5'))
  .sendTransaction();
//  → { hash: '0x…', wait }

// Payable function
const payableTx = await baas
  .contract('Vault')
  .address('0x5678…')
  .function('deposit')
  .sendTransaction({ value: SmartUnits('0.001') }); // 0.001 ETH
```

For an external wallet, finish the call with `.sendTransaction({ signer: provider })`, using the provider from sign-in. `value` uses the chain's native currency; function arguments use their configured units. See [Smart units](/baas-sdk/blockchain/smart-units.md).

### Preview before paying gas

You can simulate a write first: a revert then surfaces before the user sees a prompt.

```ts
const step = baas
  .contract('ERC20').address('0x1234…')
  .function('transfer').params('0xabc…', SmartUnits('1.5'));

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

## 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('transfer')
  .params('0xabc…', SmartUnits('1.5'))
  .estimateGas();
//  → 51000n (gas units)
```

Gas is a unit count, not a cost in ETH. It gives a relative sense of a call's cost; the actual fee depends on the network's current gas price.

## Target a specific chain

A call targets the [active chain](/baas-sdk/blockchain/networks.md#the-active-chain) when you call the method; if none has been chosen, it throws `CHAIN_SELECTION_REQUIRED`. To target another chain, select it with `baas.chains.switch()`:

```ts
// Read on another chain (passkey session)
await baas.chains.switch(10);
const [supplyOnOptimism] = await baas
  .contract('ERC20')
  .address('0x1234…')
  .function('totalSupply')
  .read<[UnitFormattedValue]>();
```

With an external wallet, pass its provider to `switch()` as `{ signer: provider }`.

The chain must be one the session can use, and every method needs a session, `read()` included. The errors are listed in [Error handling](/baas-sdk/resources/error-handling.md).

## Handle an invalid call

If a step is invalid (unknown contract class, wrong address, function not in the ABI, wrong argument types), BaaS returns a `BaasApiError` with `.level` (the step that failed) and `.validOptions` (what was expected), so you can suggest a fix. See [Smart contract validation errors](/baas-sdk/resources/error-handling.md#smart-contract-validation-errors).

### Disambiguating overloaded functions

When two overloads take the same number of arguments and JavaScript cannot tell the types apart (`value(uint8)` and `value(uint256)` both called with `100`), the call is refused with `params_ambiguous`. Wrap the argument with `Typed.*`, or pin the overload's signature:

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

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

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

// Or pin the overload's canonical signature (validOptions hands it to you ready to paste):
await baas.contract('Counter').address('0x…').function('value(uint8)').params(100).read();
```

`Typed.*` only marks the Solidity type; it does not validate the value or convert units. It works on scalar arguments, not inside arrays or tuples. For those, pin the signature. See [Exported types](/baas-sdk/resources/exported-types.md) for the helpers.

[SmartUnits](/baas-sdk/blockchain/smart-units.md) requests unit conversion, but does not select the Solidity type. For an overloaded call, use `.function('value(uint256)').params(SmartUnits('1.5'))`, with a unit binding configured for that input. Nesting `Typed` and `SmartUnits` on the same argument is rejected; using them on separate arguments is supported.

## Next

* [Smart units](/baas-sdk/blockchain/smart-units.md) — how amounts travel: `SmartUnits('1.5')` in, `{ raw, formatted }` out, and the few cases that stay raw.
* [Event history](/baas-sdk/blockchain/events.md) — read and filter what your contracts emit.
* [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) — diagnose validation and transaction errors.
* [API reference](/baas-sdk/resources/api-reference.md) — every method and signature in one place.
