Skip to content

Commit aae06b8

Browse files
committed
add hello world example
1 parent a857165 commit aae06b8

28 files changed

+1456
-18
lines changed

.github/workflows/sync.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Sync
2+
on:
3+
push:
4+
branches:
5+
- main
6+
7+
jobs:
8+
sync-branches:
9+
runs-on: ubuntu-latest
10+
name: Syncing branches
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v2
14+
- name: Set up Node
15+
uses: actions/setup-node@v1
16+
with:
17+
node-version: 12
18+
- name: Opening pull request
19+
id: pull
20+
uses: tretuna/[email protected]
21+
with:
22+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
23+
FROM_BRANCH: "main"
24+
TO_BRANCH: "develop"

README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,111 @@ To get a comprehensive introduction to Precompile-EVM, take the Avalanche Academ
3535

3636
There is an example branch [hello-world-example](https://github.com/ava-labs/precompile-evm/tree/hello-world-example) in this repository. You can check the example branch to see how to register precompiles and test them.
3737

38+
### Clone the Repo
39+
40+
```zsh
41+
git clone https://github.com/ava-labs/precompile-evm.git
42+
cd precompile-evm/ # change directory to the precompile-evm/ directory
43+
```
44+
45+
### Checkout the `hello-world-example` Branch
46+
47+
```zsh
48+
git checkout hello-world-example
49+
50+
branch 'hello-world-example' set up to track 'origin/hello-world-example'.
51+
Switched to a new branch 'hello-world-example'
52+
```
53+
54+
### Install NodeJS Dependencies
55+
56+
First you have to `cd contracts/` and run `npm install` to get the dependencies.
57+
58+
```zsh
59+
cd contracts/ # change directory to the contracts/ directory
60+
npm install
61+
```
62+
63+
### Create a New Contract
64+
65+
`hello-world-example` branch has already a precompile contract called `HelloWorld.sol`. All necessary files were already created for you. You can check existing files and see how a fully implemented precompile should look like. If you'd like to redo steps to create a new precompile contract, you can follow the steps below.
66+
67+
Copy the existing `IHelloWorld.sol` interface to a new file called `IHolaMundo.sol`.
68+
69+
```zsh
70+
cd .. # change directory back to the root of the repo
71+
cp contracts/contracts/interfaces/IHelloWorld.sol contracts/contracts/interfaces/IHolaMundo.sol
72+
```
73+
74+
### Install `solc` and Confirm Dependency Version
75+
76+
Install the `solc` dependency.
77+
78+
```zsh
79+
brew install solidity
80+
```
81+
82+
Confirm `solc` is >=0.8.8.
83+
84+
```zsh
85+
solc --version
86+
87+
solc, the solidity compiler commandline interface
88+
Version: 0.8.17+commit.8df45f5f.Darwin.appleclang
89+
```
90+
91+
### Generate an `.abi`
92+
93+
Now generate a `.abi` from a `.sol` using `solc`.
94+
95+
Passing in the following flags
96+
97+
- `--abi`
98+
- ABI specification of the contracts.
99+
- `--base-path path`
100+
- Use the given path as the root of the source tree instead of the root of the filesystem.
101+
- `--include-path path`
102+
- Make an additional source directory available to the default import callback. Use this option if you want to import contracts whose location is not fixed in relation to your main source tree, e.g. third-party libraries installed using a package manager. Can be used multiple times. Can only be used if base path has a non-empty value.
103+
- `--output-dir path`
104+
- If given, creates one file per output component and contract/file at the specified directory.
105+
- `--overwrite`
106+
- Overwrite existing files (used together with `--output-dir`).
107+
108+
```zsh
109+
cd contracts/ # change directory to the contracts/ directory
110+
solc --abi contracts/interfaces/IHolaMundo.sol --output-dir abis --base-path . --include-path ./node_modules --overwrite
111+
112+
Compiler run successful. Artifact(s) can be found in directory "abis".
113+
```
114+
38115
### Generate Precompile Files
39116

40117
First, you need to create your precompile contract interface in the `contracts` directory and build the ABI. Then you can generate your precompile files with `./scripts/generate_precompile.sh --abi {abiPath} --out {outPath}`. This script installs the `precompilegen` tool from Subnet-EVM and runs it to generate your precompile.
41118

119+
```zsh
120+
cd .. # change directory back to the root directory of the repo
121+
./scripts/generate_precompile.sh --abi contracts/abis/IHolaMundo.abi --out holamundo/
122+
123+
Using branch: hello-world-example
124+
installing precompilegen from Subnet-EVM v0.5.2
125+
generating precompile with Subnet-EVM v0.5.2
126+
Precompile files generated successfully at: holamundo/
127+
```
128+
129+
Confirm that the new `holamundo/` directory has the appropriate files.
130+
131+
```zsh
132+
ls -lh helloworld
133+
134+
-rw-r--r-- 1 user group 2.3K Jul 5 13:26 README.md
135+
-rw-r--r-- 1 user group 2.3K Jul 5 13:26 config.go
136+
-rw-r--r-- 1 user group 2.8K Jul 5 13:26 config_test.go
137+
-rw-r--r-- 1 user group 963B Jul 5 13:26 contract.abi
138+
-rw-r--r-- 1 user group 8.1K Jul 5 13:26 contract.go
139+
-rw-r--r-- 1 user group 8.3K Jul 5 13:26 contract_test.go
140+
-rw-r--r-- 1 user group 2.7K Jul 5 13:26 module.go
141+
```
142+
42143
### Register Precompile
43144

44145
In `plugin/main.go` Subnet-EVM is already imported and ready to be Run from the main package. All you need to do is explicitly register your precompiles to Subnet-EVM in `plugin/main.go` and build it together with Subnet-EVM. Precompiles generated by `precompilegen` tool have a self-registering mechanism in their `module.go/init()` function. All you need to do is to force-import your precompile packprecompile package in `plugin/main.go`.

contracts/README.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,6 @@ Subnet-EVM must activate any precompiles used in the test in the genesis:
111111
{
112112
"config": {
113113
"chainId": 43214,
114-
"homesteadBlock": 0,
115-
"eip150Block": 0,
116-
"eip155Block": 0,
117-
"eip158Block": 0,
118-
"byzantiumBlock": 0,
119-
"constantinopleBlock": 0,
120-
"petersburgBlock": 0,
121-
"istanbulBlock": 0,
122-
"muirGlacierBlock": 0,
123114
"feeConfig": {
124115
"gasLimit": 8000000,
125116
"minBaseFee": 25000000000,

contracts/contracts/.gitkeep

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "./interfaces/IHelloWorld.sol";
5+
6+
address constant HELLO_WORLD_ADDRESS = 0x0300000000000000000000000000000000000000;
7+
8+
// ExampleHelloWorld shows how the HelloWorld precompile can be used in a smart contract.
9+
contract ExampleHelloWorld {
10+
IHelloWorld helloWorld = IHelloWorld(HELLO_WORLD_ADDRESS);
11+
12+
function sayHello() public view returns (string memory) {
13+
return helloWorld.sayHello();
14+
}
15+
16+
function setGreeting(string calldata greeting) public {
17+
helloWorld.setGreeting(greeting);
18+
}
19+
}

contracts/contracts/interfaces/.gitkeep

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity >=0.8.0;
4+
import "@avalabs/subnet-evm-contracts/contracts/interfaces/IAllowList.sol";
5+
6+
interface IHelloWorld is IAllowList {
7+
event GreetingChanged(address indexed sender, string oldGreeting, string newGreeting);
8+
// sayHello returns the stored greeting string
9+
function sayHello() external view returns (string calldata result);
10+
11+
// setGreeting stores the greeting string
12+
function setGreeting(string calldata response) external;
13+
}

contracts/contracts/test/.gitkeep

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "../ExampleHelloWorld.sol";
5+
import "../interfaces/IHelloWorld.sol";
6+
import "@avalabs/subnet-evm-contracts/contracts/test/AllowListTest.sol";
7+
8+
contract ExampleHelloWorldTest is AllowListTest {
9+
IHelloWorld helloWorld = IHelloWorld(HELLO_WORLD_ADDRESS);
10+
11+
function step_getDefaultHelloWorld() public {
12+
ExampleHelloWorld example = new ExampleHelloWorld();
13+
address exampleAddress = address(example);
14+
15+
assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);
16+
assertEq(example.sayHello(), "Hello World!");
17+
}
18+
19+
function step_doesNotSetGreetingBeforeEnabled() public {
20+
ExampleHelloWorld example = new ExampleHelloWorld();
21+
address exampleAddress = address(example);
22+
23+
assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);
24+
25+
try example.setGreeting("testing") {
26+
assertTrue(false, "setGreeting should fail");
27+
} catch {} // TODO should match on an error to make sure that this is failing in the way that's expected
28+
}
29+
30+
function step_setAndGetGreeting() public {
31+
ExampleHelloWorld example = new ExampleHelloWorld();
32+
address exampleAddress = address(example);
33+
34+
assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.None);
35+
helloWorld.setEnabled(exampleAddress);
36+
assertRole(helloWorld.readAllowList(exampleAddress), AllowList.Role.Enabled);
37+
38+
string memory greeting = "testgreeting";
39+
example.setGreeting(greeting);
40+
assertEq(example.sayHello(), greeting);
41+
}
42+
}

contracts/scripts/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)