# Moonbeam Developer Documentation (LLMS Format) This file contains documentation for Moonbeam (https://moonbeam.network/). Moonbeam is a smart contract platform that makes it easy to build natively interoperable applications on Polkadot and Ethereum. It is intended for use with large language models (LLMs) to support developers working with Moonbeam. The content includes selected pages from the official docs, organized by section. This file includes documentation related to the product: Tutorials ## AI Prompt Template You are an AI developer assistant for Moonbeam (https://moonbeam.network/). Your task is to assist developers in understanding and using the product described in this file. - Provide accurate answers based on the included documentation. - Do not assume undocumented features, behaviors, or APIs. - If unsure, respond with “Not specified in the documentation. ## List of doc pages: Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/batch-approve-swap.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/call-permit-gasless-txs.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/chat-gpt.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/foundry-start-to-end.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/hardhat-start-to-end.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/how-to-build-a-dapp.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/randomness-lottery.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/thirdweb.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/eth-api/using-tenderly.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/integrations/0xgasless.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/integrations/local-subsquid.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/integrations/nft-subsquid.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/integrations/supra.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/interoperability/cross-chain-dao.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/interoperability/remote-batched-evm-calls.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/interoperability/remote-staking-xcm.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/interoperability/uniswapv2-swap-xcm.md [type: tutorials] Doc-Page: https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/master/tutorials/interoperability/using-axelar-sdk.md [type: tutorials] ## Full content for each doc page Doc-Content: https://docs.moonbeam.network/tutorials/eth-api/batch-approve-swap/ --- BEGIN CONTENT --- --- title: Approve & Swap with the Batch Precompile description: Learn how to use the Batch Precompile on Moonbeam to batch an approval and swap into a single call, so you can approve the exact amount of tokens for the swap. categories: Tutorials, Precompiles --- # Use the Batch Precompile to Approve and Swap Tokens in a Single Transaction _by Erin Shaben_ ## Introduction {: #introduction } Token approvals are critical for interacting with smart contracts securely, preventing smart contracts without permission from accessing a user's tokens. When a smart contract is given approval to access a user's tokens, the amount of tokens it has access to is often an unlimited amount, depending on the DApp. One of the reasons why many DApps use an unlimited amount is so that users don't need to continue to sign approval transactions every time they want to move their tokens. This is in addition to the second transaction required to actually swap the tokens. For networks like Ethereum, this can be expensive. However, if the approved smart contract has a vulnerability, it could be exploited and the users' tokens could be transferred at any time without requiring further approval. In addition, if a user no longer wants the DApp's contract to have access to their tokens, they have to revoke the token approval, which requires another transaction to be sent. As a DApp developer on Moonbeam, you can avoid this process entirely, providing users with more control over their assets. This can be done using the [batch precompile](/builders/ethereum/precompiles/ux/batch/){target=\_blank} to batch an approval and swap into a single transaction, instead of the typical two transaction process. This allows for the approval amount to be the exact swap amount instead of having unlimited access to your users' tokens. In this tutorial, we'll dive into the process of batching an approval and swap into one transaction using the `batchAll` function of the batch precompile contract. We'll create and deploy an ERC-20 contract and a simple DEX contract for the swap on the [Moonbase Alpha TestNet](/builders/get-started/networks/moonbase/){target=\_blank} using [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank} and [Ethers](/builders/ethereum/libraries/ethersjs/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For this tutorial, you'll need the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - An empty Hardhat project that is configured for the Moonbase Alpha TestNet. For step-by-step instructions, please refer to the [Creating a Hardhat Project](/builders/ethereum/dev-env/hardhat/#creating-a-hardhat-project){target=\_blank} and the [Hardhat Configuration File](/builders/ethereum/dev-env/hardhat/#hardhat-configuration-file){target=\_blank} sections of our Hardhat documentation page - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} ### Install Dependencies {: #install-dependencies } Once you have your [Hardhat project](/builders/ethereum/dev-env/hardhat/){target=\_blank}, you can install the [Ethers plugin](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-ethers){target=\_blank}. This provides a convenient way to use the [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} library to interact with the network. You can also install the [OpenZeppelin contracts library](https://docs.openzeppelin.com/contracts){target=\_blank}, as we'll be importing the `ERC20.sol` contract and `IERC20.sol` interface in our contracts. To install the necessary dependencies, run the following command: ```bash npm install @nomicfoundation/hardhat-ethers ethers@6 @openzeppelin/contracts ``` ## Contract Setup {: #contracts } The following are the contracts that we'll be working with today: - `Batch.sol` - one of the precompile contracts on Moonbeam that allows you to combine multiple EVM calls into one. For more information on the available methods, please refer to the [Batch Solidity Interface](/builders/ethereum/precompiles/ux/batch/#the-batch-interface){target=\_blank} documentation - `DemoToken.sol` - an ERC-20 contract for the `DemoToken` (DTOK) token, which on deployment mints an initial supply and assigns them to the contract owner. It's a standard ERC-20 token, you can review the [IERC20 interface](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20){target=\_blank} for more information on the available methods - `SimpleDex.sol` - a simple example of a DEX that on deployment deploys the `DemoToken` contract, which mints 1000 DTOKs, and allows you to swap DEV token for DTOKs and vice versa. **This contract is for demo purposes only**. The `SimpleDex` contract contains the following methods: - **token**() - a read-only method that returns the address of the `DemoToken` contract - **swapDevForDemoToken**() - a payable function that accepts DEV tokens in exchange for DTOK tokens. The function checks to make sure there are enough DTOK tokens held in the contract before making the transfer. After the transfer is made, a `Bought` event is emitted - **swapDemoTokenForDev**(*uint256* amount) - accepts the amount of DTOKs to swap for DEV tokens. The function checks to make sure the caller of the function has approved the contract to transfer their DTOKs before swapping the DTOKs back to DEV. After the transfer is made, a `Sold` event is emitted If you don't already have a `contracts` directory in your Hardhat project, you can create a new directory: ```bash mkdir contracts && cd contracts ``` Then, you can create a single file that we'll use to store the code for the `DemoToken` and `SimpleDex` contracts and another file for the batch precompile: ```bash touch SimpleDex.sol Batch.sol ``` In the `SimpleDex.sol` file, you can paste in the following code for the `DemoToken` and `SimpleDex` contracts: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract DemoToken is ERC20 { constructor(uint256 initialSupply) ERC20("DemoToken", "DTOK") { // Assign 500 DTOK tokens to the SimpleDex contract _mint(msg.sender, initialSupply / 2); // Assign 500 DTOK tokens to the EOA that deployed the SimpleDex contract _mint(tx.origin, initialSupply / 2); } } contract SimpleDex { IERC20 public token; event Bought(uint256 amount); event Sold(uint256 amount); // Make constructor payable so that DEV liquidity exists for the contract constructor() payable { // Mint 1000 DTOK tokens. Half will be assigned to the SimpleDex contract // and the other half will be assigned to the EOA that deployed the // SimpleDex contract token = new DemoToken(1000000000000000000000); } // Function to swap DEV for DTOK tokens function swapDevForDemoToken() payable public { // Verify the contract has enough tokens for the requested amount uint256 amountTobuy = msg.value; uint256 dexBalance = token.balanceOf(address(this)); require(amountTobuy > 0, "You need to send some DEV"); require(amountTobuy <= dexBalance, "Not enough tokens in the reserve"); // If enough, swap the DEV to DTOKs token.transfer(msg.sender, amountTobuy); emit Bought(amountTobuy); } // Function to swap DTOK for DEV tokens function swapDemoTokenForDev(uint256 amount) public { // Make sure the requested amount is greater than 0 and the caller // has approved the requested amount of tokens to be transferred require(amount > 0, "You need to sell at least some tokens"); uint256 allowance = token.allowance(msg.sender, address(this)); require(allowance >= amount, "Check the token allowance"); // Transfer the DTOKs to the contract token.transferFrom(msg.sender, address(this), amount); // Transfer the DEV tokens back to the caller payable(msg.sender).transfer(amount); emit Sold(amount); } } ``` In the `Batch.sol` file, you can paste in the Batch Precompile contract. ??? code "Batch.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Batch contract's address. address constant BATCH_ADDRESS = 0x0000000000000000000000000000000000000808; /// @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 through one call to the precompile. /// Can be used by EOA to do multiple calls in a single transaction. /// @custom:address 0x0000000000000000000000000000000000000808 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); } ``` ### Compile & Deploy Contracts {: #compile-deploy-contracts } To compile the contracts, we'll go ahead and run the following Hardhat command: ```bash npx hardhat compile ```
npx hardhat compile Compiled 6 Solidity files successfully (evm target: paris).
After compilation, an `artifacts` directory is created: it holds the bytecode and metadata of the contract, which are `.json` files. It’s a good idea to add this directory to the `.gitignore` file. Next, we can deploy the `SimpleDex` contract, which upon deployment will automatically deploy the `DemoToken` contract and mint 1000 DTOKs and assign half of them to the `SimpleDex` contract and the other half to the address that you're initiating the deployment from. We'll also add some initial liquidity to the contract by passing in a `value` when calling `deploy`. Since the value needs to be in Wei, we can use `ethers.parseEther` to pass in a value such as `"0.5"` DEV and it will convert the value to Wei for us. Before deploying the contract, we'll need to create the deployment script. We'll create a new directory for the script and name it `scripts` and add a new file to it called `deploy.js`: ```bash mkdir scripts && touch scripts/deploy.js ``` In the `deploy.js` script, you can paste in the following code, which will deploy the `SimpleDex` contract and print the address of the contract to the terminal upon successful deployment: ```js async function main() { // Liquidity to add in DEV (i.e., '.5') to be converted to Wei const value = ethers.parseEther('INSERT_AMOUNT_OF_DEV'); // Deploy the SimpleDex contract, which will also automatically deploy // the DemoToken contract and add liquidity to the contract const SimpleDex = await ethers.getContractFactory('SimpleDex',); const simpleDex = await SimpleDex.deploy({ value }) // Wait for the deployment transaction to be included in a block await simpleDex.waitForDeployment(); // Get and print the contract address const myContractDeployedAddress = await simpleDex.getAddress(); console.log(`SimpleDex deployed to ${myContractDeployedAddress}`); } main().catch((error) => { console.error(error); process.exitCode = 1; }); ``` Now we can deploy the `SimpleDex` contract using the `run` command and specifying `moonbase` as the network: ```bash npx hardhat run --network moonbase scripts/deploy.js ``` !!! note If you want to run the script in a standalone fashion using `node