diff --git a/.gitignore b/.gitignore index 92ceda7a9..2ff0a6950 100644 --- a/.gitignore +++ b/.gitignore @@ -118,9 +118,6 @@ deployments .idea -# auto-generated docs -docs/ - # Solidity Flattener flat_contracts/ diff --git a/dodoc/config.ts b/dodoc/config.ts index 992911d1a..4cb7dcadb 100644 --- a/dodoc/config.ts +++ b/dodoc/config.ts @@ -4,53 +4,56 @@ import { HelperContent } from 'squirrelly/dist/types/containers'; export const dodocConfig = { runOnCompile: false, include: [ - 'UniversalProfile.sol', - 'LSP0ERC725Account/LSP0ERC725Account.sol', - 'LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol', - 'LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol', - 'LSP6KeyManager/LSP6KeyManager.sol', - 'LSP9Vault/LSP9Vault.sol', - 'LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol', - 'LSP14Ownable2Step/LSP14Ownable2Step.sol', - 'LSP16UniversalFactory/LSP16UniversalFactory.sol', - 'LSP17ContractExtension/LSP17Extendable.sol', - 'LSP17ContractExtension/LSP17Extension.sol', - 'LSP20CallVerification/LSP20CallVerification.sol', - - // tokens - 'LSP4DigitalAssetMetadata/LSP4Compatibility.sol', - 'LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol', - 'LSP7DigitalAsset/LSP7DigitalAsset.sol', - 'LSP7DigitalAsset/extensions/LSP7Burnable.sol', - 'LSP7DigitalAsset/extensions/LSP7CappedSupply.sol', - 'LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol', - 'LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol', - 'LSP7DigitalAsset/presets/LSP7Mintable.sol', - 'LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol', - 'LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol', - 'LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol', - 'LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol', - 'LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol', - 'LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol', - 'LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol', + 'contracts/UniversalProfile.sol', + 'contracts/LSP0ERC725Account/LSP0ERC725Account.sol', + 'contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateUP/LSP1UniversalReceiverDelegateUP.sol', + 'contracts/LSP1UniversalReceiver/LSP1UniversalReceiverDelegateVault/LSP1UniversalReceiverDelegateVault.sol', + 'contracts/LSP6KeyManager/LSP6KeyManager.sol', + 'contracts/LSP9Vault/LSP9Vault.sol', + 'contracts/LSP11BasicSocialRecovery/LSP11BasicSocialRecovery.sol', + 'contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol', + 'contracts/LSP16UniversalFactory/LSP16UniversalFactory.sol', + 'contracts/LSP17ContractExtension/LSP17Extendable.sol', + 'contracts/LSP17ContractExtension/LSP17Extension.sol', + 'contracts/LSP20CallVerification/LSP20CallVerification.sol', + + // tokens -------------------- + 'contracts/LSP4DigitalAssetMetadata/LSP4Compatibility.sol', + 'contracts/LSP4DigitalAssetMetadata/LSP4DigitalAssetMetadata.sol', + 'contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol', + 'contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol', + 'contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.sol', + 'contracts/LSP7DigitalAsset/extensions/LSP7CompatibleERC20.sol', + 'contracts/LSP7DigitalAsset/presets/LSP7CompatibleERC20Mintable.sol', + 'contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol', + 'contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol', + 'contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.sol', + 'contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.sol', + 'contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CompatibleERC721.sol', + 'contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.sol', + 'contracts/LSP8IdentifiableDigitalAsset/presets/LSP8CompatibleERC721Mintable.sol', + 'contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.sol', // libraries -------------------- - 'LSP0ERC725Account/LSP0Utils.sol', - 'LSP1UniversalReceiver/LSP1Utils.sol', - 'LSP2ERC725YJSONSchema/LSP2Utils.sol', - 'LSP5ReceivedAssets/LSP5Utils.sol', - 'LSP6KeyManager/LSP6Utils.sol', - 'LSP10ReceivedVaults/LSP10Utils.sol', - 'LSP17ContractExtension/LSP17Utils.sol', + 'contracts/LSP0ERC725Account/LSP0Utils.sol', + 'contracts/LSP1UniversalReceiver/LSP1Utils.sol', + 'contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol', + 'contracts/LSP5ReceivedAssets/LSP5Utils.sol', + 'contracts/LSP6KeyManager/LSP6Utils.sol', + 'contracts/LSP10ReceivedVaults/LSP10Utils.sol', + 'contracts/LSP17ContractExtension/LSP17Utils.sol', + + // external -------------------- + '@erc725/smart-contracts/contracts/ERC725.sol', ], libraries: [ - 'LSP0Utils', - 'LSP1Utils', - 'LSP2Utils', - 'LSP5Utils', - 'LSP6Utils', - 'LSP10Utils', - 'LSP17Utils', + 'contracts/LSP0ERC725Account/LSP0Utils.sol', + 'contracts/LSP1UniversalReceiver/LSP1Utils.sol', + 'contracts/LSP2ERC725YJSONSchema/LSP2Utils.sol', + 'contracts/LSP5ReceivedAssets/LSP5Utils.sol', + 'contracts/LSP6KeyManager/LSP6Utils.sol', + 'contracts/LSP10ReceivedVaults/LSP10Utils.sol', + 'contracts/LSP17ContractExtension/LSP17Utils.sol', ], templatePath: './dodoc/template.sqrl', helpers: [ @@ -109,6 +112,23 @@ export const dodocConfig = { helperName: 'generateContractLink', helperFunc: (content: HelperContent) => generateContractLink(content.params[0]), }, + { + helperName: 'generateContractSpecsDetails', + helperFunc: (content: HelperContent) => + content.exec(generateContractSpecsDetails(content.params[0])), + }, + { + helperName: 'formatDisplayedCode', + helperFunc: (content: HelperContent) => formatDisplayedCode(content.params[0]), + }, + { + helperName: 'formatParamDescription', + helperFunc: (content: HelperContent) => formatParamDescription(content.params[0]), + }, + { + helperName: 'formatParamType', + helperFunc: (content: HelperContent) => formatParamType(content.params[0]), + }, ], }; @@ -208,9 +228,9 @@ const generateAdditionalMethodInfo = (contract: string, code: string) => { const { specsName, specsLink } = generateContractSpecsDetails(contract); let infoBlock = - `- Specification details in [**${specsName}**](${specsLink}#${formatedCode + `- Specification details: [**${specsName}**](${specsLink}#${formatedCode .split('(')[0] - .toLowerCase()})\n` + `- Solidity implementation in [**${contract}**](${contractLink})\n`; + .toLowerCase()})\n` + `- Solidity implementation: [\`${contract}.sol\`](${contractLink})\n`; if ( !formatedCode.startsWith('constructor') && @@ -233,12 +253,12 @@ const generateAdditionalEventInfo = (contract: string, code: string) => { const { specsName, specsLink } = generateContractSpecsDetails(contract); return ( - `- Specification details in [**${specsName}**](${specsLink}#${formatedCode + `- Specification details: [**${specsName}**](${specsLink}#${formatedCode .split('(')[0] .toLowerCase()})\n` + - `- Solidity implementation in [**${contract}**](${contractLink})\n` + + `- Solidity implementation: [\`${contract}.sol\`](${contractLink})\n` + `- Event signature: \`${formatedCode}\`\n` + - `- Event hash: \`${ethers.utils.keccak256(ethers.utils.toUtf8Bytes(formatedCode))}\`` + `- Event topic hash: \`${ethers.utils.keccak256(ethers.utils.toUtf8Bytes(formatedCode))}\`` ); }; @@ -248,10 +268,10 @@ const generateAdditionalErrorInfo = (contract: string, code: string) => { const { specsName, specsLink } = generateContractSpecsDetails(contract); return ( - `- Specification details in [**${specsName}**](${specsLink}#${formatedCode + `- Specification details: [**${specsName}**](${specsLink}#${formatedCode .split('(')[0] .toLowerCase()})\n` + - `- Solidity implementation in [**${contract}**](${contractLink})\n` + + `- Solidity implementation: [\`${contract}.sol\`](${contractLink})\n` + `- Error signature: \`${formatedCode}\`\n` + `- Error hash: \`${ethers.utils .keccak256(ethers.utils.toUtf8Bytes(formatedCode)) @@ -260,28 +280,41 @@ const generateAdditionalErrorInfo = (contract: string, code: string) => { }; const generateContractLink = (contractName: string) => { - if (contractName === 'UniversalProfile') + if (contractName === 'UniversalProfile') { return `${linkBase}lsp-smart-contracts/blob/develop/contracts/UniversalProfile.sol`; + } + + if (contractName === 'ERC725') { + return 'https://github.com/ERC725Alliance/ERC725/blob/main/implementations/contracts/ERC725.sol'; + } const contractPath = dodocConfig.include.filter((value) => { if (value.endsWith(`${contractName}.sol`)) return value; })[0]; - return `${linkBase}lsp-smart-contracts/blob/develop/contracts/${contractPath}`; + return `${linkBase}lsp-smart-contracts/blob/develop/${contractPath}`; }; const generateContractSpecsDetails = (contractName: string) => { - if (contractName === 'UniversalProfile') + if (contractName === 'UniversalProfile') { return { specsName: `${contractName}`, specsLink: `${linkBase}lips/tree/main/LSPs/LSP-3-UniversalProfile-Metadata.md`, }; + } + + if (contractName === 'ERC725') { + return { + specsName: 'ERC-725', + specsLink: 'https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md', + }; + } const contractPath = dodocConfig.include.filter((value) => { if (value.endsWith(`${contractName}.sol`)) return value; })[0]; - const specs = contractPath.split('/')[0]; + const specs = contractPath.split('/')[1]; const specsName = `LSP-${specs.match(/\d+/)[0]}-${specs.split(/LSP\d+/)[1]}`; @@ -291,3 +324,37 @@ const generateContractSpecsDetails = (contractName: string) => { return { specsName, specsLink }; }; + +const formatDisplayedCode = (textToFormat: string) => { + let formatedText = textToFormat; + while (formatedText.includes('>')) { + formatedText = formatedText.replace('>', '<'); + } + + return formatedText; +}; + +const formatParamDescription = (textToFormat: string) => { + if (!textToFormat) return '-'; + + let formatedText = textToFormat; + while (formatedText.includes('<')) { + formatedText = formatedText.replace('<', '<'); + } + while (formatedText.includes('>')) { + formatedText = formatedText.replace('>', '<'); + } + + return formatedText; +}; + +const formatParamType = (textToFormat: string) => { + if (!textToFormat) return ''; + + let formatedText = textToFormat; + while (formatedText.includes('>')) { + formatedText = formatedText.replace('>', '<'); + } + + return formatedText; +}; diff --git a/dodoc/template.sqrl b/dodoc/template.sqrl index f46677a80..ae9ec093a 100644 --- a/dodoc/template.sqrl +++ b/dodoc/template.sqrl @@ -1,9 +1,20 @@ + + + + {{@if (it.name)}} # {{it.name}} {{/if}} -:::info Soldity contract +:::info Standard Specifications + +{{@generateContractSpecsDetails(it.name) => specsDetails}} +[`{{specsDetails.specsName}}`]({{specsDetails.specsLink}}) +{{/generateContractSpecsDetails}} + +::: +:::info Solidity implementation [`{{it.name}}.sol`]({{@generateContractLink(it.name) /}}) @@ -32,7 +43,11 @@ {{@if (Object.keys(it.methods).length > 0)}} -## Methods +## Public Methods + + +Public methods are accessible externally from users, allowing interaction with this function from dApps or other smart contracts. +When marked as 'public', a method can be called both externally and internally, on the other hand, when marked as 'external', a method can only be called externally. {{@splitMethods(it.methods) => methods}} @@ -41,7 +56,7 @@ ### {{key.split('(')[0]}} -:::note Links{{'\n\n'}}{{@generateAdditionalMethodInfo(it.name, val.code) /}}{{'\n\n'}}::: +:::note References{{'\n\n'}}{{@generateAdditionalMethodInfo(it.name, val.code) /}}{{'\n\n'}}::: {{@if (val['custom:info'])}} @@ -65,7 +80,7 @@ ```solidity -{{val.code}}; +{{@formatDisplayedCode(val.code) /}}; ``` @@ -99,7 +114,7 @@ | Name | Type | Description | |---|:-:|---| {{@foreach(val.inputs) => key, val}} -| `{{key}}` | `{{val.type}}` | {{val.description ? val.description : '-' }} | +| `{{key}}` | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | {{/foreach}} {{/if}} @@ -110,9 +125,10 @@ | Name | Type | Description | |---|:-:|---| {{@foreach(val.outputs) => key, val}} -| {{@if (key[0] === '_')}}`{{key.substring(1)}}`{{#else}}`{{key}}`{{/if}} | `{{val.type}}` | {{val.description ? val.description : '-' }} | +| {{@if (key[0] === '_')}}`{{key.substring(1)}}`{{#else}}`{{key}}`{{/if}} | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | {{/foreach}} {{/if}} +
{{/foreach}} @@ -123,6 +139,95 @@ {{/if}} +{{@if (Object.keys(it.internalMethods).length > 0)}} + +## Internal Methods + +Any method labeled as `internal` serves as utility function within the contract. They can be used when writing solidity contracts that inherit from this contract. These methods can be extended or modified by overriding their internal behavior to suit specific needs. + +Internal functions cannot be called externally, whether from other smart contracts, dApp interfaces, or backend services. Their restricted accessibility ensures that they remain exclusively available within the context of the current contract, promoting controlled and encapsulated usage of these internal utilities. + + +{{@foreach(it.internalMethods) => key, val}} +### {{key.split('(')[0]}} + +{{@if (val['custom:info'])}} +:::info{{'\n\n'}}{{_ val['custom:info'].replaceAll(' - ', '\n- ') _}}{{'\n\n'}}::: +{{/if}} + + +{{@if (val['custom:hint'])}} +:::tip Hint{{'\n\n'}}{{_ val['custom:hint'].replaceAll(' - ', '\n- ') _}}{{'\n\n'}}::: +{{/if}} + + +{{@if (val['custom:warning'])}} +:::caution Warning{{'\n\n'}}{{_ val['custom:warning'].replaceAll(' - ', '\n- ') _}}{{'\n\n'}}::: +{{/if}} + + +{{@if (val['custom:danger'])}} +:::danger{{'\n\n'}}{{_ val['custom:danger'].replaceAll(' - ', '\n- ') _}}{{'\n\n'}}::: +{{/if}} + + +```solidity +{{@formatDisplayedCode(val.code) /}}; +``` + + +{{@if (val.notice)}} +*{{@parseNotice(val.notice) /}}* +{{/if}} + + +{{@if (val.details)}} +{{@parseDetails(val.details) /}} +{{/if}} + + +{{@if (val['custom:requirements'])}} +
{{'\n\n'}} +{{@parseCustomRequirements(val['custom:requirements']) /}} +{{'\n\n'}}
+{{/if}} + + +{{@if (val['custom:events'])}} +
{{'\n\n'}} +{{@parseCustomEvents(val['custom:events']) /}} +{{'\n\n'}}
+{{/if}} + + +{{@if (Object.keys(val.inputs).length > 0)}} +#### Parameters + +| Name | Type | Description | +|---|:-:|---| +{{@foreach(val.inputs) => key, val}} +| `{{key}}` | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | +{{/foreach}} +{{/if}} + + +{{@if (Object.keys(val.outputs).length > 0)}} +#### Returns + +| Name | Type | Description | +|---|:-:|---| +{{@foreach(val.outputs) => key, val}} +| {{@if (key[0] === '_')}}`{{key.substring(1)}}`{{#else}}`{{key}}`{{/if}} | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | +{{/foreach}} +{{/if}} +
+ +{{/foreach}} + + +{{/if}} + + {{@if (Object.keys(it.events).length > 0)}} ## Events @@ -131,11 +236,11 @@ ### {{key}} -:::note Links{{'\n\n'}}{{@generateAdditionalEventInfo(it.name, val.code) /}}{{'\n\n'}}::: +:::note References{{'\n\n'}}{{@generateAdditionalEventInfo(it.name, val.code) /}}{{'\n\n'}}::: ```solidity -{{val.code}}; +{{@formatDisplayedCode(val.code) /}}; ``` @@ -156,9 +261,10 @@ | Name | Type | Description | |---|:-:|---| {{@foreach(val.inputs) => key, val}} -| `{{key}}` {{@if (val.indexed)}}**`indexed`**{{/if}} | `{{val.type}}` | {{val.description ? val.description : '-' }} | +| `{{key}}` {{@if (val.indexed)}}**`indexed`**{{/if}} | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | {{/foreach}} {{/if}} +
{{/foreach}} {{/if}} @@ -172,11 +278,11 @@ ### {{key}} -:::note Links{{'\n\n'}}{{@generateAdditionalErrorInfo(it.name, val.code) /}}{{'\n\n'}}::: +:::note References{{'\n\n'}}{{@generateAdditionalErrorInfo(it.name, val.code) /}}{{'\n\n'}}::: ```solidity -{{val.code}}; +{{@formatDisplayedCode(val.code) /}}; ``` @@ -196,9 +302,10 @@ | Name | Type | Description | |---|:-:|---| {{@foreach(val.inputs) => key, val}} -| `{{key}}` | `{{val.type}}` | {{val.description ? val.description : '-' }} | +| `{{key}}` | `{{@formatParamType(val.type) /}}` | {{@formatParamDescription(val.description) /}} | {{/foreach}} {{/if}} +
{{/foreach}} {{/if}} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b2bbdebf4..6c887c2ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "solidity-bytes-utils": "0.8.0" }, "devDependencies": { - "@b00ste/hardhat-dodoc": "^0.3.1", + "@b00ste/hardhat-dodoc": "^0.3.11", "@defi-wonderland/smock": "^2.3.4", "@erc725/erc725.js": "0.17.2", "@lukso/eip191-signer.js": "^0.2.2", @@ -71,9 +71,9 @@ } }, "node_modules/@b00ste/hardhat-dodoc": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.1.tgz", - "integrity": "sha512-EMi9i7i8O3g73J4Et38Tsox8XCZ44BneyZykeDrOp8w6KjFztwI5TaZmf5pNofl/6/uWN1C/oMcTyAJI4hRwmA==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.11.tgz", + "integrity": "sha512-GzH7yOJyux47ShCGxsGDeu3phm5iDOAAM+Vj/c8hm8oH5LT5uJ+RpvMVN+U7nNvRebJPnM2J6yc5hkRarHgRDQ==", "dev": true, "dependencies": { "squirrelly": "^8.0.8" @@ -22937,9 +22937,9 @@ } }, "@b00ste/hardhat-dodoc": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.1.tgz", - "integrity": "sha512-EMi9i7i8O3g73J4Et38Tsox8XCZ44BneyZykeDrOp8w6KjFztwI5TaZmf5pNofl/6/uWN1C/oMcTyAJI4hRwmA==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@b00ste/hardhat-dodoc/-/hardhat-dodoc-0.3.11.tgz", + "integrity": "sha512-GzH7yOJyux47ShCGxsGDeu3phm5iDOAAM+Vj/c8hm8oH5LT5uJ+RpvMVN+U7nNvRebJPnM2J6yc5hkRarHgRDQ==", "dev": true, "requires": { "squirrelly": "^8.0.8" diff --git a/package.json b/package.json index 2ac205c53..e2b0842ba 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "solidity-bytes-utils": "0.8.0" }, "devDependencies": { - "@b00ste/hardhat-dodoc": "^0.3.1", + "@b00ste/hardhat-dodoc": "^0.3.11", "@defi-wonderland/smock": "^2.3.4", "@erc725/erc725.js": "0.17.2", "@lukso/eip191-signer.js": "^0.2.2",