1
1
package foundry
2
2
3
3
import (
4
+ "bytes"
4
5
"encoding/json"
6
+ "errors"
5
7
"fmt"
6
8
"os"
7
- "path/filepath"
8
9
"strings"
9
10
10
11
"github.com/holiman/uint256"
@@ -26,6 +27,7 @@ type Artifact struct {
26
27
StorageLayout solc.StorageLayout
27
28
DeployedBytecode DeployedBytecode
28
29
Bytecode Bytecode
30
+ Metadata Metadata
29
31
}
30
32
31
33
func (a * Artifact ) UnmarshalJSON (data []byte ) error {
@@ -42,6 +44,7 @@ func (a *Artifact) UnmarshalJSON(data []byte) error {
42
44
a .StorageLayout = artifact .StorageLayout
43
45
a .DeployedBytecode = artifact .DeployedBytecode
44
46
a .Bytecode = artifact .Bytecode
47
+ a .Metadata = artifact .Metadata
45
48
return nil
46
49
}
47
50
@@ -51,6 +54,7 @@ func (a Artifact) MarshalJSON() ([]byte, error) {
51
54
StorageLayout : a .StorageLayout ,
52
55
DeployedBytecode : a .DeployedBytecode ,
53
56
Bytecode : a .Bytecode ,
57
+ Metadata : a .Metadata ,
54
58
}
55
59
return json .Marshal (artifact )
56
60
}
@@ -62,22 +66,83 @@ type artifactMarshaling struct {
62
66
StorageLayout solc.StorageLayout `json:"storageLayout"`
63
67
DeployedBytecode DeployedBytecode `json:"deployedBytecode"`
64
68
Bytecode Bytecode `json:"bytecode"`
69
+ Metadata Metadata `json:"metadata"`
70
+ }
71
+
72
+ // Metadata is the subset of metadata in a foundry contract artifact that we use in OP-Stack tooling.
73
+ type Metadata struct {
74
+ Compiler struct {
75
+ Version string `json:"version"`
76
+ } `json:"compiler"`
77
+
78
+ Language string `json:"language"`
79
+
80
+ Output json.RawMessage `json:"output"`
81
+
82
+ Settings struct {
83
+ // Remappings of the contract imports
84
+ Remappings json.RawMessage `json:"remappings"`
85
+ // Optimizer settings affect the compiler output, but can be arbitrary.
86
+ // We load them opaquely, to include it in the hash of what we run.
87
+ Optimizer json.RawMessage `json:"optimizer"`
88
+ // Metadata is loaded opaquely, similar to the Optimizer, to include in hashing.
89
+ // E.g. the bytecode-hash contract suffix as setting is enabled/disabled in here.
90
+ Metadata json.RawMessage `json:"metadata"`
91
+ // Map of full contract path to compiled contract name.
92
+ CompilationTarget map [string ]string `json:"compilationTarget"`
93
+ // EVM version affects output, and hence included.
94
+ EVMVersion string `json:"evmVersion"`
95
+ // Libraries data
96
+ Libraries json.RawMessage `json:"libraries"`
97
+ } `json:"settings"`
98
+
99
+ Sources map [string ]ContractSource `json:"sources"`
100
+
101
+ Version int `json:"version"`
102
+ }
103
+
104
+ // ContractSource represents a JSON value in the "sources" map of a contract metadata dump.
105
+ // This uniquely identifies the source code of the contract.
106
+ type ContractSource struct {
107
+ Keccak256 common.Hash `json:"keccak256"`
108
+ URLs []string `json:"urls"`
109
+ License string `json:"license"`
110
+ }
111
+
112
+ var ErrLinkingUnsupported = errors .New ("cannot load bytecode with linking placeholders" )
113
+
114
+ // LinkableBytecode is not purely hex, it returns an ErrLinkingUnsupported error when
115
+ // input contains __$aaaaaaa$__ style linking placeholders.
116
+ // See https://docs.soliditylang.org/en/latest/using-the-compiler.html#library-linking
117
+ // In practice this is only used by test contracts to link in large test libraries.
118
+ type LinkableBytecode []byte
119
+
120
+ func (lb * LinkableBytecode ) UnmarshalJSON (data []byte ) error {
121
+ if bytes .Contains (data , []byte ("__$" )) {
122
+ return ErrLinkingUnsupported
123
+ }
124
+ return (* hexutil .Bytes )(lb ).UnmarshalJSON (data )
125
+ }
126
+
127
+ func (lb LinkableBytecode ) MarshalText () ([]byte , error ) {
128
+ return (hexutil .Bytes )(lb ).MarshalText ()
65
129
}
66
130
67
131
// DeployedBytecode represents the deployed bytecode section of the solc compiler output.
68
132
type DeployedBytecode struct {
69
- SourceMap string `json:"sourceMap"`
70
- Object hexutil. Bytes `json:"object"`
71
- LinkReferences json.RawMessage `json:"linkReferences"`
72
- ImmutableReferences json.RawMessage `json:"immutableReferences,omitempty"`
133
+ SourceMap string `json:"sourceMap"`
134
+ Object LinkableBytecode `json:"object"`
135
+ LinkReferences json.RawMessage `json:"linkReferences"`
136
+ ImmutableReferences json.RawMessage `json:"immutableReferences,omitempty"`
73
137
}
74
138
75
139
// Bytecode represents the bytecode section of the solc compiler output.
76
140
type Bytecode struct {
77
- SourceMap string `json:"sourceMap"`
78
- Object hexutil.Bytes `json:"object"`
79
- LinkReferences json.RawMessage `json:"linkReferences"`
80
- ImmutableReferences json.RawMessage `json:"immutableReferences,omitempty"`
141
+ SourceMap string `json:"sourceMap"`
142
+ // not purely hex, can contain __$aaaaaaa$__ style linking placeholders
143
+ Object LinkableBytecode `json:"object"`
144
+ LinkReferences json.RawMessage `json:"linkReferences"`
145
+ ImmutableReferences json.RawMessage `json:"immutableReferences,omitempty"`
81
146
}
82
147
83
148
// ReadArtifact will read an artifact from disk given a path.
@@ -130,15 +195,14 @@ func (d *ForgeAllocs) UnmarshalJSON(b []byte) error {
130
195
}
131
196
132
197
func LoadForgeAllocs (allocsPath string ) (* ForgeAllocs , error ) {
133
- path := filepath .Join (allocsPath )
134
- f , err := os .OpenFile (path , os .O_RDONLY , 0644 )
198
+ f , err := os .OpenFile (allocsPath , os .O_RDONLY , 0644 )
135
199
if err != nil {
136
- return nil , fmt .Errorf ("failed to open forge allocs %q: %w" , path , err )
200
+ return nil , fmt .Errorf ("failed to open forge allocs %q: %w" , allocsPath , err )
137
201
}
138
202
defer f .Close ()
139
203
var out ForgeAllocs
140
204
if err := json .NewDecoder (f ).Decode (& out ); err != nil {
141
- return nil , fmt .Errorf ("failed to json-decode forge allocs %q: %w" , path , err )
205
+ return nil , fmt .Errorf ("failed to json-decode forge allocs %q: %w" , allocsPath , err )
142
206
}
143
207
return & out , nil
144
208
}
0 commit comments