diff --git a/README.md b/README.md index 61bd228..d9b78c0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ pip install py-solc ``` ```python ->>> from solc import compile_source, compile_files +>>> from solc import compile_source, compile_files, link_code >>> compile_source("contract Foo { function Foo() {} }") { 'Foo': { @@ -62,4 +62,7 @@ pip install py-solc }, }, } +>>> unlinked_code = "606060405260768060106000396000f3606060405260e060020a6000350463e7f09e058114601a575b005b60187f0c55699c00000000000000000000000000000000000000000000000000000000606090815273__TestA_________________________________90630c55699c906064906000906004818660325a03f41560025750505056" +>>> link_code(unlinked_code, {'TestA': '0xd3cda913deb6f67967b99d67acdfa1712c293601'}) +... "606060405260768060106000396000f3606060405260e060020a6000350463e7f09e058114601a575b005b60187f0c55699c00000000000000000000000000000000000000000000000000000000606090815273d3cda913deb6f67967b99d67acdfa1712c29360190630c55699c906064906000906004818660325a03f41560025750505056" ``` diff --git a/solc/__init__.py b/solc/__init__.py index 1a23611..7db18c2 100644 --- a/solc/__init__.py +++ b/solc/__init__.py @@ -4,4 +4,5 @@ get_solc_version, compile_files, compile_source, + link_code, ) diff --git a/solc/main.py b/solc/main.py index 499d06f..d434034 100644 --- a/solc/main.py +++ b/solc/main.py @@ -121,3 +121,17 @@ def compile_files(source_files, output_values=ALL_OUTPUT_VALUES, **kwargs): contracts = _parse_compiler_output(stdoutdata) return contracts + + +def link_code(unliked_data, libraries): + libraries_arg = ','.join(( + ':'.join((lib_name, lib_address)) + for lib_name, lib_address in libraries.items() + )) + stdoutdata, stderrdata = solc_wrapper( + stdin_bytes=unliked_data, + link=True, + libraries=libraries_arg, + ) + + return stdoutdata.strip() diff --git a/solc/wrapper.py b/solc/wrapper.py index 7d70fa5..d470057 100644 --- a/solc/wrapper.py +++ b/solc/wrapper.py @@ -61,6 +61,9 @@ def solc_wrapper(solc_binary=SOLC_BINARY, if optimize_runs is not None: command.extend(('--optimize-runs', str(optimize_runs))) + if link: + command.append('--link') + if libraries is not None: command.extend(('--libraries', libraries)) @@ -79,9 +82,6 @@ def solc_wrapper(solc_binary=SOLC_BINARY, if source_files is not None: command.extend(source_files) - if link: - command.append('--link') - # # Output configuration # diff --git a/tests/linking/test_library_linking.py b/tests/linking/test_library_linking.py new file mode 100644 index 0000000..c8cddda --- /dev/null +++ b/tests/linking/test_library_linking.py @@ -0,0 +1,32 @@ +from solc import link_code + +CODE = "6060604052610199806100126000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806344fd4fa01461004f57806358de5f041461005e578063e7f09e051461006d5761004d565b005b61005c600480505061007c565b005b61006b60048050506100db565b005b61007a600480505061013a565b005b73__TestB_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73__TestC_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73__TestA_________________________________630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b56" + +TEST_A_ADDRESS = "0xd3cda913deb6f67967b99d67acdfa1712c293601" +TEST_B_ADDRESS = "0x304a554a310c7e546dfe434669c62820b7d83490" +TEST_C_ADDRESS = "0xbb9bc244d798123fde783fcc1c72d3bb8c189413" + +LINKED_CODE = "6060604052610199806100126000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806344fd4fa01461004f57806358de5f041461005e578063e7f09e051461006d5761004d565b005b61005c600480505061007c565b005b61006b60048050506100db565b005b61007a600480505061013a565b005b73304a554a310c7e546dfe434669c62820b7d83490630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73bb9bc244d798123fde783fcc1c72d3bb8c189413630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b565b73d3cda913deb6f67967b99d67acdfa1712c293601630c55699c604051817c01000000000000000000000000000000000000000000000000000000000281526004018090506000604051808303818660325a03f415610002575050505b56" + + +def test_partial_code_linking(): + output = link_code(CODE, {'TestA': TEST_A_ADDRESS}) + assert '__TestA__' not in output + assert '__TestB__' in output + assert '__TestC__' in output + assert TEST_A_ADDRESS[2:] in output + + +def test_full_code_linking(): + output = link_code(CODE, { + 'TestA': TEST_A_ADDRESS, + 'TestB': TEST_B_ADDRESS, + 'TestC': TEST_C_ADDRESS, + }) + assert '__TestA__' not in output + assert '__TestB__' not in output + assert '__TestC__' not in output + assert TEST_A_ADDRESS[2:] in output + assert TEST_B_ADDRESS[2:] in output + assert TEST_C_ADDRESS[2:] in output + assert output == LINKED_CODE