JavaScript bindings for the Solidity compiler with Standard JSON I/O interface
—
Link library addresses into compiled bytecode and analyze library dependencies with support for both legacy and modern placeholder formats.
Replace library placeholders in compiled bytecode with actual deployed library addresses.
/**
* Link library addresses into compiled bytecode
* @param bytecode - Hex-encoded bytecode string containing library placeholders
* @param libraries - Mapping of library names to deployed addresses
* @returns Hex-encoded bytecode string with placeholders replaced by addresses
*/
function linkBytecode(bytecode: string, libraries: LibraryAddresses): string;
interface LibraryAddresses {
[qualifiedNameOrSourceUnit: string]: string | { [unqualifiedLibraryName: string]: string };
}Usage Examples:
import linker from "solc/linker";
// Simple library linking
const bytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________73123456789...";
const linkedBytecode = linker.linkBytecode(bytecode, {
"lib.sol:MyLib": "0x1234567890123456789012345678901234567890"
});
// Multiple libraries with nested format
const libraries = {
"lib.sol:Math": "0x1111111111111111111111111111111111111111",
"lib.sol": {
"Storage": "0x2222222222222222222222222222222222222222"
}
};
const result = linker.linkBytecode(bytecode, libraries);The LibraryAddresses interface supports multiple formats for maximum compatibility:
interface LibraryAddresses {
/** Flat format: fully qualified library name to address */
[qualifiedNameOrSourceUnit: string]: string | {
/** Nested format: source unit containing unqualified library names */
[unqualifiedLibraryName: string]: string;
};
}Supported Address Formats:
// Flat format (backwards compatible)
const flatFormat = {
"MyLibrary": "0x1234567890123456789012345678901234567890",
"lib.sol:MyLibrary": "0x1234567890123456789012345678901234567890"
};
// Nested format (Standard JSON compatible)
const nestedFormat = {
"lib.sol": {
"MyLibrary": "0x1234567890123456789012345678901234567890",
"OtherLib": "0x2234567890123456789012345678901234567890"
}
};
// Mixed format
const mixedFormat = {
"utils.sol:Helper": "0x3334567890123456789012345678901234567890",
"math.sol": {
"SafeMath": "0x4434567890123456789012345678901234567890"
}
};Analyze bytecode to find library placeholder locations for manual linking or debugging.
/**
* Find all library placeholder locations in hex-encoded bytecode
* @param bytecode - Hex-encoded bytecode string
* @returns Mapping of library labels to their placeholder locations
*/
function findLinkReferences(bytecode: string): LinkReferences;
interface LinkReferences {
[libraryLabel: string]: Array<{
/** Byte offset in binary (not hex) bytecode */
start: number;
/** Length in bytes (always 20 for addresses) */
length: number;
}>;
}Usage Examples:
import linker from "solc/linker";
const bytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________73123456789...";
const references = linker.findLinkReferences(bytecode);
console.log(references);
/* Output:
{
"lib.sol:MyLib": [
{ start: 26, length: 20 }
]
}
*/
// Use with Standard JSON output
const output = JSON.parse(solc.compile(input));
const contractBytecode = output.contracts['Contract.sol']['MyContract'].evm.bytecode.object;
const linkRefs = linker.findLinkReferences(contractBytecode);
// Compare with compiler-provided link references
const compilerRefs = output.contracts['Contract.sol']['MyContract'].evm.bytecode.linkReferences;Solc supports two placeholder formats in bytecode:
Legacy Placeholders:
__<library_name>____________________ (40 characters total)__lib.sol:MyLib________________Modern Placeholders:
__$<hash>$__ (40 characters total)__$cb901161e812ceb78cfe30ca65050c4337$__// Both formats are automatically handled
const legacyBytecode = "608060405234801561001057600080fd5b50__lib.sol:MyLib________________";
const modernBytecode = "608060405234801561001057600080fd5b50__$cb901161e812ceb78cfe30ca65050c4337$__";
const libraries = { "lib.sol:MyLib": "0x1234567890123456789012345678901234567890" };
// Both will be linked correctly
const linkedLegacy = linker.linkBytecode(legacyBytecode, libraries);
const linkedModern = linker.linkBytecode(modernBytecode, libraries);Library addresses are automatically validated and formatted:
// Addresses are validated
try {
linker.linkBytecode(bytecode, {
"MyLib": "invalid_address" // Error: Invalid address
});
} catch (error) {
console.error(error.message); // "Invalid address specified for MyLib"
}
// Addresses are automatically padded
linker.linkBytecode(bytecode, {
"MyLib": "0x123" // Automatically padded to "0x0000000000000000000000000000000000000123"
});
// 0x prefix is required
linker.linkBytecode(bytecode, {
"MyLib": "1234567890123456789012345678901234567890" // Error: Invalid address
});Linking is typically done after compilation when deploying contracts with library dependencies:
import solc from "solc";
import linker from "solc/linker";
// Compile contract with library dependency
const input = {
language: 'Solidity',
sources: {
'Contract.sol': {
content: `
import "./MyLib.sol";
contract MyContract {
function test() public returns (uint) {
return MyLib.calculate(42);
}
}
`
},
'MyLib.sol': {
content: `
library MyLib {
function calculate(uint x) public pure returns (uint) {
return x * 2;
}
}
`
}
},
settings: {
outputSelection: { '*': { '*': ['evm.bytecode', 'evm.deployedBytecode'] } }
}
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
// First deploy the library
const libraryBytecode = output.contracts['MyLib.sol']['MyLib'].evm.bytecode.object;
// ... deploy library and get address ...
const libraryAddress = "0x1234567890123456789012345678901234567890";
// Then link the main contract
const contractBytecode = output.contracts['Contract.sol']['MyContract'].evm.bytecode.object;
const linkedBytecode = linker.linkBytecode(contractBytecode, {
"MyLib.sol:MyLib": libraryAddress
});
// Now linkedBytecode can be deployedInstall with Tessl CLI
npx tessl i tessl/npm-solc