Ir para o conteúdo

Interagindo com o Batch Precompile

Introdução

O Batch Precompile em redes EVM com tecnologia Tanssi permite que desenvolvedores agrupem várias chamadas EVM em uma única transação.

Sem o precompile, um usuário precisaria confirmar várias transações (por exemplo, aprovar um token e logo em seguida transferi-lo). Com o Batch Precompile, a experiência melhora porque o usuário confirma apenas uma transação, reduzindo também o gás pago por taxas básicas múltiplas.

O precompile interage diretamente com o pallet EVM do Substrate. A conta que chama a função em lote atua como msg.sender para todas as subtransações e cada contrato de destino altera o seu próprio armazenamento (diferente de delegatecall).

O Batch Precompile está localizado no seguinte endereço:

0x0000000000000000000000000000000000000801

Note

O uso de precompiladas pode trazer consequências inesperadas. As precompiladas do Tanssi são derivadas das do Moonbeam; portanto, familiarize-se com as considerações de segurança das precompiladas do Moonbeam.

A interface Solidity em lote

Batch.sol é a interface Solidity para os três métodos do precompile.

Batch.sol
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.3;

/// @dev The Batch contract's address.
address constant BATCH_ADDRESS = 0x0000000000000000000000000000000000000801;

/// @dev The Batch contract's instance.
Batch constant BATCH_CONTRACT = Batch(BATCH_ADDRESS);

/// @author The Moonbeam Team
/// @title Batch precompile
/// @dev Allows to perform multiple calls throught one call to the precompile.
/// Can be used by EOA to do multiple calls in a single transaction.
/// @custom:address 0x0000000000000000000000000000000000000801
interface Batch {
    /// @dev Batch multiple calls into a single transaction.
    /// All calls are performed from the address calling this precompile.
    ///
    /// In case of one subcall reverting following subcalls will still be attempted.
    ///
    /// @param to List of addresses to call.
    /// @param value List of values for each subcall. If array is shorter than "to" then additional
    /// calls will be performed with a value of 0.
    /// @param callData Call data for each `to` address. If array is shorter than "to" then
    /// additional calls will be performed with an empty call data.
    /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas.
    /// If array is shorter than "to" then the remaining gas available will be used.
    /// @custom:selector 79df4b9c
    function batchSome(
        address[] memory to,
        uint256[] memory value,
        bytes[] memory callData,
        uint64[] memory gasLimit
    ) external;

    /// @dev Batch multiple calls into a single transaction.
    /// All calls are performed from the address calling this precompile.
    ///
    /// In case of one subcall reverting, no more subcalls will be executed but
    /// the batch transaction will succeed. Use batchAll to revert on any subcall revert.
    ///
    /// @param to List of addresses to call.
    /// @param value List of values for each subcall. If array is shorter than "to" then additional
    /// calls will be performed with a value of 0.
    /// @param callData Call data for each `to` address. If array is shorter than "to" then
    /// additional calls will be performed with an empty call data.
    /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas.
    /// If array is shorter than "to" then the remaining gas available will be used.
    /// @custom:selector cf0491c7
    function batchSomeUntilFailure(
        address[] memory to,
        uint256[] memory value,
        bytes[] memory callData,
        uint64[] memory gasLimit
    ) external;

    /// @dev Batch multiple calls into a single transaction.
    /// All calls are performed from the address calling this precompile.
    ///
    /// In case of one subcall reverting, the entire batch will revert.
    ///
    /// @param to List of addresses to call.
    /// @param value List of values for each subcall. If array is shorter than "to" then additional
    /// calls will be performed with a value of 0.
    /// @param callData Call data for each `to` address. If array is shorter than "to" then
    /// additional calls will be performed with an empty call data.
    /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas.
    /// If array is shorter than "to" then the remaining gas available will be used.
    /// @custom:selector 96e292b8
    function batchAll(
        address[] memory to,
        uint256[] memory value,
        bytes[] memory callData,
        uint64[] memory gasLimit
    ) external;

    /// Emitted when a subcall succeeds.
    event SubcallSucceeded(uint256 index);

    /// Emitted when a subcall fails.
    event SubcallFailed(uint256 index);
}

A interface inclui as funções:

batchSome(address[] to, uint256[] value, bytes[] callData, uint64[] gasLimit) — executa várias chamadas. Cada índice dos arrays compõe uma subchamada. Se uma subchamada reverter, as seguintes ainda serão tentadas
  • to - lista de endereços das subtransações
  • value - valores em moeda nativa para cada subtransação; se a lista for menor que to, os demais valores serão 0
  • callData - dados de chamada para cada subtransação; se a lista for menor que to, as restantes não terão dados
  • gasLimit - limite de gás de cada subtransação; 0 encaminha todo o gás restante. Se a lista for menor que to, as seguintes receberão todo o gás restante
batchSomeUntilFailure(... ) — igual ao anterior, porém interrompe ao primeiro erro
batchAll(... ) — executa várias chamadas de forma atômica. Se uma subchamada reverter, todas revertem

Eventos emitidos:

  • SubcallSucceeded(uint256 index) — emitido quando uma subchamada com o índice informado é bem-sucedida
  • SubcallFailed(uint256 index) — emitido quando uma subchamada com o índice informado falha

Interaja com a interface Solidity

Verifique os pré-requisitos

  • Carteira compatível com EVM configurada para sua rede (por exemplo, MetaMask)
  • Conta com tokens nativos suficientes
  • Opcional: rede de demonstração EVM no Tanssi dApp

Contrato de exemplo

Usaremos SimpleContract.sol para demonstrar interações em lote:

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;

contract SimpleContract {
    mapping(uint256 => string) public messages;

    function setMessage(uint256 id, string calldata message) external {
        messages[id] = message;
    }
}

Configuração do Remix

  1. Abra Remix.
  2. Crie os arquivos Batch.sol e SimpleContract.sol com o conteúdo correspondente.

Compile os contratos

  1. Abra Batch.sol e clique em Compile Batch.sol (aba Compile).
  2. Repita para SimpleContract.sol.

Acesse o precompile

  1. Na aba Deploy and Run, escolha Injected Provider - MetaMask em ENVIRONMENT.
  2. Selecione Batch.sol em CONTRACT.
  3. No campo At Address, insira 0x0000000000000000000000000000000000000801 e clique em At Address.
    O contrato BATCH aparecerá em Deployed Contracts.

Implemente o contrato de exemplo

  1. Ainda na aba Deploy and Run, selecione SimpleContract em CONTRACT.
  2. Clique em Deploy e confirme no MetaMask.
    O SIMPLECONTRACT aparecerá em Deployed Contracts.

Envie moeda nativa via precompile

Para usar batchAll e enviar tokens nativos de forma atômica:

  1. Expanda o contrato BATCH em Deployed Contracts.
  2. Abra batchAll.
  3. Preencha:
  4. to: [\"ENDERECO_1\",\"ENDERECO_2\"]
  5. value: [\"1000000000000000000\",\"2000000000000000000\"] (exemplo: 1 e 2 tokens)
  6. callData: []
  7. gasLimit: []
  8. Clique em transact e confirme no MetaMask.

Obtenha o call data de uma interação de contrato

  1. Em SIMPLECONTRACT, expanda setMessage.
  2. Preencha id (ex.: 1) e message (ex.: "tanssi").
  3. Clique no ícone de copiar ao lado de transact para obter o call data codificado.

Interaja com funções via precompile

Para chamar duas vezes setMessage de forma atômica:

  1. Copie o endereço de SIMPLECONTRACT.
  2. Em batchAll, preencha:
  3. to: [\"ENDERECO_CONTRATO\",\"ENDERECO_CONTRATO\"]
  4. value: [0,0]
  5. callData: [\"CALLDATA_1\",\"CALLDATA_2\"] (obtidos no passo anterior)
  6. gasLimit: [] (ou limites específicos)
  7. Clique em transact e confirme no MetaMask.

Após a execução, consulte a função messages do SimpleContract.sol para verificar os valores definidos.

Combinando subtransações

Você pode mesclar transferências nativas e chamadas de contrato na mesma transação em lote. Forneça arrays alinhados (mesmo tamanho ou valores padrão) para to, value, callData e gasLimit. O precompile cuida do roteamento e garante a execução conforme a função escolhida (batchSome, batchSomeUntilFailure ou batchAll).

Bibliotecas de desenvolvimento Ethereum

As funções do precompile também podem ser usadas por bibliotecas:

// Import the contract ABI
const { abi } = require('./INSERT_ABI_PATH');

// Use ABI to create an interface
const yourContractInterface = new ethers.Interface(abi);

// Find call data for the setMessage function
const callData = yourContractInterface.encodeFunctionData(
  'INSERT_FUNCTION_NAME',
  [
    'INSERT_INPUT_1',
    'INSERT_INPUT_2',
    // ...
  ]
);
// Import the contract ABI
const { abi } = require('./INSERT_ABI_PATH');

// Find call data for the setMessage function
const callData = web3.eth.abi.encodeFunctionCall(abi, [
  'INSERT_INPUT_1',
  'INSERT_INPUT_2',
  // ...
]);
# Import the ABI and bytecode
from compile import abi, bytecode

# Create contract instance
your_contract = web3.eth.contract(abi=abi, bytecode=bytecode)

# Encode the contract call
call_data = your_contract.encodeABI(
    fn_name="INSERT_FUNCTION_NAME", args=["INSERT_INPUT_1", "INSERT_INPUT_2", ...]
)

Nota

Adapte os exemplos para produção e garanta validação de entradas, controle de gás e tratamento de erros adequados.

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