From 1c745ccfe6102c96487f49cca21d2fbd2a9bc6bf Mon Sep 17 00:00:00 2001 From: josemarinas <36479864+josemarinas@users.noreply.github.com> Date: Thu, 18 Apr 2024 10:42:36 +0200 Subject: [PATCH] refactor: restructure `osx-commons-sdk` (#73) * chore: folder restructure * chore: delete examples from sdk 1.0 * fix: prettier * fix: broken dependency * fix: broken dependency * fix: update yarn.lock * fix: tests missing dependency * fix: apply code structure suggestions * fix: remove regex.ts * fix: pr comments * update: package.json version --- sdk/examples/01-extended-context.ts | 63 ---- sdk/examples/02-extended-client.ts | 61 ---- sdk/package.json | 16 +- sdk/src/{bitmap/utils.ts => bitmap.ts} | 2 +- sdk/src/bitmap/errors.ts | 22 -- sdk/src/bitmap/index.ts | 2 - sdk/src/constants.ts | 15 - sdk/src/{ens/utils.ts => ens.ts} | 26 +- sdk/src/ens/index.ts | 1 - sdk/src/errors.ts | 294 ++---------------- sdk/src/{events/utils.ts => events.ts} | 0 sdk/src/events/errors.ts | 11 - sdk/src/events/index.ts | 2 - sdk/src/hex/address.ts | 12 - sdk/src/hex/bytes.ts | 43 --- sdk/src/hex/constants.ts | 6 - sdk/src/hex/errors.ts | 25 -- sdk/src/hex/index.ts | 6 - sdk/src/hex/proposal.ts | 26 -- sdk/src/hex/strings.ts | 34 -- sdk/src/index.ts | 24 +- sdk/src/{interfaces.ts => introspection.ts} | 4 +- sdk/src/ipfs.ts | 29 +- sdk/src/math.ts | 4 - sdk/src/metadata.ts | 8 +- sdk/src/multiuri.ts | 70 ----- sdk/src/permission.ts | 77 +++-- sdk/src/plugin/errors.ts | 25 -- sdk/src/plugin/index.ts | 3 - sdk/src/plugin/proposal.ts | 86 ----- sdk/src/promises.ts | 73 ----- sdk/src/proposal.ts | 7 + sdk/src/{plugin/utils.ts => ratio.ts} | 17 + sdk/src/time.ts | 20 +- sdk/src/types.ts | 46 --- sdk/src/validation.ts | 56 ---- sdk/test/constants.ts | 42 --- sdk/test/unit/bitmap.test.ts | 2 +- sdk/test/unit/ens.test.ts | 37 ++- sdk/test/unit/hex/address.test.ts | 27 -- sdk/test/unit/hex/bytes.test.ts | 75 ----- sdk/test/unit/hex/proposal.test.ts | 35 --- sdk/test/unit/hex/strings.test.ts | 44 --- sdk/test/unit/interfaces.test.ts | 11 - sdk/test/unit/introspection.test.ts | 16 + sdk/test/unit/ipfs.test.ts | 39 +++ sdk/test/unit/metadata.test.ts | 2 +- sdk/test/unit/multiuri.test.ts | 93 ------ sdk/test/unit/plugin/proposal.test.ts | 180 ----------- sdk/test/unit/promises.test.ts | 61 ---- sdk/test/unit/proposal.test.ts | 13 + .../{plugin/utils.test.ts => ratio.test.ts} | 6 +- sdk/test/unit/time.test.ts | 12 + sdk/test/unit/validation.test.ts | 117 ------- sdk/yarn.lock | 242 +------------- 55 files changed, 310 insertions(+), 1960 deletions(-) delete mode 100644 sdk/examples/01-extended-context.ts delete mode 100644 sdk/examples/02-extended-client.ts rename sdk/src/{bitmap/utils.ts => bitmap.ts} (97%) delete mode 100644 sdk/src/bitmap/errors.ts delete mode 100644 sdk/src/bitmap/index.ts delete mode 100644 sdk/src/constants.ts rename sdk/src/{ens/utils.ts => ens.ts} (66%) delete mode 100644 sdk/src/ens/index.ts rename sdk/src/{events/utils.ts => events.ts} (100%) delete mode 100644 sdk/src/events/errors.ts delete mode 100644 sdk/src/events/index.ts delete mode 100644 sdk/src/hex/address.ts delete mode 100644 sdk/src/hex/bytes.ts delete mode 100644 sdk/src/hex/constants.ts delete mode 100644 sdk/src/hex/errors.ts delete mode 100644 sdk/src/hex/index.ts delete mode 100644 sdk/src/hex/proposal.ts delete mode 100644 sdk/src/hex/strings.ts rename sdk/src/{interfaces.ts => introspection.ts} (82%) delete mode 100644 sdk/src/math.ts delete mode 100644 sdk/src/multiuri.ts delete mode 100644 sdk/src/plugin/errors.ts delete mode 100644 sdk/src/plugin/index.ts delete mode 100644 sdk/src/plugin/proposal.ts delete mode 100644 sdk/src/promises.ts rename sdk/src/{plugin/utils.ts => ratio.ts} (70%) delete mode 100644 sdk/src/types.ts delete mode 100644 sdk/src/validation.ts delete mode 100644 sdk/test/unit/hex/address.test.ts delete mode 100644 sdk/test/unit/hex/bytes.test.ts delete mode 100644 sdk/test/unit/hex/proposal.test.ts delete mode 100644 sdk/test/unit/hex/strings.test.ts delete mode 100644 sdk/test/unit/interfaces.test.ts create mode 100644 sdk/test/unit/introspection.test.ts create mode 100644 sdk/test/unit/ipfs.test.ts delete mode 100644 sdk/test/unit/multiuri.test.ts delete mode 100644 sdk/test/unit/plugin/proposal.test.ts delete mode 100644 sdk/test/unit/promises.test.ts create mode 100644 sdk/test/unit/proposal.test.ts rename sdk/test/unit/{plugin/utils.test.ts => ratio.test.ts} (95%) create mode 100644 sdk/test/unit/time.test.ts delete mode 100644 sdk/test/unit/validation.test.ts diff --git a/sdk/examples/01-extended-context.ts b/sdk/examples/01-extended-context.ts deleted file mode 100644 index 1f2abf3b..00000000 --- a/sdk/examples/01-extended-context.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* MARKDOWN ---- -title: Extended context ---- - -## Extended contex - -Use the ContextCore class to create an extended Context for you own plugin. Now you can receive a generic base context with Web3, Subgraph and IPFS capabilities add custom parameters for your client on top. - -*/ -import {Context, ContextCore} from '../src'; - -// define a custom context params -type MyContextParams = { - myParam: string; -}; - -// define a custom context that extends the ContextCore class -export class MyContext extends ContextCore { - public myParam: string; - constructor( - customContextParams?: Partial, - context?: ContextCore - ) { - super(context); - this.myParam = customContextParams?.myParam || 'default'; - } -} - -// obtained from the host UI (Web3, Subgraph and IPFS) -const genericUiCtx: Context = new Context(/* ... */); - -// define our custom context -const context1 = new MyContext({myParam: 'hello world'}, genericUiCtx); - -// call extended client functions -console.log(context1.network); -console.log(context1.myParam); -// ... - -/* MARKDOWN -Returns: -```tsx -matic -hello world -``` -*/ - -// define a custom context with default values -const context2 = new MyContext(); - -// call extended client functions -console.log(context2.network); -console.log(context2.myParam); -// ... - -/* MARKDOWN -Returns: -```tsx -mainnet -default -``` -*/ diff --git a/sdk/examples/02-extended-client.ts b/sdk/examples/02-extended-client.ts deleted file mode 100644 index 687f9566..00000000 --- a/sdk/examples/02-extended-client.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* MARKDOWN ---- -title: Extended client ---- - -## Extended client - -Use the ClientCore class to create an extended client. Now you can add your custom functions and properties to the client. - -*/ -import {ClientCore} from '../src'; -import {MyContext} from './01-extended-context'; - -// define a custom client that extends the ClientCore class -class MyClient extends ClientCore { - protected myParam: string; - constructor(ctx: MyContext) { - super(ctx); - this.myParam = ctx.myParam; - } - - public customFunction() { - return 'hello world'; - } - - public async customFunction2() { - // Use the primitives provided by the ClientCore class - const signer = this.web3.getConnectedSigner(); - const provider = this.web3.getProvider(); - const graphqlClient = this.graphql.getClient(); - const ipfsClient = this.ipfs.getClient(); - - console.log(signer); - console.log(provider); - console.log(graphqlClient); - console.log(ipfsClient); - - // ... - } - - public customFunction3() { - return this.myParam; - } -} - -// define a custom context with default values -const context = new MyContext(); -// define a custom client -const client = new MyClient(context); - -// call extended client functions -console.log(client.customFunction()); -console.log(client.customFunction3()); - -/* MARKDOWN -Returns: -```tsx -hello world -default -``` -*/ diff --git a/sdk/package.json b/sdk/package.json index 4ac8aa33..c5805f59 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,7 +1,7 @@ { "name": "@aragon/osx-commons-sdk", "author": "Aragon Association", - "version": "0.0.1-alpha.7", + "version": "0.0.1-alpha.8", "license": "MIT", "main": "dist/index.js", "module": "dist/osx-commons-sdk.esm.js", @@ -43,6 +43,7 @@ } ], "devDependencies": { + "@aragon/osx-ethers": "1.3.0", "@size-limit/preset-small-lib": "^7.0.8", "@types/node": "^20.10.0", "dts-cli": "^2.0.3", @@ -53,19 +54,10 @@ }, "dependencies": { "@aragon/osx-commons-configs": "^0.4.0", - "@aragon/osx-ethers": "^1.3.0-rc0.4", - "@aragon/osx-ethers-v1.0.0": "npm:@aragon/osx-ethers@1.2.1", - "@aragon/sdk-ipfs": "^1.1.0", - "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", "@ethersproject/contracts": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@ethersproject/providers": "^5.7.2", - "@ethersproject/wallet": "^5.7.0", - "graphql": "^16.5.0", - "graphql-request": "^4.3.0", - "ipfs-http-client": "^51.0.0", - "yup": "^1.2.0" + "@ethersproject/providers": "^5.7.0", + "ipfs-http-client": "^51.0.0" } } diff --git a/sdk/src/bitmap/utils.ts b/sdk/src/bitmap.ts similarity index 97% rename from sdk/src/bitmap/utils.ts rename to sdk/src/bitmap.ts index 68022869..7633b11a 100644 --- a/sdk/src/bitmap/utils.ts +++ b/sdk/src/bitmap.ts @@ -3,7 +3,7 @@ import { InvalidBitMapValueError, InvalidBitPositionError, } from './errors'; -import {BigNumber} from 'ethers'; +import {BigNumber} from '@ethersproject/bignumber'; /** * Flips a specific bit in a `BigNumber` object and returns a new `BigNumber` object with the bit flipped. diff --git a/sdk/src/bitmap/errors.ts b/sdk/src/bitmap/errors.ts deleted file mode 100644 index ccad996a..00000000 --- a/sdk/src/bitmap/errors.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {SdkError} from '../errors'; - -export class InvalidArraySizeError extends SdkError { - constructor(size: number, cause?: any) { - super(`Invalid array size: ${size}`, cause); - } -} - -export class InvalidBitMapValueError extends SdkError { - constructor(cause?: any) { - super('The bitmap value is too big', cause); - } -} - -export class InvalidBitPositionError extends SdkError { - constructor(position: number, cause?: any) { - super( - `Invalid bit position ${position}, minimum is 0 and maximum is 255`, - cause - ); - } -} diff --git a/sdk/src/bitmap/index.ts b/sdk/src/bitmap/index.ts deleted file mode 100644 index ee262b44..00000000 --- a/sdk/src/bitmap/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './utils'; -export * from './errors'; diff --git a/sdk/src/constants.ts b/sdk/src/constants.ts deleted file mode 100644 index a25a3e0a..00000000 --- a/sdk/src/constants.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const ADDRESS = { - ZERO: `0x${'0'.repeat(40)}`, // address(0) - ONE: `0x${'0'.repeat(39)}1`, // address(1) - TWO: `0x${'0'.repeat(39)}2`, // address(2) - LAST: `0x${'f'.repeat(40)}`, // address(-1) -}; - -export const IPFS_CID_REGEX = - /^((Qm[1-9A-HJ-NP-Za-km-z]{44,})|(b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,})|(z[1-9A-HJ-NP-Za-km-z]{48,})|(F[0-9A-F]{50,}))$/; - -export const IPFS_URI_REGEX = - /^ipfs:\/\/((Qm[1-9A-HJ-NP-Za-km-z]{44,})|(b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,})|(z[1-9A-HJ-NP-Za-km-z]{48,})|(F[0-9A-F]{50,}))$/; - -export const ENS_REGEX = /^(?:[a-z0-9-]+\.)*[a-z0-9-]+\.eth$/; -export const SUBDOMAIN_REGEX = /^[a-z0-9-]+$/; diff --git a/sdk/src/ens/utils.ts b/sdk/src/ens.ts similarity index 66% rename from sdk/src/ens/utils.ts rename to sdk/src/ens.ts index 9362b3f4..89baf7e1 100644 --- a/sdk/src/ens/utils.ts +++ b/sdk/src/ens.ts @@ -1,9 +1,11 @@ -import {InvalidEnsError, UnsupportedNetworkError} from '../errors'; -import {isEnsName} from '../validation'; +import {InvalidEnsError, UnsupportedNetworkError} from './errors'; import {getNetworkByAlias} from '@aragon/osx-commons-configs'; import {Networkish} from '@ethersproject/networks'; import {JsonRpcProvider, Provider} from '@ethersproject/providers'; +const ENS_REGEX = /^(?:[a-z0-9-]+\.)*[a-z0-9-]+\.eth$/; +const SUBDOMAIN_REGEX = /^[a-z0-9-]+$/; + /** * Resolves an ENS name to an address given a provider * @@ -35,3 +37,23 @@ export function resolveEnsName( } return provider.resolveName(ensName); } +/** + * Checks if the given string is a valid ENS name + * + * @export + * @param {string} name + * @return {*} {boolean} + */ +export function isEnsName(name: string): boolean { + return ENS_REGEX.test(name); +} +/** + * Checks if the given string is a valid subdomain + * + * @export + * @param {string} name + * @return {*} {boolean} + */ +export function isSubdomain(name: string): boolean { + return SUBDOMAIN_REGEX.test(name); +} diff --git a/sdk/src/ens/index.ts b/sdk/src/ens/index.ts deleted file mode 100644 index 04bca77e..00000000 --- a/sdk/src/ens/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './utils'; diff --git a/sdk/src/errors.ts b/sdk/src/errors.ts index f17bc27d..be10de72 100644 --- a/sdk/src/errors.ts +++ b/sdk/src/errors.ts @@ -1,3 +1,5 @@ +import {ContractReceipt} from '@ethersproject/contracts'; + export class SdkError extends Error { public cause?: Error | string; constructor(message: string, cause?: any) { @@ -10,195 +12,44 @@ export class SdkError extends Error { } } -export class TimeoutError extends SdkError { - constructor(message?: string, cause?: any) { - super(message ? message : 'Time out', cause); - } -} -export class UnsupportedProtocolError extends SdkError { - constructor(protocol: string, cause?: any) { - super('Unsupported protocol: ' + protocol, cause); - } -} -export class GraphQLError extends SdkError { - constructor(model: string, cause?: any) { - super('Cannot fetch the ' + model + ' data from GraphQL', cause); - } -} -export class IpfsError extends SdkError { - constructor(cause?: any) { - super('Cannot add or get data from ipfs', cause); - } -} -export class InvalidAddressOrEnsError extends SdkError { - constructor(cause?: any) { - super('Invalid address or ENS', cause); - } -} -export class InvalidCidError extends SdkError { - constructor(cause?: any) { - super('The value does not contain a valid CiD', cause); - } -} -export class NoProviderError extends SdkError { - constructor(cause?: any) { - super('A web3 provider is needed', cause); - } -} -export class NoSignerError extends SdkError { - constructor(cause?: any) { - super('A signer is needed', cause); - } -} -export class UnexpectedActionError extends SdkError { - constructor(cause?: any) { - super('The received action is different from the expected one', cause); - } -} - -export class NoTokenAddress extends SdkError { - constructor(cause?: any) { - super('A token address is needed', cause); - } -} - -export class NoDaoFactory extends SdkError { - constructor(cause?: any) { - super('A dao factory address is needed', cause); - } -} - -export class NoPluginRepoRegistry extends SdkError { - constructor(cause?: any) { - super('A plugin repo registry address is needed', cause); - } -} - -export class NoDaoRegistry extends SdkError { - constructor(cause?: any) { - super('A dao registry address is needed', cause); +export class InvalidRatioValueError extends SdkError { + constructor(ratio: number, cause?: any) { + super( + `The ratio value should range between 0 and 1, received value: ${ratio}`, + cause + ); } } -export class IpfsPinError extends SdkError { - constructor(cause?: any) { - super('Failed to pin data on IPFS', cause); +export class InvalidDigitsValueError extends SdkError { + constructor(digits: number, cause?: any) { + super( + `The number of digits should range between 1 and 15, received value: ${digits}`, + cause + ); } } -export class ProposalCreationError extends SdkError { - constructor(cause?: any) { - super('Failed to create proposal', cause); - } -} -export class DaoCreationError extends SdkError { +export class ValueOutOfRangeError extends SdkError { constructor(cause?: any) { - super('Failed to create DAO', cause); + super(`The value is out of range`, cause); } } -export class MissingExecPermissionError extends SdkError { - constructor(cause?: any) { - super('No plugin requests EXECUTE_PERMISSION', cause); - } -} -export class IpfsFetchError extends SdkError { - constructor(cause?: any) { - super('Failed to fetch data from IPFS', cause); - } -} -export class InvalidVotingModeError extends SdkError { - constructor(cause?: any) { - super('Invalid voting mode', cause); - } -} -export class UpdateAllowanceError extends SdkError { - constructor(cause?: any) { - super('Could not define a minimum allowance', cause); - } -} -export class InvalidPrecisionError extends SdkError { - constructor(cause?: any) { - super('Invalid precision, number must be an integer greater than 0', cause); - } -} -export class FailedDepositError extends SdkError { - constructor(cause?: any) { - super('Failed to deposit', cause); - } -} -export class AmountMismatchError extends SdkError { - constructor(expected: bigint, received: bigint, cause?: any) { +export class EventNotFoundError extends SdkError { + constructor(eventName: string, contractReceipt: ContractReceipt) { super( - `Deposited amount mismatch. Expected: ${expected}, received: ${received}`, - cause + `Event "${eventName}" could not be found in transaction ${contractReceipt.transactionHash}.`, + contractReceipt ); } } + export class UnsupportedNetworkError extends SdkError { constructor(network: string, cause?: any) { super('Unsupported network: ' + network, cause); } } -export class ClientNotInitializedError extends SdkError { - constructor(client: string, cause?: any) { - super(client + ' client is not initialized', cause); - } -} -export class NoNodesAvailableError extends SdkError { - constructor(name: string, cause?: any) { - super('No ' + name + ' nodes available', cause); - } -} - -export class PluginInstallationPreparationError extends SdkError { - constructor(cause?: any) { - super('Failed to install plugin', cause); - } -} -export class DataDecodingError extends SdkError { - constructor(message: string, cause?: any) { - super('Cannot decode data: ' + message, cause); - } -} - -export class InvalidContractAddressError extends SdkError { - constructor(cause?: any) { - super('Invalid contract address', cause); - } -} -export class InvalidContractAbiError extends SdkError { - constructor(cause?: any) { - super('Invalid contract ABI', cause); - } -} -export class CannotEstimateGasError extends SdkError { - constructor(cause?: any) { - super('Cannot estimate gas error', cause); - } -} -export class InstallationNotFoundError extends SdkError { - constructor(cause?: any) { - super('Installation not found', cause); - } -} -export class PluginUninstallationPreparationError extends SdkError { - constructor(cause?: any) { - super('plugin uninstallation error', cause); - } -} - -export class MissingMetadataError extends SdkError { - constructor(cause?: any) { - super('Missing metadata', cause); - } -} - -export class InvalidPrepareUninstallationAbiError extends SdkError { - constructor(cause?: Error) { - super('Invalid prepare uninstallation ABI', cause); - } -} export class InvalidEnsError extends SdkError { constructor(cause?: any) { @@ -206,108 +57,23 @@ export class InvalidEnsError extends SdkError { } } -export class DepositNativeTokenError extends SdkError { - constructor(cause?: any) { - super("Please, use the token's transfer function directly", cause); - } -} -export class AlwaysFailingProposalError extends SdkError { - constructor(cause?: Error) { - super( - 'invalid actions, the types or order of the actions may cause the execution to fail', - cause - ); - } -} - -export class SizeMismatchError extends SdkError { - constructor(field1: string, field2: string, cause?: Error) { - super(`Size mismatch: ${field1} and ${field2} should match`, cause); +export class InvalidArraySizeError extends SdkError { + constructor(size: number, cause?: any) { + super(`Invalid array size: ${size}`, cause); } } -export class InvalidProposalStatusError extends SdkError { - constructor(cause?: Error) { - super('Invalid proposal status', cause); - } -} - -export class NotImplementedError extends SdkError { - constructor(message?: string, cause?: Error) { - super(`Not implemented: ${message}`, cause); - } -} - -export class InvalidActionError extends SdkError { - constructor(cause?: Error) { - super('The received action is not recognized', cause); - } -} - -export class InvalidSubdomainError extends SdkError { - constructor(cause?: Error) { - super('Invalid subdomain format: use a-z, 0-9 and -', cause); - } -} - -export class InvalidGasEstimationFactorError extends SdkError { - constructor(cause?: Error) { - super( - 'Gas estimation factor value should be a number between 0 and 1', - cause - ); - } -} -export class InvalidParameter extends SdkError { - constructor(message?: string, cause?: Error) { - super('Invalid parameter:' + message, cause); - } -} -export class NotAContractError extends SdkError { - constructor(cause?: Error) { - super('The provided address does not point to a contract', cause); +export class InvalidBitMapValueError extends SdkError { + constructor(cause?: any) { + super('The bitmap value is too big', cause); } } -export class InvalidVersionError extends SdkError { - constructor(cause?: string) { +export class InvalidBitPositionError extends SdkError { + constructor(position: number, cause?: any) { super( - 'The new version and the current version should have the same release number and the new build number should be greater than the current build number', + `Invalid bit position ${position}, minimum is 0 and maximum is 255`, cause ); } } -export class PluginUpdatePreparationError extends SdkError { - constructor(cause?: string) { - super('Failed to prepare plugin update', cause); - } -} -export class ProposalNotFoundError extends SdkError { - constructor(cause?: any) { - super('Proposal not found', cause); - } -} - -export class EmptyMultiUriError extends SdkError { - constructor(cause?: any) { - super('The multi URI is empty', cause); - } -} - -export class InvalidPromiseError extends SdkError { - constructor(cause?: any) { - super('Invalid promise', cause); - } -} - -export class InvalidTimeoutError extends SdkError { - constructor(cause?: any) { - super('Invalid timeout', cause); - } -} - -export class InvalidPermissionOperationType extends SdkError { - constructor(cause?: any) { - super('Invalid permission operation', cause); - } -} diff --git a/sdk/src/events/utils.ts b/sdk/src/events.ts similarity index 100% rename from sdk/src/events/utils.ts rename to sdk/src/events.ts diff --git a/sdk/src/events/errors.ts b/sdk/src/events/errors.ts deleted file mode 100644 index a0f60b4a..00000000 --- a/sdk/src/events/errors.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {SdkError} from '../errors'; -import {ContractReceipt} from '@ethersproject/contracts'; - -export class EventNotFoundError extends SdkError { - constructor(eventName: string, contractReceipt: ContractReceipt) { - super( - `Event "${eventName}" could not be found in transaction ${contractReceipt.transactionHash}.`, - contractReceipt - ); - } -} diff --git a/sdk/src/events/index.ts b/sdk/src/events/index.ts deleted file mode 100644 index ee262b44..00000000 --- a/sdk/src/events/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './utils'; -export * from './errors'; diff --git a/sdk/src/hex/address.ts b/sdk/src/hex/address.ts deleted file mode 100644 index a8535ad0..00000000 --- a/sdk/src/hex/address.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {ADDRESS_REGEX} from './constants'; - -/** - * Returns true if the given string is a valid Ethereum address - * - * @export - * @param {string} address - * @return {boolean} - */ -export function isAddress(address: string): boolean { - return ADDRESS_REGEX.test(address); -} diff --git a/sdk/src/hex/bytes.ts b/sdk/src/hex/bytes.ts deleted file mode 100644 index d66c9b26..00000000 --- a/sdk/src/hex/bytes.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {InvalidHexStringError, OddLengthHexStringError} from './errors'; -import {ensure0x, isHexString, strip0x} from './strings'; - -/** - * Encodes a buffer into a hex string with the "0x" prefix - * - * @export - * @param {string} hexString - * @return {Uint8Array} - */ -export function hexToBytes(hexString: string): Uint8Array { - if (hexString === '') return new Uint8Array(); - else if (!isHexString(hexString)) { - throw new InvalidHexStringError(hexString); - } else if (hexString.length % 2 !== 0) { - throw new OddLengthHexStringError(); - } - - hexString = strip0x(hexString); - const bytes = []; - for (let i = 0; i < hexString.length; i += 2) { - bytes.push(parseInt(hexString.substring(i, i + 2), 16)); - } - return Uint8Array.from(bytes); -} - -/** - * Encodes a buffer into a hex string with the "0x" prefix - * - * @export - * @param {Uint8Array} buff - * @param {boolean} [skip0x] - * @return {string} - */ -export function bytesToHex(buff: Uint8Array, skip0x?: boolean): string { - const bytes: string[] = []; - for (let i = 0; i < buff.length; i++) { - if (buff[i] >= 16) bytes.push(buff[i].toString(16)); - else bytes.push('0' + buff[i].toString(16)); - } - if (skip0x) return bytes.join(''); - return ensure0x(bytes.join('')); -} diff --git a/sdk/src/hex/constants.ts b/sdk/src/hex/constants.ts deleted file mode 100644 index 73e734a9..00000000 --- a/sdk/src/hex/constants.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const HEX_STRING_REGEX = /^(0x)?[0-9a-fA-F]*$/; -export const OSX_EXTENDED_PROPOSAL_ID_REGEX = - /^(0x[A-Fa-f0-9]{40})_(0x[A-Fa-f0-9]{64})$/; -export const OSX_COMPACT_PROPOSAL_ID_REGEX = - /^(0x[A-Fa-f0-9]{40})_(0x[A-Fa-f0-9]{1,64})$/; -export const ADDRESS_REGEX = /^0x[A-Fa-f0-9]{40}$/; diff --git a/sdk/src/hex/errors.ts b/sdk/src/hex/errors.ts deleted file mode 100644 index 3400a502..00000000 --- a/sdk/src/hex/errors.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {SdkError} from '../errors'; - -export class InvalidHexStringError extends SdkError { - constructor(hexString: string, cause?: Error) { - super(`"${hexString}" is not a valid hex string.`, cause); - } -} - -export class OddLengthHexStringError extends SdkError { - constructor(cause?: Error) { - super('The hex string has an odd length', cause); - } -} - -export class InvalidAddressError extends SdkError { - constructor(address: string, cause?: Error) { - super(`"${address}" is not a valid Ethereum address.`, cause); - } -} - -export class InvalidProposalIdError extends SdkError { - constructor(proposalId: string, cause?: Error) { - super(`"${proposalId}" is not a valid proposal id.`, cause); - } -} diff --git a/sdk/src/hex/index.ts b/sdk/src/hex/index.ts deleted file mode 100644 index 8af86633..00000000 --- a/sdk/src/hex/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './proposal'; -export * from './errors'; -export * from './address'; -export * from './bytes'; -export * from './constants'; -export * from './strings'; diff --git a/sdk/src/hex/proposal.ts b/sdk/src/hex/proposal.ts deleted file mode 100644 index 1954361b..00000000 --- a/sdk/src/hex/proposal.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - OSX_COMPACT_PROPOSAL_ID_REGEX, - OSX_EXTENDED_PROPOSAL_ID_REGEX, -} from './constants'; - -/** - * Checks if a given string has the extended proposal id format used in subgraph - * - * @export - * @param {string} proposalId - * @return {boolean} - */ -export function isExtendedProposalId(proposalId: string): boolean { - return OSX_EXTENDED_PROPOSAL_ID_REGEX.test(proposalId); -} - -/** - * Checks if a given string has the compact proposal id format used in the App and SDK - * - * @export - * @param {string} proposalId - * @return {boolean} - */ -export function isProposalId(proposalId: string): boolean { - return OSX_COMPACT_PROPOSAL_ID_REGEX.test(proposalId); -} diff --git a/sdk/src/hex/strings.ts b/sdk/src/hex/strings.ts deleted file mode 100644 index f14dcd59..00000000 --- a/sdk/src/hex/strings.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {HEX_STRING_REGEX} from './constants'; - -/** - * Checks if a string is a valid hex string - * - * @export - * @param {string} value - * @return {boolean} - */ -export function isHexString(value: string): boolean { - return HEX_STRING_REGEX.test(value); -} - -/** - * Ensures that a hex string has the "0x" prefix - * - * @export - * @param {string} value - * @return {string} - */ -export function ensure0x(value: string): string { - return value.startsWith('0x') ? value : '0x' + value; -} - -/** - * Strips the "0x" prefix from a hex string - * - * @export - * @param {string} value - * @return {string} - */ -export function strip0x(value: string): string { - return value.startsWith('0x') ? value.substring(2) : value; -} diff --git a/sdk/src/index.ts b/sdk/src/index.ts index 944370f7..6ee2a458 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -1,23 +1,11 @@ -export * from './constants'; -export * from './types'; -export * from './validation'; -export * from './multiuri'; -export * from './ipfs'; -export * from './metadata'; -export * from './interfaces'; -export * from './promises'; -export * from './errors'; - -// SDK - -// From OSX export * from './bitmap'; +export * from './ens'; +export * from './errors'; export * from './events'; -export * from './math'; +export * from './introspection'; +export * from './ipfs'; +export * from './metadata'; export * from './permission'; export * from './proposal'; +export * from './ratio'; export * from './time'; - -export * from './ens'; -export * from './plugin'; -export * from './hex'; diff --git a/sdk/src/interfaces.ts b/sdk/src/introspection.ts similarity index 82% rename from sdk/src/interfaces.ts rename to sdk/src/introspection.ts index 8e6825ac..aaa1664f 100644 --- a/sdk/src/interfaces.ts +++ b/sdk/src/introspection.ts @@ -1,5 +1,5 @@ import {Interface} from '@ethersproject/abi'; -import {Zero} from '@ethersproject/constants'; +import {BigNumber} from '@ethersproject/bignumber'; /** * Gets the interfaceId of a given interface @@ -9,7 +9,7 @@ import {Zero} from '@ethersproject/constants'; * @return {*} {string} */ export function getInterfaceId(iface: Interface): string { - let interfaceId = Zero; + let interfaceId = BigNumber.from(0); const functions: string[] = Object.keys(iface.functions); for (const func of functions) { interfaceId = interfaceId.xor(iface.getSighash(func)); diff --git a/sdk/src/ipfs.ts b/sdk/src/ipfs.ts index 2739b9bd..c188e3f4 100644 --- a/sdk/src/ipfs.ts +++ b/sdk/src/ipfs.ts @@ -1,6 +1,12 @@ -import {BytesLike, ethers} from 'ethers'; import IPFS from 'ipfs-http-client'; +const IPFS_CID_REGEX = + /^((Qm[1-9A-HJ-NP-Za-km-z]{44,})|(b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,})|(z[1-9A-HJ-NP-Za-km-z]{48,})|(F[0-9A-F]{50,}))$/; + +const IPFS_URI_REGEX = + /^ipfs:\/\/((Qm[1-9A-HJ-NP-Za-km-z]{44,})|(b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,})|(z[1-9A-HJ-NP-Za-km-z]{48,})|(F[0-9A-F]{50,}))$/; + +// TODO Revisit export async function uploadToIPFS(content: string): Promise { const client = IPFS.create({ url: 'https://prod.ipfs.aragon.network/api/v0', @@ -14,6 +20,23 @@ export async function uploadToIPFS(content: string): Promise { return res.cid.toString(); } -export function toHex(input: string): BytesLike { - return ethers.utils.hexlify(ethers.utils.toUtf8Bytes(input)); +/** + * Checks if the given string is a valid IPFS CID + * + * @export + * @param {string} cid + * @return {*} {string} + */ +export function isIpfsCid(cid: string): boolean { + return IPFS_CID_REGEX.test(cid); +} +/** + * Checks if the given string is a valid IPFS URI + * + * @export + * @param {string} cid + * @return {*} {boolean} + */ +export function isIpfsUri(cid: string): boolean { + return IPFS_URI_REGEX.test(cid); } diff --git a/sdk/src/math.ts b/sdk/src/math.ts deleted file mode 100644 index c693b32b..00000000 --- a/sdk/src/math.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {BigNumber} from '@ethersproject/bignumber'; - -export const RATIO_BASE = BigNumber.from(10).pow(6); // 100% => 10**6 -export const pctToRatio = (x: number) => RATIO_BASE.mul(x).div(100); diff --git a/sdk/src/metadata.ts b/sdk/src/metadata.ts index 01eb9365..a2367fe4 100644 --- a/sdk/src/metadata.ts +++ b/sdk/src/metadata.ts @@ -1,4 +1,10 @@ -import {MetadataAbiInput} from './types'; +export type MetadataAbiInput = { + name: string; + type: string; + internalType: string; + description: string; + components?: MetadataAbiInput[]; +}; /** * Gets the named types from a metadata abi input diff --git a/sdk/src/multiuri.ts b/sdk/src/multiuri.ts deleted file mode 100644 index 243b38ae..00000000 --- a/sdk/src/multiuri.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {IPFS_CID_REGEX} from './constants'; -import {EmptyMultiUriError} from './errors'; - -/** - * Parses a multi URI and returns the IPFS or HTTP URI. - * - * @export - * @class MultiUri - */ -export class MultiUri { - readonly items: string[] = []; - - constructor(multiUri: string) { - if (!multiUri) throw new EmptyMultiUriError(); - this.items = multiUri.split(','); - } - - get ipfsCid() { - for (let item of this.items) { - if (IPFS_CID_REGEX.test(item)) return item; - else if (item.startsWith('ipfs://')) { - item = item.substring(7); - } - const idx = item.indexOf('/'); - const cid = idx < 0 ? item : item.substring(0, idx); - - if (!IPFS_CID_REGEX.test(cid)) continue; - return cid; - } - return null; - } - get ipfs() { - for (let item of this.items) { - if (IPFS_CID_REGEX.test(item)) return {cid: item, path: ''}; - else if (item.startsWith('ipfs://')) { - item = item.substring(7); - } - const pathIdx = item.indexOf('/'); - - let cid = item; - if (pathIdx < 0) { - if (!IPFS_CID_REGEX.test(cid)) continue; - return {cid, path: ''}; - } - cid = item.substring(0, pathIdx); - if (!IPFS_CID_REGEX.test(cid)) continue; - - let searchIdx = item.indexOf('?'); - if (searchIdx < 0) searchIdx = item.indexOf('#'); - - if (searchIdx < 0) { - return { - cid, - path: item.substring(pathIdx), - }; - } - - return { - cid, - path: item.substring(pathIdx, searchIdx), - }; - } - return null; - } - get http() { - return this.items.filter( - item => item.startsWith('http://') || item.startsWith('https://') - ); - } -} diff --git a/sdk/src/permission.ts b/sdk/src/permission.ts index 569b73ac..a6f9731e 100644 --- a/sdk/src/permission.ts +++ b/sdk/src/permission.ts @@ -1,6 +1,12 @@ -import {ADDRESS} from './constants'; import {id} from '@ethersproject/hash'; +/** + * Enum for PermissionType + * Reference: + * + * @export + * @enum {number} + */ export enum Operation { Grant = 0, Revoke = 1, @@ -8,12 +14,35 @@ export enum Operation { } export const PERMISSION_MANAGER_FLAGS = { - UNSET_FLAG: ADDRESS.ZERO, - ALLOW_FLAG: ADDRESS.TWO, - ANY_ADDR: ADDRESS.LAST, - NO_CONDITION: ADDRESS.ZERO, + UNSET_FLAG: `0x${'0'.repeat(40)}`, // address(0) + ALLOW_FLAG: `0x${'0'.repeat(39)}2`, // address(2) + ANY_ADDR: `0x${'f'.repeat(40)}`, // address(-1) + NO_CONDITION: `0x${'0'.repeat(40)}`, // address(0) }; +/** + * Permission IDs for ENS registrar + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/src/framework/utils/ens/ENSSubdomainRegistrar.sol + */ +export const ENS_REGISTRAR_PERMISSIONS = { + UPGRADE_REGISTRAR_PERMISSION_ID: id('UPGRADE_REGISTRAR_PERMISSION'), + REGISTER_ENS_SUBDOMAIN_PERMISSION_ID: id('REGISTER_ENS_SUBDOMAIN_PERMISSION'), +}; + +/** + * Permission IDs for DAO registry + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/src/framework/dao/DAORegistry.sol + */ +export const DAO_REGISTRY_PERMISSIONS = { + UPGRADE_REGISTRY_PERMISSION_ID: id('UPGRADE_REGISTRY_PERMISSION'), + REGISTER_DAO_PERMISSION_ID: id('REGISTER_DAO_PERMISSION'), + ENS_REGISTRAR_PERMISSIONS, +}; + +/** + * Permission IDs for DAO + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/src/core/dao/DAO.sol + */ export const DAO_PERMISSIONS = { ROOT_PERMISSION_ID: id('ROOT_PERMISSION'), EXECUTE_PERMISSION_ID: id('EXECUTE_PERMISSION'), @@ -29,35 +58,39 @@ export const DAO_PERMISSIONS = { VALIDATE_SIGNATURE_PERMISSION_ID: id('VALIDATE_SIGNATURE_PERMISSION'), }; +/** + * Permission IDs for Plugin registry + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/test/framework/plugin/plugin-repo-registry.ts + */ +export const PLUGIN_REGISTRY_PERMISSIONS = { + UPGRADE_REGISTRY_PERMISSION_ID: id('UPGRADE_REGISTRY_PERMISSION'), + REGISTER_PLUGIN_REPO_PERMISSION_ID: id('REGISTER_PLUGIN_REPO_PERMISSION'), + ENS_REGISTRAR_PERMISSIONS, +}; + +/** + * Permission IDs for Plugin UUPS upgradeable + */ export const PLUGIN_UUPS_UPGRADEABLE_PERMISSIONS = { UPGRADE_PLUGIN_PERMISSION_ID: id('UPGRADE_PLUGIN_PERMISSION'), }; +/** + * Permission IDs for plugin repo + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/src/framework/plugin/repo/PluginRepo.sol + */ export const PLUGIN_REPO_PERMISSIONS = { ROOT_PERMISSION_ID: id('ROOT_PERMISSION'), MAINTAINER_PERMISSION_ID: id('MAINTAINER_PERMISSION'), UPGRADE_REPO_PERMISSION_ID: id('UPGRADE_REPO_PERMISSION'), }; +/** + * Permission IDs for Plugin setup processor + * Reference: https://github.com/aragon/osx/blob/736187bed3302fb56fadd04f091a5f68ae134518/packages/contracts/src/framework/plugin/setup/PluginSetupProcessor.sol + */ export const PLUGIN_SETUP_PROCESSOR_PERMISSIONS = { APPLY_INSTALLATION_PERMISSION_ID: id('APPLY_INSTALLATION_PERMISSION'), APPLY_UPDATE_PERMISSION_ID: id('APPLY_UPDATE_PERMISSION'), APPLY_UNINSTALLATION_PERMISSION_ID: id('APPLY_UNINSTALLATION_PERMISSION'), }; - -export const ENS_REGISTRAR_PERMISSIONS = { - UPGRADE_REGISTRAR_PERMISSION_ID: id('UPGRADE_REGISTRAR_PERMISSION'), - REGISTER_ENS_SUBDOMAIN_PERMISSION_ID: id('REGISTER_ENS_SUBDOMAIN_PERMISSION'), -}; - -export const PLUGIN_REGISTRY_PERMISSIONS = { - UPGRADE_REGISTRY_PERMISSION_ID: id('UPGRADE_REGISTRY_PERMISSION'), - REGISTER_PLUGIN_REPO_PERMISSION_ID: id('REGISTER_PLUGIN_REPO_PERMISSION'), - ENS_REGISTRAR_PERMISSIONS, -}; - -export const DAO_REGISTRY_PERMISSIONS = { - UPGRADE_REGISTRY_PERMISSION_ID: id('UPGRADE_REGISTRY_PERMISSION'), - REGISTER_DAO_PERMISSION_ID: id('REGISTER_DAO_PERMISSION'), - ENS_REGISTRAR_PERMISSIONS, -}; diff --git a/sdk/src/plugin/errors.ts b/sdk/src/plugin/errors.ts deleted file mode 100644 index 04e62607..00000000 --- a/sdk/src/plugin/errors.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {SdkError} from '../errors'; - -export class InvalidRatioValueError extends SdkError { - constructor(ratio: number, cause?: any) { - super( - `The ratio value should range between 0 and 1, received value: ${ratio}`, - cause - ); - } -} - -export class InvalidDigitsValueError extends SdkError { - constructor(digits: number, cause?: any) { - super( - `The number of digits should range between 1 and 15, received value: ${digits}`, - cause - ); - } -} - -export class ValueOutOfRangeError extends SdkError { - constructor(cause?: any) { - super(`The value is out of range`, cause); - } -} diff --git a/sdk/src/plugin/index.ts b/sdk/src/plugin/index.ts deleted file mode 100644 index 5ba475e0..00000000 --- a/sdk/src/plugin/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './utils'; -export * from './errors'; -export * from './proposal'; diff --git a/sdk/src/plugin/proposal.ts b/sdk/src/plugin/proposal.ts deleted file mode 100644 index f02b4f0c..00000000 --- a/sdk/src/plugin/proposal.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - InvalidAddressError, - InvalidProposalIdError, - OSX_COMPACT_PROPOSAL_ID_REGEX, - isAddress, - isExtendedProposalId, - isProposalId, - strip0x, -} from '../hex'; -import {hexZeroPad} from '@ethersproject/bytes'; - -/** - * Encodes the particles of a proposalId into a globally unique value for subgraph - * - * @export - * @param {string} pluginAddress - * @param {number} id - * @return {string} - */ -export function encodeProposalId(pluginAddress: string, id: number) { - if (!isAddress(pluginAddress)) { - throw new InvalidAddressError(pluginAddress); - } - return `${pluginAddress}_0x${id.toString(16)}`; -} - -/** - * Decodes a proposalId from subgraph and returns the original pluginAddress and the nonce - * - * @export - * @param {string} proposalId - * @return {string} pluginAddress - * @return {number} id - */ -export function decodeProposalId(proposalId: string): { - pluginAddress: string; - id: number; -} { - if (!isProposalId(proposalId)) { - throw new InvalidProposalIdError(proposalId); - } - - const matchedRegexResult = - proposalId.match(OSX_COMPACT_PROPOSAL_ID_REGEX) || []; - if (matchedRegexResult.length !== 3) { - throw new InvalidProposalIdError(proposalId); - } - - const pluginAddress = matchedRegexResult[1]; - const hexProposalNonce = matchedRegexResult[2]; - - return { - pluginAddress, - id: parseInt(strip0x(hexProposalNonce), 16), - }; -} - -/** - * Gets the extended version of a proposal id from the compact one - * - * @export - * @param {string} proposalId - * @returns {string} - */ -export const getExtendedProposalId = (proposalId: string): string => { - if (!isProposalId(proposalId)) { - throw new InvalidProposalIdError(proposalId); - } - const splits = proposalId.split('_'); - return splits[0].toLowerCase() + '_' + hexZeroPad(splits[1], 32); -}; - -/** - * Gets the compact version of a proposal id from the extended one - * - * @export - * @param {string} proposalId - * @returns {string} - */ -export const getCompactProposalId = (proposalId: string): string => { - if (!isExtendedProposalId(proposalId)) { - throw new InvalidProposalIdError(proposalId); - } - const splits = proposalId.split('_'); - return splits[0].toLowerCase() + '_0x' + parseInt(splits[1]).toString(16); -}; diff --git a/sdk/src/promises.ts b/sdk/src/promises.ts deleted file mode 100644 index 7cdcf487..00000000 --- a/sdk/src/promises.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {InvalidPromiseError, InvalidTimeoutError, TimeoutError} from './errors'; - -/** - * Run a promise with a timeout - * - * @export - * @template T - * @param {Promise} prom The promise to track - * @param {number} timeout Timeout (in milliseconds) to wait before failing - * @param {string} [timeoutMessage] (optional) Message to use when throwing a timeout error. By default: `"Time out"` - * @return {*} {Promise} - */ -export function promiseWithTimeout( - prom: Promise, - timeout: number, - timeoutMessage?: string -): Promise { - if ( - !prom || - typeof prom.then !== 'function' || - typeof prom.catch !== 'function' - ) { - throw new InvalidPromiseError(); - } else if (isNaN(timeout) || timeout < 0) throw new InvalidTimeoutError(); - - return new Promise((resolve, reject) => { - setTimeout( - () => reject(new TimeoutError(timeoutMessage || 'Time out')), - timeout - ); - - return prom.then(result => resolve(result)).catch(err => reject(err)); - }); -} - -/** - * Run a promise and retry it until it succeeds or the `shouldRetry` function returns false - * - * @export - * @template T - * @param {{ - * func: () => Promise; - * onFail?: (e: Error) => void; - * shouldRetry: () => boolean; - * }} { func, onFail, shouldRetry } - * @return {*} - */ -export async function runAndRetry({ - func, - onFail, - shouldRetry, -}: { - func: () => Promise; - onFail?: (e: Error) => void; - shouldRetry: () => boolean; -}) { - let lastErr: Error; - do { - try { - const result = await func(); - // it worked - return result; - } catch (err) { - lastErr = err as Error; - if (typeof onFail === 'function') { - onFail(err as Error); - } - } - } while (shouldRetry()); - - // all the iterations failed - throw lastErr; -} diff --git a/sdk/src/proposal.ts b/sdk/src/proposal.ts index 98f3c472..90581730 100644 --- a/sdk/src/proposal.ts +++ b/sdk/src/proposal.ts @@ -1,3 +1,10 @@ +/** + * Convert a proposalId to a bytes32 string. + * + * @export + * @param {number} proposalId + * @return {*} {string} + */ export function proposalIdToBytes32(proposalId: number): string { const hex = proposalId.toString(16); return `0x${'0'.repeat(64 - hex.length)}${hex}`; diff --git a/sdk/src/plugin/utils.ts b/sdk/src/ratio.ts similarity index 70% rename from sdk/src/plugin/utils.ts rename to sdk/src/ratio.ts index ed08b935..c7f2bdf7 100644 --- a/sdk/src/plugin/utils.ts +++ b/sdk/src/ratio.ts @@ -3,6 +3,23 @@ import { InvalidRatioValueError, ValueOutOfRangeError, } from './errors'; +import {BigNumber} from '@ethersproject/bignumber'; + +/** + * The base ratio used for percentage calculations (10^6) + */ +export const RATIO_BASE = BigNumber.from(10).pow(6); // 100% => 10**6 + +/** + * Converts a percentage to a ratio using the ratio base (10^6) + * 100.0000% -> 1_000_000 + * 99.9999% -> 999_999 + * 0.0001% -> 1 + * 0.0000% -> 0 + * @param x + * @returns BigNumber + */ +export const pctToRatio = (x: number) => RATIO_BASE.mul(x).div(100); /** * Encodes a 0-1 ratio within the given digit precision for storage on a smart contract diff --git a/sdk/src/time.ts b/sdk/src/time.ts index b7f697c6..836fbbae 100644 --- a/sdk/src/time.ts +++ b/sdk/src/time.ts @@ -1,3 +1,4 @@ +// Time-related constants. export const TIME = { SECOND: 1, get MINUTE() { @@ -15,23 +16,4 @@ export const TIME = { get YEAR() { return 365 * this.DAY; }, - - toMilliseconds(seconds: number) { - return seconds * 1000; - }, - get SECOND_MS() { - return this.toMilliseconds(this.SECOND); - }, - get HOUR_MS() { - return this.toMilliseconds(this.HOUR); - }, - get DAY_MS() { - return this.toMilliseconds(this.DAY); - }, - get WEEK_MS() { - return this.toMilliseconds(this.WEEK); - }, - get YEAR_MS() { - return this.toMilliseconds(this.YEAR); - }, }; diff --git a/sdk/src/types.ts b/sdk/src/types.ts deleted file mode 100644 index e3f987cc..00000000 --- a/sdk/src/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Contains the supported plugin types - */ -export enum PluginType { - UUPS = 0, - Cloneable = 1, - Constructable = 2, -} - -/** - * Contains the payload passed to governance contracts, serializing - * the actions to do upon approval - */ - -export type MetadataAbiInput = { - name: string; - type: string; - internalType: string; - description: string; - components?: MetadataAbiInput[]; -}; - -export type VersionTag = { - build: number; - release: number; -}; - -export enum PermissionOperationType { - GRANT = 0, - REVOKE = 1, - GRANT_WITH_CONDITION = 2, -} - -export type SingleTargetPermission = { - operation: PermissionOperationType; - who: string; - permissionId: string; -}; - -export type MultiTargetPermission = { - operation: PermissionOperationType; - where: string; - who: string; - condition?: string; - permissionId: string; -}; diff --git a/sdk/src/validation.ts b/sdk/src/validation.ts deleted file mode 100644 index e83bee43..00000000 --- a/sdk/src/validation.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ENS_REGEX, IPFS_URI_REGEX, SUBDOMAIN_REGEX} from './constants'; -import {InvalidCidError} from './errors'; -import {MultiUri} from './multiuri'; - -/** - * Attempts to parse the given string as a URL and returns the IPFS CiD contained in it. - * Alternatively it tries to use the raw value after validating it. - * - * @export - * @param {string} data - * @return {*} {string} - */ -export function resolveIpfsCid(data: string): string { - const uri = new MultiUri(data); - const cid = uri.ipfsCid; - if (!cid) { - throw new InvalidCidError(); - } - return cid; -} - -/** - * Checks if the given string is a valid ENS name - * - * @export - * @param {string} name - * @return {*} {boolean} - */ -export function isEnsName(name: string): boolean { - const regex = new RegExp(ENS_REGEX); - return regex.test(name); -} - -/** - * Checks if the given string is a valid IPFS URI - * - * @export - * @param {string} cid - * @return {*} {boolean} - */ -export function isIpfsUri(cid: string): boolean { - const regex = new RegExp(IPFS_URI_REGEX); - return regex.test(cid); -} - -/** - * Checks if the given string is a valid subdomain - * - * @export - * @param {string} name - * @return {*} {boolean} - */ -export function isSubdomain(name: string): boolean { - const regex = new RegExp(SUBDOMAIN_REGEX); - return regex.test(name); -} diff --git a/sdk/test/constants.ts b/sdk/test/constants.ts index 66453eba..22cf5b97 100644 --- a/sdk/test/constants.ts +++ b/sdk/test/constants.ts @@ -1,21 +1,5 @@ import {MetadataAbiInput} from '../src'; -export const TEST_WALLET = - '0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e'; -export const TEST_WALLET_ADDRESS = '0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199'; -export const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; -export const ADDRESS_ONE = '0x0000000000000000000000000000000000000001'; - -export const web3endpoints = { - working: ['https://cloudflare-eth.com/'], - failing: ['https://bad-url-gateway.io/'], -}; - -export const DEFAULT_IPFS_ENDPOINTS = [ - 'https://prod.ipfs.aragon.network/api/v0/', - 'https://test.ipfs.aragon.network/api/v0/', -]; - export const TEST_ABI: MetadataAbiInput[] = [ { name: 'a', @@ -109,10 +93,6 @@ export const TEST_ABI: MetadataAbiInput[] = [ }, ]; -export const TEST_ADDRESS = '0x0000000000000000000000000000000000000001'; -export const TEST_INVALID_ADDRESS = - '0x000000000000000000000000000000000000000P'; - export const TEST_ENS_NAME = 'subdomain.test.eth'; export const TEST_INVALID_ENS_NAME = 'test.invalid'; @@ -127,28 +107,6 @@ export const TEST_INVALID_IPFS_CID = '1nv4l1d_c1d'; export const TEST_INVALID_IPFS_URI = `ipfs://${TEST_INVALID_IPFS_CID}`; export const TEST_HTTP_URI = 'https://test.com'; -export const TEST_INVALID_HTTP_URI = 'https://te?st.com-invalid'; export const TEST_SUBDOMAIN = 'test'; export const TEST_INVALID_SUBDOMAIN = 'test.invalid'; -export const ERC165_ABI = [ - { - inputs: [ - { - internalType: 'bytes4', - name: 'interfaceId', - type: 'bytes4', - }, - ], - name: 'supportsInterface', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, -]; diff --git a/sdk/test/unit/bitmap.test.ts b/sdk/test/unit/bitmap.test.ts index eeb12484..aba19dd1 100644 --- a/sdk/test/unit/bitmap.test.ts +++ b/sdk/test/unit/bitmap.test.ts @@ -4,7 +4,7 @@ import { getBit, boolArrayToBitmap, InvalidBitPositionError, -} from '../../src/bitmap'; +} from '../../src'; import {getEmpty256Array} from '../utils'; import {BigNumber} from '@ethersproject/bignumber'; diff --git a/sdk/test/unit/ens.test.ts b/sdk/test/unit/ens.test.ts index 15dfeae9..a5b364d9 100644 --- a/sdk/test/unit/ens.test.ts +++ b/sdk/test/unit/ens.test.ts @@ -1,5 +1,16 @@ -import {InvalidEnsError, resolveEnsName} from '../../src'; -import {ADDRESS_ONE, TEST_ENS_NAME, TEST_HTTP_URI} from '../constants'; +import { + InvalidEnsError, + isEnsName, + isSubdomain, + resolveEnsName, +} from '../../src'; +import { + TEST_ENS_NAME, + TEST_HTTP_URI, + TEST_INVALID_ENS_NAME, + TEST_INVALID_SUBDOMAIN, + TEST_SUBDOMAIN, +} from '../constants'; import {JsonRpcProvider} from '@ethersproject/providers'; describe('ens', () => { @@ -9,7 +20,7 @@ describe('ens', () => { { input: TEST_ENS_NAME, network: 'mainnet', - output: ADDRESS_ONE, + output: `0x${'0'.repeat(39)}1`, }, { input: TEST_HTTP_URI, @@ -37,7 +48,7 @@ describe('ens', () => { { input: TEST_ENS_NAME, network: 'mainnet', - output: ADDRESS_ONE, + output: `0x${'0'.repeat(39)}1`, }, { input: TEST_HTTP_URI, @@ -62,4 +73,22 @@ describe('ens', () => { } }); }); + describe('isSubdomain', () => { + const inputs = [ + {in: TEST_SUBDOMAIN, out: true}, + {in: TEST_INVALID_SUBDOMAIN, out: false}, + ]; + for (const input of inputs) { + expect(isSubdomain(input.in)).toBe(input.out); + } + }); + describe('isEnsName', () => { + const inputs = [ + {in: TEST_ENS_NAME, out: true}, + {in: TEST_INVALID_ENS_NAME, out: false}, + ]; + for (const input of inputs) { + expect(isEnsName(input.in)).toBe(input.out); + } + }); }); diff --git a/sdk/test/unit/hex/address.test.ts b/sdk/test/unit/hex/address.test.ts deleted file mode 100644 index 8957a1ce..00000000 --- a/sdk/test/unit/hex/address.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {isAddress} from '../../../src'; -import { - ADDRESS_ONE, - ADDRESS_ZERO, - TEST_ENS_NAME, - TEST_WALLET, - TEST_WALLET_ADDRESS, -} from '../../constants'; - -describe('hex/address', () => { - describe('isAddress', () => { - it('should validate addresses', () => { - const tests = [ - {input: '0x', output: false}, - {input: '0x0', output: false}, - {input: ADDRESS_ZERO, output: true}, - {input: ADDRESS_ONE, output: true}, - {input: TEST_WALLET_ADDRESS, output: true}, - {input: TEST_WALLET, output: false}, - {input: TEST_ENS_NAME, output: false}, - ]; - for (const test of tests) { - expect(isAddress(test.input)).toBe(test.output); - } - }); - }); -}); diff --git a/sdk/test/unit/hex/bytes.test.ts b/sdk/test/unit/hex/bytes.test.ts deleted file mode 100644 index ae6ac664..00000000 --- a/sdk/test/unit/hex/bytes.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {bytesToHex, hexToBytes} from '../../../src'; - -describe('hex/bytes', () => { - describe('hexToBytes', () => { - it('Should convert hex strings to a buffer', () => { - const tests = [ - {hex: '0x00', serializedBuffer: '0'}, - {hex: '0x10', serializedBuffer: '16'}, - {hex: '0xff', serializedBuffer: '255'}, - {hex: '0xffffffff', serializedBuffer: '255,255,255,255'}, - { - hex: '0xaaaaaaaaaaaaaaaa', - serializedBuffer: '170,170,170,170,170,170,170,170', - }, - {hex: '00', serializedBuffer: '0'}, - {hex: '0x', serializedBuffer: ''}, - {hex: '10', serializedBuffer: '16'}, - {hex: 'ff', serializedBuffer: '255'}, - {hex: 'ffffffff', serializedBuffer: '255,255,255,255'}, - { - hex: 'aaaaaaaaaaaaaaaa', - serializedBuffer: '170,170,170,170,170,170,170,170', - }, - ]; - - for (const test of tests) { - const result = hexToBytes(test.hex); - expect(result.join(',')).toEqual(test.serializedBuffer); - } - }); - }); - describe('bytesToHex', () => { - it("Should convert Uint8Array's into hex strings", () => { - const items = [ - {buffer: new Uint8Array([]), skip0x: false, output: '0x'}, - {buffer: new Uint8Array([]), skip0x: true, output: ''}, - {buffer: new Uint8Array([0]), skip0x: false, output: '0x00'}, - {buffer: new Uint8Array([0]), skip0x: true, output: '00'}, - {buffer: new Uint8Array([1]), skip0x: false, output: '0x01'}, - {buffer: new Uint8Array([1]), skip0x: true, output: '01'}, - { - buffer: new Uint8Array([ - 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 250, 255, - ]), - skip0x: false, - output: '0x0a141e28323c46505a64c8faff', - }, - { - buffer: new Uint8Array([ - 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 250, 255, - ]), - skip0x: true, - output: '0a141e28323c46505a64c8faff', - }, - { - buffer: new Uint8Array([100, 100, 100, 100, 100, 100]), - skip0x: false, - output: '0x646464646464', - }, - { - buffer: new Uint8Array([100, 100, 100, 100, 100, 100]), - skip0x: true, - output: '646464646464', - }, - {buffer: new Uint8Array([0, 255]), skip0x: false, output: '0x00ff'}, - {buffer: new Uint8Array([0, 255]), skip0x: true, output: '00ff'}, - ]; - - for (const item of items) { - const hex = bytesToHex(item.buffer, item.skip0x); - expect(hex).toEqual(item.output); - } - }); - }); -}); diff --git a/sdk/test/unit/hex/proposal.test.ts b/sdk/test/unit/hex/proposal.test.ts deleted file mode 100644 index 9a273cb0..00000000 --- a/sdk/test/unit/hex/proposal.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {isProposalId, isExtendedProposalId} from '../../../src'; -import {TEST_ADDRESS} from '../../constants'; -import {hexZeroPad} from '@ethersproject/bytes'; - -const tests = [ - {input: '0x', output: false}, - {input: '0x00', output: false}, - {input: '', output: false}, - {input: TEST_ADDRESS, output: false}, - {input: `${TEST_ADDRESS}_${hexZeroPad('0x1', 32)}`, output: true}, -]; -describe('hex/proposal', () => { - describe('isExtendedProposalId', () => { - it('should validate extended proposal ids', () => { - for (const test of [ - ...tests, - {input: `${TEST_ADDRESS}_${TEST_ADDRESS}`, output: false}, - {input: `${TEST_ADDRESS}_0x1`, output: false}, - ]) { - expect(isExtendedProposalId(test.input)).toBe(test.output); - } - }); - }); - describe('isProposalId', () => { - it('should validate proposal ids', () => { - for (const test of [ - ...tests, - {input: `${TEST_ADDRESS}_${TEST_ADDRESS}`, output: true}, - {input: `${TEST_ADDRESS}_0x1`, output: true}, - ]) { - expect(isProposalId(test.input)).toBe(test.output); - } - }); - }); -}); diff --git a/sdk/test/unit/hex/strings.test.ts b/sdk/test/unit/hex/strings.test.ts deleted file mode 100644 index 4762d94a..00000000 --- a/sdk/test/unit/hex/strings.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {ensure0x, strip0x} from '../../../src'; - -describe('hex/strings', () => { - describe('ensure0x', () => { - it('Should ensure 0x prefixes', () => { - const tests = [ - // strip - {in: '0', out: '0x0'}, - {in: '00', out: '0x00'}, - {in: '1234', out: '0x1234'}, - {in: '55555555555555555555', out: '0x55555555555555555555'}, - // skip - {in: '0x1234', out: '0x1234'}, - {in: '0xabcd', out: '0xabcd'}, - {in: '0x1234567890abcdef', out: '0x1234567890abcdef'}, - ]; - - for (const test of tests) { - const result = ensure0x(test.in); - expect(result).toEqual(test.out); - } - }); - }); - describe('strip0x', () => { - it('Should strip 0x prefixes', () => { - const tests = [ - // strip - {in: '0x0', out: '0'}, - {in: '0x00', out: '00'}, - {in: '0x1234', out: '1234'}, - {in: '0x55555555555555555555', out: '55555555555555555555'}, - // skip - {in: '1234', out: '1234'}, - {in: 'abcd', out: 'abcd'}, - {in: '1234567890abcdef', out: '1234567890abcdef'}, - ]; - - for (const test of tests) { - const result = strip0x(test.in); - expect(result).toEqual(test.out); - } - }); - }); -}); diff --git a/sdk/test/unit/interfaces.test.ts b/sdk/test/unit/interfaces.test.ts deleted file mode 100644 index 1e078cbe..00000000 --- a/sdk/test/unit/interfaces.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {getInterfaceId} from '../../src/interfaces'; -import {ERC165_ABI} from '../constants'; -import {Interface} from '@ethersproject/abi'; - -describe('getInterfaceId', () => { - it('should return the interface id for an ERC165 contract', () => { - const result = getInterfaceId(new Interface(ERC165_ABI)); - // defined here: https://eips.ethereum.org/EIPS/eip-165 - expect(result).toEqual('0x01ffc9a7'); - }); -}); diff --git a/sdk/test/unit/introspection.test.ts b/sdk/test/unit/introspection.test.ts new file mode 100644 index 00000000..d2834210 --- /dev/null +++ b/sdk/test/unit/introspection.test.ts @@ -0,0 +1,16 @@ +import {getInterfaceId} from '../../src'; +import {Interface} from '@ethersproject/abi'; + +describe('introspection', () => { + describe('getInterfaceId', () => { + it('should return the correct interfaceId', () => { + const iface = new Interface([ + 'function foo()', + 'function bar()', + 'function baz()', + ]); + const interfaceId = getInterfaceId(iface); + expect(interfaceId).toEqual('0x9bb235aa'); + }); + }); +}); diff --git a/sdk/test/unit/ipfs.test.ts b/sdk/test/unit/ipfs.test.ts new file mode 100644 index 00000000..8bdb44cc --- /dev/null +++ b/sdk/test/unit/ipfs.test.ts @@ -0,0 +1,39 @@ +import {isIpfsCid, isIpfsUri} from '../../src'; +import { + TEST_INVALID_IPFS_URI, + TEST_IPFS_CID_V0, + TEST_IPFS_CID_V1, + TEST_IPFS_URI_V0, + TEST_IPFS_URI_V1, +} from '../constants'; + +describe('ipfs', () => { + describe('isIpfsUri', () => { + it('Should validate IPFS URIs V1 and V0', () => { + const inputs = [ + {in: TEST_IPFS_CID_V0, out: false}, + {in: TEST_IPFS_CID_V1, out: false}, + {in: TEST_INVALID_IPFS_URI, out: false}, + {in: TEST_IPFS_URI_V0, out: true}, + {in: TEST_IPFS_URI_V1, out: true}, + ]; + for (const input of inputs) { + expect(isIpfsUri(input.in)).toBe(input.out); + } + }); + }); + describe('isIpfsCid', () => { + it('Should validate IPFS CIDs V1 and V0', () => { + const inputs = [ + {in: TEST_IPFS_CID_V0, out: true}, + {in: TEST_IPFS_CID_V1, out: true}, + {in: TEST_INVALID_IPFS_URI, out: false}, + {in: TEST_IPFS_URI_V0, out: false}, + {in: TEST_IPFS_URI_V1, out: false}, + ]; + for (const input of inputs) { + expect(isIpfsCid(input.in)).toBe(input.out); + } + }); + }); +}); diff --git a/sdk/test/unit/metadata.test.ts b/sdk/test/unit/metadata.test.ts index c617d5e7..453ebbbb 100644 --- a/sdk/test/unit/metadata.test.ts +++ b/sdk/test/unit/metadata.test.ts @@ -1,4 +1,4 @@ -import {getNamedTypesFromMetadata} from '../../src/metadata'; +import {getNamedTypesFromMetadata} from '../../src'; import {TEST_ABI} from '../constants'; describe('Utils', () => { diff --git a/sdk/test/unit/multiuri.test.ts b/sdk/test/unit/multiuri.test.ts deleted file mode 100644 index f3321311..00000000 --- a/sdk/test/unit/multiuri.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {MultiUri} from '../../src'; -import { - TEST_HTTP_URI, - TEST_INVALID_IPFS_CID, - TEST_IPFS_CID_V0, - TEST_IPFS_URI_V0, -} from '../constants'; - -describe('MultiUri', () => { - it('Should get http and ipfs urls', () => { - const uris = [TEST_IPFS_URI_V0, TEST_HTTP_URI]; - const cid = uris[0].substring(7); - const multiuri = new MultiUri(uris.join(',')); - expect(multiuri.http.length).toBe(1); - expect(multiuri.http[0]).toBe(uris[1]); - expect(multiuri.ipfsCid).toBe(cid); - expect(multiuri.ipfs === null).toBe(false); - if (multiuri.ipfs) { - expect(multiuri.ipfs.cid).toBe(cid); - } - }); - it('Should get an ipfs cid', () => { - const cid = TEST_IPFS_CID_V0; - const multiuri = new MultiUri(cid); - expect(multiuri.http.length).toBe(0); - expect(multiuri.ipfs === null).toBe(false); - if (multiuri.ipfs) { - expect(multiuri.ipfs.cid).toBe(cid); - } - expect(multiuri.ipfsCid).toBe(cid); - }); - it('Should get an invalid ipfs cid and return an empty string', () => { - const cid = TEST_INVALID_IPFS_CID; - const multiuri = new MultiUri(cid); - expect(multiuri.http.length).toBe(0); - expect(multiuri.ipfs).toBe(null); - expect(multiuri.ipfsCid).toBe(null); - }); - it('Should get a valid ipfs uri', () => { - const uri = TEST_IPFS_URI_V0; - const cid = uri.substring(7); - const multiuri = new MultiUri(uri); - expect(multiuri.http.length).toBe(0); - expect(multiuri.ipfs === null).toBe(false); - if (multiuri.ipfs) { - expect(multiuri.ipfs.cid).toBe(cid); - } - expect(multiuri.ipfsCid).toBe(cid); - }); - it('Should get multiple http urls', () => { - const uris = [ - `${TEST_HTTP_URI}/1`, - `${TEST_HTTP_URI}/2`, - `${TEST_HTTP_URI}/3`, - ]; - const multiuri = new MultiUri(uris.join(',')); - expect(multiuri.http.length).toBe(uris.length); - for (const idx in uris) { - expect(multiuri.http[idx]).toBe(uris[idx]); - } - expect(multiuri.ipfs).toBe(null); - expect(multiuri.ipfsCid).toBe(null); - }); - it('Should get an ipfs uri with path', () => { - const uri = `${TEST_IPFS_URI_V0}/some/path`; - const pathCid = uri.substring(7); - const pathIdx = pathCid.indexOf('/'); - const cid = pathCid.substring(0, pathIdx); - const path = pathCid.substring(pathIdx); - const multiuri = new MultiUri(uri); - expect(multiuri.http.length).toBe(0); - expect(multiuri.ipfs === null).toBe(false); - if (multiuri.ipfs) { - expect(multiuri.ipfs.cid).toBe(cid); - expect(multiuri.ipfs.path).toBe(path); - } - expect(multiuri.ipfsCid).toBe(cid); - }); - it('Should get an ipfs cid with path', () => { - const pathCid = `${TEST_IPFS_CID_V0}/some/path`; - const pathIdx = pathCid.indexOf('/'); - const cid = pathCid.substring(0, pathIdx); - const path = pathCid.substring(pathIdx); - const multiuri = new MultiUri(pathCid); - expect(multiuri.http.length).toBe(0); - expect(multiuri.ipfs === null).toBe(false); - if (multiuri.ipfs) { - expect(multiuri.ipfs.cid).toBe(cid); - expect(multiuri.ipfs.path).toBe(path); - } - expect(multiuri.ipfsCid).toBe(cid); - }); -}); diff --git a/sdk/test/unit/plugin/proposal.test.ts b/sdk/test/unit/plugin/proposal.test.ts deleted file mode 100644 index cbe4a429..00000000 --- a/sdk/test/unit/plugin/proposal.test.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { - encodeProposalId, - decodeProposalId, - getCompactProposalId, - getExtendedProposalId, - InvalidProposalIdError, -} from '../../../src'; -import {ADDRESS_ONE, ADDRESS_ZERO} from '../../constants'; - -describe('plugin/proposal', () => { - describe('encodeProposalId', () => { - it('Should encode a nonce-based proposalId', () => { - const tests = [ - { - addr: ADDRESS_ZERO, - nonce: 0, - output: `${ADDRESS_ZERO}_0x0`, - }, - { - addr: ADDRESS_ZERO, - nonce: 1, - output: `${ADDRESS_ZERO}_0x1`, - }, - { - addr: ADDRESS_ONE, - nonce: 0, - output: `${ADDRESS_ONE}_0x0`, - }, - { - addr: ADDRESS_ONE, - nonce: 10, - output: `${ADDRESS_ONE}_0xa`, - }, - { - addr: ADDRESS_ONE, - nonce: 15, - output: `${ADDRESS_ONE}_0xf`, - }, - { - addr: ADDRESS_ONE, - nonce: 16, - output: `${ADDRESS_ONE}_0x10`, - }, - { - addr: ADDRESS_ONE, - nonce: 1 << 24, - output: `${ADDRESS_ONE}_0x1000000`, - }, - ]; - - for (const test of tests) { - expect(encodeProposalId(test.addr, test.nonce)).toBe(test.output); - } - }); - }); - describe('decodeProposalId', () => { - it('Should decode a nonce-based proposalId', () => { - const tests = [ - { - input: '0x0000000000000000000000000000000000000000_0x0', - addr: '0x0000000000000000000000000000000000000000', - nonce: 0, - }, - { - input: '0x0000000000000000000000000000000000000000_0x1', - addr: '0x0000000000000000000000000000000000000000', - nonce: 1, - }, - { - input: '0x1111111111111111111111111111111111111111_0x1', - addr: '0x1111111111111111111111111111111111111111', - nonce: 1, - }, - { - input: '0x1111111111111111111111111111111111111111_0xa', - addr: '0x1111111111111111111111111111111111111111', - nonce: 10, - }, - { - input: '0x1111111111111111111111111111111111111111_0xf', - addr: '0x1111111111111111111111111111111111111111', - nonce: 15, - }, - { - input: '0x1111111111111111111111111111111111111111_0x10', - addr: '0x1111111111111111111111111111111111111111', - nonce: 16, - }, - { - input: '0x1111111111111111111111111111111111111111_0x1000000', - addr: '0x1111111111111111111111111111111111111111', - nonce: 1 << 24, - }, - ]; - - for (const test of tests) { - const result = decodeProposalId(test.input); - expect(result.pluginAddress).toBe(test.addr); - expect(result.id).toBe(test.nonce); - } - }); - }); - describe('getExtendedProposalId', () => { - it('Should get an extended version of a proposal id', () => { - const tests = [ - { - in: '0x0000000000000000000000000000000000000000_0x1', - out: '0x0000000000000000000000000000000000000000_0x0000000000000000000000000000000000000000000000000000000000000001', - error: '', - }, - { - in: '0x0000000000000000000000000000000000000000_0xffff', - out: '0x0000000000000000000000000000000000000000_0x000000000000000000000000000000000000000000000000000000000000ffff', - error: '', - }, - { - in: 'invalid_proposal', - out: '', - error: InvalidProposalIdError, - }, - { - in: '0x0000000000000000000000000000000000000000_0x000000000000000000000000000000000000000000000000000000000000pppp', - out: '', - error: InvalidProposalIdError, - }, - ]; - - for (const test of tests) { - if (test.error) { - expect(() => getExtendedProposalId(test.in)).toThrow(test.error); - } else { - const result = getExtendedProposalId(test.in); - expect(result).toBe(test.out); - } - } - }); - }); - describe('getCompactProposalId', () => { - it('Should get a compact version of a proposal id', () => { - const tests = [ - { - in: '0x0000000000000000000000000000000000000000_0x0000000000000000000000000000000000000000000000000000000000000001', - out: '0x0000000000000000000000000000000000000000_0x1', - error: '', - }, - { - in: '0x0000000000000000000000000000000000000000_0x000000000000000000000000000000000000000000000000000000000000ffff', - out: '0x0000000000000000000000000000000000000000_0xffff', - error: '', - }, - { - in: '0x0000000000000000000000000000000000000000_0x1', - out: '', - error: - '"0x0000000000000000000000000000000000000000_0x1" is not a valid proposal id.', - }, - { - in: 'invalid_proposal', - out: '', - error: '"invalid_proposal" is not a valid proposal id.', - }, - { - in: '0x0000000000000000000000000000000000000000_0x000000000000000000000000000000000000000000000000000000000000pppp', - out: '', - error: - '"0x0000000000000000000000000000000000000000_0x000000000000000000000000000000000000000000000000000000000000pppp" is not a valid proposal id.', - }, - ]; - - for (const test of tests) { - if (test.error) { - expect(() => getCompactProposalId(test.in)).toThrow(test.error); - } else { - const result = getCompactProposalId(test.in); - expect(result).toBe(test.out); - } - } - }); - }); -}); diff --git a/sdk/test/unit/promises.test.ts b/sdk/test/unit/promises.test.ts deleted file mode 100644 index 6ced3def..00000000 --- a/sdk/test/unit/promises.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {promiseWithTimeout, runAndRetry} from '../../src'; - -describe('Test promise helpers', () => { - describe('runAndRetry', () => { - it('Should run and retry 3 times', async () => { - let countFunc = 0; - let countOnFail = 0; - const message = 'success'; - - const res = await runAndRetry({ - func: async () => { - countFunc++; - if (countFunc < 3) { - throw new Error(); - } else { - return message; - } - }, - onFail: () => countOnFail++, - shouldRetry: () => true, - }); - - expect(countFunc).toBe(3); - expect(res).toBe(message); - expect(countOnFail).toBe(2); - }); - it('Should run and throw', async () => { - let countRetries = 0; - await expect(async () => { - await runAndRetry({ - func: () => { - countRetries++; - throw new Error(); - }, - shouldRetry: () => countRetries < 3, - }); - }).rejects.toThrow(); - expect(countRetries).toBe(3); - }); - }); - describe('promiseWithTimeout', () => { - it('Should timeout', async () => { - const timeout = 100; - const promise = new Promise(resolve => - setTimeout(resolve, timeout * 2).unref() - ); - await expect(promiseWithTimeout(promise, timeout)).rejects.toThrow( - 'Time out' - ); - }); - it('Should not timeout', async () => { - const timeout = 100; - const promise = new Promise(resolve => - setTimeout(resolve, timeout / 2).unref() - ); - await expect( - promiseWithTimeout(promise, timeout) - ).resolves.toBeUndefined(); - }); - }); -}); diff --git a/sdk/test/unit/proposal.test.ts b/sdk/test/unit/proposal.test.ts new file mode 100644 index 00000000..998fa9b6 --- /dev/null +++ b/sdk/test/unit/proposal.test.ts @@ -0,0 +1,13 @@ +import {proposalIdToBytes32} from '../../src'; + +describe('proposal', () => { + describe('proposalIdToBytes32', () => { + it('should return the correct bytes32', () => { + const proposalId = 123; + const bytes32 = proposalIdToBytes32(proposalId); + expect(bytes32).toEqual( + '0x000000000000000000000000000000000000000000000000000000000000007b' + ); + }); + }); +}); diff --git a/sdk/test/unit/plugin/utils.test.ts b/sdk/test/unit/ratio.test.ts similarity index 95% rename from sdk/test/unit/plugin/utils.test.ts rename to sdk/test/unit/ratio.test.ts index 8451dd18..3d913548 100644 --- a/sdk/test/unit/plugin/utils.test.ts +++ b/sdk/test/unit/ratio.test.ts @@ -3,9 +3,9 @@ import { ValueOutOfRangeError, decodeRatio, encodeRatio, -} from '../../../src'; +} from '../../src'; -describe('plugin/utils', () => { +describe('ratio', () => { describe('encodeRatio', () => { it('Should encode a bigint from a float and the number of digits', () => { const tests = [ @@ -30,7 +30,7 @@ describe('plugin/utils', () => { continue; } const result = encodeRatio(test.float, test.digits); - expect(result.toString()).toEqual(test.out.toString()); + expect(result.toString()).toEqual(test.out?.toString()); } }); }); diff --git a/sdk/test/unit/time.test.ts b/sdk/test/unit/time.test.ts new file mode 100644 index 00000000..9b0c78b2 --- /dev/null +++ b/sdk/test/unit/time.test.ts @@ -0,0 +1,12 @@ +import {TIME} from '../../src'; + +describe('time', () => { + it('should return the correct time values', () => { + expect(TIME.SECOND).toEqual(1); + expect(TIME.MINUTE).toEqual(60 * TIME.SECOND); + expect(TIME.HOUR).toEqual(60 * TIME.MINUTE); + expect(TIME.DAY).toEqual(24 * TIME.HOUR); + expect(TIME.WEEK).toEqual(7 * TIME.DAY); + expect(TIME.YEAR).toEqual(365 * TIME.DAY); + }); +}); diff --git a/sdk/test/unit/validation.test.ts b/sdk/test/unit/validation.test.ts deleted file mode 100644 index 01a2b2f9..00000000 --- a/sdk/test/unit/validation.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { - InvalidCidError, - isEnsName, - isIpfsUri, - isProposalId, - isSubdomain, - resolveIpfsCid, -} from '../../src'; -import { - ADDRESS_ONE, - TEST_ENS_NAME, - TEST_INVALID_ENS_NAME, - TEST_INVALID_IPFS_CID, - TEST_INVALID_IPFS_URI, - TEST_INVALID_SUBDOMAIN, - TEST_IPFS_CID_V0, - TEST_IPFS_CID_V1, - TEST_IPFS_URI_V0, - TEST_IPFS_URI_V1, - TEST_SUBDOMAIN, -} from '../constants'; - -describe('Test Validations', () => { - describe('resolveIpfsCid', () => { - it("Should resolve IPFS CiD's", () => { - let cid = TEST_IPFS_CID_V0; - let result = resolveIpfsCid(cid); - expect(result).toEqual(cid); - - cid = TEST_IPFS_CID_V0; - result = resolveIpfsCid(cid); - expect(result).toEqual(cid); - }); - it("Should resolve IPFS URI's V0", () => { - let cid = TEST_IPFS_CID_V0; - let result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V0); - - cid = TEST_IPFS_URI_V0; - result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V0); - - cid = `${TEST_IPFS_URI_V0}/path`; - result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V0); - }); - it("Should resolve IPFS URI's V1", () => { - let cid = TEST_IPFS_CID_V1; - let result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V1); - - cid = TEST_IPFS_URI_V1; - result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V1); - - cid = `${TEST_IPFS_URI_V1}/path`; - result = resolveIpfsCid(cid); - expect(result).toEqual(TEST_IPFS_CID_V1); - }); - it('Should fail to recognize a non-IPFS origin', () => { - expect(() => resolveIpfsCid(TEST_INVALID_IPFS_CID)).toThrow( - new InvalidCidError() - ); - expect(() => resolveIpfsCid(TEST_INVALID_IPFS_URI)).toThrow( - new InvalidCidError() - ); - expect(() => resolveIpfsCid(`${TEST_INVALID_IPFS_URI}/path`)).toThrow( - new InvalidCidError() - ); - }); - }); - describe('isProposalId', () => { - it('Should recognize invalid proposal IDs', () => { - const inputs = [ - {in: '1', out: false}, - {in: '0x1', out: false}, - {in: ADDRESS_ONE + '_0x1', out: true}, - {in: ADDRESS_ONE, out: false}, - {in: '0x1_0x1', out: false}, - {in: ADDRESS_ONE + '_0x' + '0'.repeat(64), out: true}, - ]; - for (const input of inputs) { - expect(isProposalId(input.in)).toBe(input.out); - } - }); - }); - describe('isIpfsUri', () => { - const inputs = [ - {in: TEST_IPFS_CID_V0, out: false}, - {in: TEST_IPFS_CID_V1, out: false}, - {in: TEST_INVALID_IPFS_URI, out: false}, - {in: TEST_IPFS_URI_V0, out: true}, - {in: TEST_IPFS_URI_V1, out: true}, - ]; - for (const input of inputs) { - expect(isIpfsUri(input.in)).toBe(input.out); - } - }); - describe('isSubdomain', () => { - const inputs = [ - {in: TEST_SUBDOMAIN, out: true}, - {in: TEST_INVALID_SUBDOMAIN, out: false}, - ]; - for (const input of inputs) { - expect(isSubdomain(input.in)).toBe(input.out); - } - }); - describe('isEnsName', () => { - const inputs = [ - {in: TEST_ENS_NAME, out: true}, - {in: TEST_INVALID_ENS_NAME, out: false}, - ]; - for (const input of inputs) { - expect(isEnsName(input.in)).toBe(input.out); - } - }); -}); diff --git a/sdk/yarn.lock b/sdk/yarn.lock index 2e511bfe..2a4e08cc 100644 --- a/sdk/yarn.lock +++ b/sdk/yarn.lock @@ -22,30 +22,13 @@ dependencies: tslib "^2.6.2" -"@aragon/osx-ethers-v1.0.0@npm:@aragon/osx-ethers@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@aragon/osx-ethers/-/osx-ethers-1.2.1.tgz#a442048137153ed5a3ca4eff3f3927b45a5134b5" - integrity sha512-3Fscq8C9elIktiI6OT7fR5iaAvim+ghU6IUvZF3P/phvWm9roNp/GXAROhA/Vx41NQxeqmfXokgFo6KOWt4drA== - dependencies: - ethers "^5.6.2" - -"@aragon/osx-ethers@^1.3.0-rc0.4": - version "1.3.0-rc0.4" - resolved "https://registry.yarnpkg.com/@aragon/osx-ethers/-/osx-ethers-1.3.0-rc0.4.tgz#878af071e454ef068801104deae8439f0f8f1720" - integrity sha512-FDuF6LC1OLnjFK4C8+P4Wf0sORrrUQ/JtUAxL5ABVtBD8JpyyhtdWGDiv/yWIooLyC2l8aqbDLPuiYWhw1DjEQ== +"@aragon/osx-ethers@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@aragon/osx-ethers/-/osx-ethers-1.3.0.tgz#85ddd93f4448789e94154b313f9ddd8069dff568" + integrity sha512-zfLAYdgZ3SSifHiyJLkBKmoDw/IEX/yzvw6liUAa/gz7HZOsrwp3JsBJaIwB2epOnGa6vhXyWTKKZ15aJvoMaA== dependencies: ethers "^5.6.2" -"@aragon/sdk-ipfs@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@aragon/sdk-ipfs/-/sdk-ipfs-1.1.0.tgz#178ee5ce840ce40b44ba0345dd5068e1b5608f9d" - integrity sha512-2uAh/QPcmaita4AfHYV93lESzAhrmGEZ6CL7pvOH86HTkU6j7LnePvD1ly+x0hxRznTb+zgVgSPPKUn0ArPycw== - dependencies: - "@web-std/fetch" "^4.1.0" - "@web-std/file" "^3.0.2" - "@web-std/form-data" "^3.0.2" - isomorphic-unfetch "^3.1.0" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.22.5", "@babel/code-frame@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.4.tgz#03ae5af150be94392cb5c7ccd97db5a19a5da6aa" @@ -1259,7 +1242,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -1367,7 +1350,7 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/wallet@5.7.0", "@ethersproject/wallet@^5.7.0": +"@ethersproject/wallet@5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== @@ -2036,9 +2019,9 @@ undici-types "~5.26.4" "@types/node@>=13.7.0": - version "20.10.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" - integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== dependencies: undici-types "~5.26.4" @@ -2168,66 +2151,6 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@web-std/blob@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@web-std/blob/-/blob-3.0.5.tgz#391e652dd3cc370dbb32c828368a3022b4d55c9c" - integrity sha512-Lm03qr0eT3PoLBuhkvFBLf0EFkAsNz/G/AYCzpOdi483aFaVX86b4iQs0OHhzHJfN5C15q17UtDbyABjlzM96A== - dependencies: - "@web-std/stream" "1.0.0" - web-encoding "1.1.5" - -"@web-std/fetch@^4.1.0": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@web-std/fetch/-/fetch-4.2.1.tgz#692c5545787081217fce3c024708fa8979c21f9c" - integrity sha512-M6sgHDgKegcjuVsq8J6jb/4XvhPGui8uwp3EIoADGXUnBl9vKzKLk9H9iFzrPJ6fSV6zZzFWXPyziBJp9hxzBA== - dependencies: - "@web-std/blob" "^3.0.3" - "@web-std/file" "^3.0.2" - "@web-std/form-data" "^3.0.2" - "@web-std/stream" "^1.0.1" - "@web3-storage/multipart-parser" "^1.0.0" - abort-controller "^3.0.0" - data-uri-to-buffer "^3.0.1" - mrmime "^1.0.0" - -"@web-std/file@^3.0.2": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@web-std/file/-/file-3.0.3.tgz#a29b9164d34155a126d1ab2af5e5867e83c8b098" - integrity sha512-X7YYyvEERBbaDfJeC9lBKC5Q5lIEWYCP1SNftJNwNH/VbFhdHm+3neKOQP+kWEYJmosbDFq+NEUG7+XIvet/Jw== - dependencies: - "@web-std/blob" "^3.0.3" - -"@web-std/form-data@^3.0.2": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@web-std/form-data/-/form-data-3.1.0.tgz#573b40f6296e8bdba31f1bbf2db398f104ef4831" - integrity sha512-WkOrB8rnc2hEK2iVhDl9TFiPMptmxJA1HaIzSdc2/qk3XS4Ny4cCt6/V36U3XmoYKz0Md2YyK2uOZecoZWPAcA== - dependencies: - web-encoding "1.1.5" - -"@web-std/stream@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@web-std/stream/-/stream-1.0.0.tgz#01066f40f536e4329d9b696dc29872f3a14b93c1" - integrity sha512-jyIbdVl+0ZJyKGTV0Ohb9E6UnxP+t7ZzX4Do3AHjZKxUXKMs9EmqnBDQgHF7bEw0EzbQygOjtt/7gvtmi//iCQ== - dependencies: - web-streams-polyfill "^3.1.1" - -"@web-std/stream@^1.0.1": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@web-std/stream/-/stream-1.0.3.tgz#a1df4d4612990d3607f77ad17d0338c7960bbe2e" - integrity sha512-5MIngxWyq4rQiGoDAC2WhjLuDraW8+ff2LD2et4NRY933K3gL8CHlUXrh8ZZ3dC9A9Xaub8c9sl5exOJE58D9Q== - dependencies: - web-streams-polyfill "^3.1.1" - -"@web3-storage/multipart-parser@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz#6b69dc2a32a5b207ba43e556c25cc136a56659c4" - integrity sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw== - -"@zxing/text-encoding@0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" - integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== - abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -3007,13 +2930,6 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^3.1.5: - version "3.1.8" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" - integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== - dependencies: - node-fetch "^2.6.12" - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -3045,11 +2961,6 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== -data-uri-to-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" - integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== - data-urls@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" @@ -3919,11 +3830,6 @@ expect@^29.0.0, expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" -extract-files@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-9.0.0.tgz#8a7744f2437f81f5ed3250ed9f1550de902fe54a" - integrity sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ== - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -4050,15 +3956,6 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -4285,20 +4182,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -graphql-request@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-4.3.0.tgz#b934e08fcae764aa2cdc697d3c821f046cb5dbf2" - integrity sha512-2v6hQViJvSsifK606AliqiNiijb1uwWp6Re7o0RTyH+uRTv/u7Uqm2g4Fjq/LgZIzARB38RZEvVBFOQOVdlBow== - dependencies: - cross-fetch "^3.1.5" - extract-files "^9.0.0" - form-data "^3.0.0" - -graphql@^16.5.0: - version "16.8.1" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.1.tgz#1930a965bef1170603702acdb68aedd3f3cf6f07" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -4601,14 +4484,6 @@ ipfs-utils@^8.1.2, ipfs-utils@^8.1.4: react-native-fetch-api "^2.0.0" stream-to-it "^0.2.2" -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" @@ -4710,7 +4585,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.10, is-generator-function@^1.0.7: +is-generator-function@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -4829,7 +4704,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: version "1.1.12" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== @@ -4881,14 +4756,6 @@ iso-url@^1.1.5: resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-1.2.1.tgz#db96a49d8d9a64a1c889fc07cc525d093afb1811" integrity sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng== -isomorphic-unfetch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" - integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== - dependencies: - node-fetch "^2.6.1" - unfetch "^4.2.0" - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" @@ -5804,11 +5671,6 @@ mri@^1.1.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== -mrmime@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" - integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -5888,13 +5750,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^2.6.1, node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - "node-fetch@https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz": version "2.6.7" resolved "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz#1b5d62978f2ed07b99444f64f0df39f960a6d34d" @@ -6243,11 +6098,6 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -property-expr@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" - integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== - protobufjs@^6.10.2: version "6.11.4" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa" @@ -6962,11 +6812,6 @@ timeout-abort-controller@^1.1.1: abort-controller "^3.0.0" retimer "^2.0.0" -tiny-case@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" - integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== - tiny-glob@^0.2.9: version "0.2.9" resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2" @@ -6992,11 +6837,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" - integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== - tough-cookie@^4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" @@ -7014,11 +6854,6 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - ts-jest@^29.0.5: version "29.1.1" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" @@ -7189,11 +7024,6 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unfetch@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== - unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -7255,17 +7085,6 @@ util-deprecate@^1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.3: - version "0.12.5" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" - integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - which-typed-array "^1.1.2" - v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -7306,25 +7125,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-encoding@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864" - integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA== - dependencies: - util "^0.12.3" - optionalDependencies: - "@zxing/text-encoding" "0.9.0" - -web-streams-polyfill@^3.1.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -7350,14 +7150,6 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -7397,7 +7189,7 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2, which-typed-array@^1.1.9: +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: version "1.1.13" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== @@ -7512,13 +7304,3 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -yup@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/yup/-/yup-1.3.2.tgz#afffc458f1513ed386e6aaf4bcaa4e67a9e270dc" - integrity sha512-6KCM971iQtJ+/KUaHdrhVr2LDkfhBtFPRnsG1P8F4q3uUVQ2RfEM9xekpha9aA4GXWJevjM10eDcPQ1FfWlmaQ== - dependencies: - property-expr "^2.0.5" - tiny-case "^1.0.3" - toposort "^2.0.2" - type-fest "^2.19.0"