From 609c7e1d4173bc641b74235ffda3a7a51061fd24 Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Sat, 9 Dec 2023 15:44:44 +0200 Subject: [PATCH 1/3] Handled the partially linked Bytecode --- src/deployer/Linker.ts | 47 +++++++++++++++++++++++++ src/deployer/adapters/TruffleAdapter.ts | 18 ++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/deployer/Linker.ts b/src/deployer/Linker.ts index 1ef01d2..b24b25d 100644 --- a/src/deployer/Linker.ts +++ b/src/deployer/Linker.ts @@ -44,6 +44,8 @@ export class Linker { }); } + linksToApply = this._fillLinksToApply(bytecode, artifact, neededLibraries); + if (linksToApply.size < neededLibraries.length) { const separatelyDeployedLibraries = await this._findMissingLibraries( neededLibraries.filter((lib) => !linksToApply.has(`${lib.sourceName}:${lib.libName}`)), @@ -143,10 +145,55 @@ export class Linker { } } + private static _fillLinksToApply( + bytecode: string, + artifact: Artifact, + libraries: NeededLibrary[], + ): Map { + const linksToApplyFilled: Map = new Map(); + + for (const { sourceName, libName } of libraries) { + const linkReferences = artifact.linkReferences[sourceName][libName]; + + for (const { start, length } of linkReferences) { + const [isLinkedLibrary, address] = this._getLinkedLibrary(bytecode, start, length); + + if (isLinkedLibrary) { + linksToApplyFilled.set(`${sourceName}:${libName}`, { + sourceName: sourceName, + libraryName: libName, + address, + }); + } + } + } + + return linksToApplyFilled; + } + + private static _getLinkedLibrary(bytecode: string, start: number, length: number): [boolean, string] { + 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); + + const address = bytecode.slice(prefixLength + 2, suffixStart + 2); + + return [`${prefix}${suffix}` !== "__$$__", `0x${address}`]; + } + 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 [isLinkedLibrary] = this._getLinkedLibrary(bytecode, start, length); + + if (isLinkedLibrary) { + continue; + } + 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}`; + } } From be5701dbdf1efc938eb0c527414ef5665d75bfee Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Sat, 9 Dec 2023 15:47:41 +0200 Subject: [PATCH 2/3] Updated versions and CHANGELOG.md --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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", From 3ad5b406e644fd69b14633b71ea7a2bf1f80a09b Mon Sep 17 00:00:00 2001 From: Kyryl R Date: Sat, 9 Dec 2023 16:05:16 +0200 Subject: [PATCH 3/3] Refactored --- src/deployer/Linker.ts | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/src/deployer/Linker.ts b/src/deployer/Linker.ts index b24b25d..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)) { @@ -44,8 +44,6 @@ export class Linker { }); } - linksToApply = this._fillLinksToApply(bytecode, artifact, neededLibraries); - if (linksToApply.size < neededLibraries.length) { const separatelyDeployedLibraries = await this._findMissingLibraries( neededLibraries.filter((lib) => !linksToApply.has(`${lib.sourceName}:${lib.libName}`)), @@ -145,42 +143,37 @@ export class Linker { } } - private static _fillLinksToApply( + private static _cleanNeededLibraries( bytecode: string, artifact: Artifact, libraries: NeededLibrary[], - ): Map { - const linksToApplyFilled: Map = new Map(); + ): NeededLibrary[] { + const actuallyNeededLibs: Map = new Map(); for (const { sourceName, libName } of libraries) { const linkReferences = artifact.linkReferences[sourceName][libName]; for (const { start, length } of linkReferences) { - const [isLinkedLibrary, address] = this._getLinkedLibrary(bytecode, start, length); - - if (isLinkedLibrary) { - linksToApplyFilled.set(`${sourceName}:${libName}`, { - sourceName: sourceName, - libraryName: libName, - address, - }); + if (!this._isLinkedLibrary(bytecode, start, length)) { + actuallyNeededLibs.set(`${sourceName}:${libName}`, { sourceName, libName }); } } } - return linksToApplyFilled; + return [...actuallyNeededLibs.values()]; } - private static _getLinkedLibrary(bytecode: string, start: number, length: number): [boolean, string] { + /** + * 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); - const address = bytecode.slice(prefixLength + 2, suffixStart + 2); - - return [`${prefix}${suffix}` !== "__$$__", `0x${address}`]; + return `${prefix}${suffix}` !== "__$$__"; } private static _linkBytecode(bytecode: string, artifact: Artifact, libraries: Link[]): string { @@ -188,12 +181,6 @@ export class Linker { const linkReferences = artifact.linkReferences[sourceName][libraryName]; for (const { start, length } of linkReferences) { - const [isLinkedLibrary] = this._getLinkedLibrary(bytecode, start, length); - - if (isLinkedLibrary) { - continue; - } - const prefixLength = 2 + start * 2; const prefix = bytecode.slice(0, prefixLength);