@boostxyz/sdk 2.0.0-alpha.35 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Actions/Action.cjs +1 -1
- package/dist/Actions/Action.js +4 -4
- package/dist/Actions/EventAction.cjs +1 -1
- package/dist/Actions/EventAction.js +17 -17
- package/dist/Actions/EventAction.js.map +1 -1
- package/dist/AllowLists/AllowList.cjs +1 -1
- package/dist/AllowLists/AllowList.js +5 -5
- package/dist/AllowLists/SimpleAllowList.cjs +1 -1
- package/dist/AllowLists/SimpleAllowList.js +19 -19
- package/dist/AllowLists/SimpleDenyList.cjs +1 -1
- package/dist/AllowLists/SimpleDenyList.js +3 -3
- package/dist/Auth/PassthroughAuth.cjs +1 -1
- package/dist/Auth/PassthroughAuth.js +1 -1
- package/dist/BoostCore.cjs +2 -2
- package/dist/BoostCore.cjs.map +1 -1
- package/dist/BoostCore.d.ts +14 -0
- package/dist/BoostCore.d.ts.map +1 -1
- package/dist/BoostCore.js +100 -81
- package/dist/BoostCore.js.map +1 -1
- package/dist/BoostRegistry.cjs +1 -1
- package/dist/BoostRegistry.js +31 -31
- package/dist/Budget-B0kJsZtZ.cjs +2 -0
- package/dist/Budget-B0kJsZtZ.cjs.map +1 -0
- package/dist/Budget-NtzY9H7G.js +462 -0
- package/dist/Budget-NtzY9H7G.js.map +1 -0
- package/dist/Budgets/Budget.cjs +1 -1
- package/dist/Budgets/Budget.cjs.map +1 -1
- package/dist/Budgets/Budget.d.ts +5 -4
- package/dist/Budgets/Budget.d.ts.map +1 -1
- package/dist/Budgets/Budget.js +9 -26
- package/dist/Budgets/Budget.js.map +1 -1
- package/dist/Budgets/ManagedBudget.cjs +1 -1
- package/dist/Budgets/ManagedBudget.js +34 -34
- package/dist/Budgets/ManagedBudgetWithFees.d.ts +1203 -0
- package/dist/Budgets/ManagedBudgetWithFees.d.ts.map +1 -0
- package/dist/Deployable/DeployableTarget.cjs +1 -1
- package/dist/Deployable/DeployableTarget.js +1 -1
- package/dist/Deployable/DeployableTargetWithRBAC.cjs +1 -1
- package/dist/Deployable/DeployableTargetWithRBAC.js +23 -23
- package/dist/Incentives/AllowListIncentive.cjs +1 -1
- package/dist/Incentives/AllowListIncentive.cjs.map +1 -1
- package/dist/Incentives/AllowListIncentive.d.ts +18 -0
- package/dist/Incentives/AllowListIncentive.d.ts.map +1 -1
- package/dist/Incentives/AllowListIncentive.js +48 -22
- package/dist/Incentives/AllowListIncentive.js.map +1 -1
- package/dist/Incentives/CGDAIncentive.cjs +1 -1
- package/dist/Incentives/CGDAIncentive.cjs.map +1 -1
- package/dist/Incentives/CGDAIncentive.d.ts +18 -0
- package/dist/Incentives/CGDAIncentive.d.ts.map +1 -1
- package/dist/Incentives/CGDAIncentive.js +47 -16
- package/dist/Incentives/CGDAIncentive.js.map +1 -1
- package/dist/Incentives/ERC20Incentive.cjs +1 -1
- package/dist/Incentives/ERC20Incentive.cjs.map +1 -1
- package/dist/Incentives/ERC20Incentive.d.ts +18 -0
- package/dist/Incentives/ERC20Incentive.d.ts.map +1 -1
- package/dist/Incentives/ERC20Incentive.js +58 -32
- package/dist/Incentives/ERC20Incentive.js.map +1 -1
- package/dist/Incentives/ERC20VariableCriteriaIncentive.cjs +1 -1
- package/dist/Incentives/ERC20VariableCriteriaIncentive.cjs.map +1 -1
- package/dist/Incentives/ERC20VariableCriteriaIncentive.js +29 -29
- package/dist/Incentives/ERC20VariableCriteriaIncentive.js.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.cjs +1 -1
- package/dist/Incentives/ERC20VariableIncentive.cjs.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.d.ts +18 -0
- package/dist/Incentives/ERC20VariableIncentive.d.ts.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.js +37 -11
- package/dist/Incentives/ERC20VariableIncentive.js.map +1 -1
- package/dist/Incentives/Incentive.cjs +1 -1
- package/dist/Incentives/Incentive.js +4 -4
- package/dist/Incentives/PointsIncentive.cjs +1 -1
- package/dist/Incentives/PointsIncentive.cjs.map +1 -1
- package/dist/Incentives/PointsIncentive.d.ts +18 -0
- package/dist/Incentives/PointsIncentive.d.ts.map +1 -1
- package/dist/Incentives/PointsIncentive.js +49 -23
- package/dist/Incentives/PointsIncentive.js.map +1 -1
- package/dist/{SimpleDenyList-wDvsNIuY.cjs → SimpleDenyList-B65fnca2.cjs} +2 -2
- package/dist/{SimpleDenyList-wDvsNIuY.cjs.map → SimpleDenyList-B65fnca2.cjs.map} +1 -1
- package/dist/{SimpleDenyList-D-rGBaay.js → SimpleDenyList-UvXQl2vm.js} +20 -20
- package/dist/{SimpleDenyList-D-rGBaay.js.map → SimpleDenyList-UvXQl2vm.js.map} +1 -1
- package/dist/Validators/LimitedSignerValidator.cjs +1 -1
- package/dist/Validators/LimitedSignerValidator.js +9 -9
- package/dist/Validators/SignerValidator.cjs +1 -1
- package/dist/Validators/SignerValidator.js +8 -8
- package/dist/Validators/Validator.cjs +1 -1
- package/dist/Validators/Validator.cjs.map +1 -1
- package/dist/Validators/Validator.js +20 -20
- package/dist/componentInterfaces-Bt-4sNB5.cjs +2 -0
- package/dist/componentInterfaces-Bt-4sNB5.cjs.map +1 -0
- package/dist/componentInterfaces-dakxtQHf.js +16 -0
- package/dist/componentInterfaces-dakxtQHf.js.map +1 -0
- package/dist/deployments-DxkwtCyu.cjs +2 -0
- package/dist/deployments-DxkwtCyu.cjs.map +1 -0
- package/dist/{deployments-BdPDIh-i.js → deployments-ZLVwJGZD.js} +33 -30
- package/dist/deployments-ZLVwJGZD.js.map +1 -0
- package/dist/deployments.json +17 -14
- package/dist/{generated-CDEDSOGZ.js → generated-B0XfMfoq.js} +1037 -470
- package/dist/generated-B0XfMfoq.js.map +1 -0
- package/dist/generated-pNKCp_Ez.cjs +3 -0
- package/dist/generated-pNKCp_Ez.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -144
- package/dist/utils.cjs +1 -1
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts +12 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +64 -35
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/BoostCore.ts +30 -0
- package/src/Budgets/Budget.ts +8 -3
- package/src/Budgets/ManagedBudgetWithFees.test.ts +286 -0
- package/src/Budgets/ManagedBudgetWithFees.ts +671 -0
- package/src/Incentives/AllowListIncentive.test.ts +52 -4
- package/src/Incentives/AllowListIncentive.ts +28 -0
- package/src/Incentives/CGDAIncentive.test.ts +48 -3
- package/src/Incentives/CGDAIncentive.ts +34 -0
- package/src/Incentives/ERC20Incentive.test.ts +42 -0
- package/src/Incentives/ERC20Incentive.ts +28 -0
- package/src/Incentives/ERC20VariableIncentive.test.ts +41 -1
- package/src/Incentives/ERC20VariableIncentive.ts +28 -0
- package/src/Incentives/PointsIncentive.test.ts +47 -3
- package/src/Incentives/PointsIncentive.ts +28 -0
- package/src/index.ts +1 -0
- package/src/utils.ts +46 -0
- package/dist/componentInterfaces-BQw7DH-m.cjs +0 -2
- package/dist/componentInterfaces-BQw7DH-m.cjs.map +0 -1
- package/dist/componentInterfaces-C0vuWQlh.js +0 -15
- package/dist/componentInterfaces-C0vuWQlh.js.map +0 -1
- package/dist/deployments--f75Pthq.cjs +0 -2
- package/dist/deployments--f75Pthq.cjs.map +0 -1
- package/dist/deployments-BdPDIh-i.js.map +0 -1
- package/dist/generated-CDEDSOGZ.js.map +0 -1
- package/dist/generated-D3DE5TfH.cjs +0 -3
- package/dist/generated-D3DE5TfH.cjs.map +0 -1
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import {\n type Config,\n type ReadContractParameters,\n type SimulateContractParameters,\n type WatchContractEventParameters,\n getAccount,\n getChainId,\n waitForTransactionReceipt,\n} from '@wagmi/core';\nimport type { ExtractAbiEvent } from 'abitype';\nimport type {\n Abi,\n AbiEvent,\n Address,\n ContractEventName,\n ContractFunctionName,\n GetLogsParameters,\n Hash,\n Hex,\n Log,\n WaitForTransactionReceiptParameters,\n} from 'viem';\nimport { isHex, keccak256, slice, toHex } from 'viem';\nimport {\n InvalidProtocolChainIdError,\n NoContractAddressUponReceiptError,\n} from './errors';\n\nexport type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;\n\n/**\n * Enum encapsulating all the different types of targets used in the Boost V2 Protocol.\n *\n * @export\n * @enum {number}\n */\nexport enum RegistryType {\n ACTION = 0,\n ALLOW_LIST = 1,\n BUDGET = 2,\n INCENTIVE = 3,\n VALIDATOR = 4,\n}\n\n/**\n * Enum encapsulating all the different cheat codes for criteria modules.\n * An Event Action action step criteria with a `fieldIndex` set to `CheatCodes.ANY_ACTION_PARAM`, fieldType set to `PrimitiveType.BYTES`, and `filterType` set to `FilterType.EQUAL` will always return true when validating the field, regardless of inputs\n * An Event Action `ActionClaimant` with a `fieldIndex` set to `CheatCodes.TX_SENDER_CLAIMANT`, will always validate with the sender of a given transaction.\n *\n *\n * @export\n * @enum {number}\n */\nexport enum CheatCodes {\n /* An Event Action action step criteria with a `fieldIndex` set to `CheatCodes.ANY_ACTION_PARAM`, fieldType set to `PrimitiveType.BYTES`, and `filterType` set to `FilterType.EQUAL` will always return true when validating the field, regardless of inputs */\n ANY_ACTION_PARAM = 255,\n /* An Event Action `ActionClaimant` with a `fieldIndex` set to `CheatCodes.TX_SENDER_CLAIMANT`, will always validate with the sender of a given transaction. */\n TX_SENDER_CLAIMANT = 255,\n /* For use with `ERC20VariableCriteriaIncentive`, if the criteria's `fieldIndex` is set to `CheatCodes.GAS_REBATE_INCENTIVE`, will claim an incentive amount equal to the transaction's gas used. */\n GAS_REBATE_INCENTIVE = 255,\n}\n\n/**\n * Helper type that encapsulates common writeContract parameters without fields like `abi`, `args`, `functionName`, `address` that are expected to be provided the SDK.\n * See (writeContract)[https://viem.sh/docs/contract/writeContract]\n *\n * @export\n * @typedef {WriteParams}\n * @template {Abi} abi\n * @template {ContractFunctionName<abi>} functionName\n */\nexport type WriteParams = Partial<\n Omit<SimulateContractParameters, 'address' | 'args' | 'functionName' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common readContract parameters without fields like `abi`, `args`, `functionName`, `address` that are expected to be provided the SDK.\n * See (readContract)[https://viem.sh/docs/contract/readContract]\n *\n * @export\n * @typedef {ReadParams}\n * @template {Abi} abi\n * @template {ContractFunctionName<abi>} functionName\n */\nexport type ReadParams = Partial<\n Omit<ReadContractParameters, 'address' | 'args' | 'functionName' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common `watchContractEvent` parameters without fields like `address`, and `abi` that are expected to be provided the SDK.\n * See (watchContractEvent)[https://wagmi.sh/core/api/actions/watchContractEvent]\n *\n * @export\n * @typedef {WatchParams}\n * @template {Abi} abi\n * @template {ContractEventName<abi> | undefined} [eventName=undefined]\n */\nexport type WatchParams<\n abi extends Abi,\n eventName extends ContractEventName<abi> | undefined = undefined,\n> = Partial<\n Omit<WatchContractEventParameters<abi, eventName>, 'address' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common `getLogs` parameters without fields like `address` that are expected to be provided the SDK.\n * See (getLogs)[https://viem.sh/docs/actions/public/getLogs#getlogs]\n *\n * @export\n * @typedef {GetLogsParams}\n * @template {Abi} abi\n * @template {ContractEventName<abi>} event\n * @template {ExtractAbiEvent<abi, event>} [abiEvent=ExtractAbiEvent<abi, event>]\n * @template {| readonly AbiEvent[]\n * | readonly unknown[]\n * | undefined} [abiEvents=abiEvent extends AbiEvent ? [abiEvent] : undefined]\n */\nexport type GetLogsParams<\n abi extends Abi,\n event extends ContractEventName<abi>,\n abiEvent extends ExtractAbiEvent<abi, event> = ExtractAbiEvent<abi, event>,\n abiEvents extends\n | readonly AbiEvent[]\n | readonly unknown[]\n | undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,\n> = Partial<Omit<GetLogsParameters<abiEvent, abiEvents>, 'address'>> & {\n chainId?: number | undefined;\n};\n\n/**\n * A generic `viem.Log` event with typed `args` support via a given `Abi` and `ContractEventName`\n *\n * @export\n * @typedef {GenericLog}\n * @template {Abi} abi\n * @template {ContractEventName<abi>} [event=ContractEventName<abi>]\n */\nexport type GenericLog<\n abi extends Abi,\n event extends ContractEventName<abi> = ContractEventName<abi>,\n> = Log<bigint, number, false, ExtractAbiEvent<abi, event>, false>;\n\n/**\n * Helper utility to convert a string to a `bytes4` type\n *\n * @export\n * @param {string} input\n * @returns {Hex}\n */\nexport function bytes4(input: string) {\n return slice(isHex(input) ? keccak256(input) : keccak256(toHex(input)), 0, 4);\n}\n\n/**\n * Utility function to wait for a transaction receipt, and extract the contractAddress\n *\n * @export\n * @async\n * @param {WagmiConfig} config - [Wagmi Configuration](https://wagmi.sh/core/api/createConfig)\n * @param {Promise<Hash>} hash - A transaction hash promise\n * @param {?Omit<WaitForTransactionReceiptParameters, 'hash'>} [waitParams] - @see {@link WaitForTransactionReceiptParameters}\n * @returns {Promise<Address>}\n * @throws {@link NoContractAddressUponReceiptError} if no `contractAddress` exists after the transaction has been received\n */\nexport async function getDeployedContractAddress(\n config: Config,\n hash: Promise<Hash>,\n waitParams?: Omit<WaitForTransactionReceiptParameters, 'hash'>,\n) {\n const receipt = await waitForTransactionReceipt(config, {\n ...waitParams,\n hash: await hash,\n });\n if (!receipt.contractAddress)\n throw new NoContractAddressUponReceiptError(receipt);\n return receipt.contractAddress;\n}\n\n/**\n * Utility type to encapsulate a transaction hash, and the simulated result prior to submitting the transaction.\n *\n * @export\n * @typedef {HashAndSimulatedResult}\n * @template [T=unknown]\n */\nexport type HashAndSimulatedResult<T = unknown> = { hash: Hash; result: T };\n\n/**\n * Helper function to wait for a transaction receipt given a hash promise.\n *\n * @export\n * @async\n * @template [Result=unknown]\n * @param {WagmiConfig} config\n * @param {Promise<HashAndSimulatedResult<Result>>} hashPromise\n * @param {?Omit<WaitForTransactionReceiptParameters, 'hash'>} [waitParams]\n * @returns {Promise<Result>}\n */\nexport async function awaitResult<Result = unknown>(\n config: Config,\n hashPromise: Promise<HashAndSimulatedResult<Result>>,\n waitParams?: Omit<WaitForTransactionReceiptParameters, 'hash'>,\n): Promise<Result> {\n const { hash, result } = await hashPromise;\n await waitForTransactionReceipt(config, {\n ...waitParams,\n hash,\n });\n return result;\n}\n\n/**\n * Given a wagmi config and a map of chain id's to addresses, determine an address/chainId combo that maps to the currently connected chain id, or throw a typed error.\n *\n * @export\n * @param {Config} config\n * @param {Record<string, Address>} addressByChainId\n * @param {number} desiredChainId\n * @returns {{ chainId: number, address: Address }}\n * @throws {@link InvalidProtocolChainIdError}\n */\nexport function assertValidAddressByChainId(\n config: Config,\n addressByChainId: Record<number, Address>,\n desiredChainId?: number,\n): { chainId: number; address: Address } {\n let chainId: number | undefined = undefined;\n\n const wagmiChainId = getChainId(config);\n if (wagmiChainId && addressByChainId[wagmiChainId]) chainId = wagmiChainId;\n // if manually providing a chain id for some contract operation, try to use it\n if (desiredChainId !== undefined) {\n if (addressByChainId[desiredChainId]) chainId = desiredChainId;\n } else if (wagmiChainId !== undefined) {\n // otherwise if we can get the current chain id off the connected account and it matches one of ours, use it\n if (addressByChainId[wagmiChainId]) chainId = wagmiChainId;\n }\n // chainId is still undefined, try to get chain id off viem client\n if (chainId === undefined) {\n const wagmiAccount = getAccount(config);\n if (wagmiAccount.chainId !== undefined) {\n // otherwise if we can get the current chain id off the connected account and it matches one of ours, use it\n if (addressByChainId[wagmiAccount.chainId])\n chainId = wagmiAccount.chainId;\n }\n }\n // if chainId is STILL undefined, use our default addresses\n // TODO: update this when on prod network\n if (chainId === undefined) chainId = Number(__DEFAULT_CHAIN_ID__);\n if (!addressByChainId[chainId])\n throw new InvalidProtocolChainIdError(\n chainId,\n Object.keys(addressByChainId).map(Number),\n );\n // biome-ignore lint/style/noNonNullAssertion: this type should be narrowed by the above statement but isn't?\n return { chainId, address: addressByChainId[chainId]! };\n}\n"],"names":["RegistryType","CheatCodes","bytes4","input","slice","isHex","keccak256","toHex","getDeployedContractAddress","config","hash","waitParams","receipt","waitForTransactionReceipt","NoContractAddressUponReceiptError","awaitResult","hashPromise","result","assertValidAddressByChainId","addressByChainId","desiredChainId","chainId","wagmiChainId","getChainId","wagmiAccount","getAccount","InvalidProtocolChainIdError"],"mappings":";;;AAoCY,IAAAA,sBAAAA,OACVA,EAAAA,EAAA,SAAS,CAAT,IAAA,UACAA,EAAAA,EAAA,aAAa,CAAb,IAAA,cACAA,EAAAA,EAAA,SAAS,CAAT,IAAA,UACAA,EAAAA,EAAA,YAAY,CAAZ,IAAA,aACAA,EAAAA,EAAA,YAAY,CAAZ,IAAA,aALUA,IAAAA,KAAA,CAAA,CAAA,GAiBAC,sBAAAA,OAEVA,EAAAA,EAAA,mBAAmB,GAAnB,IAAA,oBAEAA,EAAAA,EAAA,qBAAqB,GAArB,IAAA,sBAEAA,EAAAA,EAAA,uBAAuB,GAAvB,IAAA,wBANUA,IAAAA,KAAA,CAAA,CAAA;AAgGL,SAASC,EAAOC,GAAe;AACpC,SAAOC,EAAMC,EAAMF,CAAK,IAAIG,EAAUH,CAAK,IAAIG,EAAUC,EAAMJ,CAAK,CAAC,GAAG,GAAG,CAAC;AAC9E;AAasB,eAAAK,EACpBC,GACAC,GACAC,GACA;AACM,QAAAC,IAAU,MAAMC,EAA0BJ,GAAQ;AAAA,IACtD,GAAGE;AAAA,IACH,MAAM,MAAMD;AAAA,EAAA,CACb;AACD,MAAI,CAACE,EAAQ;AACL,UAAA,IAAIE,EAAkCF,CAAO;AACrD,SAAOA,EAAQ;AACjB;AAsBsB,eAAAG,EACpBN,GACAO,GACAL,GACiB;AACjB,QAAM,EAAE,MAAAD,GAAM,QAAAO,EAAO,IAAI,MAAMD;AAC/B,eAAMH,EAA0BJ,GAAQ;AAAA,IACtC,GAAGE;AAAA,IACH,MAAAD;AAAA,EAAA,CACD,GACMO;AACT;AAYgB,SAAAC,EACdT,GACAU,GACAC,GACuC;AACvC,MAAIC;AAEE,QAAAC,IAAeC,EAAWd,CAAM;AAUtC,MATIa,KAAgBH,EAAiBG,CAAY,MAAaD,IAAAC,IAE1DF,MAAmB,SACjBD,EAAiBC,CAAc,MAAaC,IAAAD,KACvCE,MAAiB,UAEtBH,EAAiBG,CAAY,MAAaD,IAAAC,IAG5CD,MAAY,QAAW;AACnB,UAAAG,IAAeC,EAAWhB,CAAM;AAClC,IAAAe,EAAa,YAAY,UAEvBL,EAAiBK,EAAa,OAAO,MACvCH,IAAUG,EAAa;AAAA,EAE7B;AAII,MADAH,MAAY,WAAqBA,IAAO,WACxC,CAACF,EAAiBE,CAAO;AAC3B,UAAM,IAAIK;AAAA,MACRL;AAAA,MACA,OAAO,KAAKF,CAAgB,EAAE,IAAI,MAAM;AAAA,IAAA;AAG5C,SAAO,EAAE,SAAAE,GAAS,SAASF,EAAiBE,CAAO,EAAG;AACxD;"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import {\n type Config,\n type ReadContractParameters,\n type SimulateContractParameters,\n type WatchContractEventParameters,\n getAccount,\n getChainId,\n readContract,\n waitForTransactionReceipt,\n} from '@wagmi/core';\nimport type { ExtractAbiEvent } from 'abitype';\nimport type {\n Abi,\n AbiEvent,\n Address,\n ContractEventName,\n ContractFunctionName,\n GetLogsParameters,\n Hash,\n Hex,\n Log,\n WaitForTransactionReceiptParameters,\n} from 'viem';\nimport { isHex, keccak256, slice, toHex } from 'viem';\nimport {\n InvalidProtocolChainIdError,\n NoContractAddressUponReceiptError,\n} from './errors';\n\nexport type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;\n\n/**\n * Enum encapsulating all the different types of targets used in the Boost V2 Protocol.\n *\n * @export\n * @enum {number}\n */\nexport enum RegistryType {\n ACTION = 0,\n ALLOW_LIST = 1,\n BUDGET = 2,\n INCENTIVE = 3,\n VALIDATOR = 4,\n}\n\n/**\n * Enum encapsulating all the different cheat codes for criteria modules.\n * An Event Action action step criteria with a `fieldIndex` set to `CheatCodes.ANY_ACTION_PARAM`, fieldType set to `PrimitiveType.BYTES`, and `filterType` set to `FilterType.EQUAL` will always return true when validating the field, regardless of inputs\n * An Event Action `ActionClaimant` with a `fieldIndex` set to `CheatCodes.TX_SENDER_CLAIMANT`, will always validate with the sender of a given transaction.\n *\n *\n * @export\n * @enum {number}\n */\nexport enum CheatCodes {\n /* An Event Action action step criteria with a `fieldIndex` set to `CheatCodes.ANY_ACTION_PARAM`, fieldType set to `PrimitiveType.BYTES`, and `filterType` set to `FilterType.EQUAL` will always return true when validating the field, regardless of inputs */\n ANY_ACTION_PARAM = 255,\n /* An Event Action `ActionClaimant` with a `fieldIndex` set to `CheatCodes.TX_SENDER_CLAIMANT`, will always validate with the sender of a given transaction. */\n TX_SENDER_CLAIMANT = 255,\n /* For use with `ERC20VariableCriteriaIncentive`, if the criteria's `fieldIndex` is set to `CheatCodes.GAS_REBATE_INCENTIVE`, will claim an incentive amount equal to the transaction's gas used. */\n GAS_REBATE_INCENTIVE = 255,\n}\n\n/**\n * Helper type that encapsulates common writeContract parameters without fields like `abi`, `args`, `functionName`, `address` that are expected to be provided the SDK.\n * See (writeContract)[https://viem.sh/docs/contract/writeContract]\n *\n * @export\n * @typedef {WriteParams}\n * @template {Abi} abi\n * @template {ContractFunctionName<abi>} functionName\n */\nexport type WriteParams = Partial<\n Omit<SimulateContractParameters, 'address' | 'args' | 'functionName' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common readContract parameters without fields like `abi`, `args`, `functionName`, `address` that are expected to be provided the SDK.\n * See (readContract)[https://viem.sh/docs/contract/readContract]\n *\n * @export\n * @typedef {ReadParams}\n * @template {Abi} abi\n * @template {ContractFunctionName<abi>} functionName\n */\nexport type ReadParams = Partial<\n Omit<ReadContractParameters, 'address' | 'args' | 'functionName' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common `watchContractEvent` parameters without fields like `address`, and `abi` that are expected to be provided the SDK.\n * See (watchContractEvent)[https://wagmi.sh/core/api/actions/watchContractEvent]\n *\n * @export\n * @typedef {WatchParams}\n * @template {Abi} abi\n * @template {ContractEventName<abi> | undefined} [eventName=undefined]\n */\nexport type WatchParams<\n abi extends Abi,\n eventName extends ContractEventName<abi> | undefined = undefined,\n> = Partial<\n Omit<WatchContractEventParameters<abi, eventName>, 'address' | 'abi'>\n>;\n\n/**\n * Helper type that encapsulates common `getLogs` parameters without fields like `address` that are expected to be provided the SDK.\n * See (getLogs)[https://viem.sh/docs/actions/public/getLogs#getlogs]\n *\n * @export\n * @typedef {GetLogsParams}\n * @template {Abi} abi\n * @template {ContractEventName<abi>} event\n * @template {ExtractAbiEvent<abi, event>} [abiEvent=ExtractAbiEvent<abi, event>]\n * @template {| readonly AbiEvent[]\n * | readonly unknown[]\n * | undefined} [abiEvents=abiEvent extends AbiEvent ? [abiEvent] : undefined]\n */\nexport type GetLogsParams<\n abi extends Abi,\n event extends ContractEventName<abi>,\n abiEvent extends ExtractAbiEvent<abi, event> = ExtractAbiEvent<abi, event>,\n abiEvents extends\n | readonly AbiEvent[]\n | readonly unknown[]\n | undefined = abiEvent extends AbiEvent ? [abiEvent] : undefined,\n> = Partial<Omit<GetLogsParameters<abiEvent, abiEvents>, 'address'>> & {\n chainId?: number | undefined;\n};\n\n/**\n * A generic `viem.Log` event with typed `args` support via a given `Abi` and `ContractEventName`\n *\n * @export\n * @typedef {GenericLog}\n * @template {Abi} abi\n * @template {ContractEventName<abi>} [event=ContractEventName<abi>]\n */\nexport type GenericLog<\n abi extends Abi,\n event extends ContractEventName<abi> = ContractEventName<abi>,\n> = Log<bigint, number, false, ExtractAbiEvent<abi, event>, false>;\n\n/**\n * Helper utility to convert a string to a `bytes4` type\n *\n * @export\n * @param {string} input\n * @returns {Hex}\n */\nexport function bytes4(input: string) {\n return slice(isHex(input) ? keccak256(input) : keccak256(toHex(input)), 0, 4);\n}\n\n/**\n * Utility function to wait for a transaction receipt, and extract the contractAddress\n *\n * @export\n * @async\n * @param {WagmiConfig} config - [Wagmi Configuration](https://wagmi.sh/core/api/createConfig)\n * @param {Promise<Hash>} hash - A transaction hash promise\n * @param {?Omit<WaitForTransactionReceiptParameters, 'hash'>} [waitParams] - @see {@link WaitForTransactionReceiptParameters}\n * @returns {Promise<Address>}\n * @throws {@link NoContractAddressUponReceiptError} if no `contractAddress` exists after the transaction has been received\n */\nexport async function getDeployedContractAddress(\n config: Config,\n hash: Promise<Hash>,\n waitParams?: Omit<WaitForTransactionReceiptParameters, 'hash'>,\n) {\n const receipt = await waitForTransactionReceipt(config, {\n ...waitParams,\n hash: await hash,\n });\n if (!receipt.contractAddress)\n throw new NoContractAddressUponReceiptError(receipt);\n return receipt.contractAddress;\n}\n\n/**\n * Utility type to encapsulate a transaction hash, and the simulated result prior to submitting the transaction.\n *\n * @export\n * @typedef {HashAndSimulatedResult}\n * @template [T=unknown]\n */\nexport type HashAndSimulatedResult<T = unknown> = { hash: Hash; result: T };\n\n/**\n * Helper function to wait for a transaction receipt given a hash promise.\n *\n * @export\n * @async\n * @template [Result=unknown]\n * @param {WagmiConfig} config\n * @param {Promise<HashAndSimulatedResult<Result>>} hashPromise\n * @param {?Omit<WaitForTransactionReceiptParameters, 'hash'>} [waitParams]\n * @returns {Promise<Result>}\n */\nexport async function awaitResult<Result = unknown>(\n config: Config,\n hashPromise: Promise<HashAndSimulatedResult<Result>>,\n waitParams?: Omit<WaitForTransactionReceiptParameters, 'hash'>,\n): Promise<Result> {\n const { hash, result } = await hashPromise;\n await waitForTransactionReceipt(config, {\n ...waitParams,\n hash,\n });\n return result;\n}\n\n/**\n * Given a wagmi config and a map of chain id's to addresses, determine an address/chainId combo that maps to the currently connected chain id, or throw a typed error.\n *\n * @export\n * @param {Config} config\n * @param {Record<string, Address>} addressByChainId\n * @param {number} desiredChainId\n * @returns {{ chainId: number, address: Address }}\n * @throws {@link InvalidProtocolChainIdError}\n */\nexport function assertValidAddressByChainId(\n config: Config,\n addressByChainId: Record<number, Address>,\n desiredChainId?: number,\n): { chainId: number; address: Address } {\n let chainId: number | undefined = undefined;\n\n const wagmiChainId = getChainId(config);\n if (wagmiChainId && addressByChainId[wagmiChainId]) chainId = wagmiChainId;\n // if manually providing a chain id for some contract operation, try to use it\n if (desiredChainId !== undefined) {\n if (addressByChainId[desiredChainId]) chainId = desiredChainId;\n } else if (wagmiChainId !== undefined) {\n // otherwise if we can get the current chain id off the connected account and it matches one of ours, use it\n if (addressByChainId[wagmiChainId]) chainId = wagmiChainId;\n }\n // chainId is still undefined, try to get chain id off viem client\n if (chainId === undefined) {\n const wagmiAccount = getAccount(config);\n if (wagmiAccount.chainId !== undefined) {\n // otherwise if we can get the current chain id off the connected account and it matches one of ours, use it\n if (addressByChainId[wagmiAccount.chainId])\n chainId = wagmiAccount.chainId;\n }\n }\n // if chainId is STILL undefined, use our default addresses\n // TODO: update this when on prod network\n if (chainId === undefined) chainId = Number(__DEFAULT_CHAIN_ID__);\n if (!addressByChainId[chainId])\n throw new InvalidProtocolChainIdError(\n chainId,\n Object.keys(addressByChainId).map(Number),\n );\n // biome-ignore lint/style/noNonNullAssertion: this type should be narrowed by the above statement but isn't?\n return { chainId, address: addressByChainId[chainId]! };\n}\n\n/**\n * Check an ERC20's balance for a given asset and\n *\n * @public\n * @async\n * @param {Config} [config]\n * @param {Address} [asset]\n * @param {Address} [owner]\n * @param {?ReadParams} [params]\n * @returns {Promise<bigint>} - The erc20 balance\n */\nexport async function getErc20Balance(\n config: Config,\n asset: Address,\n owner: Address,\n params?: ReadParams,\n) {\n return await readContract(config, {\n ...params,\n functionName: 'balanceOf',\n address: asset,\n args: [owner],\n abi: [\n {\n constant: true,\n inputs: [\n {\n name: '_owner',\n type: 'address',\n },\n ],\n name: 'balanceOf',\n outputs: [\n {\n name: 'balance',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n ],\n });\n}\n"],"names":["RegistryType","CheatCodes","bytes4","input","slice","isHex","keccak256","toHex","getDeployedContractAddress","config","hash","waitParams","receipt","waitForTransactionReceipt","NoContractAddressUponReceiptError","awaitResult","hashPromise","result","assertValidAddressByChainId","addressByChainId","desiredChainId","chainId","wagmiChainId","getChainId","wagmiAccount","getAccount","InvalidProtocolChainIdError","getErc20Balance","asset","owner","params","readContract"],"mappings":";;;AAqCY,IAAAA,sBAAAA,OACVA,EAAAA,EAAA,SAAS,CAAT,IAAA,UACAA,EAAAA,EAAA,aAAa,CAAb,IAAA,cACAA,EAAAA,EAAA,SAAS,CAAT,IAAA,UACAA,EAAAA,EAAA,YAAY,CAAZ,IAAA,aACAA,EAAAA,EAAA,YAAY,CAAZ,IAAA,aALUA,IAAAA,KAAA,CAAA,CAAA,GAiBAC,sBAAAA,OAEVA,EAAAA,EAAA,mBAAmB,GAAnB,IAAA,oBAEAA,EAAAA,EAAA,qBAAqB,GAArB,IAAA,sBAEAA,EAAAA,EAAA,uBAAuB,GAAvB,IAAA,wBANUA,IAAAA,KAAA,CAAA,CAAA;AAgGL,SAASC,EAAOC,GAAe;AACpC,SAAOC,EAAMC,EAAMF,CAAK,IAAIG,EAAUH,CAAK,IAAIG,EAAUC,EAAMJ,CAAK,CAAC,GAAG,GAAG,CAAC;AAC9E;AAasB,eAAAK,EACpBC,GACAC,GACAC,GACA;AACM,QAAAC,IAAU,MAAMC,EAA0BJ,GAAQ;AAAA,IACtD,GAAGE;AAAA,IACH,MAAM,MAAMD;AAAA,EAAA,CACb;AACD,MAAI,CAACE,EAAQ;AACL,UAAA,IAAIE,EAAkCF,CAAO;AACrD,SAAOA,EAAQ;AACjB;AAsBsB,eAAAG,EACpBN,GACAO,GACAL,GACiB;AACjB,QAAM,EAAE,MAAAD,GAAM,QAAAO,EAAO,IAAI,MAAMD;AAC/B,eAAMH,EAA0BJ,GAAQ;AAAA,IACtC,GAAGE;AAAA,IACH,MAAAD;AAAA,EAAA,CACD,GACMO;AACT;AAYgB,SAAAC,EACdT,GACAU,GACAC,GACuC;AACvC,MAAIC;AAEE,QAAAC,IAAeC,EAAWd,CAAM;AAUtC,MATIa,KAAgBH,EAAiBG,CAAY,MAAaD,IAAAC,IAE1DF,MAAmB,SACjBD,EAAiBC,CAAc,MAAaC,IAAAD,KACvCE,MAAiB,UAEtBH,EAAiBG,CAAY,MAAaD,IAAAC,IAG5CD,MAAY,QAAW;AACnB,UAAAG,IAAeC,EAAWhB,CAAM;AAClC,IAAAe,EAAa,YAAY,UAEvBL,EAAiBK,EAAa,OAAO,MACvCH,IAAUG,EAAa;AAAA,EAE7B;AAII,MADAH,MAAY,WAAqBA,IAAO,WACxC,CAACF,EAAiBE,CAAO;AAC3B,UAAM,IAAIK;AAAA,MACRL;AAAA,MACA,OAAO,KAAKF,CAAgB,EAAE,IAAI,MAAM;AAAA,IAAA;AAG5C,SAAO,EAAE,SAAAE,GAAS,SAASF,EAAiBE,CAAO,EAAG;AACxD;AAaA,eAAsBM,EACpBlB,GACAmB,GACAC,GACAC,GACA;AACO,SAAA,MAAMC,EAAatB,GAAQ;AAAA,IAChC,GAAGqB;AAAA,IACH,cAAc;AAAA,IACd,SAASF;AAAA,IACT,MAAM,CAACC,CAAK;AAAA,IACZ,KAAK;AAAA,MACH;AAAA,QACE,UAAU;AAAA,QACV,QAAQ;AAAA,UACN;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,MAAM;AAAA,QACN,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,iBAAiB;AAAA,QACjB,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EAAA,CACD;AACH;"}
|
package/package.json
CHANGED
package/src/BoostCore.ts
CHANGED
|
@@ -59,12 +59,17 @@ import {
|
|
|
59
59
|
ManagedBudget,
|
|
60
60
|
type ManagedBudgetPayload,
|
|
61
61
|
} from './Budgets/ManagedBudget';
|
|
62
|
+
import {
|
|
63
|
+
ManagedBudgetWithFees,
|
|
64
|
+
type ManagedBudgetWithFeesPayload,
|
|
65
|
+
} from './Budgets/ManagedBudgetWithFees';
|
|
62
66
|
import {
|
|
63
67
|
Deployable,
|
|
64
68
|
type DeployableOptions,
|
|
65
69
|
type DeployablePayloadOrAddress,
|
|
66
70
|
type GenericDeployableParams,
|
|
67
71
|
} from './Deployable/Deployable';
|
|
72
|
+
import { Roles } from './Deployable/DeployableTargetWithRBAC';
|
|
68
73
|
import {
|
|
69
74
|
AllowListIncentive,
|
|
70
75
|
type AllowListIncentivePayload,
|
|
@@ -1268,6 +1273,31 @@ export class BoostCore extends Deployable<
|
|
|
1268
1273
|
options,
|
|
1269
1274
|
);
|
|
1270
1275
|
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Bound {@link ManagedBudgetWithFees} constructor that reuses the same configuration as the Boost Core instance.
|
|
1278
|
+
* Prepends the BoostCore address to the authorized list because it's structurally critical to calculating payouts.
|
|
1279
|
+
*
|
|
1280
|
+
* @example
|
|
1281
|
+
* ```ts
|
|
1282
|
+
* const budget = core.ManagedBudgetWithFees('0x') // is roughly equivalent to
|
|
1283
|
+
* const budget = new ManagedBudgetWithFees({ config: core._config, account: core._account }, '0x')
|
|
1284
|
+
* ```
|
|
1285
|
+
* @param {DeployablePayloadOrAddress<ManagedBudgetWithFeesPayload>} options
|
|
1286
|
+
* @returns {ManagedBudgetWithFees}
|
|
1287
|
+
*/
|
|
1288
|
+
ManagedBudgetWithFees(
|
|
1289
|
+
options: DeployablePayloadOrAddress<ManagedBudgetWithFeesPayload>,
|
|
1290
|
+
) {
|
|
1291
|
+
if (typeof options !== 'string') {
|
|
1292
|
+
options.authorized = [this.assertValidAddress(), ...options.authorized];
|
|
1293
|
+
options.roles = [Roles.MANAGER, ...options.roles];
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
return new ManagedBudgetWithFees(
|
|
1297
|
+
{ config: this._config, account: this._account },
|
|
1298
|
+
options,
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1271
1301
|
// /**
|
|
1272
1302
|
// * Bound {@link VestingBudget} constructor that reuses the same configuration as the Boost Core instance.
|
|
1273
1303
|
// *
|
package/src/Budgets/Budget.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { aBudgetAbi } from '@boostxyz/evm';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AManagedBudget,
|
|
4
|
+
AManagedBudgetWithFees,
|
|
5
|
+
} from '@boostxyz/evm/deploys/componentInterfaces.json';
|
|
3
6
|
import { readContract } from '@wagmi/core';
|
|
4
7
|
import type { Address, Hex } from 'viem';
|
|
5
8
|
import type { DeployableOptions } from '../Deployable/Deployable';
|
|
6
9
|
import { InvalidComponentInterfaceError } from '../errors';
|
|
7
10
|
import { ManagedBudget } from './ManagedBudget';
|
|
11
|
+
import { ManagedBudgetWithFees } from './ManagedBudgetWithFees';
|
|
8
12
|
|
|
9
13
|
export {
|
|
10
14
|
// VestingBudget,
|
|
@@ -17,7 +21,7 @@ export {
|
|
|
17
21
|
* @export
|
|
18
22
|
* @typedef {Budget}
|
|
19
23
|
*/
|
|
20
|
-
export type Budget = ManagedBudget; // | VestingBudget
|
|
24
|
+
export type Budget = ManagedBudget | ManagedBudgetWithFees; // | VestingBudget
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* A map of Budget component interfaces to their constructors.
|
|
@@ -28,6 +32,7 @@ export const BudgetByComponentInterface = {
|
|
|
28
32
|
// ['0x64683da1']: VestingBudget,
|
|
29
33
|
// ['0x2929d19c']: SimpleBudget,
|
|
30
34
|
[AManagedBudget as Hex]: ManagedBudget,
|
|
35
|
+
[AManagedBudgetWithFees as Hex]: ManagedBudgetWithFees,
|
|
31
36
|
};
|
|
32
37
|
|
|
33
38
|
/**
|
|
@@ -37,7 +42,7 @@ export const BudgetByComponentInterface = {
|
|
|
37
42
|
* @async
|
|
38
43
|
* @param {DeployableOptions} options
|
|
39
44
|
* @param {Address} address
|
|
40
|
-
* @returns {Promise<ManagedBudget>}
|
|
45
|
+
* @returns {Promise<ManagedBudget | ManagedBudgetWithFees>}
|
|
41
46
|
* @throws {@link InvalidComponentInterfaceError}
|
|
42
47
|
*/
|
|
43
48
|
export async function budgetFromAddress(
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { writeMockErc1155SetApprovalForAll } from "@boostxyz/evm";
|
|
2
|
+
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
|
3
|
+
import { isAddress, parseEther, zeroAddress } from "viem";
|
|
4
|
+
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
5
|
+
import type { MockERC20 } from "@boostxyz/test/MockERC20";
|
|
6
|
+
import type { MockERC1155 } from "@boostxyz/test/MockERC1155";
|
|
7
|
+
import { accounts } from "@boostxyz/test/accounts";
|
|
8
|
+
import {
|
|
9
|
+
type Fixtures,
|
|
10
|
+
defaultOptions,
|
|
11
|
+
deployFixtures,
|
|
12
|
+
freshManagedBudgetWithFees,
|
|
13
|
+
fundErc20,
|
|
14
|
+
fundErc1155,
|
|
15
|
+
fundManagedBudget,
|
|
16
|
+
freshBoost,
|
|
17
|
+
fundManagedBudgetWithFees,
|
|
18
|
+
} from "@boostxyz/test/helpers";
|
|
19
|
+
import { testAccount } from "@boostxyz/test/viem";
|
|
20
|
+
import { ManagedBudgetWithFees } from "./ManagedBudgetWithFees";
|
|
21
|
+
import { Roles } from "../Deployable/DeployableTargetWithRBAC";
|
|
22
|
+
import { StrategyType } from "../claiming";
|
|
23
|
+
|
|
24
|
+
let fixtures: Fixtures,
|
|
25
|
+
budget: ManagedBudgetWithFees,
|
|
26
|
+
erc20: MockERC20,
|
|
27
|
+
erc1155: MockERC1155;
|
|
28
|
+
|
|
29
|
+
beforeAll(async () => {
|
|
30
|
+
fixtures = await loadFixture(deployFixtures(defaultOptions));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("ManagedBudgetWithFees", () => {
|
|
34
|
+
test("can successfully be deployed", async () => {
|
|
35
|
+
const action = new ManagedBudgetWithFees(defaultOptions, {
|
|
36
|
+
owner: testAccount.address,
|
|
37
|
+
authorized: [],
|
|
38
|
+
roles: [],
|
|
39
|
+
managementFee: 100n,
|
|
40
|
+
});
|
|
41
|
+
await action.deploy();
|
|
42
|
+
expect(isAddress(action.assertValidAddress())).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("can set ManagementFee", async () => {
|
|
46
|
+
const budget = await loadFixture(
|
|
47
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
48
|
+
);
|
|
49
|
+
await budget.setManagementFee(5000n);
|
|
50
|
+
const fee = await budget.managementFee();
|
|
51
|
+
expect(fee).toBe(5000n);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
test("can grant manager role to many users", async () => {
|
|
56
|
+
const budget = await loadFixture(
|
|
57
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
58
|
+
);
|
|
59
|
+
const one = accounts[1].account;
|
|
60
|
+
const two = accounts[2].account;
|
|
61
|
+
await budget.setAuthorized([one, two], [true, true]);
|
|
62
|
+
expect(await budget.hasAllRoles(one, Roles.ADMIN)).toBe(false);
|
|
63
|
+
expect(await budget.hasAllRoles(one, Roles.MANAGER)).toBe(true);
|
|
64
|
+
expect(await budget.hasAllRoles(two, Roles.MANAGER)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("can grant role", async () => {
|
|
68
|
+
const budget = await loadFixture(
|
|
69
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
70
|
+
);
|
|
71
|
+
const manager = accounts[1].account;
|
|
72
|
+
await budget.grantRoles(manager, Roles.MANAGER);
|
|
73
|
+
expect(await budget.hasAllRoles(manager, Roles.ADMIN)).toBe(false);
|
|
74
|
+
expect(await budget.hasAllRoles(manager, Roles.MANAGER)).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("can revoke role", async () => {
|
|
78
|
+
const budget = await loadFixture(
|
|
79
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
80
|
+
);
|
|
81
|
+
const manager = accounts[1].account;
|
|
82
|
+
await budget.grantRoles(manager, Roles.MANAGER);
|
|
83
|
+
await budget.grantRoles(manager, Roles.ADMIN);
|
|
84
|
+
await budget.revokeRoles(manager, Roles.MANAGER);
|
|
85
|
+
expect(await budget.hasAllRoles(manager, Roles.MANAGER)).toBe(false);
|
|
86
|
+
expect(await budget.hasAllRoles(manager, Roles.ADMIN)).toBe(true);
|
|
87
|
+
await budget.revokeRoles(manager, Roles.ADMIN);
|
|
88
|
+
expect(await budget.hasAllRoles(manager, Roles.ADMIN)).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("can grant many roles", async () => {
|
|
92
|
+
const budget = await loadFixture(
|
|
93
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
94
|
+
);
|
|
95
|
+
const admin = accounts[1].account;
|
|
96
|
+
const manager = accounts[2].account;
|
|
97
|
+
await budget.grantManyRoles([admin, manager], [Roles.ADMIN, Roles.MANAGER]);
|
|
98
|
+
expect(await budget.hasAllRoles(admin, Roles.ADMIN)).toBe(true);
|
|
99
|
+
expect(await budget.hasAllRoles(manager, Roles.MANAGER)).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("can revoke many roles", async () => {
|
|
103
|
+
const budget = await loadFixture(
|
|
104
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
105
|
+
);
|
|
106
|
+
const admin = accounts[1].account;
|
|
107
|
+
const manager = accounts[2].account;
|
|
108
|
+
await budget.grantManyRoles([admin, manager], [Roles.ADMIN, Roles.MANAGER]);
|
|
109
|
+
await budget.revokeManyRoles(
|
|
110
|
+
[admin, manager],
|
|
111
|
+
[Roles.ADMIN, Roles.MANAGER],
|
|
112
|
+
);
|
|
113
|
+
expect(await budget.hasAllRoles(admin, Roles.ADMIN)).toBe(false);
|
|
114
|
+
expect(await budget.hasAllRoles(manager, Roles.MANAGER)).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("can be owned", async () => {
|
|
118
|
+
const budget = await loadFixture(
|
|
119
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
120
|
+
);
|
|
121
|
+
expect(await budget.owner()).toBe(defaultOptions.account.address);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("can have authorized users", async () => {
|
|
125
|
+
const budget = await loadFixture(
|
|
126
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
127
|
+
);
|
|
128
|
+
expect(await budget.isAuthorized(defaultOptions.account.address)).toBe(
|
|
129
|
+
true,
|
|
130
|
+
);
|
|
131
|
+
expect(await budget.isAuthorized(zeroAddress)).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("can have no initial balance", async () => {
|
|
135
|
+
const budget = await loadFixture(
|
|
136
|
+
freshManagedBudgetWithFees(defaultOptions, fixtures),
|
|
137
|
+
);
|
|
138
|
+
expect(await budget.available()).toBe(0n);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("can allocate", () => {
|
|
142
|
+
beforeEach(async () => {
|
|
143
|
+
budget = await loadFixture(freshManagedBudgetWithFees(defaultOptions, fixtures));
|
|
144
|
+
erc20 = await loadFixture(fundErc20(defaultOptions));
|
|
145
|
+
erc1155 = await loadFixture(fundErc1155(defaultOptions));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("native assets", async () => {
|
|
149
|
+
await budget.allocate(
|
|
150
|
+
{
|
|
151
|
+
amount: parseEther("1.0"),
|
|
152
|
+
asset: zeroAddress,
|
|
153
|
+
target: defaultOptions.account.address,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
value: parseEther("1.0"),
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
expect(await budget.available()).toBe(parseEther("1.0"));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("erc20", async () => {
|
|
163
|
+
await erc20.approve(budget.assertValidAddress(), parseEther("110"));
|
|
164
|
+
await budget.allocate({
|
|
165
|
+
amount: parseEther("110"),
|
|
166
|
+
asset: erc20.assertValidAddress(),
|
|
167
|
+
target: defaultOptions.account.address,
|
|
168
|
+
});
|
|
169
|
+
expect(await budget.available(erc20.assertValidAddress())).toBe(
|
|
170
|
+
parseEther("110"),
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("erc1155", async () => {
|
|
175
|
+
await writeMockErc1155SetApprovalForAll(defaultOptions.config, {
|
|
176
|
+
args: [budget.assertValidAddress(), true],
|
|
177
|
+
address: erc1155.assertValidAddress(),
|
|
178
|
+
account: defaultOptions.account,
|
|
179
|
+
});
|
|
180
|
+
await budget.allocate({
|
|
181
|
+
tokenId: 1n,
|
|
182
|
+
amount: 110n,
|
|
183
|
+
asset: erc1155.assertValidAddress(),
|
|
184
|
+
target: defaultOptions.account.address,
|
|
185
|
+
});
|
|
186
|
+
expect(await budget.available(erc1155.assertValidAddress(), 1n)).toBe(
|
|
187
|
+
110n,
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("can disburse", () => {
|
|
193
|
+
beforeEach(async () => {
|
|
194
|
+
const budgetFixtures = await loadFixture(
|
|
195
|
+
fundManagedBudgetWithFees(defaultOptions, fixtures),
|
|
196
|
+
);
|
|
197
|
+
budget = budgetFixtures.budget as ManagedBudgetWithFees;
|
|
198
|
+
erc20 = budgetFixtures.erc20;
|
|
199
|
+
erc1155 = budgetFixtures.erc1155;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("to a fee-compatible incentive", async () => {
|
|
203
|
+
|
|
204
|
+
const reward = 1_000_000_000n;
|
|
205
|
+
const fee = await budget.managementFee();
|
|
206
|
+
const erc20Incentive = fixtures.core.ERC20Incentive({
|
|
207
|
+
asset: erc20.assertValidAddress(),
|
|
208
|
+
strategy: StrategyType.POOL,
|
|
209
|
+
reward: 1_000_000_000n,
|
|
210
|
+
limit: 1n,
|
|
211
|
+
manager: budget.assertValidAddress(),
|
|
212
|
+
});
|
|
213
|
+
await budget.grantRoles(fixtures.core.assertValidAddress(), Roles.MANAGER);
|
|
214
|
+
const boost = await freshBoost(fixtures, {
|
|
215
|
+
budget: budget,
|
|
216
|
+
incentives: [erc20Incentive],
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const trustedSigner = accounts.at(0)!;
|
|
220
|
+
const claimant = trustedSigner.account;
|
|
221
|
+
const incentiveData = erc20Incentive.buildClaimData();
|
|
222
|
+
const claimDataPayload = await boost.validator.encodeClaimData({
|
|
223
|
+
signer: trustedSigner,
|
|
224
|
+
incentiveData,
|
|
225
|
+
chainId: defaultOptions.config.chains[0].id,
|
|
226
|
+
incentiveQuantity: boost.incentives.length,
|
|
227
|
+
claimant,
|
|
228
|
+
boostId: boost.id,
|
|
229
|
+
});
|
|
230
|
+
await fixtures.core.claimIncentive(
|
|
231
|
+
boost.id,
|
|
232
|
+
0n,
|
|
233
|
+
trustedSigner.account,
|
|
234
|
+
claimDataPayload,
|
|
235
|
+
);
|
|
236
|
+
let originalBalance = await erc20.balanceOf(accounts[0].account);
|
|
237
|
+
|
|
238
|
+
await budget.payManagementFee(boost.id, 0n);
|
|
239
|
+
let balance = await erc20.balanceOf(accounts[0].account);
|
|
240
|
+
|
|
241
|
+
expect(balance - originalBalance).toBe(reward*fee/10_000n);
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
test("native assets", async () => {
|
|
245
|
+
const originalAmount = await budget.available();
|
|
246
|
+
const disbursalAmount = parseEther("0.5");
|
|
247
|
+
const fee = await budget.managementFee();
|
|
248
|
+
await budget.disburse({
|
|
249
|
+
amount: disbursalAmount,
|
|
250
|
+
asset: zeroAddress,
|
|
251
|
+
target: defaultOptions.account.address,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
expect(await budget.available()).toBe(originalAmount - disbursalAmount - disbursalAmount*fee / 10_000n);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("erc20 assets", async () => {
|
|
259
|
+
const originalAmount = await budget.available(erc20.assertValidAddress());
|
|
260
|
+
const disbursalAmount = parseEther("10");
|
|
261
|
+
const fee = await budget.managementFee();
|
|
262
|
+
await budget.disburse({
|
|
263
|
+
amount: disbursalAmount,
|
|
264
|
+
asset: erc20.assertValidAddress(),
|
|
265
|
+
target: defaultOptions.account.address,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
expect(await budget.available(erc20.assertValidAddress())).toBe(
|
|
269
|
+
originalAmount - disbursalAmount - disbursalAmount*fee / 10_000n
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("erc1155 assets", async () => {
|
|
274
|
+
await budget.disburse({
|
|
275
|
+
tokenId: 1n,
|
|
276
|
+
amount: 5n,
|
|
277
|
+
asset: erc1155.assertValidAddress(),
|
|
278
|
+
target: defaultOptions.account.address,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
expect(await budget.available(erc1155.assertValidAddress(), 1n)).to.equal(
|
|
282
|
+
105n,
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|