diff --git a/CHANGELOG.md b/CHANGELOG.md index fd45fc5..12ac28f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 2.0.0-alpha.18 + +* Handle the partially linked Bytecode in the Truffle Adapter. + ## Version 2.0.0-alpha.17 * Separated the logic of the Reporter and moved transaction-related functions to the TransactionRunner class. diff --git a/package.json b/package.json index 8d0cff0..9e89ffa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@solarity/hardhat-migrate", - "version": "2.0.0-alpha.17", + "version": "2.0.0-alpha.18", "description": "Automatic deployment and verification of smart contracts", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", diff --git a/src/deployer/Linker.ts b/src/deployer/Linker.ts index 1ef01d2..ceee8ae 100644 --- a/src/deployer/Linker.ts +++ b/src/deployer/Linker.ts @@ -29,7 +29,7 @@ export class Linker { public static async tryLinkBytecode(contractName: string, bytecode: string, libraries: Libraries): Promise { const artifact: ArtifactExtended = this._mustGetContractArtifact(contractName); - const neededLibraries = artifact.neededLibraries; + const neededLibraries = this._cleanNeededLibraries(bytecode, artifact, artifact.neededLibraries); let linksToApply: Map = new Map(); for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) { @@ -143,9 +143,43 @@ export class Linker { } } + private static _cleanNeededLibraries( + bytecode: string, + artifact: Artifact, + libraries: NeededLibrary[], + ): NeededLibrary[] { + const actuallyNeededLibs: Map = new Map(); + + for (const { sourceName, libName } of libraries) { + const linkReferences = artifact.linkReferences[sourceName][libName]; + + for (const { start, length } of linkReferences) { + if (!this._isLinkedLibrary(bytecode, start, length)) { + actuallyNeededLibs.set(`${sourceName}:${libName}`, { sourceName, libName }); + } + } + } + + return [...actuallyNeededLibs.values()]; + } + + /** + * The address of the linked library can be extracted like this: bytecode.slice(prefixLength + 2, suffixStart + 2) + */ + private static _isLinkedLibrary(bytecode: string, start: number, length: number): boolean { + const prefixLength = start * 2; + const prefix = bytecode.slice(prefixLength + 2, prefixLength + 5); + + const suffixStart = (start + length) * 2; + const suffix = bytecode.slice(suffixStart - 1, suffixStart + 2); + + return `${prefix}${suffix}` !== "__$$__"; + } + private static _linkBytecode(bytecode: string, artifact: Artifact, libraries: Link[]): string { for (const { sourceName, libraryName, address } of libraries) { const linkReferences = artifact.linkReferences[sourceName][libraryName]; + for (const { start, length } of linkReferences) { const prefixLength = 2 + start * 2; const prefix = bytecode.slice(0, prefixLength); diff --git a/src/deployer/adapters/TruffleAdapter.ts b/src/deployer/adapters/TruffleAdapter.ts index bd73ea9..2c80401 100644 --- a/src/deployer/adapters/TruffleAdapter.ts +++ b/src/deployer/adapters/TruffleAdapter.ts @@ -69,7 +69,11 @@ export class TruffleAdapter extends Adapter { } public getRawBytecode(instance: TruffleContract): string { - return bytecodeToString(instance.bytecode); + try { + return bytecodeToString(instance.binary); + } catch { + return bytecodeToString(instance.bytecode); + } } public getContractName(instance: Instance, parameters: OverridesAndName): string { @@ -80,8 +84,8 @@ export class TruffleAdapter extends Adapter { try { return ArtifactProcessor.tryGetContractName(this.getRawBytecode(instance)); } catch { - if ((instance as any).contractName) { - return (instance as any).contractName; + if ((instance as any)._hArtifact) { + return this._getFullyQualifiedName(instance as any) || (instance as any).contractName; } return UNKNOWN_CONTRACT_NAME; @@ -238,4 +242,12 @@ export class TruffleAdapter extends Adapter { return UNKNOWN_TRANSACTION_NAME; } + + private _getFullyQualifiedName(instance: any): string | undefined { + if (!instance._hArtifact.sourceName || !instance._hArtifact.contractName) { + return undefined; + } + + return `${instance._hArtifact.sourceName}:${instance._hArtifact.contractName}`; + } }