0
# Bytecode Linking
1
2
Link library addresses into compiled bytecode and analyze library dependencies with support for both legacy and modern placeholder formats.
3
4
## Capabilities
5
6
### Link Bytecode
7
8
Replace library placeholders in compiled bytecode with actual deployed library addresses.
9
10
```typescript { .api }
11
/**
12
* Link library addresses into compiled bytecode
13
* @param bytecode - Hex-encoded bytecode string containing library placeholders
14
* @param libraries - Mapping of library names to deployed addresses
15
* @returns Hex-encoded bytecode string with placeholders replaced by addresses
16
*/
17
function linkBytecode(bytecode: string, libraries: LibraryAddresses): string;
18
19
interface LibraryAddresses {
20
[qualifiedNameOrSourceUnit: string]: string | { [unqualifiedLibraryName: string]: string };
21
}
22
```
23
24
**Usage Examples:**
25
26
```typescript
27
import linker from "solc/linker";
28
29
// Simple library linking
30
const bytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________73123456789...";
31
const linkedBytecode = linker.linkBytecode(bytecode, {
32
"lib.sol:MyLib": "0x1234567890123456789012345678901234567890"
33
});
34
35
// Multiple libraries with nested format
36
const libraries = {
37
"lib.sol:Math": "0x1111111111111111111111111111111111111111",
38
"lib.sol": {
39
"Storage": "0x2222222222222222222222222222222222222222"
40
}
41
};
42
const result = linker.linkBytecode(bytecode, libraries);
43
```
44
45
### Library Address Formats
46
47
The `LibraryAddresses` interface supports multiple formats for maximum compatibility:
48
49
```typescript { .api }
50
interface LibraryAddresses {
51
/** Flat format: fully qualified library name to address */
52
[qualifiedNameOrSourceUnit: string]: string | {
53
/** Nested format: source unit containing unqualified library names */
54
[unqualifiedLibraryName: string]: string;
55
};
56
}
57
```
58
59
**Supported Address Formats:**
60
61
```typescript
62
// Flat format (backwards compatible)
63
const flatFormat = {
64
"MyLibrary": "0x1234567890123456789012345678901234567890",
65
"lib.sol:MyLibrary": "0x1234567890123456789012345678901234567890"
66
};
67
68
// Nested format (Standard JSON compatible)
69
const nestedFormat = {
70
"lib.sol": {
71
"MyLibrary": "0x1234567890123456789012345678901234567890",
72
"OtherLib": "0x2234567890123456789012345678901234567890"
73
}
74
};
75
76
// Mixed format
77
const mixedFormat = {
78
"utils.sol:Helper": "0x3334567890123456789012345678901234567890",
79
"math.sol": {
80
"SafeMath": "0x4434567890123456789012345678901234567890"
81
}
82
};
83
```
84
85
### Find Link References
86
87
Analyze bytecode to find library placeholder locations for manual linking or debugging.
88
89
```typescript { .api }
90
/**
91
* Find all library placeholder locations in hex-encoded bytecode
92
* @param bytecode - Hex-encoded bytecode string
93
* @returns Mapping of library labels to their placeholder locations
94
*/
95
function findLinkReferences(bytecode: string): LinkReferences;
96
97
interface LinkReferences {
98
[libraryLabel: string]: Array<{
99
/** Byte offset in binary (not hex) bytecode */
100
start: number;
101
/** Length in bytes (always 20 for addresses) */
102
length: number;
103
}>;
104
}
105
```
106
107
**Usage Examples:**
108
109
```typescript
110
import linker from "solc/linker";
111
112
const bytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________73123456789...";
113
const references = linker.findLinkReferences(bytecode);
114
115
console.log(references);
116
/* Output:
117
{
118
"lib.sol:MyLib": [
119
{ start: 26, length: 20 }
120
]
121
}
122
*/
123
124
// Use with Standard JSON output
125
const output = JSON.parse(solc.compile(input));
126
const contractBytecode = output.contracts['Contract.sol']['MyContract'].evm.bytecode.object;
127
const linkRefs = linker.findLinkReferences(contractBytecode);
128
129
// Compare with compiler-provided link references
130
const compilerRefs = output.contracts['Contract.sol']['MyContract'].evm.bytecode.linkReferences;
131
```
132
133
### Placeholder Formats
134
135
Solc supports two placeholder formats in bytecode:
136
137
**Legacy Placeholders:**
138
- Format: `__<library_name>____________________` (40 characters total)
139
- Example: `__lib.sol:MyLib________________`
140
- Truncated to 36 characters, padded with underscores
141
142
**Modern Placeholders:**
143
- Format: `__$<hash>$__` (40 characters total)
144
- Example: `__$cb901161e812ceb78cfe30ca65050c4337$__`
145
- Uses keccak256 hash of fully qualified library name
146
147
```typescript
148
// Both formats are automatically handled
149
const legacyBytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________";
150
const modernBytecode = "608060405234801561001057600080fd5b50__$cb901161e812ceb78cfe30ca65050c4337$__";
151
152
const libraries = { "lib.sol:MyLib": "0x1234567890123456789012345678901234567890" };
153
154
// Both will be linked correctly
155
const linkedLegacy = linker.linkBytecode(legacyBytecode, libraries);
156
const linkedModern = linker.linkBytecode(modernBytecode, libraries);
157
```
158
159
### Address Validation
160
161
Library addresses are automatically validated and formatted:
162
163
```typescript
164
// Addresses are validated
165
try {
166
linker.linkBytecode(bytecode, {
167
"MyLib": "invalid_address" // Error: Invalid address
168
});
169
} catch (error) {
170
console.error(error.message); // "Invalid address specified for MyLib"
171
}
172
173
// Addresses are automatically padded
174
linker.linkBytecode(bytecode, {
175
"MyLib": "0x123" // Automatically padded to "0x0000000000000000000000000000000000000123"
176
});
177
178
// 0x prefix is required
179
linker.linkBytecode(bytecode, {
180
"MyLib": "1234567890123456789012345678901234567890" // Error: Invalid address
181
});
182
```
183
184
### Integration with Compilation
185
186
Linking is typically done after compilation when deploying contracts with library dependencies:
187
188
```typescript
189
import solc from "solc";
190
import linker from "solc/linker";
191
192
// Compile contract with library dependency
193
const input = {
194
language: 'Solidity',
195
sources: {
196
'Contract.sol': {
197
content: `
198
import "./MyLib.sol";
199
contract MyContract {
200
function test() public returns (uint) {
201
return MyLib.calculate(42);
202
}
203
}
204
`
205
},
206
'MyLib.sol': {
207
content: `
208
library MyLib {
209
function calculate(uint x) public pure returns (uint) {
210
return x * 2;
211
}
212
}
213
`
214
}
215
},
216
settings: {
217
outputSelection: { '*': { '*': ['evm.bytecode', 'evm.deployedBytecode'] } }
218
}
219
};
220
221
const output = JSON.parse(solc.compile(JSON.stringify(input)));
222
223
// First deploy the library
224
const libraryBytecode = output.contracts['MyLib.sol']['MyLib'].evm.bytecode.object;
225
// ... deploy library and get address ...
226
const libraryAddress = "0x1234567890123456789012345678901234567890";
227
228
// Then link the main contract
229
const contractBytecode = output.contracts['Contract.sol']['MyContract'].evm.bytecode.object;
230
const linkedBytecode = linker.linkBytecode(contractBytecode, {
231
"MyLib.sol:MyLib": libraryAddress
232
});
233
234
// Now linkedBytecode can be deployed
235
```