Ir para o conteúdo

Biblioteca viem TypeScript Ethereum

Introdução

viem é uma biblioteca TypeScript modular que fornece abstrações sobre a API JSON-RPC, facilitando a interação com nós Ethereum. Como as redes EVM da Tanssi expõem uma API compatível com Ethereum/JSON-RPC, você pode usar viem para interagir com qualquer rede EVM Tanssi. Veja a documentação do viem para mais detalhes.

Neste guia, você verá como usar viem para enviar uma transação e implantar um contrato na rede EVM de demonstração. O mesmo fluxo se aplica a qualquer rede EVM da Tanssi.

Note

Os exemplos deste guia partem de um ambiente MacOS ou Ubuntu 20.04. Se estiver usando Windows, adapte os comandos conforme necessário.

Verifique também se você tem o Node.js e um gerenciador de pacotes (como npm ou yarn) instalados. Para saber como instalar o Node.js, consulte a documentação oficial.

Além disso, certifique-se de ter inicializado um arquivo package.json para módulos ES6. Você pode criar um package.json padrão com npm executando npm init --yes.

Verificando pré-requisitos

Para os exemplos, você precisará de:

  • Uma conta com fundos na rede EVM Tanssi que estiver usando

Instalando viem

Crie um projeto TypeScript básico e instale dependências:

mkdir viem-examples && cd viem-examples && npm init --y

Instale viem e o compilador Solidity:

npm install typescript ts-node viem solc@0.8.0
yarn add typescript ts-node viem solc@0.8.0

Gere o tsconfig:

npx tsc --init

Nota

Tutorial criado usando Node.js v18.18.0.

Configurar um cliente viem (provedor)

Você pode criar: - um cliente de leitura com createPublicClient, para saldos/dados; ou - um cliente de escrita com createWalletClient, para enviar transações.

Primeiro defina a cadeia com defineChain, informando todos os campos (incluindo public e default RPC).

Para ler dados da cadeia

Passos:

  1. Importe createPublicClient, http e defineChain de viem.
  2. Defina os detalhes da cadeia (inclua URLs public e default).
  3. Crie o client com createPublicClient, passando rede e RPC HTTP.
// 1. Import the necessary components from viem
import { createPublicClient, http, defineChain } from 'viem';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a public client for reading chain data
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

Para gravar dados da cadeia

Passos:

  1. Importe createWalletClient, http, defineChain de viem e privateKeyToAccount de viem/accounts.
  2. Defina os detalhes da cadeia (inclua URLs public e default).
  3. Crie a conta com privateKeyToAccount.
  4. Crie o client com createWalletClient, passando conta, rede e RPC HTTP.

Remember

Demonstração apenas. Nunca salve chave privada em arquivo TypeScript.

// 1. Import the necessary components from viem and viem/accounts
import { createWalletClient, http, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create your account using the privateKeyToAccount function
const account = privateKeyToAccount('INSERT_PRIVATE_KEY');
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';

//4. Create a wallet client for writing chain data
const walletClient = createWalletClient({
  account,
  chain: demoEVM,
  transport: http(rpcUrl),
});

Nota

Para carteiras de navegador, veja este exemplo (onde demo é a rede definida em defineChain):

const [account] = await window.ethereum.request({
  method: 'eth_requestAccounts',
});
const walletClient = createWalletClient({
  account,
  chain: demo,
  transport: custom(window.ethereum),
});

Enviar uma transação

Criaremos dois scripts: um para saldos e outro para enviar a transação.

Script de saldos

Crie o arquivo:

touch balances.ts

Passos:

  1. Importe createPublicClient, http, formatEther, defineChain.
  2. Defina a cadeia (inclua URLs public/default).
  3. Configure o cliente público.
  4. Defina addressFrom e addressTo.
  5. Crie a função balances usando publicClient.getBalance.
  6. Formate com formatEther e exiba.
  7. Chame balances().
Ver balances.ts
// 1. Import the necessary components from viem
import { createPublicClient, http, formatEther, defineChain } from 'viem';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'UNIT',
    symbol: 'UNIT',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a public client for reading chain data
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 4. Create address variables
const addressFrom = 'INSERT_ADDRESS_FROM';
const addressTo = 'INSERT_ADDRESS_TO';

// 5. Create balances function
const balances = async () => {
  // 6. Fetch balances
  const balanceFrom = formatEther(
    await publicClient.getBalance({ address: addressFrom })
  );
  const balanceTo = formatEther(
    await publicClient.getBalance({ address: addressTo })
  );

  console.log(`The balance of ${addressFrom} is: ${balanceFrom} TANGO`);
  console.log(`The balance of ${addressTo} is: ${balanceTo} TANGO`);
};

// 7. Call the balances function
balances();

Execute:

npx ts-node balances.ts

Saldos em TANGO serão exibidos.

Resultado do script balances

Script de envio

Crie o arquivo:

touch transaction.ts

Passos:

  1. Importe createPublicClient, createWalletClient, http, parseEther, defineChain e privateKeyToAccount.
  2. Defina a cadeia (inclua URLs public/default).
  3. Configure o cliente de carteira (escrita) com sua chave (não salve chaves reais em TS).
  4. Configure o cliente público (leitura) para aguardar recibo.
  5. Defina addressTo.
  6. Crie send() com o objeto da transação.
  7. Envie com walletClient.sendTransaction e aguarde o hash.
  8. Aguarde o recibo com publicClient.waitForTransactionReceipt.
  9. Chame send().
Ver transaction.ts
// 1. Import the necessary components from viem and viem/accounts
import {
  createPublicClient,
  createWalletClient,
  http,
  parseEther,
  defineChain,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a wallet client for writing chain data
// The private key must be prepended with `0x` to avoid errors
const account = privateKeyToAccount('INSERT_PRIVATE_KEY');
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const walletClient = createWalletClient({
  account,
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 4. Create a public client for reading chain data
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 5. Create to address variable
const addressTo = 'INSERT_ADDRESS_TO';

// 6. Create send function
const send = async () => {
  console.log(
    `Attempting to send transaction from ${account.address} to ${addressTo}`
  );

  // 7. Sign and send transaction
  const hash = await walletClient.sendTransaction({
    to: addressTo,
    value: parseEther('1'),
  });

  // 8. Wait for the transaction receipt
  await publicClient.waitForTransactionReceipt({
    hash,
  });

  console.log(`Transaction successful with hash: ${hash}`);
};

// 9. Call the send function
send();

Execute:

npx ts-node transaction.ts

Você verá o hash; use balances.ts antes/depois para confirmar saldos.

Resultado dos scripts transaction e balances

Implantar um contrato

O contrato que você irá compilar e implantar nas próximas seções é um simples incrementador, chamado Incrementer.sol. Comece criando o arquivo do contrato:

touch Incrementer.sol

Depois, adicione o código Solidity ao arquivo:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Incrementer {
    uint256 public number;

    constructor(uint256 _initialNumber) {
        number = _initialNumber;
    }

    function increment(uint256 _value) public {
        number = number + _value;
    }

    function reset() public {
        number = 0;
    }
}

A função constructor, executada quando o contrato é implantado, define o valor inicial da variável number armazenada on-chain (padrão é 0). A função increment soma o _value informado ao número atual, mas exige uma transação, pois modifica o dado armazenado. Por fim, a função reset zera o valor armazenado.

Note

Este contrato é apenas um exemplo simples para fins ilustrativos.

Script de compilação

Nesta seção, você criará um script em TypeScript que usa o compilador Solidity para gerar o bytecode e a interface (ABI) do contrato Incrementer.sol. Para começar, crie o arquivo compile.ts executando:

touch compile.ts

Depois, escreva o script seguindo estas etapas:

  1. Importe os pacotes fs e solc
  2. Use fs.readFileSync para ler e salvar o conteúdo de Incrementer.sol em source
  3. Monte o objeto input para o compilador Solidity especificando language, sources e settings
  4. Compile o contrato com solc.compile usando o objeto input
  5. Extraia o contrato compilado e exporte-o para ser usado no script de implantação
// 1. Import packages
const fs = require('fs');
const solc = require('solc');

// 2. Get path and load contract
const source = fs.readFileSync('Incrementer.sol', 'utf8');

// 3. Create input object
const input = {
  language: 'Solidity',
  sources: {
    'Incrementer.sol': {
      content: source,
    },
  },
  settings: {
    outputSelection: {
      '*': {
        '*': ['*'],
      },
    },
  },
};
// 4. Compile the contract
const tempFile = JSON.parse(solc.compile(JSON.stringify(input)));
const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer'];

// 5. Export contract data
export default contractFile;

Script de deploy

Compile Incrementer.sol e crie deploy.ts:

touch deploy.ts

Passos:

  1. Importe createPublicClient, createWalletClient, http, defineChain, privateKeyToAccount e o contractFile de compile.ts.
  2. Defina a cadeia (inclua URLs public/default).
  3. Configure o cliente de carteira (escrita) para implantar (não salve chaves reais em TS).
  4. Configure o cliente público (leitura) para obter recibo.
  5. Carregue bytecode e abi.
  6. Crie a função deploy.
  7. Use walletClient.deployContract com ABI, bytecode, conta e valor inicial.
  8. Aguarde recibo/leitura conforme necessário.
  9. Chame deploy().
Ver deploy.ts
// 1. Update import
import {
  createPublicClient,
  createWalletClient,
  http,
  defineChain,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import contractFile from './compile';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a wallet client for writing chain data
// The private key must be prepended with `0x` to avoid errors
const account = privateKeyToAccount('INSERT_PRIVATE_KEY');
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const walletClient = createWalletClient({
  account,
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 4. Create a public client for reading chain data
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 5. Load contract information
const bytecode = contractFile.evm.bytecode.object;
const abi = contractFile.abi;
const _initialNumber = 5;

// 6. Create deploy function
const deploy = async () => {
  console.log(`Attempting to deploy from account: ${account.address}`);

  // 7. Send transaction (initial value set to 5)
  const contract = await walletClient.deployContract({
    abi,
    account,
    bytecode,
    args: [_initialNumber],
  });

  // 8. Get the transaction receipt for the deployment
  const transaction = await publicClient.waitForTransactionReceipt({
    hash: contract,
  });

  console.log(`Contract deployed at address: ${transaction.contractAddress}`);
};

// 9. Call the deploy function
deploy();

Execute:

npx ts-node deploy.ts

O endereço do contrato será exibido.

Resultado do script deploy

Ler dados do contrato (calls)

Calls não alteram estado; não precisam de transação. Crie get.ts:

touch get.ts

Passos:

  1. Importe createPublicClient, http, defineChain e contractFile de compile.ts.
  2. Defina a cadeia (inclua URLs public/default).
  3. Configure o cliente público.
  4. Defina contractAddress e abi.
  5. Crie a função get.
  6. Chame publicClient.readContract (função number) e exiba o valor.
  7. Chame get().
Ver get.ts
// 1. Update import
import { createPublicClient, http, defineChain } from 'viem';
import contractFile from './compile';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a public client for reading chain data
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});
// 4. Create contract variables
const contractAddress = 'INSERT_CONTRACT_ADDRESS';
const abi = contractFile.abi;

// 5. Create get function
const get = async () => {
  console.log(`Making a call to contract at address: ${contractAddress}`);

  // 6. Call contract
  const data = await publicClient.readContract({
    abi,
    functionName: 'number',
    address: contractAddress,
    args: [],
  });

  console.log(`The current number stored is: ${data}`);
};

// 7. Call get function
get();

Execute:

npx ts-node get.ts

Resultado do script get

Interagir com o contrato (sends)

Sends alteram estado e exigem transação. Crie increment.ts e reset.ts:

touch increment.ts reset.ts

increment.ts:

  1. Importe createPublicClient, createWalletClient, http, defineChain, privateKeyToAccount e contractFile.
  2. Defina a cadeia (inclua URLs public/default).
  3. Configure o cliente de carteira (escrita) (não salve chaves reais em TS).
  4. Configure o cliente público (leitura) para recibo.
  5. Defina contractAddress, abi, _value.
  6. Crie increment().
  7. Chame walletClient.writeContract com _value e aguarde hash.
  8. Aguarde recibo com publicClient.waitForTransactionReceipt.
  9. Chame increment().
Ver increment.ts
// 1. Update import
import {
  createPublicClient,
  createWalletClient,
  http,
  defineChain,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import contractFile from './compile';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a wallet client for writing chain data
// The private key must be prepended with `0x` to avoid errors
const account = privateKeyToAccount('INSERT_PRIVATE_KEY');
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const walletClient = createWalletClient({
  account,
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 4. Create a public client for reading chain data
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 5. Create contract variables
const contractAddress = 'INSERT_CONTRACT_ADDRESS';
const abi = contractFile.abi;
const _value = 3;

// 6. Create increment function
const increment = async () => {
  console.log(
    `Calling the increment by ${_value} function in contract at address: ${contractAddress}`
  );
  // 7. Call contract
  const hash = await walletClient.writeContract({
    abi,
    functionName: 'increment',
    address: contractAddress,
    args: [_value],
  });

  // 8. Wait for the transaction receipt
  await publicClient.waitForTransactionReceipt({
    hash,
  });

  console.log(`Transaction successful with hash: ${hash}`);
};

// 9. Call increment function
increment();

Execute:

npx ts-node increment.ts

Resultado dos scripts increment e get

reset.ts:

  1. Importe as mesmas dependências de increment.ts.
  2. Defina a cadeia.
  3. Configure clientes de carteira e público.
  4. Defina contractAddress e abi.
  5. Crie reset().
  6. Chame walletClient.writeContract (função reset) e aguarde hash.
  7. Aguarde recibo com publicClient.waitForTransactionReceipt.
  8. Chame reset().
Ver reset.ts
// 1. Update import
import {
  createPublicClient,
  createWalletClient,
  http,
  defineChain,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import contractFile from './compile';

// 2. Specify the details of your EVM network
export const demoEVM = defineChain({
  id: 5678,
  name: 'demo',
  network: 'demo',
  nativeCurrency: {
    decimals: 18,
    name: 'TANGO',
    symbol: 'TANGO',
  },
  rpcUrls: {
    default: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
    public: {
      http: ['https://services.tanssi-testnet.network/dancelight-2001'],
      webSocket: ['wss://services.tanssi-testnet.network/dancelight-2001'],
    },
  },
  blockExplorers: {
    default: {
      name: 'Explorer',
      url: 'https://dancelight-2001-blockscout.tanssi-chains.network/',
    },
  },
});

// 3. Create a wallet client for writing chain data
// The private key must be prepended with `0x` to avoid errors
const account = privateKeyToAccount('INSERT_PRIVATE_KEY');
const rpcUrl = 'https://services.tanssi-testnet.network/dancelight-2001';
const walletClient = createWalletClient({
  account,
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 4. Create a public client for reading chain data
const publicClient = createPublicClient({
  chain: demoEVM,
  transport: http(rpcUrl),
});

// 5. Create contract variables
const contractAddress = 'INSERT_CONTRACT_ADDRESS';
const abi = contractFile.abi;

// 6. Create reset function
const reset = async () => {
  console.log(
    `Calling the reset function in contract at address: ${contractAddress}`
  );

  // 7. Call contract
  const hash = await walletClient.writeContract({
    abi,
    functionName: 'reset',
    address: contractAddress,
    args: [],
  });

  // 8. Wait for the transaction receipt
  await publicClient.waitForTransactionReceipt({
    hash,
  });

  console.log(`Transaction successful with hash: ${hash}`);
};

// 9. Call reset function
reset();

Execute:

npx ts-node reset.ts

Resultado dos scripts reset e get

As informações apresentadas aqui foram fornecidas por terceiros e estão disponíveis apenas para fins informativos gerais. A Tanssi não endossa nenhum projeto listado e descrito no Site de Documentação da Tanssi (https://docs.tanssi.network/). A Tanssi Foundation não garante a precisão, integridade ou utilidade dessas informações. Qualquer confiança depositada nelas é de sua exclusiva responsabilidade. A Tanssi Foundation se exime de toda responsabilidade decorrente de qualquer confiança que você ou qualquer outra pessoa possa ter em qualquer parte deste conteúdo. Todas as declarações e/ou opiniões expressas nesses materiais são de responsabilidade exclusiva da pessoa ou entidade que as fornece e não representam necessariamente a opinião da Tanssi Foundation. As informações aqui não devem ser interpretadas como aconselhamento profissional ou financeiro de qualquer tipo. Sempre busque orientação de um profissional devidamente qualificado em relação a qualquer assunto ou circunstância em particular. As informações aqui podem conter links ou integração com outros sites operados ou conteúdo fornecido por terceiros, e tais sites podem apontar para este site. A Tanssi Foundation não tem controle sobre esses sites ou seu conteúdo e não terá responsabilidade decorrente ou relacionada a eles. A existência de qualquer link não constitui endosso desses sites, de seu conteúdo ou de seus operadores. Esses links são fornecidos apenas para sua conveniência, e você isenta e exonera a Tanssi Foundation de qualquer responsabilidade decorrente do uso dessas informações ou das informações fornecidas por qualquer site ou serviço de terceiros.
Última atualização: 9 de dezembro de 2025
| Criada: 9 de dezembro de 2025