Ethereum Scripts

This is some quick documentation I threw together to explain how scripts work. Scroll down for the documentation and ping me if you have any questions.

Setup

Take the secret you received and construct the plugin URL in the form https://ethereum-scripts.svc.samczsun.com/:secret. Add this URL as a plugin in Remix by following the steps below:

  1. Click the bottom-most button (it looks like a plug)
  2. Click "Connect to a Local Plugin"
  3. Set Plugin Name to "scripts", Display Name to "Scripts", and URL to the URL you received. The type of connection should be Iframe and the location should be side panel

The Basics

Every script is a contract that extends from script. Scripts must override the setup() and run() functions.

The setup() function

This is where you configure global settings, such as the script name or the block that the script should run on (however, this feature is currently broken).

The run() function

This is where you define the execution of your script. A script is a sequence of steps executed sequentially and this is where you define those steps.

Hello World

Here's a Hello World script:

pragma solidity ^0.5.0;

import "./script.sol";

contract HelloWorld is script {
	function setup() public {}
    
	function run() public {
		run(this.helloWorld);
	}
    
	function helloWorld() external {
		fmt.print("hello world\n");
	}
}

Copy it into a new contract, switch to the Scripts plugin, and hit run. You should see something like this:

[#] running script "HelloWorld" on block 10536938

[#] running "helloWorld()" as 0x522cf4C80219711eddB229be3f9f119DCF442d8f with 0.000000000000000000 ether
[0x522cf4C80219711eddB229be3f9f119DCF442d8f] hello world
[#] finished running "helloWorld()"

If it's not immediately clear what's happening, read the documentation for more information.

The Documentation

Here are some things that are good to know

  • Each step must be marked external
  • Script-level variables are allowed, but cannot be initialized in-line (that is to say, declaring uint private cost; is allowed, but initializing it with uint private cost = 50; won't work)
  • A step that reverts will terminate the script
  • Varargs are not supported in Solidity, so you need to wrap them using abi.encode()

Steps

A step is a block of code executed by an address. The code within the step executes as the address. That is to say, address(this) will be equal to the address that the step is executing as, and if the step calls an external contract then msg.sender and tx.origin will be set accordingly. You can use steps to simulate a set of actions that an EOA might perform (albeit non-atomically).

By default, all steps will be executed by the same caller. This caller is randomly generated. If you want a step to be executed by a specific caller (for example, the owner of a contract), you may do so using .withCaller():

run(this.pauseToken)
	.withCaller(0xtokenowner);

By default, the caller's balance will be unchanged. That is to say, if you specify a caller who owns Ether, then your step will have access to that Ether. However, if you would like more Ether (to simulate a flash loan, perhaps), you can do so using .withBalance():

run(this.buyDai)
	.withBalance(10000 ether);

Advancing Time

By default, all steps execute on the same block. However, sometimes you may need to wait for a timelock to expire, or wait for some interest to accrue. You can advance time in seconds or in blocks by using the advanceTime(t) or advanceBlocks(b) functions:

function run() public {
	run(this.mintCEther)
    	.withBalance(1000 ether);

	advanceBlocks(30);

	run(this.checkInterest);
}

The fmt library

Inspired by Golang, the fmt library provides string formatting tools as well as an interface to "standard out".

These four methods print things to "standard out":

  • fmt.printf(message, abi.encode(args))
  • fmt.print(message)
  • fmt.println(message)
  • fmt.println()

This method provides string formatting for use with, for example, revert:

  • fmt.sprintf(message, abi.encode(args))

Formatting Codes

The following formatting codes are available to you:

Code Meaning
%% Prints a percent sign
%d Prints a signed integer
%.[n]d Prints a signed integer with n decimal places
%u Prints an unsigned integer
%.[n]u Prints an unsigned integer with n decimal places
%b Prints a boolean value
%a Prints a checksummed address
%s Prints a string
%x Prints a hex-encoded bytes
%[n]x Prints a hex-encoded bytes[n]