Skip to content

Commit 2e8b255

Browse files
committed
feat(@embark/contracts): add proxyFor property for contracts
Requested here #1689 Adds proxyFor to contracts that merges the ABI of the parent contract to the child (proxy) contract so that the proxy can use the methods of the parent but is deployed as itself
1 parent 414de52 commit 2e8b255

File tree

1 file changed

+63
-42
lines changed
  • packages/stack/contracts-manager/src

1 file changed

+63
-42
lines changed

packages/stack/contracts-manager/src/index.js

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ export default class ContractsManager {
338338

339339
if (contract.address && typeof contract.address === 'function') {
340340
contract.addressHandler = contract.address;
341-
delete contract.addres;
341+
delete contract.address;
342342
} else if (contract.address && typeof contract.address === 'string') {
343343
contract.deployedAddress = contract.address;
344344
}
@@ -385,64 +385,63 @@ export default class ContractsManager {
385385
}
386386
callback();
387387
},
388-
/*eslint complexity: ["error", 11]*/
388+
// eslint-disable-next-line complexity
389389
function dealWithSpecialConfigs(callback) {
390390
let className, contract, parentContractName, parentContract;
391391
let dictionary = Object.keys(self.contracts);
392392

393393
for (className in self.contracts) {
394394
contract = self.contracts[className];
395395

396-
if (contract.instanceOf === undefined) {
396+
if (!contract.instanceOf && !contract.proxyFor) {
397397
continue;
398398
}
399399

400-
parentContractName = contract.instanceOf;
401-
parentContract = self.contracts[parentContractName];
402-
403-
if (parentContract === className) {
404-
self.logger.error(__("%s : instanceOf is set to itself", className));
405-
continue;
406-
}
400+
if (contract.instanceOf) {
401+
parentContractName = contract.instanceOf;
402+
parentContract = self.contracts[parentContractName];
403+
if (!self._isParentContractDependencyCorrect(className, parentContract, 'instanceOf', dictionary)) {
404+
continue;
405+
}
407406

408-
if (parentContract === undefined) {
409-
self.logger.error(__("{{className}}: couldn't find instanceOf contract {{parentContractName}}", {
410-
className: className,
411-
parentContractName: parentContractName
412-
}));
413-
let suggestion = proposeAlternative(parentContractName, dictionary, [className, parentContractName]);
414-
if (suggestion) {
415-
self.logger.warn(__('did you mean "%s"?', suggestion));
407+
// If the contract has no args and the parent has them, use the parent's args in its place
408+
if (parentContract.args?.length > 0 && contract.args?.length === 0) {
409+
contract.args = parentContract.args;
416410
}
417-
continue;
418-
}
419411

420-
if (parentContract.args && parentContract.args.length > 0 && ((contract.args && contract.args.length === 0) || contract.args === undefined)) {
421-
contract.args = parentContract.args;
422-
}
412+
if (!contract.code) {
413+
self.logger.error(__("{{className}} has code associated to it but it's configured as an instanceOf {{parentContractName}}", {
414+
className,
415+
parentContractName
416+
}));
417+
}
423418

424-
if (contract.code !== undefined) {
425-
self.logger.error(__("{{className}} has code associated to it but it's configured as an instanceOf {{parentContractName}}", {
426-
className: className,
427-
parentContractName: parentContractName
428-
}));
419+
contract.path = parentContract.path;
420+
contract.originalFilename = parentContract.originalFilename;
421+
contract.filename = parentContract.filename;
422+
contract.code = parentContract.code;
423+
contract.runtimeBytecode = parentContract.runtimeBytecode;
424+
contract.realRuntimeBytecode = (parentContract.realRuntimeBytecode || parentContract.runtimeBytecode);
425+
contract.gasEstimates = parentContract.gasEstimates;
426+
contract.functionHashes = parentContract.functionHashes;
427+
contract.abiDefinition = parentContract.abiDefinition;
428+
contract.linkReferences = parentContract.linkReferences;
429+
430+
contract.gas = contract.gas || parentContract.gas;
431+
contract.gasPrice = contract.gasPrice || parentContract.gasPrice;
432+
contract.type = 'instance';
429433
}
430434

431-
contract.path = parentContract.path;
432-
contract.originalFilename = parentContract.originalFilename;
433-
contract.filename = parentContract.filename;
434-
contract.code = parentContract.code;
435-
contract.runtimeBytecode = parentContract.runtimeBytecode;
436-
contract.realRuntimeBytecode = (parentContract.realRuntimeBytecode || parentContract.runtimeBytecode);
437-
contract.gasEstimates = parentContract.gasEstimates;
438-
contract.functionHashes = parentContract.functionHashes;
439-
contract.abiDefinition = parentContract.abiDefinition;
440-
contract.linkReferences = parentContract.linkReferences;
441-
442-
contract.gas = contract.gas || parentContract.gas;
443-
contract.gasPrice = contract.gasPrice || parentContract.gasPrice;
444-
contract.type = 'instance';
435+
if (contract.proxyFor) {
436+
parentContractName = contract.proxyFor;
437+
parentContract = self.contracts[parentContractName];
438+
if (!self._isParentContractDependencyCorrect(className, parentContract, 'proxyFor', dictionary)) {
439+
continue;
440+
}
445441

442+
// Merge ABI of contract and proxy so that the contract shares both ABIs, but remove the constructor
443+
contract.abiDefinition = contract.abiDefinition.concat(parentContract.abiDefinition.filter(def => def.type !== 'constructor'));
444+
}
446445
}
447446
callback();
448447
},
@@ -552,6 +551,28 @@ export default class ContractsManager {
552551
});
553552
}
554553

554+
_isParentContractDependencyCorrect(className, parentContract, typeOfInheritance, dictionary) {
555+
const parentContractName = parentContract.className;
556+
if (parentContract === className) {
557+
this.logger.error(__("{{className}} : {{typeOfInheritance}} is set to itself", {className, typeOfInheritance}));
558+
return false;
559+
}
560+
561+
if (parentContract === undefined) {
562+
this.logger.error(__("{{className}}: couldn't find {{typeOfInheritance}} contract {{parentContractName}}", {
563+
className,
564+
parentContractName,
565+
typeOfInheritance
566+
}));
567+
let suggestion = proposeAlternative(parentContractName, dictionary, [className, parentContractName]);
568+
if (suggestion) {
569+
this.logger.warn(__('did you mean "%s"?', suggestion));
570+
}
571+
return false;
572+
}
573+
return true;
574+
}
575+
555576
_contractsForApi() {
556577
const contracts = this.formatContracts();
557578
contracts.forEach((contract) => {

0 commit comments

Comments
 (0)