Using Remix

Using Remix

An online IDE that makes it easy to tinker with and deploy smart contracts.

Remix (https://remix.ethereum.org/) is a useful tool whenever you need to test out Solidity contracts locally, curiously inspect gas costs, or even deploy actual contracts to live chain deployments.

Synopsis

There are a few scenarios that will come about when developing with Tableland:

  1. While using a local testnet, it can be helpful to deploy the TablelandTables (and associated) contracts to understand how the registry smart contract will behave.
  2. If you are leveraging a live testnet or mainnet registry deployment, you’ll beed to instantiate an interface ITablelandTabales to then call the registry itself.
  3. For advanced access control, you might implement the ITablelandController interface and even deploy it, allowing you to setController by calling this method on the registry smart contract (or the corresponding SDK / CLI client calls).

Understanding Remix

Let’s review the primary capabilities:

  1. File explorer — Create workspaces and files.
  2. File search — Search for files.
  3. Compiler — Compiles the desired smart contracts (if possible, try for at least 0.8.12 since this introduced string concatenation bug fixes, which is used in writing SQL).
  4. Deployer — Deploy and interact / transact with contracts.
image

There are also a number of useful plugins that you could choose to install, including:

Creating & Deploying on Remix

When doing quick development in Remix, the most typical pattern is to:

  1. Create a workspace.
  2. Create a contract (or many of them).
  3. Compile.
  4. Deploy.

The first two steps are straightforward; simply, click the Create Workspace button, and after creating one, click the New File button and create a smart contract (.sol extension). From there, you’ll want to import and copy / paste the required Tableland smart contracts, write your custom smart contract, and compile them separately (with a version that matches the pragma in the file). Lastly, the contract deployment defaults to a local testnet (Remix VM), but you can select Injected Provider to use a wallet provider and deploy contracts to testnets or mainnets. The Injected Provider leverages your actual wallet’s accounts.

image

Using TablelandTables

There does exist a detailed overview of how to create tables from contracts, so that level of detail will not be covered here. For local development environment setup, please ensure the following contracts are created in the same directory:

  1. TablelandTables.sol
  2. ITablelandTables.sol
  3. ITablelandController.sol

Thus, your environment should resemble the following — but creating the contracts noted above is only needed if you plan to do local environment testing where you call the registry contract.

image

Separately, your custom smart contract may look like the following, where it instantiates and subsequently calls the registry using an interface ITablelandTables. Namely, the state variable _tableland is assigned the value ITablelandTables(registry), where registry is the deployed TablelandTables contract address.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; // Required for contracts to receive ERC721 tokens
import "@openzeppelin/contracts/utils/Strings.sol"; // Useful for working with strings (not shown below)
import "@tableland/evm/contracts/ITablelandTables.sol";

contract CallingTablelandTables is ERC721Holder {
    ITablelandTables private _tableland;

    constructor(address registry) {
        _tableland = ITablelandTables(registry);
    }

		function create() public payable {
        _tableland.createTable(/* do create logic */);
		}

		function writeToTable() public payable {
        _tableland.runSQL(/* do write logic */);
		}
}

When deploying, first compile & push the TablelandTables contract, and note its address. Then, compile & deploy the custom CallingTablelandTables, passing that address to it.

The process of compiling, deploying, and calling is very useful when writing quick & dirty contracts for testing some Tableland contract interaction.
The process of compiling, deploying, and calling is very useful when writing quick & dirty contracts for testing some Tableland contract interaction.

Using a TablelandController

A much simpler Remix use case is to deploy a TablelandController contract. This could follow the same design above — just create a new contract that imports and implements the ITablelandController. For detailed information on the controller, please read the documentation on configuring table write access.

Let’s also take the use case where you want to quickly deploy a controller without the additional setup work. This is all that’s required:

  1. Create a contract.
  2. Import ITablelandController.sol; optionally, the Policies library.
  3. Implement ITablelandController and its Policy functionality.
  4. Compile & deploy.

For example, the following shows an “allow all inserts” controller, which means that any address can insert into the table, but the update and delete policies are set to false to prevent table alterations. The main requirement is to implement the getPolicy method and return the desired Policy object.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "@tableland/evm/contracts/ITablelandController.sol";
import "@tableland/evm/contracts/policies/Policies.sol"; // Optional

contract AllowAllInsertController is ITablelandController {
    function getPolicy(address)
        public
        payable
        override
        returns (ITablelandController.Policy memory)
    {
        return
            ITablelandController.Policy({
                allowInsert: true,
                allowUpdate: false,
                allowDelete: false,
                whereClause: Policies.joinClauses(new string[](0)), // Can use an empty string, instead: `""`
                withCheck: "", // Example using an empty string vs. the `Policies` library
                updatableColumns: new string[](0) // Must be a string array; this one is empty
            });
    }
}

From there, you can deploy this contract to a live testnet — the example below pushes this contract to Polygon Mumbai and logs some useful information:

An example of sending an on-chain testnet transaction and deploying the controller contract.
An example of sending an on-chain testnet transaction and deploying the controller contract.

Setting the Controller

You can then use tools like Etherscan to manually call the smart contract’s setController method from a UI. Alternatively, this same method is made available in direct smart contract calls, SDK, and CLI.

image

Here, we set the controller to 0x966b2E6615962cdeeD891323e66504B6C3214cB1 (transaction hash here, for reference) for the table tbl_calls_80001_1887 (i.e., tableId is 1887), owned by the address 0x9bA89c8aD3856C0137E268bD76ed12d14696E140.

You can test it out yourself — try and successfully insert some row into tbl_calls_80001_1887 (schema here), but updates or deletes will fail! You could try the following, but replace <your_address> with your address or some message string, and then view the results via a read query.

INSERT INTO tbl_calls_80001_1887 (message) VALUES ('<your_address>')

Bonus — Verifying Remix Contracts

There does exist an Etherscan Remix verification tool, which requires an API key from the Etherscan website. As an alternative, the flattener plugin can be used to create a single flat Solidity file; this can be used to verify a contract manually.

  1. Navigate to Verify & Publish on the block explorer where <contract_address> should be replaced with the deployed contract’s address and fill out the required information.
    1.  https://mumbai.polygonscan.com/verifyContract?a=<contract_address>
    2. Please select Compiler TypeSolidity (Single Part).
    3. Please select Compiler Version ⇒ Whatever was used for compilation, e.g., v0.8.12+commitf00d7308.
    4. Please select Open Source License Type ⇒ Often, it’ll be MIT License (MIT).
    5. Click Continue
  2. Back in Remix, navigate to the installed Flattener plugin, click Flatten (while your screen is opened / highlighting the desired contract), click Save, and then copy the flattened file to your clipboard.
  3. An example of how to manually flatten a file for contract verification purposes.
    An example of how to manually flatten a file for contract verification purposes.
  4. Back in the block explorer, paste the flattened file in the text area (Enter the Solidity Contract Code below), and then click Verify & Publish.
  5. image
  6. Contract is verified and easily readable! See it here.
  7. A verified contract after going through the block explorer verification process.
    A verified contract after going through the block explorer verification process.