Skip to content

Commit c126722

Browse files
committed
First commit
1 parent 34c4358 commit c126722

File tree

15 files changed

+589
-140
lines changed

15 files changed

+589
-140
lines changed

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize]
6+
push:
7+
branches:
8+
- main
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
fmt:
16+
strategy:
17+
fail-fast: true
18+
19+
name: Format
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v3
23+
with:
24+
submodules: recursive
25+
26+
- name: Setup Foundry
27+
uses: foundry-rs/foundry-toolchain@v1
28+
with:
29+
version: stable
30+
31+
- name: Format
32+
run: |
33+
forge fmt --check
34+
id: fmt
35+
36+
test:
37+
strategy:
38+
fail-fast: true
39+
40+
name: Test
41+
runs-on: ubuntu-latest
42+
steps:
43+
- uses: actions/checkout@v3
44+
with:
45+
submodules: recursive
46+
47+
- name: Setup Foundry
48+
uses: foundry-rs/foundry-toolchain@v1
49+
with:
50+
version: stable
51+
52+
- name: Test
53+
run: |
54+
forge test --ffi -vvv
55+
id: test

.github/workflows/test.yml

Lines changed: 0 additions & 43 deletions
This file was deleted.

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/openzeppelin-contracts"]
5+
path = lib/openzeppelin-contracts
6+
url = https://github.com/openzeppelin/openzeppelin-contracts
7+
[submodule "lib/solidity-stringutils"]
8+
path = lib/solidity-stringutils
9+
url = https://github.com/Arachnid/solidity-stringutils

README.md

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,80 @@
1-
## Foundry
1+
## solidity-http
22

3-
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**
3+
Solidity HTTP client library for Foundry scripting
44

5-
Foundry consists of:
5+
### Installation
66

7-
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
8-
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
9-
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
10-
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
7+
```bash
8+
forge install Recon-Fuzz/solidity-http
9+
```
1110

12-
## Documentation
11+
### Usage
1312

14-
https://book.getfoundry.sh/
13+
### 1. Import the library
1514

16-
## Usage
15+
```solidity
16+
import {HTTP} from "solidity-http/HTTP.sol";
17+
import {HTTPBuilder} from "solidity-http/HTTPBuilder.sol";
18+
```
1719

18-
### Build
20+
### 2. Build and send your request
1921

20-
```shell
21-
$ forge build
22-
```
22+
Use builder functions to compose your request with headers, body, and query parameters.
2323

24-
### Test
24+
```solidity
25+
contract MyScript is Script {
26+
using HTTPBuilder for HTTP.Request;
2527
26-
```shell
27-
$ forge test
28-
```
28+
HTTP.Request request;
29+
30+
function run() external {
31+
request
32+
.withUrl("https://httpbin.org/post")
33+
.withMethod(HTTP.Method.POST)
34+
.withHeader("Content-Type", "application/json")
35+
.withBody('{"foo": "bar"}');
2936
30-
### Format
37+
HTTP.Response memory response = HTTP.request(request);
3138
32-
```shell
33-
$ forge fmt
39+
console.log("Status:", response.status);
40+
console.log("Data:", response.data);
41+
}
42+
}
3443
```
3544

36-
### Gas Snapshots
45+
### 3. Enable FFI
3746

38-
```shell
39-
$ forge snapshot
40-
```
47+
This library relies on Foundry's [FFI cheatcode](https://book.getfoundry.sh/cheatcodes/ffi.html) to call external processes. Enable it by:
4148

42-
### Anvil
49+
- Passing the `--ffi` flag to your command:
4350

44-
```shell
45-
$ anvil
51+
```bash
52+
forge test --ffi
4653
```
4754

48-
### Deploy
55+
- Or setting `ffi = true` in your `foundry.toml`:
4956

50-
```shell
51-
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
57+
```toml
58+
[profile.default]
59+
ffi = true
5260
```
5361

54-
### Cast
62+
---
5563

56-
```shell
57-
$ cast <subcommand>
58-
```
64+
## Requirements
5965

60-
### Help
66+
- Foundry with FFI enabled:
67+
- Either pass `--ffi` to commands (e.g. `forge test --ffi`)
68+
- Or set `ffi = true` in `foundry.toml`
6169

62-
```shell
63-
$ forge --help
64-
$ anvil --help
65-
$ cast --help
70+
```toml
71+
[profile.default]
72+
ffi = true
6673
```
74+
75+
- A UNIX-based machine with the following installed:
76+
- `bash`, `curl`, `tail`, `sed`, `tr`, `cast`
77+
78+
### Acknowledgements
79+
80+
This library was inspired by [surl](https://github.com/memester-xyz/surl) and [axios](https://github.com/axios/axios)

lib/openzeppelin-contracts

Submodule openzeppelin-contracts added at acd4ff7

lib/solidity-stringutils

Submodule solidity-stringutils added at 4b2fcc4

remappings.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@openzeppelin=lib/openzeppelin-contracts
2+
@src=src
3+
@test=test
4+
@script=script
5+
solidity-stringutils=lib/solidity-stringutils
6+

script/Counter.s.sol

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/Counter.sol

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/HTTP.sol

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.13;
3+
4+
import {Vm} from "forge-std/Vm.sol";
5+
import {StringMap} from "@src/StringMap.sol";
6+
7+
library HTTP {
8+
using StringMap for StringMap.StringToStringMap;
9+
10+
Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))));
11+
12+
enum Method {
13+
GET,
14+
POST,
15+
PUT,
16+
DELETE,
17+
PATCH
18+
}
19+
20+
struct Request {
21+
string url;
22+
string body;
23+
Method method;
24+
StringMap.StringToStringMap headers;
25+
StringMap.StringToStringMap query;
26+
}
27+
28+
struct Response {
29+
uint256 status;
30+
string data;
31+
}
32+
33+
function request(Request storage req) internal returns (Response memory res) {
34+
string memory scriptStart = 'response=$(curl -s -w "\\n%{http_code}" ';
35+
string memory scriptEnd =
36+
'); status=$(tail -n1 <<< "$response"); data=$(sed "$ d" <<< "$response");data=$(echo "$data" | tr -d "\\n"); cast abi-encode "response(uint256,string)" "$status" "$data";';
37+
38+
string memory curlParams = "";
39+
40+
for (uint256 i = 0; i < req.headers.length(); i++) {
41+
(string memory key, string memory value) = req.headers.at(i);
42+
curlParams = string.concat(curlParams, '-H "', key, ": ", value, '" ');
43+
}
44+
45+
curlParams = string.concat(curlParams, " -X ", toString(req.method), " ");
46+
47+
if (bytes(req.body).length > 0) {
48+
curlParams = string.concat(curlParams, "-d '", req.body, "' ");
49+
}
50+
51+
string memory quotedURL = string.concat('"', req.url, '"');
52+
53+
string[] memory inputs = new string[](3);
54+
inputs[0] = "bash";
55+
inputs[1] = "-c";
56+
inputs[2] = string.concat(scriptStart, curlParams, quotedURL, scriptEnd, "");
57+
bytes memory output = vm.ffi(inputs);
58+
59+
(res.status, res.data) = abi.decode(output, (uint256, string));
60+
}
61+
62+
function toString(Method method) internal pure returns (string memory) {
63+
if (method == Method.GET) {
64+
return "GET";
65+
} else if (method == Method.POST) {
66+
return "POST";
67+
} else if (method == Method.PUT) {
68+
return "PUT";
69+
} else if (method == Method.DELETE) {
70+
return "DELETE";
71+
} else if (method == Method.PATCH) {
72+
return "PATCH";
73+
} else {
74+
revert();
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)