ethier (pronounced "easier" with a lisp) intends to:
- Gradually replace the reliance on JavaScript in Ethereum development with Go as it is (a) faster due to in-process backends for testing, and (b) more robust due to type safety. Although unlikely, ethier's "North Star" is a replacement for Truffle/Hardhat.
- Provide reusable Solidity functionality not covered by OpenZeppelin and, where appropriate, provide respective Go bindings with round-trip testing.
ethier uses Semantic Versioning 2.0.0. As the major version is currently zero, the API is open to change without warning.
Contracts are very thoroughly tested but have not been subject to audit nor widespread use. Early adopters are not only welcome, but will be greatly appreciated.
Although ethier intends to use Go as much as possible, users may not, and NPM is the de facto standard in Ethereum development. While this gives us a weird mashup of go.mod and package.json, it's fit for purpose.
- Assuming
solc
andgo
are already installed:
go install github.com/divergencetech/ethier/ethier@latest
go install github.com/ethereum/go-ethereum/cmd/abigen@latest
- Ensure that the
go/bin
directory is in your$PATH
. This can be confirmed by runningwhich ethier && echo GOOD
; if the wordGOOD
is printed then theethier
binary has been found.
This example assumes that the file is in the contracts
directory with all
Solidity files present. If moving to a different directory, simply change the
relative paths.
package contracts
//go:generate ethier gen MyContract.sol
Run go generate ./...
to generate Go bindings, including deployment functions.
The above example will generate contracts/generated.go
with bindings to
MyContract.sol
. These bindings can be used for (1) testing and/or (2) connecting to a
gateway node (e.g. Infura or Alchemy), depending on the
ContractBackend
being used:
-
For tests, use ethier's
ethtest.SimulatedBackend
, which extends the standard geth simulator with convenience behaviour like auto commitment of transactions. -
For a gateway, use the
ethclient
package.
package contracts
import (
"testing"
"github.com/divergencetech/ethier/ethtest"
)
// The test backend creates as many accounts as needed, each representing a different
// "actor" in the test scenarios. A useful pattern is to simply enumerate them the iota
// pattern (which automatically increments) and add a `numAccounts` at the end.
const (
deployer = iota
vandal
numAccounts
)
func TestMyContract(t *testing.T){
sim := ethtest.NewSimulatedBackend(t, numAccounts)
// The DeployMyContract function is automatically generated when running `go generate`.
// addr and tx generally aren't useful, but are documented here for completeness
addr, tx, contract, err := DeployMyContract(sim.Acc(deployer), sim /*,,, [constructor arguments]*/)
if err != nil {
t.Fatalf("DeployMyContract(%v) error %v", …, err)
}
// NOTE: If connecting to a deployed contract above, use NewMyContract() and substitute `sim`
// for an *ethclient.Client`.
t.Run("protect something sensitive", func(t *testing.T){
// The test-actor pattern in the consts above makes tests self-documenting.
_, err := contract.DoSomethingImportant(sim.Acc(vandal))
// Confirm that there's an error because the vandal shouldn't be allowed to do anything
// important!!! See the ethtest/revert package.
})
}
See tests/
for further usage examples. Remember to add generated.go
to your
.gitignore
file.