From ca2031dfe74e2968a24338337f63b66afcdc964d Mon Sep 17 00:00:00 2001 From: imon-ccp Date: Thu, 5 Mar 2026 14:25:11 +0100 Subject: [PATCH 01/14] add: initial scratch --- packages/contracts/package.json | 3 + packages/contracts/src/abis/all-or-nothing.ts | 435 +++++++++++ .../src/abis/campaign-info-factory.ts | 130 ++++ packages/contracts/src/abis/campaign-info.ts | 497 +++++++++++++ packages/contracts/src/abis/global-params.ts | 445 +++++++++++ packages/contracts/src/abis/item-registry.ts | 75 ++ .../contracts/src/abis/keep-whats-raised.ts | 699 ++++++++++++++++++ .../contracts/src/abis/payment-treasury.ts | 454 ++++++++++++ .../contracts/src/abis/treasury-factory.ts | 110 +++ packages/contracts/src/client.ts | 80 ++ packages/contracts/src/constants/index.ts | 37 + .../src/entities/all-or-nothing-treasury.ts | 15 + .../src/entities/campaign-info-factory.ts | 15 + .../contracts/src/entities/campaign-info.ts | 34 + .../contracts/src/entities/global-params.ts | 16 + .../contracts/src/entities/item-registry.ts | 15 + .../entities/keep-whats-raised-treasury.ts | 15 + .../src/entities/payment-treasury.ts | 15 + .../src/entities/treasuries/index.ts | 7 + .../src/entities/treasury-factory.ts | 15 + .../src/errors/campaign-info-factory.ts | 77 ++ .../contracts/src/errors/contract-error.ts | 10 + .../contracts/src/errors/global-params.ts | 176 +++++ packages/contracts/src/errors/index.ts | 35 + .../src/errors/parse-contract-error.ts | 174 +++++ packages/contracts/src/index.ts | 43 +- packages/contracts/src/types/client.ts | 66 ++ .../contracts/src/types/config-options.ts | 11 + packages/contracts/src/types/index.ts | 98 +++ .../contracts/src/utils/chain-registry.ts | 44 ++ packages/contracts/src/utils/index.ts | 200 +++++ packages/contracts/src/viem/index.ts | 27 + packages/contracts/tsconfig.json | 3 +- 33 files changed, 4065 insertions(+), 11 deletions(-) create mode 100644 packages/contracts/src/abis/all-or-nothing.ts create mode 100644 packages/contracts/src/abis/campaign-info-factory.ts create mode 100644 packages/contracts/src/abis/campaign-info.ts create mode 100644 packages/contracts/src/abis/global-params.ts create mode 100644 packages/contracts/src/abis/item-registry.ts create mode 100644 packages/contracts/src/abis/keep-whats-raised.ts create mode 100644 packages/contracts/src/abis/payment-treasury.ts create mode 100644 packages/contracts/src/abis/treasury-factory.ts create mode 100644 packages/contracts/src/client.ts create mode 100644 packages/contracts/src/constants/index.ts create mode 100644 packages/contracts/src/entities/all-or-nothing-treasury.ts create mode 100644 packages/contracts/src/entities/campaign-info-factory.ts create mode 100644 packages/contracts/src/entities/campaign-info.ts create mode 100644 packages/contracts/src/entities/global-params.ts create mode 100644 packages/contracts/src/entities/item-registry.ts create mode 100644 packages/contracts/src/entities/keep-whats-raised-treasury.ts create mode 100644 packages/contracts/src/entities/payment-treasury.ts create mode 100644 packages/contracts/src/entities/treasuries/index.ts create mode 100644 packages/contracts/src/entities/treasury-factory.ts create mode 100644 packages/contracts/src/errors/campaign-info-factory.ts create mode 100644 packages/contracts/src/errors/contract-error.ts create mode 100644 packages/contracts/src/errors/global-params.ts create mode 100644 packages/contracts/src/errors/index.ts create mode 100644 packages/contracts/src/errors/parse-contract-error.ts create mode 100644 packages/contracts/src/types/client.ts create mode 100644 packages/contracts/src/types/config-options.ts create mode 100644 packages/contracts/src/types/index.ts create mode 100644 packages/contracts/src/utils/chain-registry.ts create mode 100644 packages/contracts/src/utils/index.ts create mode 100644 packages/contracts/src/viem/index.ts diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 76a30e0..1f22dfe 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -13,6 +13,9 @@ "test": "jest --coverage", "test:watch": "jest --watchAll" }, + "dependencies": { + "viem": "^2.23.0" + }, "devDependencies": { "@types/jest": "^30.0.0", "@types/node": "^20.14.11", diff --git a/packages/contracts/src/abis/all-or-nothing.ts b/packages/contracts/src/abis/all-or-nothing.ts new file mode 100644 index 0000000..cd8baa6 --- /dev/null +++ b/packages/contracts/src/abis/all-or-nothing.ts @@ -0,0 +1,435 @@ +const REWARD_TIER_COMPONENTS = [ + { internalType: "uint256", name: "rewardValue", type: "uint256" }, + { internalType: "bool", name: "isRewardTier", type: "bool" }, + { internalType: "bytes32[]", name: "itemId", type: "bytes32[]" }, + { internalType: "uint256[]", name: "itemValue", type: "uint256[]" }, + { internalType: "uint256[]", name: "itemQuantity", type: "uint256[]" }, +] as const; + +export const ALL_OR_NOTHING_ABI = [ + { inputs: [], name: "AccessCheckerUnauthorized", type: "error" }, + { inputs: [], name: "AllOrNothingFeeNotDisbursed", type: "error" }, + { inputs: [], name: "AllOrNothingInvalidInput", type: "error" }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "AllOrNothingNotClaimable", + type: "error", + }, + { inputs: [], name: "AllOrNothingNotSuccessful", type: "error" }, + { inputs: [], name: "AllOrNothingRewardExists", type: "error" }, + { inputs: [], name: "AllOrNothingTransferFailed", type: "error" }, + { inputs: [], name: "AllOrNothingUnAuthorized", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "inputTime", type: "uint256" }, + { internalType: "uint256", name: "currentTime", type: "uint256" }, + ], + name: "CurrentTimeIsGreater", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "inputTime", type: "uint256" }, + { internalType: "uint256", name: "currentTime", type: "uint256" }, + ], + name: "CurrentTimeIsLess", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "initialTime", type: "uint256" }, + { internalType: "uint256", name: "finalTime", type: "uint256" }, + ], + name: "CurrentTimeIsNotWithinRange", + type: "error", + }, + { inputs: [], name: "AllOrNothingFeeAlreadyDisbursed", type: "error" }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "AllOrNothingTokenNotAccepted", + type: "error", + }, + { inputs: [], name: "TreasuryCampaignInfoIsPaused", type: "error" }, + { inputs: [], name: "TreasuryFeeNotDisbursed", type: "error" }, + { inputs: [], name: "TreasurySuccessConditionNotFulfilled", type: "error" }, + { inputs: [], name: "TreasuryTransferFailed", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "approved", type: "address" }, + { indexed: true, internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "operator", type: "address" }, + { indexed: false, internalType: "bool", name: "approved", type: "bool" }, + ], + name: "ApprovalForAll", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "protocolShare", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "platformShare", type: "uint256" }, + ], + name: "FeesDisbursed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "backer", type: "address" }, + { indexed: true, internalType: "address", name: "pledgeToken", type: "address" }, + { indexed: false, internalType: "bytes32", name: "reward", type: "bytes32" }, + { indexed: false, internalType: "uint256", name: "pledgeAmount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "shippingFee", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "tokenId", type: "uint256" }, + { indexed: false, internalType: "bytes32[]", name: "rewards", type: "bytes32[]" }, + ], + name: "Receipt", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "tokenId", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "refundAmount", type: "uint256" }, + { indexed: false, internalType: "address", name: "claimer", type: "address" }, + ], + name: "RefundClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "rewardName", type: "bytes32" }, + { + components: REWARD_TIER_COMPONENTS, + indexed: false, + internalType: "struct AllOrNothing.Reward", + name: "reward", + type: "tuple", + }, + ], + name: "RewardAdded", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "RewardRemoved", + type: "event", + }, + { anonymous: false, inputs: [], name: "SuccessConditionNotFulfilled", type: "event" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: true, internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Unpaused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "WithdrawalSuccessful", + type: "event", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "pauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "unpauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, + { + components: [...REWARD_TIER_COMPONENTS], + internalType: "struct AllOrNothing.Reward[]", + name: "rewards", + type: "tuple[]", + }, + ], + name: "addRewards", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "_platformHash", type: "bytes32" }, + { internalType: "address", name: "_infoAddress", type: "address" }, + { internalType: "address", name: "_trustedForwarder", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "claimRefund", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "disburseFees", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "getApproved", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getLifetimeRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "getReward", + outputs: [ + { + components: REWARD_TIER_COMPONENTS, + internalType: "struct AllOrNothing.Reward", + name: "reward", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPlatformHash", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRefundedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getplatformFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "operator", type: "address" }, + ], + name: "isApprovedForAll", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "ownerOf", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "backer", type: "address" }, + { internalType: "address", name: "pledgeToken", type: "address" }, + { internalType: "uint256", name: "shippingFee", type: "uint256" }, + { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, + ], + name: "pledgeForAReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "backer", type: "address" }, + { internalType: "address", name: "pledgeToken", type: "address" }, + { internalType: "uint256", name: "pledgeAmount", type: "uint256" }, + ], + name: "pledgeWithoutAReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "removeReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "operator", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "tokenURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/campaign-info-factory.ts b/packages/contracts/src/abis/campaign-info-factory.ts new file mode 100644 index 0000000..cfc804e --- /dev/null +++ b/packages/contracts/src/abis/campaign-info-factory.ts @@ -0,0 +1,130 @@ +/** + * CampaignInfoFactory ABI — from provided ICampaignInfoFactory + CampaignInfoFactory.sol. + * UUPS; no constructor; initialize + createCampaign (with NFT params), updateImplementation. + */ +const CAMPAIGN_DATA_COMPONENTS = [ + { internalType: "uint256", name: "launchTime", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint256", name: "goalAmount", type: "uint256" }, + { internalType: "bytes32", name: "currency", type: "bytes32" }, +] as const; + +export const CAMPAIGN_INFO_FACTORY_ABI = [ + { inputs: [], name: "CampaignInfoFactoryInvalidInput", type: "error" }, + { inputs: [], name: "CampaignInfoFactoryCampaignInitializationFailed", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "platformHash", type: "bytes32" }], + name: "CampaignInfoFactoryPlatformNotListed", + type: "error", + }, + { + inputs: [ + { internalType: "bytes32", name: "identifierHash", type: "bytes32" }, + { internalType: "address", name: "cloneExists", type: "address" }, + ], + name: "CampaignInfoFactoryCampaignWithSameIdentifierExists", + type: "error", + }, + { inputs: [], name: "CampaignInfoInvalidTokenList", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "identifierHash", type: "bytes32" }, + { indexed: true, internalType: "address", name: "campaignInfoAddress", type: "address" }, + ], + name: "CampaignInfoFactoryCampaignCreated", + type: "event", + }, + { + anonymous: false, + inputs: [], + name: "CampaignInfoFactoryCampaignInitialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + inputs: [ + { internalType: "address", name: "creator", type: "address" }, + { internalType: "bytes32", name: "identifierHash", type: "bytes32" }, + { internalType: "bytes32[]", name: "selectedPlatformHash", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "platformDataKey", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "platformDataValue", type: "bytes32[]" }, + { + components: [...CAMPAIGN_DATA_COMPONENTS], + internalType: "struct ICampaignData.CampaignData", + name: "campaignData", + type: "tuple", + }, + { internalType: "string", name: "nftName", type: "string" }, + { internalType: "string", name: "nftSymbol", type: "string" }, + { internalType: "string", name: "nftImageURI", type: "string" }, + { internalType: "string", name: "contractURI", type: "string" }, + ], + name: "createCampaign", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "identifierHash", type: "bytes32" }], + name: "identifierToCampaignInfo", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "initialOwner", type: "address" }, + { internalType: "contract IGlobalParams", name: "globalParams", type: "address" }, + { internalType: "address", name: "campaignImplementation", type: "address" }, + { internalType: "address", name: "treasuryFactoryAddress", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "campaignInfo", type: "address" }], + name: "isValidCampaignInfo", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newImplementation", type: "address" }], + name: "updateImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/campaign-info.ts b/packages/contracts/src/abis/campaign-info.ts new file mode 100644 index 0000000..e8b9cbc --- /dev/null +++ b/packages/contracts/src/abis/campaign-info.ts @@ -0,0 +1,497 @@ +const CAMPAIGN_DATA_COMPONENTS = [ + { internalType: "uint256", name: "launchTime", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint256", name: "goalAmount", type: "uint256" }, + { internalType: "bytes32", name: "currency", type: "bytes32" }, +] as const; + +export const CAMPAIGN_INFO_ABI = [ + { inputs: [], name: "AdminAccessCheckerUnauthorized", type: "error" }, + { inputs: [], name: "CampaignInfoInvalidInput", type: "error" }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "bool", name: "selection", type: "bool" }, + ], + name: "CampaignInfoInvalidPlatformUpdate", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "CampaignInfoPlatformNotSelected", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "platformHash", type: "bytes32" }], + name: "CampaignInfoPlatformAlreadyApproved", + type: "error", + }, + { inputs: [], name: "CampaignInfoUnauthorized", type: "error" }, + { inputs: [], name: "CampaignInfoIsLocked", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "inputTime", type: "uint256" }, + { internalType: "uint256", name: "currentTime", type: "uint256" }, + ], + name: "CurrentTimeIsGreater", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "inputTime", type: "uint256" }, + { internalType: "uint256", name: "currentTime", type: "uint256" }, + ], + name: "CurrentTimeIsLess", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "initialTime", type: "uint256" }, + { internalType: "uint256", name: "finalTime", type: "uint256" }, + ], + name: "CurrentTimeIsNotWithinRange", + type: "error", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newDeadline", type: "uint256" }], + name: "CampaignInfoDeadlineUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newGoalAmount", type: "uint256" }], + name: "CampaignInfoGoalAmountUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newLaunchTime", type: "uint256" }], + name: "CampaignInfoLaunchTimeUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" }, + ], + name: "CampaignInfoOwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "address", name: "platformTreasury", type: "address" }, + ], + name: "CampaignInfoPlatformInfoUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "address", name: "platformTreasury", type: "address" }, + ], + name: "CampaignInfoPlatformSelected", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: false, internalType: "bool", name: "selection", type: "bool" }, + ], + name: "CampaignInfoSelectedPlatformUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "_pauseCampaign", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "address", name: "platformTreasuryAddress", type: "address" }, + ], + name: "_setPlatformInfo", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "_unpauseCampaign", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "checkIfPlatformSelected", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getGoalAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getIdentifierHash", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getLaunchTime", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformAdminAddress", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformDataKey", type: "bytes32" }], + name: "getPlatformData", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getProtocolAdminAddress", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getProtocolFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCampaignCurrency", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAcceptedTokens", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "isTokenAccepted", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformHash", type: "bytes32" }], + name: "getPlatformClaimDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalLifetimeRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalRefundedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalAvailableRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalCancelledAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTotalExpectedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "key", type: "bytes32" }], + name: "getDataFromRegistry", + outputs: [{ internalType: "bytes32", name: "value", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getBufferTime", + outputs: [{ internalType: "uint256", name: "bufferTime", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + ], + name: "getLineItemType", + outputs: [ + { internalType: "bool", name: "exists", type: "bool" }, + { internalType: "string", name: "label", type: "string" }, + { internalType: "bool", name: "countsTowardGoal", type: "bool" }, + { internalType: "bool", name: "applyProtocolFee", type: "bool" }, + { internalType: "bool", name: "canRefund", type: "bool" }, + { internalType: "bool", name: "instantTransfer", type: "bool" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCampaignConfig", + outputs: [ + { + components: [ + { internalType: "address", name: "treasuryFactory", type: "address" }, + { internalType: "uint256", name: "protocolFeePercent", type: "uint256" }, + { internalType: "bytes32", name: "identifierHash", type: "bytes32" }, + ], + internalType: "struct CampaignInfo.Config", + name: "config", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getApprovedPlatformHashes", + outputs: [{ internalType: "bytes32[]", name: "", type: "bytes32[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "isLocked", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformHash", type: "bytes32" }], + name: "checkIfPlatformApproved", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "cancelled", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "creator", type: "address" }, + { internalType: "contract IGlobalParams", name: "globalParams", type: "address" }, + { internalType: "bytes32[]", name: "selectedPlatformHash", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "platformDataKey", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "platformDataValue", type: "bytes32[]" }, + { + components: [...CAMPAIGN_DATA_COMPONENTS], + internalType: "struct ICampaignData.CampaignData", + name: "campaignData", + type: "tuple", + }, + { internalType: "address[]", name: "acceptedTokens", type: "address[]" }, + { internalType: "string", name: "nftName", type: "string" }, + { internalType: "string", name: "nftSymbol", type: "string" }, + { internalType: "string", name: "nftImageURI", type: "string" }, + { internalType: "string", name: "nftContractURI", type: "string" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "backer", type: "address" }, + { internalType: "bytes32", name: "reward", type: "bytes32" }, + { internalType: "address", name: "tokenAddress", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint256", name: "shippingFee", type: "uint256" }, + { internalType: "uint256", name: "tipAmount", type: "uint256" }, + ], + name: "mintNFTForPledge", + outputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "string", name: "newImageURI", type: "string" }], + name: "setImageURI", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "string", name: "newContractURI", type: "string" }], + name: "updateContractURI", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "account", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "deadline", type: "uint256" }], + name: "updateDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "goalAmount", type: "uint256" }], + name: "updateGoalAmount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "launchTime", type: "uint256" }], + name: "updateLaunchTime", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bool", name: "selection", type: "bool" }, + { internalType: "bytes32[]", name: "platformDataKey", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "platformDataValue", type: "bytes32[]" }, + ], + name: "updateSelectedPlatform", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/global-params.ts b/packages/contracts/src/abis/global-params.ts new file mode 100644 index 0000000..28d3b90 --- /dev/null +++ b/packages/contracts/src/abis/global-params.ts @@ -0,0 +1,445 @@ +export const GLOBAL_PARAMS_ABI = [ + { inputs: [], name: "GlobalParamsInvalidInput", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "GlobalParamsPlatformAdminNotSet", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "GlobalParamsPlatformAlreadyListed", + type: "error", + }, + { inputs: [], name: "GlobalParamsPlatformDataAlreadySet", type: "error" }, + { inputs: [], name: "GlobalParamsPlatformDataNotSet", type: "error" }, + { inputs: [], name: "GlobalParamsPlatformDataSlotTaken", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "GlobalParamsPlatformFeePercentIsZero", + type: "error", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "address", name: "platformAdminAddress", type: "address" }, + ], + name: "GlobalParamsPlatformNotListed", + type: "error", + }, + { inputs: [], name: "GlobalParamsUnauthorized", type: "error" }, + { inputs: [], name: "GlobalParamsCurrencyTokenLengthMismatch", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "currency", type: "bytes32" }], + name: "GlobalParamsCurrencyHasNoTokens", + type: "error", + }, + { + inputs: [ + { internalType: "bytes32", name: "currency", type: "bytes32" }, + { internalType: "address", name: "token", type: "address" }, + ], + name: "GlobalParamsTokenNotInCurrency", + type: "error", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + ], + name: "GlobalParamsPlatformLineItemTypeNotFound", + type: "error", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, + { indexed: true, internalType: "address", name: "newOwner", type: "address" }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "address", name: "account", type: "address" }], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "address", name: "newAdminAddress", type: "address" }, + ], + name: "PlatformAdminAddressUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "bytes32", name: "platformDataKey", type: "bytes32" }, + ], + name: "PlatformDataAdded", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: false, internalType: "bytes32", name: "platformDataKey", type: "bytes32" }, + ], + name: "PlatformDataRemoved", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "PlatformDelisted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "address", name: "platformAdminAddress", type: "address" }, + { indexed: false, internalType: "uint256", name: "platformFeePercent", type: "uint256" }, + ], + name: "PlatformEnlisted", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "address", name: "newAdminAddress", type: "address" }], + name: "ProtocolAdminAddressUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newFeePercent", type: "uint256" }], + name: "ProtocolFeePercentUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "currency", type: "bytes32" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + ], + name: "TokenAddedToCurrency", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "currency", type: "bytes32" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + ], + name: "TokenRemovedFromCurrency", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: true, internalType: "address", name: "platformAdapter", type: "address" }, + ], + name: "PlatformAdapterSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { indexed: false, internalType: "uint256", name: "claimDelay", type: "uint256" }, + ], + name: "PlatformClaimDelayUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "address", name: "account", type: "address" }], + name: "Unpaused", + type: "event", + }, + { + inputs: [ + { internalType: "bytes32", name: "key", type: "bytes32" }, + { internalType: "bytes32", name: "value", type: "bytes32" }, + ], + name: "addToRegistry", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "bytes32", name: "platformDataKey", type: "bytes32" }, + ], + name: "addPlatformData", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "currency", type: "bytes32" }, + { internalType: "address", name: "token", type: "address" }, + ], + name: "addTokenToCurrency", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformDataKey", type: "bytes32" }], + name: "checkIfPlatformDataKeyValid", + outputs: [{ internalType: "bool", name: "isValid", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "checkIfPlatformIsListed", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "delistPlatform", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "address", name: "platformAdminAddress", type: "address" }, + { internalType: "uint256", name: "platformFeePercent", type: "uint256" }, + { internalType: "address", name: "platformAdapter", type: "address" }, + ], + name: "enlistPlatform", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "key", type: "bytes32" }], + name: "getFromRegistry", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getNumberOfListedPlatforms", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformAdminAddress", + outputs: [{ internalType: "address", name: "account", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformDataKey", type: "bytes32" }], + name: "getPlatformDataOwner", + outputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformAdapter", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformClaimDelay", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], + name: "getPlatformFeePercent", + outputs: [{ internalType: "uint256", name: "platformFeePercent", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + ], + name: "getPlatformLineItemType", + outputs: [ + { internalType: "bool", name: "exists", type: "bool" }, + { internalType: "string", name: "label", type: "string" }, + { internalType: "bool", name: "countsTowardGoal", type: "bool" }, + { internalType: "bool", name: "applyProtocolFee", type: "bool" }, + { internalType: "bool", name: "canRefund", type: "bool" }, + { internalType: "bool", name: "instantTransfer", type: "bool" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "protocolAdminAddress", type: "address" }, + { internalType: "uint256", name: "protocolFeePercent", type: "uint256" }, + { internalType: "bytes32[]", name: "currencies", type: "bytes32[]" }, + { internalType: "address[][]", name: "tokensPerCurrency", type: "address[][]" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getProtocolAdminAddress", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getProtocolFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "currency", type: "bytes32" }], + name: "getTokensForCurrency", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "bytes32", name: "platformDataKey", type: "bytes32" }, + ], + name: "removePlatformData", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + ], + name: "removePlatformLineItemType", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "currency", type: "bytes32" }, + { internalType: "address", name: "token", type: "address" }, + ], + name: "removeTokenFromCurrency", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "address", name: "platformAdapter", type: "address" }, + ], + name: "setPlatformAdapter", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + { internalType: "string", name: "label", type: "string" }, + { internalType: "bool", name: "countsTowardGoal", type: "bool" }, + { internalType: "bool", name: "applyProtocolFee", type: "bool" }, + { internalType: "bool", name: "canRefund", type: "bool" }, + { internalType: "bool", name: "instantTransfer", type: "bool" }, + ], + name: "setPlatformLineItemType", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "address", name: "platformAdminAddress", type: "address" }, + ], + name: "updatePlatformAdminAddress", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, + { internalType: "uint256", name: "claimDelay", type: "uint256" }, + ], + name: "updatePlatformClaimDelay", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "protocolAdminAddress", type: "address" }], + name: "updateProtocolAdminAddress", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "protocolFeePercent", type: "uint256" }], + name: "updateProtocolFeePercent", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; + +export type GlobalParamsAbi = typeof GLOBAL_PARAMS_ABI; diff --git a/packages/contracts/src/abis/item-registry.ts b/packages/contracts/src/abis/item-registry.ts new file mode 100644 index 0000000..b679f1f --- /dev/null +++ b/packages/contracts/src/abis/item-registry.ts @@ -0,0 +1,75 @@ +const ITEM_COMPONENTS = [ + { internalType: "uint256", name: "actualWeight", type: "uint256" }, + { internalType: "uint256", name: "height", type: "uint256" }, + { internalType: "uint256", name: "width", type: "uint256" }, + { internalType: "uint256", name: "length", type: "uint256" }, + { internalType: "bytes32", name: "category", type: "bytes32" }, + { internalType: "bytes32", name: "declaredCurrency", type: "bytes32" }, +] as const; + +export const ITEM_REGISTRY_ABI = [ + { inputs: [], name: "ItemRegistryMismatchedArraysLength", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "bytes32", name: "itemId", type: "bytes32" }, + { + components: ITEM_COMPONENTS, + indexed: false, + internalType: "struct IItem.Item", + name: "item", + type: "tuple", + }, + ], + name: "ItemAdded", + type: "event", + }, + { + inputs: [ + { internalType: "bytes32", name: "itemId", type: "bytes32" }, + { + components: ITEM_COMPONENTS, + internalType: "struct IItem.Item", + name: "item", + type: "tuple", + }, + ], + name: "addItem", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32[]", name: "itemIds", type: "bytes32[]" }, + { + components: [...ITEM_COMPONENTS], + internalType: "struct IItem.Item[]", + name: "items", + type: "tuple[]", + }, + ], + name: "addItemsBatch", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "bytes32", name: "itemId", type: "bytes32" }, + ], + name: "getItem", + outputs: [ + { + components: ITEM_COMPONENTS, + internalType: "struct IItem.Item", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/keep-whats-raised.ts b/packages/contracts/src/abis/keep-whats-raised.ts new file mode 100644 index 0000000..68b4669 --- /dev/null +++ b/packages/contracts/src/abis/keep-whats-raised.ts @@ -0,0 +1,699 @@ +/** + * KeepWhatsRaised treasury ABI — pledgeId-based pledges and withdraw(token, amount). + * Matches the provided KeepWhatsRaised contract (no Fiat; different signatures from AllOrNothing). + */ +const REWARD_TIER_COMPONENTS = [ + { internalType: "uint256", name: "rewardValue", type: "uint256" }, + { internalType: "bool", name: "isRewardTier", type: "bool" }, + { internalType: "bytes32[]", name: "itemId", type: "bytes32[]" }, + { internalType: "uint256[]", name: "itemValue", type: "uint256[]" }, + { internalType: "uint256[]", name: "itemQuantity", type: "uint256[]" }, +] as const; + +const CONFIG_COMPONENTS = [ + { internalType: "uint256", name: "minimumWithdrawalForFeeExemption", type: "uint256" }, + { internalType: "uint256", name: "withdrawalDelay", type: "uint256" }, + { internalType: "uint256", name: "refundDelay", type: "uint256" }, + { internalType: "uint256", name: "configLockPeriod", type: "uint256" }, + { internalType: "bool", name: "isColombianCreator", type: "bool" }, +] as const; + +const FEE_KEYS_COMPONENTS = [ + { internalType: "bytes32", name: "flatFeeKey", type: "bytes32" }, + { internalType: "bytes32", name: "cumulativeFlatFeeKey", type: "bytes32" }, + { internalType: "bytes32[]", name: "grossPercentageFeeKeys", type: "bytes32[]" }, +] as const; + +const FEE_VALUES_COMPONENTS = [ + { internalType: "uint256", name: "flatFeeValue", type: "uint256" }, + { internalType: "uint256", name: "cumulativeFlatFeeValue", type: "uint256" }, + { internalType: "uint256[]", name: "grossPercentageFeeValues", type: "uint256[]" }, +] as const; + +const CAMPAIGN_DATA_COMPONENTS = [ + { internalType: "uint256", name: "launchTime", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { internalType: "uint256", name: "goalAmount", type: "uint256" }, + { internalType: "bytes32", name: "currency", type: "bytes32" }, +] as const; + +export const KEEP_WHATS_RAISED_ABI = [ + { inputs: [], name: "AccessCheckerUnauthorized", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedUnAuthorized", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedInvalidInput", type: "error" }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "KeepWhatsRaisedTokenNotAccepted", + type: "error", + }, + { inputs: [], name: "KeepWhatsRaisedRewardExists", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedDisabled", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedAlreadyEnabled", type: "error" }, + { + inputs: [ + { internalType: "uint256", name: "availableAmount", type: "uint256" }, + { internalType: "uint256", name: "withdrawalAmount", type: "uint256" }, + { internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "KeepWhatsRaisedInsufficientFundsForWithdrawalAndFee", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "withdrawalAmount", type: "uint256" }, + { internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "KeepWhatsRaisedInsufficientFundsForFee", + type: "error", + }, + { inputs: [], name: "KeepWhatsRaisedAlreadyWithdrawn", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedAlreadyClaimed", type: "error" }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "KeepWhatsRaisedNotClaimable", + type: "error", + }, + { inputs: [], name: "KeepWhatsRaisedNotClaimableAdmin", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedConfigLocked", type: "error" }, + { inputs: [], name: "KeepWhatsRaisedDisbursementBlocked", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "pledgeId", type: "bytes32" }], + name: "KeepWhatsRaisedPledgeAlreadyProcessed", + type: "error", + }, + { inputs: [], name: "TreasuryCampaignInfoIsPaused", type: "error" }, + { inputs: [], name: "TreasuryFeeNotDisbursed", type: "error" }, + { inputs: [], name: "TreasuryTransferFailed", type: "error" }, + { inputs: [], name: "TreasuryCampaignInfoIsPaused", type: "error" }, + { inputs: [], name: "TreasuryFeeNotDisbursed", type: "error" }, + { inputs: [], name: "TreasuryTransferFailed", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "approved", type: "address" }, + { indexed: true, internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "operator", type: "address" }, + { indexed: false, internalType: "bool", name: "approved", type: "bool" }, + ], + name: "ApprovalForAll", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "protocolShare", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "platformShare", type: "uint256" }, + ], + name: "FeesDisbursed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "backer", type: "address" }, + { indexed: true, internalType: "address", name: "pledgeToken", type: "address" }, + { indexed: false, internalType: "bytes32", name: "reward", type: "bytes32" }, + { indexed: false, internalType: "uint256", name: "pledgeAmount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "tip", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "tokenId", type: "uint256" }, + { indexed: false, internalType: "bytes32[]", name: "rewards", type: "bytes32[]" }, + ], + name: "Receipt", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, + { + components: [...REWARD_TIER_COMPONENTS], + indexed: false, + internalType: "struct IReward.Reward[]", + name: "rewards", + type: "tuple[]", + }, + ], + name: "RewardsAdded", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "RewardRemoved", + type: "event", + }, + { + anonymous: false, + inputs: [], + name: "WithdrawalApproved", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + components: [...CONFIG_COMPONENTS], + indexed: false, + internalType: "struct KeepWhatsRaised.Config", + name: "config", + type: "tuple", + }, + { + components: [...CAMPAIGN_DATA_COMPONENTS], + indexed: false, + internalType: "struct ICampaignData.CampaignData", + name: "campaignData", + type: "tuple", + }, + { + components: [...FEE_KEYS_COMPONENTS], + indexed: false, + internalType: "struct KeepWhatsRaised.FeeKeys", + name: "feeKeys", + type: "tuple", + }, + { + components: [...FEE_VALUES_COMPONENTS], + indexed: false, + internalType: "struct KeepWhatsRaised.FeeValues", + name: "feeValues", + type: "tuple", + }, + ], + name: "TreasuryConfigured", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: true, internalType: "address", name: "claimer", type: "address" }, + ], + name: "TipClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: true, internalType: "address", name: "claimer", type: "address" }, + ], + name: "FundClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "uint256", name: "tokenId", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "refundAmount", type: "uint256" }, + { indexed: true, internalType: "address", name: "claimer", type: "address" }, + ], + name: "RefundClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newDeadline", type: "uint256" }], + name: "KeepWhatsRaisedDeadlineUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "uint256", name: "newGoalAmount", type: "uint256" }], + name: "KeepWhatsRaisedGoalAmountUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "pledgeId", type: "bytes32" }, + { indexed: false, internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "KeepWhatsRaisedPaymentGatewayFeeSet", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "WithdrawalSuccessful", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "WithdrawalWithFeeSuccessful", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: true, internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "account", type: "address" }, + { indexed: false, internalType: "bytes32", name: "message", type: "bytes32" }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [ + { internalType: "bytes32", name: "_platformHash", type: "bytes32" }, + { internalType: "address", name: "_infoAddress", type: "address" }, + { internalType: "address", name: "_trustedForwarder", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "pauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "unpauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, + { + components: [...REWARD_TIER_COMPONENTS], + internalType: "struct KeepWhatsRaised.Reward[]", + name: "rewards", + type: "tuple[]", + }, + ], + name: "addRewards", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "owner", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "claimRefund", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "disburseFees", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "getApproved", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAvailableRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getWithdrawalApprovalStatus", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getLaunchTime", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getDeadline", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getGoalAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "pledgeId", type: "bytes32" }], + name: "getPaymentGatewayFee", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "feeKey", type: "bytes32" }], + name: "getFeeValue", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "pledgeId", type: "bytes32" }, + { internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "setPaymentGatewayFee", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "approveWithdrawal", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [...CONFIG_COMPONENTS], + internalType: "struct KeepWhatsRaised.Config", + name: "config", + type: "tuple", + }, + { + components: [...CAMPAIGN_DATA_COMPONENTS], + internalType: "struct ICampaignData.CampaignData", + name: "campaignData", + type: "tuple", + }, + { + components: [...FEE_KEYS_COMPONENTS], + internalType: "struct KeepWhatsRaised.FeeKeys", + name: "feeKeys", + type: "tuple", + }, + { + components: [...FEE_VALUES_COMPONENTS], + internalType: "struct KeepWhatsRaised.FeeValues", + name: "feeValues", + type: "tuple", + }, + ], + name: "configureTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "deadline", type: "uint256" }], + name: "updateDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "goalAmount", type: "uint256" }], + name: "updateGoalAmount", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "pledgeId", type: "bytes32" }, + { internalType: "address", name: "backer", type: "address" }, + { internalType: "address", name: "pledgeToken", type: "address" }, + { internalType: "uint256", name: "pledgeAmount", type: "uint256" }, + { internalType: "uint256", name: "tip", type: "uint256" }, + { internalType: "uint256", name: "fee", type: "uint256" }, + { internalType: "bytes32[]", name: "reward", type: "bytes32[]" }, + { internalType: "bool", name: "isPledgeForAReward", type: "bool" }, + ], + name: "setFeeAndPledge", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "claimTip", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "claimFund", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "getLifetimeRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "getReward", + outputs: [ + { + components: REWARD_TIER_COMPONENTS, + internalType: "struct KeepWhatsRaised.Reward", + name: "reward", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getPlatformHash", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRefundedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getplatformFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "operator", type: "address" }, + ], + name: "isApprovedForAll", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "ownerOf", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "pledgeId", type: "bytes32" }, + { internalType: "address", name: "backer", type: "address" }, + { internalType: "address", name: "pledgeToken", type: "address" }, + { internalType: "uint256", name: "tip", type: "uint256" }, + { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, + ], + name: "pledgeForAReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "pledgeId", type: "bytes32" }, + { internalType: "address", name: "backer", type: "address" }, + { internalType: "address", name: "pledgeToken", type: "address" }, + { internalType: "uint256", name: "pledgeAmount", type: "uint256" }, + { internalType: "uint256", name: "tip", type: "uint256" }, + ], + name: "pledgeWithoutAReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "rewardName", type: "bytes32" }], + name: "removeReward", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "operator", type: "address" }, + { internalType: "bool", name: "approved", type: "bool" }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + name: "tokenURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "tokenId", type: "uint256" }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/payment-treasury.ts b/packages/contracts/src/abis/payment-treasury.ts new file mode 100644 index 0000000..46f3e89 --- /dev/null +++ b/packages/contracts/src/abis/payment-treasury.ts @@ -0,0 +1,454 @@ +/** + * PaymentTreasury / TimeConstrainedPaymentTreasury ABI — from ICampaignPaymentTreasury. + * Same interface for both; use this ABI for either contract. + */ +const PAYMENT_LINE_ITEM_COMPONENTS = [ + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "string", name: "label", type: "string" }, + { internalType: "bool", name: "countsTowardGoal", type: "bool" }, + { internalType: "bool", name: "applyProtocolFee", type: "bool" }, + { internalType: "bool", name: "canRefund", type: "bool" }, + { internalType: "bool", name: "instantTransfer", type: "bool" }, +] as const; + +const LINE_ITEM_COMPONENTS = [ + { internalType: "bytes32", name: "typeId", type: "bytes32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, +] as const; + +const EXTERNAL_FEES_COMPONENTS = [ + { internalType: "bytes32", name: "feeType", type: "bytes32" }, + { internalType: "uint256", name: "feeAmount", type: "uint256" }, +] as const; + +export const PAYMENT_TREASURY_ABI = [ + { inputs: [], name: "PaymentTreasuryUnAuthorized", type: "error" }, + { inputs: [], name: "PaymentTreasuryInvalidInput", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentAlreadyExist", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentAlreadyConfirmed", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentAlreadyExpired", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentNotExist", + type: "error", + }, + { inputs: [], name: "PaymentTreasuryCampaignInfoIsPaused", type: "error" }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "PaymentTreasuryTokenNotAccepted", + type: "error", + }, + { inputs: [], name: "PaymentTreasurySuccessConditionNotFulfilled", type: "error" }, + { inputs: [], name: "PaymentTreasuryFeeNotDisbursed", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentNotConfirmed", + type: "error", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryPaymentNotClaimable", + type: "error", + }, + { inputs: [], name: "PaymentTreasuryAlreadyWithdrawn", type: "error" }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentTreasuryCryptoPayment", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "withdrawalAmount", type: "uint256" }, + { internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "PaymentTreasuryInsufficientFundsForFee", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "required", type: "uint256" }, + { internalType: "uint256", name: "available", type: "uint256" }, + ], + name: "PaymentTreasuryInsufficientBalance", + type: "error", + }, + { + inputs: [ + { internalType: "uint256", name: "expiration", type: "uint256" }, + { internalType: "uint256", name: "maxExpiration", type: "uint256" }, + ], + name: "PaymentTreasuryExpirationExceedsMax", + type: "error", + }, + { + inputs: [{ internalType: "uint256", name: "claimableAt", type: "uint256" }], + name: "PaymentTreasuryClaimWindowNotReached", + type: "error", + }, + { inputs: [], name: "PaymentTreasuryNoFundsToClaim", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "address", name: "buyerAddress", type: "address" }, + { indexed: true, internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { indexed: false, internalType: "bytes32", name: "buyerId", type: "bytes32" }, + { indexed: true, internalType: "bytes32", name: "itemId", type: "bytes32" }, + { indexed: true, internalType: "address", name: "paymentToken", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "expiration", type: "uint256" }, + { indexed: false, internalType: "bool", name: "isCryptoPayment", type: "bool" }, + ], + name: "PaymentCreated", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentCancelled", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: true, internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "PaymentConfirmed", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "bytes32[]", name: "paymentIds", type: "bytes32[]" }], + name: "PaymentBatchConfirmed", + type: "event", + }, + { + anonymous: false, + inputs: [{ indexed: false, internalType: "bytes32[]", name: "paymentIds", type: "bytes32[]" }], + name: "PaymentBatchCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: false, internalType: "uint256", name: "protocolShare", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "platformShare", type: "uint256" }, + ], + name: "FeesDisbursed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "fee", type: "uint256" }, + ], + name: "WithdrawalWithFeeSuccessful", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { indexed: false, internalType: "uint256", name: "refundAmount", type: "uint256" }, + { indexed: true, internalType: "address", name: "claimer", type: "address" }, + ], + name: "RefundClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, + { indexed: true, internalType: "address", name: "platformAdmin", type: "address" }, + ], + name: "NonGoalLineItemsClaimed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: false, internalType: "uint256", name: "platformAmount", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "protocolAmount", type: "uint256" }, + ], + name: "ExpiredFundsClaimed", + type: "event", + }, + { + inputs: [], + name: "getplatformHash", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getplatformFeePercent", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAvailableRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "getPaymentData", + outputs: [ + { + components: [ + { internalType: "address", name: "buyerAddress", type: "address" }, + { internalType: "bytes32", name: "buyerId", type: "bytes32" }, + { internalType: "bytes32", name: "itemId", type: "bytes32" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint256", name: "expiration", type: "uint256" }, + { internalType: "bool", name: "isConfirmed", type: "bool" }, + { internalType: "bool", name: "isCryptoPayment", type: "bool" }, + { internalType: "uint256", name: "lineItemCount", type: "uint256" }, + { internalType: "address", name: "paymentToken", type: "address" }, + { + components: [...PAYMENT_LINE_ITEM_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.PaymentLineItem[]", + name: "lineItems", + type: "tuple[]", + }, + { + components: [...EXTERNAL_FEES_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.ExternalFees[]", + name: "externalFees", + type: "tuple[]", + }, + ], + internalType: "struct ICampaignPaymentTreasury.PaymentData", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getLifetimeRaisedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRefundedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getExpectedAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "cancelled", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { internalType: "bytes32", name: "buyerId", type: "bytes32" }, + { internalType: "bytes32", name: "itemId", type: "bytes32" }, + { internalType: "address", name: "paymentToken", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint256", name: "expiration", type: "uint256" }, + { + components: [...LINE_ITEM_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.LineItem[]", + name: "lineItems", + type: "tuple[]", + }, + { + components: [...EXTERNAL_FEES_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.ExternalFees[]", + name: "externalFees", + type: "tuple[]", + }, + ], + name: "createPayment", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32[]", name: "paymentIds", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "buyerIds", type: "bytes32[]" }, + { internalType: "bytes32[]", name: "itemIds", type: "bytes32[]" }, + { internalType: "address[]", name: "paymentTokens", type: "address[]" }, + { internalType: "uint256[]", name: "amounts", type: "uint256[]" }, + { internalType: "uint256[]", name: "expirations", type: "uint256[]" }, + { + components: [...LINE_ITEM_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.LineItem[][]", + name: "lineItemsArray", + type: "tuple[][]", + }, + { + components: [...EXTERNAL_FEES_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.ExternalFees[][]", + name: "externalFeesArray", + type: "tuple[][]", + }, + ], + name: "createPaymentBatch", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { internalType: "bytes32", name: "itemId", type: "bytes32" }, + { internalType: "address", name: "buyerAddress", type: "address" }, + { internalType: "address", name: "paymentToken", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { + components: [...LINE_ITEM_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.LineItem[]", + name: "lineItems", + type: "tuple[]", + }, + { + components: [...EXTERNAL_FEES_COMPONENTS], + internalType: "struct ICampaignPaymentTreasury.ExternalFees[]", + name: "externalFees", + type: "tuple[]", + }, + ], + name: "processCryptoPayment", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "cancelPayment", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { internalType: "address", name: "buyerAddress", type: "address" }, + ], + name: "confirmPayment", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32[]", name: "paymentIds", type: "bytes32[]" }, + { internalType: "address[]", name: "buyerAddresses", type: "address[]" }, + ], + name: "confirmPaymentBatch", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "disburseFees", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "paymentId", type: "bytes32" }, + { internalType: "address", name: "refundAddress", type: "address" }, + ], + name: "claimRefund", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "paymentId", type: "bytes32" }], + name: "claimRefund", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "claimExpiredFunds", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "token", type: "address" }], + name: "claimNonGoalLineItems", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "pauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "unpauseTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "cancelTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/abis/treasury-factory.ts b/packages/contracts/src/abis/treasury-factory.ts new file mode 100644 index 0000000..1ba9eb8 --- /dev/null +++ b/packages/contracts/src/abis/treasury-factory.ts @@ -0,0 +1,110 @@ +/** + * TreasuryFactory ABI — from provided ITreasuryFactory + TreasuryFactory.sol. + * UUPS; initialize(globalParams); register/approve/disapprove/remove implementation; deploy returns address. + */ +export const TREASURY_FACTORY_ABI = [ + { inputs: [], name: "AdminAccessCheckerUnauthorized", type: "error" }, + { inputs: [], name: "TreasuryFactoryUnauthorized", type: "error" }, + { inputs: [], name: "TreasuryFactoryInvalidKey", type: "error" }, + { inputs: [], name: "TreasuryFactoryTreasuryCreationFailed", type: "error" }, + { inputs: [], name: "TreasuryFactoryInvalidAddress", type: "error" }, + { inputs: [], name: "TreasuryFactoryImplementationNotSet", type: "error" }, + { inputs: [], name: "TreasuryFactoryImplementationNotSetOrApproved", type: "error" }, + { inputs: [], name: "TreasuryFactoryTreasuryInitializationFailed", type: "error" }, + { inputs: [], name: "TreasuryFactorySettingPlatformInfoFailed", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { indexed: true, internalType: "uint256", name: "implementationId", type: "uint256" }, + { indexed: true, internalType: "address", name: "infoAddress", type: "address" }, + { indexed: false, internalType: "address", name: "treasuryAddress", type: "address" }, + ], + name: "TreasuryFactoryTreasuryDeployed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { indexed: true, internalType: "uint256", name: "implementationId", type: "uint256" }, + { indexed: true, internalType: "address", name: "implementation", type: "address" }, + ], + name: "TreasuryImplementationRegistered", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { indexed: true, internalType: "uint256", name: "implementationId", type: "uint256" }, + ], + name: "TreasuryImplementationRemoved", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "implementation", type: "address" }, + { indexed: false, internalType: "bool", name: "isApproved", type: "bool" }, + ], + name: "TreasuryImplementationApproval", + type: "event", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "uint256", name: "implementationId", type: "uint256" }, + { internalType: "address", name: "implementation", type: "address" }, + ], + name: "registerTreasuryImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "uint256", name: "implementationId", type: "uint256" }, + ], + name: "approveTreasuryImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "implementation", type: "address" }], + name: "disapproveTreasuryImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "uint256", name: "implementationId", type: "uint256" }, + ], + name: "removeTreasuryImplementation", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "bytes32", name: "platformHash", type: "bytes32" }, + { internalType: "address", name: "infoAddress", type: "address" }, + { internalType: "uint256", name: "implementationId", type: "uint256" }, + ], + name: "deploy", + outputs: [{ internalType: "address", name: "clone", type: "address" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "contract IGlobalParams", name: "globalParams", type: "address" }], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/packages/contracts/src/client.ts b/packages/contracts/src/client.ts new file mode 100644 index 0000000..bd6eac3 --- /dev/null +++ b/packages/contracts/src/client.ts @@ -0,0 +1,80 @@ +import type { + ChainIdentifier, + OakContractsClient, + OakContractsClientConfig, + PublicOakContractsClientConfig, + Chain, +} from "./types"; +import { DEFAULT_CLIENT_OPTIONS, type OakContractsClientOptions } from "./types"; +import { getChainFromId } from "./utils/chain-registry"; + +/** + * Resolves chain identifier to Chain object + * Supports both Chain objects and chain ID numbers + */ +function resolveChain(chain: ChainIdentifier): Chain { + if (typeof chain === "number") { + return getChainFromId(chain); + } + return chain; +} + +/** + * Creates a new Oak Contracts SDK client instance. + * + * @param config - Client configuration including chain, provider, signer, and optional options + * @returns Configured OakContractsClient instance + * + * @example + * ```typescript + * import { + * createOakContractsClient, + * createJsonRpcProvider, + * createWallet, + * createBrowserProvider, + * getSigner, + * mainnet, + * type Chain + * } from '@oaknetwork/contracts' + * + * // Backend with default timeout (3000ms) - using Chain object + * const provider = createJsonRpcProvider(rpcUrl, mainnet) + * const signer = createWallet(privateKey, provider, rpcUrl) + * const contractSdk = createOakContractsClient({ chain: mainnet, provider, signer }) + * + * // Backend with chain ID number (automatically converted to Chain object) + * const contractSdk = createOakContractsClient({ chain: 1, provider, signer }) + * + * // Backend with custom timeout + * const contractSdk = createOakContractsClient({ + * chain: 1, + * provider, + * signer, + * options: { timeout: 5000 } + * }) + * + * // Frontend (MetaMask, or any wallet via Web3Modal) + * const provider = createBrowserProvider(window.ethereum, mainnet) + * const signer = await getSigner(window.ethereum, mainnet) + * const contractSdk = createOakContractsClient({ chain: mainnet, provider, signer }) + * ``` + */ +export function createOakContractsClient( + config: OakContractsClientConfig, +): OakContractsClient { + const resolvedChain = resolveChain(config.chain); + + const publicConfig: PublicOakContractsClientConfig = { + chain: resolvedChain, + }; + + const options: OakContractsClientOptions = { + ...DEFAULT_CLIENT_OPTIONS, + ...config?.options, + }; + + return { + config: publicConfig, + options, + }; +} diff --git a/packages/contracts/src/constants/index.ts b/packages/contracts/src/constants/index.ts new file mode 100644 index 0000000..8dbc72c --- /dev/null +++ b/packages/contracts/src/constants/index.ts @@ -0,0 +1,37 @@ +import { keccak256, toHex, encodeAbiParameters, type Hex } from "viem"; + +/** Basis points denominator used for fee calculations (100% = 10_000 bps) */ +export const BPS_DENOMINATOR = 10_000n; + +/** Zero bytes32 value */ +export const BYTES32_ZERO: Hex = `0x${"00".repeat(32)}`; + +/** ERC-165 interface IDs */ +export const INTERFACE_IDS = { + ERC721: "0x80ac58cd", + ERC721Metadata: "0x5b5e139f", + ERC2612: "0xd505accf", +} as const; + +/** + * Data registry keys used in GlobalParams (matches DataRegistryKeys.sol). + * Use these when reading/writing GlobalParams data registry or with getDataFromRegistry. + */ +export const DATA_REGISTRY_KEYS = { + BUFFER_TIME: keccak256(toHex("bufferTime")), + MAX_PAYMENT_EXPIRATION: keccak256(toHex("maxPaymentExpiration")), + CAMPAIGN_LAUNCH_BUFFER: keccak256(toHex("campaignLaunchBuffer")), + MINIMUM_CAMPAIGN_DURATION: keccak256(toHex("minimumCampaignDuration")), +} as const; + +/** + * Generates a namespaced registry key scoped to a platform (matches DataRegistryKeys.scopedToPlatform). + */ +export function scopedToPlatform(baseKey: Hex, platformHash: Hex): Hex { + return keccak256( + encodeAbiParameters( + [{ type: "bytes32" }, { type: "bytes32" }], + [baseKey, platformHash], + ), + ); +} diff --git a/packages/contracts/src/entities/all-or-nothing-treasury.ts b/packages/contracts/src/entities/all-or-nothing-treasury.ts new file mode 100644 index 0000000..0eec882 --- /dev/null +++ b/packages/contracts/src/entities/all-or-nothing-treasury.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { ALL_OR_NOTHING_ABI } from "../abis/all-or-nothing.js"; + +/** + * Returns a typed contract config for AllOrNothing treasury. + * + * @example + * const aon = allOrNothingContract('0x...'); + * const raised = await publicClient.readContract({ ...aon, functionName: 'getRaisedAmount' }); + */ +export function allOrNothingContract(address: Address) { + return { address, abi: ALL_OR_NOTHING_ABI } as const; +} + +export type AllOrNothingContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/campaign-info-factory.ts b/packages/contracts/src/entities/campaign-info-factory.ts new file mode 100644 index 0000000..d584ec2 --- /dev/null +++ b/packages/contracts/src/entities/campaign-info-factory.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { CAMPAIGN_INFO_FACTORY_ABI } from "../abis/campaign-info-factory.js"; + +/** + * Returns a typed contract config for CampaignInfoFactory. + * + * @example + * const factory = campaignInfoFactoryContract('0x...'); + * const isValid = await publicClient.readContract({ ...factory, functionName: 'isValidCampaignInfo', args: [addr] }); + */ +export function campaignInfoFactoryContract(address: Address) { + return { address, abi: CAMPAIGN_INFO_FACTORY_ABI } as const; +} + +export type CampaignInfoFactoryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/campaign-info.ts b/packages/contracts/src/entities/campaign-info.ts new file mode 100644 index 0000000..bfb7a22 --- /dev/null +++ b/packages/contracts/src/entities/campaign-info.ts @@ -0,0 +1,34 @@ +import type { Address, PublicClient } from "viem"; +import { CAMPAIGN_INFO_ABI } from "../abis/campaign-info.js"; +import type { CampaignData } from "../types/index.js"; + +/** + * Returns a typed contract config for CampaignInfo. + * + * @example + * const ci = campaignInfoContract('0x...'); + * const deadline = await publicClient.readContract({ ...ci, functionName: 'getDeadline' }); + */ +export function campaignInfoContract(address: Address) { + return { address, abi: CAMPAIGN_INFO_ABI } as const; +} + +export type CampaignInfoContractConfig = ReturnType; + +/** + * Convenience: fetch the core campaign data in one batched call set. + * Uses Promise.all over individual reads for simplicity. + */ +export async function getCampaignData( + publicClient: PublicClient, + address: Address, +): Promise { + const config = campaignInfoContract(address); + const [launchTime, deadline, goalAmount, currency] = await Promise.all([ + publicClient.readContract({ ...config, functionName: "getLaunchTime" }), + publicClient.readContract({ ...config, functionName: "getDeadline" }), + publicClient.readContract({ ...config, functionName: "getGoalAmount" }), + publicClient.readContract({ ...config, functionName: "getCampaignCurrency" }), + ]); + return { launchTime, deadline, goalAmount, currency }; +} diff --git a/packages/contracts/src/entities/global-params.ts b/packages/contracts/src/entities/global-params.ts new file mode 100644 index 0000000..6ac5c53 --- /dev/null +++ b/packages/contracts/src/entities/global-params.ts @@ -0,0 +1,16 @@ +import type { Address } from "viem"; +import { GLOBAL_PARAMS_ABI } from "../abis/global-params.js"; + +/** + * Returns a typed contract config for GlobalParams that can be spread into + * viem's readContract, writeContract, simulateContract, etc. + * + * @example + * const gp = globalParamsContract('0x...'); + * const fee = await publicClient.readContract({ ...gp, functionName: 'getProtocolFeePercent' }); + */ +export function globalParamsContract(address: Address) { + return { address, abi: GLOBAL_PARAMS_ABI } as const; +} + +export type GlobalParamsContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/item-registry.ts b/packages/contracts/src/entities/item-registry.ts new file mode 100644 index 0000000..60c8677 --- /dev/null +++ b/packages/contracts/src/entities/item-registry.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { ITEM_REGISTRY_ABI } from "../abis/item-registry.js"; + +/** + * Returns a typed contract config for ItemRegistry. + * + * @example + * const ir = itemRegistryContract('0x...'); + * const item = await publicClient.readContract({ ...ir, functionName: 'getItem', args: [owner, itemId] }); + */ +export function itemRegistryContract(address: Address) { + return { address, abi: ITEM_REGISTRY_ABI } as const; +} + +export type ItemRegistryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/keep-whats-raised-treasury.ts b/packages/contracts/src/entities/keep-whats-raised-treasury.ts new file mode 100644 index 0000000..f665189 --- /dev/null +++ b/packages/contracts/src/entities/keep-whats-raised-treasury.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { KEEP_WHATS_RAISED_ABI } from "../abis/keep-whats-raised.js"; + +/** + * Returns a typed contract config for KeepWhatsRaised treasury. + * + * @example + * const kwr = keepWhatsRaisedContract('0x...'); + * const raised = await publicClient.readContract({ ...kwr, functionName: 'getRaisedAmount' }); + */ +export function keepWhatsRaisedContract(address: Address) { + return { address, abi: KEEP_WHATS_RAISED_ABI } as const; +} + +export type KeepWhatsRaisedContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/payment-treasury.ts b/packages/contracts/src/entities/payment-treasury.ts new file mode 100644 index 0000000..9820a10 --- /dev/null +++ b/packages/contracts/src/entities/payment-treasury.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { PAYMENT_TREASURY_ABI } from "../abis/payment-treasury.js"; + +/** + * Returns a typed contract config for PaymentTreasury / TimeConstrainedPaymentTreasury. + * + * @example + * const pt = paymentTreasuryContract('0x...'); + * const data = await publicClient.readContract({ ...pt, functionName: 'getPaymentData', args: [paymentId] }); + */ +export function paymentTreasuryContract(address: Address) { + return { address, abi: PAYMENT_TREASURY_ABI } as const; +} + +export type PaymentTreasuryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/treasuries/index.ts b/packages/contracts/src/entities/treasuries/index.ts new file mode 100644 index 0000000..c1a0d24 --- /dev/null +++ b/packages/contracts/src/entities/treasuries/index.ts @@ -0,0 +1,7 @@ +/** + * Treasury contract config factories. Use these for per-treasury instances (AllOrNothing, + * KeepWhatsRaised, PaymentTreasury, TimeConstrainedPaymentTreasury). + */ +export { allOrNothingContract, type AllOrNothingContractConfig } from "../all-or-nothing-treasury.js"; +export { keepWhatsRaisedContract, type KeepWhatsRaisedContractConfig } from "../keep-whats-raised-treasury.js"; +export { paymentTreasuryContract, type PaymentTreasuryContractConfig } from "../payment-treasury.js"; diff --git a/packages/contracts/src/entities/treasury-factory.ts b/packages/contracts/src/entities/treasury-factory.ts new file mode 100644 index 0000000..7179648 --- /dev/null +++ b/packages/contracts/src/entities/treasury-factory.ts @@ -0,0 +1,15 @@ +import type { Address } from "viem"; +import { TREASURY_FACTORY_ABI } from "../abis/treasury-factory.js"; + +/** + * Returns a typed contract config for TreasuryFactory. + * + * @example + * const tf = treasuryFactoryContract('0x...'); + * const hash = await walletClient.writeContract({ ...tf, functionName: 'deploy', args: [platformHash, infoAddr, implId] }); + */ +export function treasuryFactoryContract(address: Address) { + return { address, abi: TREASURY_FACTORY_ABI } as const; +} + +export type TreasuryFactoryContractConfig = ReturnType; diff --git a/packages/contracts/src/errors/campaign-info-factory.ts b/packages/contracts/src/errors/campaign-info-factory.ts new file mode 100644 index 0000000..c039237 --- /dev/null +++ b/packages/contracts/src/errors/campaign-info-factory.ts @@ -0,0 +1,77 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class CampaignInfoFactoryCampaignInitializationFailedError + extends Error + implements ContractErrorBase +{ + readonly name = "CampaignInfoFactoryCampaignInitializationFailed"; + readonly args: Record = {}; + readonly recoveryHint = + "Campaign initialization failed. Check campaign data, platform listing, and implementation."; + + constructor() { + super("CampaignInfoFactoryCampaignInitializationFailed()"); + Object.setPrototypeOf(this, CampaignInfoFactoryCampaignInitializationFailedError.prototype); + } +} + +export class CampaignInfoFactoryInvalidInputError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoFactoryInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = + "Invalid input for campaign creation. Check creator, platforms, and campaign data."; + + constructor() { + super("CampaignInfoFactoryInvalidInput()"); + Object.setPrototypeOf(this, CampaignInfoFactoryInvalidInputError.prototype); + } +} + +export class CampaignInfoFactoryPlatformNotListedError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoFactoryPlatformNotListed"; + readonly args: { platformHash: string }; + readonly recoveryHint = "The given platform is not listed in GlobalParams. Enlist the platform first."; + + constructor(args: { platformHash: string }) { + super(`CampaignInfoFactoryPlatformNotListed(platformHash: ${args.platformHash})`); + this.args = args; + Object.setPrototypeOf(this, CampaignInfoFactoryPlatformNotListedError.prototype); + } +} + +export class CampaignInfoFactoryCampaignWithSameIdentifierExistsError + extends Error + implements ContractErrorBase +{ + readonly name = "CampaignInfoFactoryCampaignWithSameIdentifierExists"; + readonly args: { identifierHash: string; cloneExists: string }; + readonly recoveryHint = + "A campaign with this identifier already exists. Use a different identifier or the existing campaign."; + + constructor(args: { identifierHash: string; cloneExists: string }) { + super( + `CampaignInfoFactoryCampaignWithSameIdentifierExists(identifierHash: ${args.identifierHash}, cloneExists: ${args.cloneExists})`, + ); + this.args = args; + Object.setPrototypeOf(this, CampaignInfoFactoryCampaignWithSameIdentifierExistsError.prototype); + } +} + +export class CampaignInfoInvalidTokenListError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoInvalidTokenList"; + readonly args: Record = {}; + readonly recoveryHint = + "Campaign currency tokens do not match GlobalParams for the campaign currency. Fix token list."; + + constructor() { + super("CampaignInfoInvalidTokenList()"); + Object.setPrototypeOf(this, CampaignInfoInvalidTokenListError.prototype); + } +} + +export type CampaignInfoFactoryError = + | CampaignInfoFactoryCampaignInitializationFailedError + | CampaignInfoFactoryInvalidInputError + | CampaignInfoFactoryPlatformNotListedError + | CampaignInfoFactoryCampaignWithSameIdentifierExistsError + | CampaignInfoInvalidTokenListError; diff --git a/packages/contracts/src/errors/contract-error.ts b/packages/contracts/src/errors/contract-error.ts new file mode 100644 index 0000000..2bbc088 --- /dev/null +++ b/packages/contracts/src/errors/contract-error.ts @@ -0,0 +1,10 @@ +/** + * Base type for contract revert errors. All typed SDK errors extend this. + * Preserves decoded parameters from the chain for logging and retries. + */ +export interface ContractErrorBase { + readonly name: string; + readonly args: Record; + /** Optional human-readable recovery suggestion for developers. */ + readonly recoveryHint?: string; +} diff --git a/packages/contracts/src/errors/global-params.ts b/packages/contracts/src/errors/global-params.ts new file mode 100644 index 0000000..e25eb03 --- /dev/null +++ b/packages/contracts/src/errors/global-params.ts @@ -0,0 +1,176 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class GlobalParamsInvalidInputError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = + "One or more inputs are invalid. Check addresses, fee percent, and platform bytes."; + + constructor() { + super("GlobalParamsInvalidInput()"); + Object.setPrototypeOf(this, GlobalParamsInvalidInputError.prototype); + } +} + +export class GlobalParamsPlatformAdminNotSetError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformAdminNotSet"; + readonly args: { platformBytes: string }; + readonly recoveryHint = "Set the platform admin address before performing this operation."; + + constructor(args: { platformBytes: string }) { + super(`GlobalParamsPlatformAdminNotSet(platformBytes: ${args.platformBytes})`); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsPlatformAdminNotSetError.prototype); + } +} + +export class GlobalParamsPlatformAlreadyListedError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformAlreadyListed"; + readonly args: { platformBytes: string }; + readonly recoveryHint = + "Platform is already listed. Use a different platform hash or update the existing platform."; + + constructor(args: { platformBytes: string }) { + super(`GlobalParamsPlatformAlreadyListed(platformBytes: ${args.platformBytes})`); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsPlatformAlreadyListedError.prototype); + } +} + +export class GlobalParamsPlatformDataAlreadySetError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformDataAlreadySet"; + readonly args: Record = {}; + readonly recoveryHint = "Platform data for this key is already set. Use a different key or update."; + + constructor() { + super("GlobalParamsPlatformDataAlreadySet()"); + Object.setPrototypeOf(this, GlobalParamsPlatformDataAlreadySetError.prototype); + } +} + +export class GlobalParamsPlatformDataNotSetError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformDataNotSet"; + readonly args: Record = {}; + readonly recoveryHint = "Platform data is not set. Add platform data first."; + + constructor() { + super("GlobalParamsPlatformDataNotSet()"); + Object.setPrototypeOf(this, GlobalParamsPlatformDataNotSetError.prototype); + } +} + +export class GlobalParamsPlatformDataSlotTakenError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformDataSlotTaken"; + readonly args: Record = {}; + readonly recoveryHint = "This platform data slot is already taken. Use a different key."; + + constructor() { + super("GlobalParamsPlatformDataSlotTaken()"); + Object.setPrototypeOf(this, GlobalParamsPlatformDataSlotTakenError.prototype); + } +} + +export class GlobalParamsPlatformFeePercentIsZeroError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformFeePercentIsZero"; + readonly args: { platformBytes: string }; + readonly recoveryHint = "Platform fee percent must be greater than zero."; + + constructor(args: { platformBytes: string }) { + super(`GlobalParamsPlatformFeePercentIsZero(platformBytes: ${args.platformBytes})`); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsPlatformFeePercentIsZeroError.prototype); + } +} + +export class GlobalParamsPlatformNotListedError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformNotListed"; + readonly args: { platformBytes: string; platformAdminAddress: string }; + readonly recoveryHint = + "Platform is not enlisted in GlobalParams. Enlist the platform first."; + + constructor(args: { platformBytes: string; platformAdminAddress: string }) { + super( + `GlobalParamsPlatformNotListed(platformBytes: ${args.platformBytes}, platformAdminAddress: ${args.platformAdminAddress})`, + ); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsPlatformNotListedError.prototype); + } +} + +export class GlobalParamsUnauthorizedError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsUnauthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this operation."; + + constructor() { + super("GlobalParamsUnauthorized()"); + Object.setPrototypeOf(this, GlobalParamsUnauthorizedError.prototype); + } +} + +export class GlobalParamsCurrencyTokenLengthMismatchError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsCurrencyTokenLengthMismatch"; + readonly args: Record = {}; + readonly recoveryHint = + "Length of currencies array must match length of tokensPerCurrency. Check initialize or currency config."; + + constructor() { + super("GlobalParamsCurrencyTokenLengthMismatch()"); + Object.setPrototypeOf(this, GlobalParamsCurrencyTokenLengthMismatchError.prototype); + } +} + +export class GlobalParamsCurrencyHasNoTokensError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsCurrencyHasNoTokens"; + readonly args: { currency: string }; + readonly recoveryHint = "This currency has no accepted tokens. Add at least one token for the currency."; + + constructor(args: { currency: string }) { + super(`GlobalParamsCurrencyHasNoTokens(currency: ${args.currency})`); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsCurrencyHasNoTokensError.prototype); + } +} + +export class GlobalParamsTokenNotInCurrencyError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsTokenNotInCurrency"; + readonly args: { currency: string; token: string }; + readonly recoveryHint = + "The given token is not in the accepted list for this currency. Use an approved token."; + + constructor(args: { currency: string; token: string }) { + super(`GlobalParamsTokenNotInCurrency(currency: ${args.currency}, token: ${args.token})`); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsTokenNotInCurrencyError.prototype); + } +} + +export class GlobalParamsPlatformLineItemTypeNotFoundError extends Error implements ContractErrorBase { + readonly name = "GlobalParamsPlatformLineItemTypeNotFound"; + readonly args: { platformHash: string; typeId: string }; + readonly recoveryHint = + "Platform line item type not found. Register the line item type for this platform first."; + + constructor(args: { platformHash: string; typeId: string }) { + super( + `GlobalParamsPlatformLineItemTypeNotFound(platformHash: ${args.platformHash}, typeId: ${args.typeId})`, + ); + this.args = args; + Object.setPrototypeOf(this, GlobalParamsPlatformLineItemTypeNotFoundError.prototype); + } +} + +export type GlobalParamsError = + | GlobalParamsInvalidInputError + | GlobalParamsPlatformAdminNotSetError + | GlobalParamsPlatformAlreadyListedError + | GlobalParamsPlatformDataAlreadySetError + | GlobalParamsPlatformDataNotSetError + | GlobalParamsPlatformDataSlotTakenError + | GlobalParamsPlatformFeePercentIsZeroError + | GlobalParamsPlatformNotListedError + | GlobalParamsUnauthorizedError + | GlobalParamsCurrencyTokenLengthMismatchError + | GlobalParamsCurrencyHasNoTokensError + | GlobalParamsTokenNotInCurrencyError + | GlobalParamsPlatformLineItemTypeNotFoundError; diff --git a/packages/contracts/src/errors/index.ts b/packages/contracts/src/errors/index.ts new file mode 100644 index 0000000..44cacc2 --- /dev/null +++ b/packages/contracts/src/errors/index.ts @@ -0,0 +1,35 @@ +export type { ContractErrorBase } from "./contract-error.js"; +export { parseContractError } from "./parse-contract-error.js"; +export { + GlobalParamsCurrencyHasNoTokensError, + GlobalParamsCurrencyTokenLengthMismatchError, + GlobalParamsInvalidInputError, + GlobalParamsPlatformAdminNotSetError, + GlobalParamsPlatformAlreadyListedError, + GlobalParamsPlatformDataAlreadySetError, + GlobalParamsPlatformDataNotSetError, + GlobalParamsPlatformDataSlotTakenError, + GlobalParamsPlatformFeePercentIsZeroError, + GlobalParamsPlatformLineItemTypeNotFoundError, + GlobalParamsPlatformNotListedError, + GlobalParamsTokenNotInCurrencyError, + GlobalParamsUnauthorizedError, +} from "./global-params.js"; +export type { GlobalParamsError } from "./global-params.js"; +export { + CampaignInfoFactoryCampaignInitializationFailedError, + CampaignInfoFactoryCampaignWithSameIdentifierExistsError, + CampaignInfoFactoryInvalidInputError, + CampaignInfoFactoryPlatformNotListedError, + CampaignInfoInvalidTokenListError, +} from "./campaign-info-factory.js"; +export type { CampaignInfoFactoryError } from "./campaign-info-factory.js"; + +import type { ContractErrorBase } from "./contract-error.js"; + +/** + * Returns a human-readable recovery suggestion for a typed contract error, if available. + */ +export function getRecoveryHint(error: ContractErrorBase): string | undefined { + return error.recoveryHint; +} diff --git a/packages/contracts/src/errors/parse-contract-error.ts b/packages/contracts/src/errors/parse-contract-error.ts new file mode 100644 index 0000000..14a8d83 --- /dev/null +++ b/packages/contracts/src/errors/parse-contract-error.ts @@ -0,0 +1,174 @@ +import { decodeErrorResult, type Hex } from "viem"; +import { GLOBAL_PARAMS_ABI } from "../abis/global-params.js"; +import { CAMPAIGN_INFO_FACTORY_ABI } from "../abis/campaign-info-factory.js"; +import type { ContractErrorBase } from "./contract-error.js"; +import { + GlobalParamsCurrencyHasNoTokensError, + GlobalParamsCurrencyTokenLengthMismatchError, + GlobalParamsInvalidInputError, + GlobalParamsPlatformAdminNotSetError, + GlobalParamsPlatformAlreadyListedError, + GlobalParamsPlatformDataAlreadySetError, + GlobalParamsPlatformDataNotSetError, + GlobalParamsPlatformDataSlotTakenError, + GlobalParamsPlatformFeePercentIsZeroError, + GlobalParamsPlatformLineItemTypeNotFoundError, + GlobalParamsPlatformNotListedError, + GlobalParamsTokenNotInCurrencyError, + GlobalParamsUnauthorizedError, +} from "./global-params.js"; +import { + CampaignInfoFactoryCampaignInitializationFailedError, + CampaignInfoFactoryCampaignWithSameIdentifierExistsError, + CampaignInfoFactoryInvalidInputError, + CampaignInfoFactoryPlatformNotListedError, + CampaignInfoInvalidTokenListError, +} from "./campaign-info-factory.js"; + +function isHex(data: string): data is Hex { + return typeof data === "string" && data.startsWith("0x") && /^0x[0-9a-fA-F]*$/.test(data); +} + +function toGlobalParamsError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "GlobalParamsInvalidInput": + return new GlobalParamsInvalidInputError(); + case "GlobalParamsPlatformAdminNotSet": + return new GlobalParamsPlatformAdminNotSetError({ + platformBytes: args["platformBytes"] as string, + }); + case "GlobalParamsPlatformAlreadyListed": + return new GlobalParamsPlatformAlreadyListedError({ + platformBytes: args["platformBytes"] as string, + }); + case "GlobalParamsPlatformDataAlreadySet": + return new GlobalParamsPlatformDataAlreadySetError(); + case "GlobalParamsPlatformDataNotSet": + return new GlobalParamsPlatformDataNotSetError(); + case "GlobalParamsPlatformDataSlotTaken": + return new GlobalParamsPlatformDataSlotTakenError(); + case "GlobalParamsPlatformFeePercentIsZero": + return new GlobalParamsPlatformFeePercentIsZeroError({ + platformBytes: args["platformBytes"] as string, + }); + case "GlobalParamsPlatformNotListed": + return new GlobalParamsPlatformNotListedError({ + platformBytes: args["platformBytes"] as string, + platformAdminAddress: args["platformAdminAddress"] as string, + }); + case "GlobalParamsUnauthorized": + return new GlobalParamsUnauthorizedError(); + case "GlobalParamsCurrencyTokenLengthMismatch": + return new GlobalParamsCurrencyTokenLengthMismatchError(); + case "GlobalParamsCurrencyHasNoTokens": + return new GlobalParamsCurrencyHasNoTokensError({ + currency: args["currency"] as string, + }); + case "GlobalParamsTokenNotInCurrency": + return new GlobalParamsTokenNotInCurrencyError({ + currency: args["currency"] as string, + token: args["token"] as string, + }); + case "GlobalParamsPlatformLineItemTypeNotFound": + return new GlobalParamsPlatformLineItemTypeNotFoundError({ + platformHash: args["platformHash"] as string, + typeId: args["typeId"] as string, + }); + default: + return new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`); + } +} + +function toCampaignInfoFactoryError( + name: string, + args: Record, +): ContractErrorBase { + switch (name) { + case "CampaignInfoFactoryCampaignInitializationFailed": + return new CampaignInfoFactoryCampaignInitializationFailedError(); + case "CampaignInfoFactoryInvalidInput": + return new CampaignInfoFactoryInvalidInputError(); + case "CampaignInfoFactoryPlatformNotListed": + return new CampaignInfoFactoryPlatformNotListedError({ + platformHash: args["platformHash"] as string, + }); + case "CampaignInfoFactoryCampaignWithSameIdentifierExists": + return new CampaignInfoFactoryCampaignWithSameIdentifierExistsError({ + identifierHash: args["identifierHash"] as string, + cloneExists: args["cloneExists"] as string, + }); + case "CampaignInfoInvalidTokenList": + return new CampaignInfoInvalidTokenListError(); + default: + return new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`); + } +} + +/** + * Parses raw revert data from a contract call and returns a typed SDK error if the error + * is recognized. Currently supports: GlobalParams, CampaignInfoFactory. Returns null if + * the data is not valid or not from a known contract. + * + * Use this when you have raw revert data (e.g. from a provider or estimateGas) and want + * to get a typed, discriminable error with decoded args and optional recovery hints. + * + * @param revertData - Hex string (0x + selector + encoded args), e.g. from catch (e) \{ e.data \} + * @returns Typed ContractErrorBase instance or null + */ +export function parseContractError(revertData: string): ContractErrorBase | null { + if (!revertData || !isHex(revertData) || revertData.length < 10) { + return null; + } + + const data = revertData as Hex; + + try { + const decoded = decodeErrorResult({ abi: GLOBAL_PARAMS_ABI, data }); + const args: Record = {}; + if (decoded.args) { + const decodedArgs = decoded.args as readonly unknown[]; + const errorAbi = GLOBAL_PARAMS_ABI.find( + (item) => item.type === "error" && item.name === decoded.errorName, + ); + if (errorAbi && "inputs" in errorAbi && errorAbi.inputs) { + errorAbi.inputs.forEach((input, i) => { + if (input.name && decodedArgs[i] !== undefined) { + args[input.name] = decodedArgs[i]; + } + }); + } + } + return toGlobalParamsError(decoded.errorName, args); + } catch { + // not a GlobalParams error, try next + } + + try { + const decoded = decodeErrorResult({ abi: CAMPAIGN_INFO_FACTORY_ABI, data }); + const args: Record = {}; + if (decoded.args) { + const decodedArgs = decoded.args as readonly unknown[]; + const errorAbi = CAMPAIGN_INFO_FACTORY_ABI.find( + (item) => item.type === "error" && item.name === decoded.errorName, + ); + if (errorAbi && "inputs" in errorAbi && errorAbi.inputs) { + errorAbi.inputs.forEach((input, i) => { + if (input.name && decodedArgs[i] !== undefined) { + args[input.name] = decodedArgs[i]; + } + }); + } + } + return toCampaignInfoFactoryError(decoded.errorName, args); + } catch { + // unknown error + } + + return null; +} diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts index a75b354..072b653 100644 --- a/packages/contracts/src/index.ts +++ b/packages/contracts/src/index.ts @@ -1,10 +1,33 @@ -// Contract definitions and types -// Add your contract code here - -/** - * Placeholder function to ensure coverage collection works - * Remove this once you add actual contract code - */ -export function placeholder(): void { - // This ensures coverage is calculated -} +export { createOakContractsClient } from "./client"; + +export * from "./utils"; +export * from "./types"; + +export type { + Account, + Address, + Hex, + PublicClient, + WalletClient, + Chain, +} from "./viem"; + +export { + createPublicClient, + createWalletClient, + http, + custom, + keccak256, + stringToHex, + parseEther, + formatEther, + parseUnits, + isAddress, + getAddress, + mainnet, + sepolia, + goerli, +} from "./viem"; + +export * from "./constants"; +export * from "./errors"; diff --git a/packages/contracts/src/types/client.ts b/packages/contracts/src/types/client.ts new file mode 100644 index 0000000..32a8e80 --- /dev/null +++ b/packages/contracts/src/types/client.ts @@ -0,0 +1,66 @@ +import type { + Account, + Address, + PublicClient, + WalletClient, + Chain, +} from "../viem"; +import type { OakContractsClientOptions } from "./config-options"; + +// Re-export Chain for convenience +export type { Chain }; + +/** + * Chain identifier - can be a chain ID number or a Chain object from viem + */ +export type ChainIdentifier = number | Chain; + +/** + * Provider interface - wraps viem's PublicClient + * This is a type alias for viem's PublicClient to provide a familiar API + */ +export type JsonRpcProvider = PublicClient; + +/** + * Signer interface - wraps viem's WalletClient with Account + * This is a type alias for viem's WalletClient with Account to provide a familiar API + */ +export interface Wallet extends WalletClient { + account: Account; +} + +/** + * Configuration for creating an Oak Contracts SDK client + */ +export interface OakContractsClientConfig { + /** Chain identifier (chain ID number or Chain object) */ + chain: ChainIdentifier; + /** Provider instance (wrapped viem PublicClient) */ + provider: JsonRpcProvider; + /** Signer instance (wrapped viem WalletClient with Account) */ + signer: Wallet; + /** Optional client options */ + options?: Partial; +} + +/** + * Resolved client configuration with resolved chain + */ +export interface ResolvedOakContractsClientConfig extends Omit { + chain: Chain; +} + +/** + * Public client configuration (without sensitive data) + */ +export interface PublicOakContractsClientConfig { + chain: Chain; +} + +/** + * Oak Contracts SDK Client interface + */ +export interface OakContractsClient { + readonly config: PublicOakContractsClientConfig; + readonly options: OakContractsClientOptions; +} diff --git a/packages/contracts/src/types/config-options.ts b/packages/contracts/src/types/config-options.ts new file mode 100644 index 0000000..b1184f1 --- /dev/null +++ b/packages/contracts/src/types/config-options.ts @@ -0,0 +1,11 @@ +/** + * Client options configuration + */ +export interface OakContractsClientOptions { + /** Request timeout in milliseconds */ + timeout?: number; +} + +export const DEFAULT_CLIENT_OPTIONS: OakContractsClientOptions = { + timeout: 3000, +}; diff --git a/packages/contracts/src/types/index.ts b/packages/contracts/src/types/index.ts new file mode 100644 index 0000000..91e65d3 --- /dev/null +++ b/packages/contracts/src/types/index.ts @@ -0,0 +1,98 @@ +/** + * Shared struct types derived from contract ABIs. + * All uint256 values are represented as bigint. + */ + +import type { Address, Hex } from "viem"; + +/** ICampaignData.CampaignData -- used by CampaignInfo and CampaignInfoFactory */ +export interface CampaignData { + launchTime: bigint; + deadline: bigint; + goalAmount: bigint; + /** bytes32 currency identifier (e.g. keccak256("USD")) */ + currency: Hex; +} + +/** + * Reward struct for AllOrNothing and KeepWhatsRaised treasuries. + * Includes the `isRewardTier` flag to distinguish tiers from flat rewards. + */ +export interface TieredReward { + rewardValue: bigint; + isRewardTier: boolean; + itemId: readonly Hex[]; + itemValue: readonly bigint[]; + itemQuantity: readonly bigint[]; +} + +/** ICampaignPaymentTreasury.LineItem -- line item in a payment (typeId + amount). */ +export interface LineItem { + typeId: Hex; + amount: bigint; +} + +/** IItem.Item -- used by ItemRegistry */ +export interface Item { + actualWeight: bigint; + height: bigint; + width: bigint; + length: bigint; + /** bytes32 category identifier */ + category: Hex; + /** bytes32 declared currency identifier */ + declaredCurrency: Hex; +} + +/** + * ICampaignPaymentTreasury.PaymentLineItem -- stored with configuration snapshot. + * All uint256 values are bigint; bytes32 are hex strings. + */ +export interface PaymentLineItem { + typeId: Hex; + amount: bigint; + label: string; + countsTowardGoal: boolean; + applyProtocolFee: boolean; + canRefund: boolean; + instantTransfer: boolean; +} + +/** ICampaignPaymentTreasury.ExternalFees -- informational external fee metadata. */ +export interface ExternalFees { + feeType: Hex; + feeAmount: bigint; +} + +/** + * ICampaignPaymentTreasury.PaymentData -- comprehensive payment snapshot. + * Mirrors the on-chain struct; lineItems and externalFees include config snapshots. + */ +export interface PaymentData { + buyerAddress: Address; + buyerId: Hex; + itemId: Hex; + amount: bigint; + expiration: bigint; + isConfirmed: boolean; + isCryptoPayment: boolean; + lineItemCount: bigint; + paymentToken: Address; + lineItems: readonly PaymentLineItem[]; + externalFees: readonly ExternalFees[]; +} + +/** EIP-2612 permit parameters */ +export interface PermitParams { + owner: Address; + spender: Address; + value: bigint; + deadline: bigint; + v: number; + r: Hex; + s: Hex; +} + +// Re-export client types +export * from "./client"; +export * from "./config-options"; \ No newline at end of file diff --git a/packages/contracts/src/utils/chain-registry.ts b/packages/contracts/src/utils/chain-registry.ts new file mode 100644 index 0000000..2d51aab --- /dev/null +++ b/packages/contracts/src/utils/chain-registry.ts @@ -0,0 +1,44 @@ +import { defineChain } from "../viem"; +import { mainnet, sepolia, goerli } from "../viem"; +import type { Chain } from "../viem"; + +/** + * Registry mapping chain IDs to Chain objects + * Contains common Ethereum chains + */ +const CHAIN_REGISTRY: Record = { + 1: mainnet, + 11155111: sepolia, + 5: goerli, +}; + +/** + * Resolves a chain ID number to a Chain object + * @param chainId - Chain ID number + * @returns Chain object + */ +export function getChainFromId(chainId: number): Chain { + // Check if we have a predefined chain for this ID + const predefinedChain = CHAIN_REGISTRY[chainId]; + if (predefinedChain) { + return predefinedChain; + } + + // For unknown chain IDs, create a minimal chain object + // This allows the SDK to work with any chain ID, though some features + // may require a full chain definition + return defineChain({ + id: chainId, + name: `Chain ${chainId}`, + nativeCurrency: { + decimals: 18, + name: "Ether", + symbol: "ETH", + }, + rpcUrls: { + default: { + http: [], + }, + }, + }); +} diff --git a/packages/contracts/src/utils/index.ts b/packages/contracts/src/utils/index.ts new file mode 100644 index 0000000..4877038 --- /dev/null +++ b/packages/contracts/src/utils/index.ts @@ -0,0 +1,200 @@ +// Re-export viem utility functions directly +export { + parseEther, + formatEther, + parseUnits, + isAddress, + getAddress, + stringToHex, +} from "../viem"; + +import { + keccak256 as viemKeccak256, + stringToHex, + type Hex, + createPublicClient, + createWalletClient, + http, + custom, + type Account, + type PublicClient, + type WalletClient, + type Chain, +} from "../viem"; +import type { JsonRpcProvider, Wallet } from "../types"; + +/** + * Hash data using keccak256 + * @param data - String (will be converted to hex) or Uint8Array to hash + * @returns Hex string hash + */ +export function keccak256(data: string | Uint8Array): `0x${string}` { + if (typeof data === "string") { + // If it's already a hex string, use it directly; otherwise convert + if (data.startsWith("0x")) { + return viemKeccak256(data as Hex) as `0x${string}`; + } + return viemKeccak256(stringToHex(data)) as `0x${string}`; + } + return viemKeccak256(data) as `0x${string}`; +} + +/** + * Hash a string using keccak256 (alias for id) + * This is equivalent to keccak256(stringToHex(input)) + * @param input - String to hash + * @returns Hex string hash + */ +export function id(input: string): `0x${string}` { + return keccak256(stringToHex(input)); +} + +/** + * Get current Unix timestamp in seconds + * @returns Current timestamp as bigint + */ +export function getCurrentTimestamp(): bigint { + return BigInt(Math.floor(Date.now() / 1000)); +} + +/** + * Add days to a timestamp + * @param timestamp - Unix timestamp in seconds + * @param days - Number of days to add + * @returns New timestamp as bigint + */ +export function addDays(timestamp: bigint, days: number): bigint { + const secondsPerDay = BigInt(86400); + return timestamp + BigInt(days) * secondsPerDay; +} + +// Export chain registry utility +export { getChainFromId } from "./chain-registry"; + +/** + * Creates a JsonRpcProvider (wrapped viem PublicClient) from an RPC URL + * @param rpcUrl - RPC URL string + * @param chain - Chain configuration + * @returns JsonRpcProvider instance + * + * @example + * ```typescript + * import { createJsonRpcProvider, mainnet } from '@oaknetwork/contracts' + * + * const provider = createJsonRpcProvider('https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY', mainnet) + * ``` + */ +export function createJsonRpcProvider( + rpcUrl: string, + chain: Chain, +): JsonRpcProvider { + return createPublicClient({ + chain, + transport: http(rpcUrl), + }) as JsonRpcProvider; +} + +/** + * Creates a Wallet (wrapped viem WalletClient) from a private key + * @param privateKey - Private key as hex string + * @param provider - Provider instance (PublicClient) - used to get chain config + * @param rpcUrl - Optional RPC URL. If not provided, will attempt to use the provider's transport + * @returns Wallet instance + * + * @example + * ```typescript + * import { createWallet, createJsonRpcProvider, mainnet } from '@oaknetwork/contracts' + * + * const provider = createJsonRpcProvider(rpcUrl, mainnet) + * const signer = createWallet(privateKey, provider, rpcUrl) + * ``` + */ +export function createWallet( + privateKey: `0x${string}`, + provider: PublicClient, + rpcUrl?: string, +): Wallet { + // Use the provided RPC URL or try to extract from provider's transport + // For http transports, we need the URL; for custom transports, we reuse the transport + const transport = rpcUrl + ? http(rpcUrl) + : (provider as any).transport || http(); + + const walletClient = createWalletClient({ + account: privateKey as `0x${string}`, + chain: provider.chain, + transport, + }); + + // Get the account from the wallet client + const account = walletClient.account as Account; + + return { + ...walletClient, + account, + } as Wallet; +} + +/** + * Creates a BrowserProvider (wrapped viem PublicClient) from window.ethereum + * This is a helper for frontend usage with MetaMask or other injected wallets + * @param ethereum - window.ethereum object (EIP-1193 provider) + * @param chain - Chain configuration + * @returns JsonRpcProvider instance + * + * @example + * ```typescript + * import { createBrowserProvider, mainnet } from '@oaknetwork/contracts' + * + * const provider = createBrowserProvider(window.ethereum, mainnet) + * ``` + */ +export function createBrowserProvider( + ethereum: any, + chain: Chain, +): JsonRpcProvider { + return createPublicClient({ + chain, + transport: custom(ethereum), + }) as JsonRpcProvider; +} + +/** + * Gets a signer from a browser provider (for use with MetaMask, etc.) + * This creates a WalletClient from the browser provider's ethereum object + * @param ethereum - window.ethereum object (EIP-1193 provider) + * @param chain - Chain configuration + * @returns Promise that resolves to a Wallet instance + * + * @example + * ```typescript + * import { createBrowserProvider, getSigner, mainnet } from '@oaknetwork/contracts' + * + * const provider = createBrowserProvider(window.ethereum, mainnet) + * const signer = await getSigner(window.ethereum, mainnet) + * ``` + */ +export async function getSigner( + ethereum: any, + chain: Chain, +): Promise { + // Request accounts from the provider + const accounts = await ethereum.request({ + method: "eth_requestAccounts", + }); + + if (!accounts || accounts.length === 0) { + throw new Error("No accounts found. Please connect your wallet."); + } + + const walletClient = createWalletClient({ + account: accounts[0] as `0x${string}`, + chain, + transport: custom(ethereum), + }); + + return { + ...walletClient, + account: walletClient.account as Account, + } as Wallet; +} diff --git a/packages/contracts/src/viem/index.ts b/packages/contracts/src/viem/index.ts new file mode 100644 index 0000000..4e5319d --- /dev/null +++ b/packages/contracts/src/viem/index.ts @@ -0,0 +1,27 @@ +// Re-export commonly used viem types and functions +export type { + Account, + Address, + Hex, + PublicClient, + WalletClient, +} from "viem"; + +export { + createPublicClient, + createWalletClient, + http, + custom, + keccak256, + stringToHex, + parseEther, + formatEther, + parseUnits, + isAddress, + getAddress, + defineChain, +} from "viem"; + +// Re-export Chain type and common chains +export type { Chain } from "viem/chains"; +export { mainnet, sepolia, goerli } from "viem/chains"; diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json index 309e9ce..e31f78d 100644 --- a/packages/contracts/tsconfig.json +++ b/packages/contracts/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", + "lib": ["ES2021", "DOM"], "module": "commonjs", "outDir": "./dist", "rootDir": "./src", From b3cff517e4fc9bac5687d66aa65ff020b8e2a396 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:51:12 +0600 Subject: [PATCH 02/14] chore: reorganize package structure and update build configuration - Updated `package.json` to use `tsup` for building and added module exports. - Changed TypeScript module resolution to `bundler` and updated module target to `ES2022`. - Introduced `tsup.config.ts` for build configuration. --- packages/contracts/package.json | 24 +- packages/contracts/tsconfig.json | 5 +- packages/contracts/tsup.config.ts | 15 + pnpm-lock.yaml | 950 +++++++++++++++++++++++++++++- 4 files changed, 979 insertions(+), 15 deletions(-) create mode 100644 packages/contracts/tsup.config.ts diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 1f22dfe..3d90e55 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -5,11 +5,30 @@ "publishConfig": { "access": "public" }, + "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./utils": { + "types": "./dist/utils/index.d.ts", + "import": "./dist/utils/index.js" + }, + "./contracts": { + "types": "./dist/contracts/index.d.ts", + "import": "./dist/contracts/index.js" + }, + "./client": { + "types": "./dist/client/index.d.ts", + "import": "./dist/client/index.js" + } + }, "scripts": { - "build": "tsc", - "prepublishOnly": "npm run build", + "build": "tsup", + "prepublishOnly": "pnpm run build", "test": "jest --coverage", "test:watch": "jest --watchAll" }, @@ -22,6 +41,7 @@ "jest": "^30.0.5", "ts-jest": "^29.4.6", "ts-node": "^10.9.2", + "tsup": "^8.5.1", "typescript": "^5.5.4" }, "author": "oaknetwork", diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json index e31f78d..b723b07 100644 --- a/packages/contracts/tsconfig.json +++ b/packages/contracts/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2020", "lib": ["ES2021", "DOM"], - "module": "commonjs", + "module": "ES2022", "outDir": "./dist", "rootDir": "./src", "strict": true, @@ -10,7 +10,8 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "declaration": true, - "moduleResolution": "node" + "moduleResolution": "bundler", + "noEmitOnError": false }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] diff --git a/packages/contracts/tsup.config.ts b/packages/contracts/tsup.config.ts new file mode 100644 index 0000000..bf46cfb --- /dev/null +++ b/packages/contracts/tsup.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: { + index: "src/index.ts", + "utils/index": "src/utils/index.ts", + "contracts/index": "src/contracts/index.ts", + "client/index": "src/client/index.ts", + }, + format: ["esm"], + dts: true, + splitting: false, + clean: true, + sourcemap: false, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94a164c..29cf8a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,11 @@ importers: specifier: ^30.0.0 version: 30.0.0 - packages/payments: + packages/contracts: + dependencies: + viem: + specifier: ^2.23.0 + version: 2.47.0(typescript@5.9.3) devDependencies: '@types/jest': specifier: ^30.0.0 @@ -27,26 +31,23 @@ importers: '@types/node': specifier: ^20.14.11 version: 20.19.33 - dotenv: - specifier: ^17.2.1 - version: 17.3.1 jest: specifier: ^30.0.5 version: 30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)) - nock: - specifier: ^14.0.10 - version: 14.0.11 ts-jest: specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(esbuild@0.27.3)(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.33)(typescript@5.9.3) + tsup: + specifier: ^8.5.1 + version: 8.5.1(typescript@5.9.3) typescript: specifier: ^5.5.4 version: 5.9.3 - packages/contracts: + packages/payments: devDependencies: '@types/jest': specifier: ^30.0.0 @@ -54,12 +55,18 @@ importers: '@types/node': specifier: ^20.14.11 version: 20.19.33 + dotenv: + specifier: ^17.2.1 + version: 17.3.1 jest: specifier: ^30.0.5 version: 30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)) + nock: + specifier: ^14.0.10 + version: 14.0.11 ts-jest: specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(esbuild@0.27.3)(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.33)(typescript@5.9.3) @@ -69,6 +76,9 @@ importers: packages: + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -306,6 +316,162 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@inquirer/external-editor@1.0.3': resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -441,6 +607,18 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -470,6 +648,140 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + cpu: [x64] + os: [win32] + + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} @@ -506,6 +818,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -631,6 +946,17 @@ packages: cpu: [x64] os: [win32] + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + acorn-walk@8.3.5: resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} @@ -668,6 +994,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -746,6 +1075,16 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -772,6 +1111,10 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -801,6 +1144,17 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -875,6 +1229,11 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -888,6 +1247,9 @@ packages: engines: {node: '>=4'} hasBin: true + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -916,6 +1278,15 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -924,6 +1295,9 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -1051,6 +1425,11 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -1202,6 +1581,10 @@ packages: node-notifier: optional: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1236,9 +1619,17 @@ packages: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -1255,6 +1646,9 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -1291,6 +1685,9 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -1298,6 +1695,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1327,6 +1727,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -1337,6 +1741,14 @@ packages: outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + ox@0.14.0: + resolution: {integrity: sha512-WLOB7IKnmI3Ol6RAqY7CJdZKl8QaI44LN91OGF1061YIeN6bL5IsFcdp7+oQShRyamE/8fW/CBRWhJAOzI35Dw==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} @@ -1387,6 +1799,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1410,6 +1825,27 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -1439,6 +1875,10 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -1455,6 +1895,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1496,6 +1941,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -1545,6 +1994,11 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1565,6 +2019,20 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -1572,6 +2040,13 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-jest@29.4.6: resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -1616,6 +2091,25 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} @@ -1633,6 +2127,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -1661,6 +2158,14 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + viem@2.47.0: + resolution: {integrity: sha512-jU5e1E1s5E5M1y+YrELDnNar/34U8NXfVcRfxtVETigs2gS1vvW2ngnBoQUGBwLnNr0kNv+NUu4m10OqHByoFw==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} @@ -1684,6 +2189,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -1709,6 +2226,8 @@ packages: snapshots: + '@adraffy/ens-normalize@1.11.1': {} + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -2064,6 +2583,84 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + '@inquirer/external-editor@1.0.3(@types/node@20.19.33)': dependencies: chardet: 2.1.1 @@ -2325,6 +2922,14 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2351,6 +2956,94 @@ snapshots: '@pkgr/core@0.2.9': {} + '@rollup/rollup-android-arm-eabi@4.59.0': + optional: true + + '@rollup/rollup-android-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-x64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.59.0': + optional: true + + '@rollup/rollup-openbsd-x64@4.59.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.59.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.59.0': + optional: true + + '@scure/base@1.2.6': {} + + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@sinclair/typebox@0.34.48': {} '@sinonjs/commons@3.0.1': @@ -2395,6 +3088,8 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/estree@1.0.8': {} + '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -2485,6 +3180,10 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + abitype@1.2.3(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + acorn-walk@8.3.5: dependencies: acorn: 8.16.0 @@ -2509,6 +3208,8 @@ snapshots: ansi-styles@6.2.3: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -2610,6 +3311,13 @@ snapshots: buffer-from@1.1.2: {} + bundle-require@5.1.0(esbuild@0.27.3): + dependencies: + esbuild: 0.27.3 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + callsites@3.1.0: {} camelcase@5.3.1: {} @@ -2627,6 +3335,10 @@ snapshots: chardet@2.1.1: {} + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + ci-info@3.9.0: {} ci-info@4.4.0: {} @@ -2649,6 +3361,12 @@ snapshots: color-name@1.1.4: {} + commander@4.1.1: {} + + confbox@0.1.8: {} + + consola@3.4.2: {} + convert-source-map@2.0.0: {} create-require@1.1.1: {} @@ -2698,12 +3416,43 @@ snapshots: dependencies: is-arrayish: 0.2.1 + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + escalade@3.2.0: {} escape-string-regexp@2.0.0: {} esprima@4.0.1: {} + eventemitter3@5.0.1: {} + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -2747,6 +3496,10 @@ snapshots: dependencies: bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -2756,6 +3509,12 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.1 + rollup: 4.59.0 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -2864,6 +3623,10 @@ snapshots: isexe@2.0.0: {} + isows@1.0.7(ws@8.18.3): + dependencies: + ws: 8.18.3 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@6.0.3: @@ -3213,6 +3976,8 @@ snapshots: - supports-color - ts-node + joycon@3.1.1: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -3238,8 +4003,12 @@ snapshots: leven@3.1.0: {} + lilconfig@3.1.3: {} + lines-and-columns@1.2.4: {} + load-tsconfig@0.2.5: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -3254,6 +4023,10 @@ snapshots: dependencies: yallist: 3.1.1 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + make-dir@4.0.0: dependencies: semver: 7.7.4 @@ -3283,10 +4056,23 @@ snapshots: minipass@7.1.3: {} + mlly@1.8.1: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + mri@1.2.0: {} ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -3309,6 +4095,8 @@ snapshots: dependencies: path-key: 3.1.1 + object-assign@4.1.1: {} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -3317,6 +4105,21 @@ snapshots: outvariant@1.4.3: {} + ox@0.14.0(typescript@5.9.3): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + p-filter@2.1.0: dependencies: p-map: 2.1.0 @@ -3361,6 +4164,8 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3375,6 +4180,16 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.1 + pathe: 2.0.3 + + postcss-load-config@6.0.1: + dependencies: + lilconfig: 3.1.3 + prettier@2.8.8: {} pretty-format@30.2.0: @@ -3400,6 +4215,8 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readdirp@4.1.2: {} + require-directory@2.1.1: {} resolve-cwd@3.0.0: @@ -3410,6 +4227,37 @@ snapshots: reusify@1.1.0: {} + rollup@4.59.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -3439,6 +4287,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -3485,6 +4335,16 @@ snapshots: strip-json-comments@3.1.1: {} + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -3505,13 +4365,32 @@ snapshots: glob: 10.5.0 minimatch: 10.2.2 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tmpl@1.0.5: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3): + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(esbuild@0.27.3)(jest-util@30.2.0)(jest@30.2.0(@types/node@20.19.33)(ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -3529,6 +4408,7 @@ snapshots: '@jest/transform': 30.2.0 '@jest/types': 30.2.0 babel-jest: 30.2.0(@babel/core@7.29.0) + esbuild: 0.27.3 jest-util: 30.2.0 ts-node@10.9.2(@types/node@20.19.33)(typescript@5.9.3): @@ -3552,6 +4432,33 @@ snapshots: tslib@2.8.1: optional: true + tsup@8.5.1(typescript@5.9.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.3) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.3 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1 + resolve-from: 5.0.0 + rollup: 4.59.0 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + type-detect@4.0.8: {} type-fest@0.21.3: {} @@ -3560,6 +4467,8 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.3: {} + uglify-js@3.19.3: optional: true @@ -3605,6 +4514,23 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + viem@2.47.0(typescript@5.9.3): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.0(typescript@5.9.3) + ws: 8.18.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + walker@1.0.8: dependencies: makeerror: 1.0.12 @@ -3632,6 +4558,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.18.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} From b507e5ab8caa2ef8be615e3855b4155215a5b9ee Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:51:44 +0600 Subject: [PATCH 03/14] feat: add common chain IDs for Celo networks - Introduced a new constant `CHAIN_IDS` to define common chain IDs for various Celo networks, including CELO_SEPOLIA and ALFAJORES, to facilitate contract client creation. --- packages/contracts/src/constants/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/contracts/src/constants/index.ts b/packages/contracts/src/constants/index.ts index 8dbc72c..7236a30 100644 --- a/packages/contracts/src/constants/index.ts +++ b/packages/contracts/src/constants/index.ts @@ -1,5 +1,18 @@ import { keccak256, toHex, encodeAbiParameters, type Hex } from "viem"; +/** + * Common chain IDs for use with createOakContractsClient({ chainId, rpcUrl, privateKey }). + * CELO_SEPOLIA is the Celo Sepolia testnet (11142220). + * ALFAJORES is the legacy Celo testnet (44787); use CELO_SEPOLIA for new development. + */ +export const CHAIN_IDS = { + MAINNET: 1, + SEPOLIA: 11155111, + GOERLI: 5, + CELO_SEPOLIA: 11142220, + ALFAJORES: 44787, +} as const; + /** Basis points denominator used for fee calculations (100% = 10_000 bps) */ export const BPS_DENOMINATOR = 10_000n; From dff511303e86e33d633a2efb5b8ef2a0a7c41325 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:52:16 +0600 Subject: [PATCH 04/14] feat: implement Oak Contracts SDK client - Added a new `index.ts` file to define the `createOakContractsClient` function, which supports both simple and full configuration for creating a client instance. - Included utility functions for client configuration and chain resolution, along with type guards for better type safety. - The client allows interaction with various contract entities such as global parameters, campaign info, and treasury factories. --- packages/contracts/src/client/index.ts | 155 +++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 packages/contracts/src/client/index.ts diff --git a/packages/contracts/src/client/index.ts b/packages/contracts/src/client/index.ts new file mode 100644 index 0000000..339c3f9 --- /dev/null +++ b/packages/contracts/src/client/index.ts @@ -0,0 +1,155 @@ +import { createPublicClient, createWalletClient, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import type { Address, Hex, PublicClient, WalletClient } from "viem"; +import type { Chain } from "viem/chains"; +import type { + ChainIdentifier, + OakContractsClient, + OakContractsClientConfig, + PublicOakContractsClientConfig, + FullOakContractsClientConfig, + SimpleOakContractsClientConfig, + TransactionReceipt, + GlobalParamsEntity, + CampaignInfoFactoryEntity, + TreasuryFactoryEntity, + CampaignInfoEntity, + PaymentTreasuryEntity, + AllOrNothingTreasuryEntity, + KeepWhatsRaisedTreasuryEntity, + ItemRegistryEntity, +} from "../types"; +import { DEFAULT_CLIENT_OPTIONS, type OakContractsClientOptions } from "../types"; +import { getChainFromId } from "../utils/chain-registry"; +import { createGlobalParamsEntity } from "../contracts/global-params"; +import { createCampaignInfoFactoryEntity } from "../contracts/campaign-info-factory"; +import { createTreasuryFactoryEntity } from "../contracts/treasury-factory"; +import { createCampaignInfoEntity } from "../contracts/campaign-info"; +import { createPaymentTreasuryEntity } from "../contracts/payment-treasury"; +import { createAllOrNothingEntity } from "../contracts/all-or-nothing"; +import { createKeepWhatsRaisedEntity } from "../contracts/keep-whats-raised"; +import { createItemRegistryEntity } from "../contracts/item-registry"; + +/** + * Type guard for simple client config (chainId + rpcUrl + privateKey). + */ +function isSimpleConfig( + config: OakContractsClientConfig, +): config is SimpleOakContractsClientConfig { + return "chainId" in config && "rpcUrl" in config && "privateKey" in config; +} + +/** + * Resolves a chain identifier (number or Chain object) to a Chain object. + */ +function resolveChain(chain: ChainIdentifier): Chain { + if (typeof chain === "number") { + return getChainFromId(chain); + } + return chain; +} + +/** + * Builds viem publicClient and walletClient from the given config. + */ +function buildClients(config: OakContractsClientConfig): { + chain: Chain; + publicClient: PublicClient; + walletClient: WalletClient; +} { + if (isSimpleConfig(config)) { + const chain = getChainFromId(config.chainId); + const transport = http(config.rpcUrl); + const publicClient = createPublicClient({ chain, transport }); + const account = privateKeyToAccount(config.privateKey); + const walletClient = createWalletClient({ account, chain, transport }); + return { chain, publicClient, walletClient }; + } + + const fullConfig = config as FullOakContractsClientConfig; + const chain = resolveChain(fullConfig.chain); + return { + chain, + publicClient: fullConfig.provider as PublicClient, + walletClient: fullConfig.signer as WalletClient, + }; +} + +/** + * Creates a new Oak Contracts SDK client instance. + * Supports simple config (chainId, rpcUrl, privateKey) or full config (chain, provider, signer). + * + * @param config - Simple: `{ chainId, rpcUrl, privateKey }` or full: `{ chain, provider, signer }` + * @returns Configured OakContractsClient + * + * @example + * ```typescript + * const oak = createOakContractsClient({ + * chainId: CHAIN_IDS.CELO_SEPOLIA, + * rpcUrl: "https://forno.celo-sepolia.org", + * privateKey: "0x...", + * }); + * + * const gp = oak.globalParams(GP_ADDRESS); + * const admin = await gp.getProtocolAdminAddress(); + * + * const factory = oak.campaignInfoFactory(FACTORY_ADDRESS); + * const txHash = await factory.createCampaign({ creator, identifierHash, campaignData, ... }); + * ``` + */ +export function createOakContractsClient( + config: OakContractsClientConfig, +): OakContractsClient { + const options: OakContractsClientOptions = { + ...DEFAULT_CLIENT_OPTIONS, + ...config?.options, + }; + + const { chain, publicClient, walletClient } = buildClients(config); + const publicConfig: PublicOakContractsClientConfig = { chain }; + + async function waitForReceipt(txHash: Hex): Promise { + const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); + return { + blockNumber: receipt.blockNumber, + gasUsed: receipt.gasUsed, + logs: receipt.logs.map((log) => ({ + topics: log.topics as readonly Hex[], + data: log.data, + })), + }; + } + + return { + config: publicConfig, + options, + publicClient, + walletClient, + waitForReceipt, + + globalParams(address: Address): GlobalParamsEntity { + return createGlobalParamsEntity(address, publicClient, walletClient, chain); + }, + campaignInfoFactory(address: Address): CampaignInfoFactoryEntity { + return createCampaignInfoFactoryEntity(address, publicClient, walletClient, chain); + }, + treasuryFactory(address: Address): TreasuryFactoryEntity { + return createTreasuryFactoryEntity(address, walletClient, chain); + }, + campaignInfo(address: Address): CampaignInfoEntity { + return createCampaignInfoEntity(address, publicClient, walletClient, chain); + }, + paymentTreasury(address: Address): PaymentTreasuryEntity { + return createPaymentTreasuryEntity(address, publicClient, walletClient, chain); + }, + allOrNothingTreasury(address: Address): AllOrNothingTreasuryEntity { + return createAllOrNothingEntity(address, publicClient, walletClient, chain); + }, + keepWhatsRaisedTreasury(address: Address): KeepWhatsRaisedTreasuryEntity { + return createKeepWhatsRaisedEntity(address, publicClient, walletClient, chain); + }, + itemRegistry(address: Address): ItemRegistryEntity { + return createItemRegistryEntity(address, publicClient, walletClient, chain); + }, + }; +} From b74b35330902317e812a3c763a6133eddca7567b Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:52:51 +0600 Subject: [PATCH 05/14] feat: enhance client types and reorganization - Expanded `client.ts` with new interfaces for campaign data, payment structures, and treasury configurations to improve type safety and clarity. - Consolidated protocol types in `index.ts` to streamline exports and reduce circular dependencies. - Introduced `SimpleOakContractsClientConfig` and `FullOakContractsClientConfig` for flexible client configuration options. --- packages/contracts/src/types/client.ts | 481 ++++++++++++++++++++++++- packages/contracts/src/types/index.ts | 99 +---- 2 files changed, 479 insertions(+), 101 deletions(-) diff --git a/packages/contracts/src/types/client.ts b/packages/contracts/src/types/client.ts index 32a8e80..ffee23d 100644 --- a/packages/contracts/src/types/client.ts +++ b/packages/contracts/src/types/client.ts @@ -1,15 +1,150 @@ import type { Account, Address, + Hex, PublicClient, WalletClient, - Chain, -} from "../viem"; +} from "viem"; +import type { Chain } from "viem/chains"; import type { OakContractsClientOptions } from "./config-options"; // Re-export Chain for convenience export type { Chain }; +// ─── Shared protocol struct types ───────────────────────────────────────────── + +/** ICampaignData.CampaignData -- used by CampaignInfo and CampaignInfoFactory */ +export interface CampaignData { + launchTime: bigint; + deadline: bigint; + goalAmount: bigint; + /** bytes32 currency identifier (e.g. keccak256("USD")) */ + currency: Hex; +} + +/** + * Reward struct for AllOrNothing and KeepWhatsRaised treasuries. + * Includes the `isRewardTier` flag to distinguish tiers from flat rewards. + */ +export interface TieredReward { + rewardValue: bigint; + isRewardTier: boolean; + itemId: readonly Hex[]; + itemValue: readonly bigint[]; + itemQuantity: readonly bigint[]; +} + +/** ICampaignPaymentTreasury.LineItem -- line item in a payment (typeId + amount). */ +export interface LineItem { + typeId: Hex; + amount: bigint; +} + +/** IItem.Item -- used by ItemRegistry */ +export interface Item { + actualWeight: bigint; + height: bigint; + width: bigint; + length: bigint; + /** bytes32 category identifier */ + category: Hex; + /** bytes32 declared currency identifier */ + declaredCurrency: Hex; +} + +/** + * ICampaignPaymentTreasury.PaymentLineItem -- stored with configuration snapshot. + * All uint256 values are bigint; bytes32 are hex strings. + */ +export interface PaymentLineItem { + typeId: Hex; + amount: bigint; + label: string; + countsTowardGoal: boolean; + applyProtocolFee: boolean; + canRefund: boolean; + instantTransfer: boolean; +} + +/** ICampaignPaymentTreasury.ExternalFees -- informational external fee metadata. */ +export interface ExternalFees { + feeType: Hex; + feeAmount: bigint; +} + +/** + * ICampaignPaymentTreasury.PaymentData -- comprehensive payment snapshot. + * Mirrors the on-chain struct; lineItems and externalFees include config snapshots. + */ +export interface PaymentData { + buyerAddress: Address; + buyerId: Hex; + itemId: Hex; + amount: bigint; + expiration: bigint; + isConfirmed: boolean; + isCryptoPayment: boolean; + lineItemCount: bigint; + paymentToken: Address; + lineItems: readonly PaymentLineItem[]; + externalFees: readonly ExternalFees[]; +} + +/** EIP-2612 permit parameters */ +export interface PermitParams { + owner: Address; + spender: Address; + value: bigint; + deadline: bigint; + v: number; + r: Hex; + s: Hex; +} + +/** + * Return type for getLineItemType / getPlatformLineItemType. + */ +export interface LineItemTypeInfo { + exists: boolean; + label: string; + countsTowardGoal: boolean; + applyProtocolFee: boolean; + canRefund: boolean; + instantTransfer: boolean; +} + +/** Return type for CampaignInfo.getCampaignConfig. */ +export interface CampaignConfig { + treasuryFactory: Address; + protocolFeePercent: bigint; + identifierHash: Hex; +} + +/** Config struct for KeepWhatsRaised.configureTreasury. */ +export interface KeepWhatsRaisedConfig { + minimumWithdrawalForFeeExemption: bigint; + withdrawalDelay: bigint; + refundDelay: bigint; + configLockPeriod: bigint; + isColombianCreator: boolean; +} + +/** FeeKeys struct for KeepWhatsRaised.configureTreasury. */ +export interface KeepWhatsRaisedFeeKeys { + flatFeeKey: Hex; + cumulativeFlatFeeKey: Hex; + grossPercentageFeeKeys: readonly Hex[]; +} + +/** FeeValues struct for KeepWhatsRaised.configureTreasury. */ +export interface KeepWhatsRaisedFeeValues { + flatFeeValue: bigint; + cumulativeFlatFeeValue: bigint; + grossPercentageFeeValues: readonly bigint[]; +} + +// ─── Client config types ─────────────────────────────────────────────────────── + /** * Chain identifier - can be a chain ID number or a Chain object from viem */ @@ -30,9 +165,24 @@ export interface Wallet extends WalletClient { } /** - * Configuration for creating an Oak Contracts SDK client + * Simple configuration for creating an Oak Contracts SDK client from chainId + RPC + private key. + * Use this for backend scripts or when you have a single signer. */ -export interface OakContractsClientConfig { +export interface SimpleOakContractsClientConfig { + /** Chain ID (e.g. CHAIN_IDS.CELO_SEPOLIA) */ + chainId: number; + /** RPC URL for the chain */ + rpcUrl: string; + /** Private key as hex string (0x-prefixed) */ + privateKey: `0x${string}`; + /** Optional client options */ + options?: Partial; +} + +/** + * Configuration for creating an Oak Contracts SDK client with explicit provider and signer. + */ +export interface FullOakContractsClientConfig { /** Chain identifier (chain ID number or Chain object) */ chain: ChainIdentifier; /** Provider instance (wrapped viem PublicClient) */ @@ -43,10 +193,18 @@ export interface OakContractsClientConfig { options?: Partial; } +/** + * Configuration for creating an Oak Contracts SDK client. + * Either simple (chainId, rpcUrl, privateKey) or full (chain, provider, signer). + */ +export type OakContractsClientConfig = + | SimpleOakContractsClientConfig + | FullOakContractsClientConfig; + /** * Resolved client configuration with resolved chain */ -export interface ResolvedOakContractsClientConfig extends Omit { +export interface ResolvedOakContractsClientConfig extends Omit { chain: Chain; } @@ -57,10 +215,321 @@ export interface PublicOakContractsClientConfig { chain: Chain; } +// ─── Entity interfaces ───────────────────────────────────────────────────────── + +/** + * GlobalParams entity — read and write methods for a GlobalParams contract instance. + */ +export interface GlobalParamsEntity { + // Reads + getProtocolAdminAddress(): Promise
; + getProtocolFeePercent(): Promise; + getNumberOfListedPlatforms(): Promise; + checkIfPlatformIsListed(platformBytes: Hex): Promise; + checkIfPlatformDataKeyValid(platformDataKey: Hex): Promise; + getPlatformAdminAddress(platformBytes: Hex): Promise
; + getPlatformFeePercent(platformBytes: Hex): Promise; + getPlatformClaimDelay(platformBytes: Hex): Promise; + getPlatformAdapter(platformBytes: Hex): Promise
; + getPlatformDataOwner(platformDataKey: Hex): Promise; + getPlatformLineItemType(platformHash: Hex, typeId: Hex): Promise; + getTokensForCurrency(currency: Hex): Promise; + getFromRegistry(key: Hex): Promise; + owner(): Promise
; + paused(): Promise; + // Writes + enlistPlatform(platformHash: Hex, platformAdminAddress: Address, platformFeePercent: bigint, platformAdapter: Address): Promise; + delistPlatform(platformBytes: Hex): Promise; + updatePlatformAdminAddress(platformBytes: Hex, platformAdminAddress: Address): Promise; + updatePlatformClaimDelay(platformBytes: Hex, claimDelay: bigint): Promise; + updateProtocolAdminAddress(protocolAdminAddress: Address): Promise; + updateProtocolFeePercent(protocolFeePercent: bigint): Promise; + setPlatformAdapter(platformBytes: Hex, platformAdapter: Address): Promise; + setPlatformLineItemType(platformHash: Hex, typeId: Hex, label: string, countsTowardGoal: boolean, applyProtocolFee: boolean, canRefund: boolean, instantTransfer: boolean): Promise; + removePlatformLineItemType(platformHash: Hex, typeId: Hex): Promise; + addTokenToCurrency(currency: Hex, token: Address): Promise; + removeTokenFromCurrency(currency: Hex, token: Address): Promise; + addPlatformData(platformBytes: Hex, platformDataKey: Hex): Promise; + removePlatformData(platformBytes: Hex, platformDataKey: Hex): Promise; + addToRegistry(key: Hex, value: Hex): Promise; + transferOwnership(newOwner: Address): Promise; + renounceOwnership(): Promise; +} + +/** + * Campaign data shape for createCampaign (matches ICampaignData.CampaignData). + */ +export interface CreateCampaignData { + launchTime: bigint; + deadline: bigint; + goalAmount: bigint; + currency: Hex; +} + +/** + * Parameters for createCampaign on CampaignInfoFactory. + */ +export interface CreateCampaignParams { + creator: Address; + identifierHash: Hex; + selectedPlatformHash: readonly Hex[]; + /** Optional platform-specific data keys (parallel array with platformDataValue) */ + platformDataKey?: readonly Hex[]; + /** Optional platform-specific data values (parallel array with platformDataKey) */ + platformDataValue?: readonly Hex[]; + campaignData: CreateCampaignData; + nftName: string; + nftSymbol: string; + nftImageURI: string; + contractURI: string; +} + +/** + * CampaignInfoFactory entity — createCampaign (write) and identifier/ownership reads. + */ +export interface CampaignInfoFactoryEntity { + createCampaign(params: CreateCampaignParams): Promise; + identifierToCampaignInfo(identifierHash: Hex): Promise
; + isValidCampaignInfo(campaignInfo: Address): Promise; + owner(): Promise
; + updateImplementation(newImplementation: Address): Promise; + transferOwnership(newOwner: Address): Promise; + renounceOwnership(): Promise; +} + +/** + * TreasuryFactory entity — deploy and manage treasury implementations. + */ +export interface TreasuryFactoryEntity { + deploy(platformHash: Hex, infoAddress: Address, implementationId: bigint): Promise; + registerTreasuryImplementation(platformHash: Hex, implementationId: bigint, implementation: Address): Promise; + approveTreasuryImplementation(platformHash: Hex, implementationId: bigint): Promise; + disapproveTreasuryImplementation(implementation: Address): Promise; + removeTreasuryImplementation(platformHash: Hex, implementationId: bigint): Promise; +} + +/** + * CampaignInfo entity — full reads and writes for a deployed CampaignInfo contract. + */ +export interface CampaignInfoEntity { + // Reads + getLaunchTime(): Promise; + getDeadline(): Promise; + getGoalAmount(): Promise; + getCampaignCurrency(): Promise; + getIdentifierHash(): Promise; + checkIfPlatformSelected(platformBytes: Hex): Promise; + checkIfPlatformApproved(platformHash: Hex): Promise; + getPlatformAdminAddress(platformBytes: Hex): Promise
; + getPlatformData(platformDataKey: Hex): Promise; + getPlatformFeePercent(platformBytes: Hex): Promise; + getPlatformClaimDelay(platformHash: Hex): Promise; + getProtocolAdminAddress(): Promise
; + getProtocolFeePercent(): Promise; + getAcceptedTokens(): Promise; + isTokenAccepted(token: Address): Promise; + getTotalRaisedAmount(): Promise; + getTotalLifetimeRaisedAmount(): Promise; + getTotalRefundedAmount(): Promise; + getTotalAvailableRaisedAmount(): Promise; + getTotalCancelledAmount(): Promise; + getTotalExpectedAmount(): Promise; + getDataFromRegistry(key: Hex): Promise; + getBufferTime(): Promise; + getLineItemType(platformHash: Hex, typeId: Hex): Promise; + getCampaignConfig(): Promise; + getApprovedPlatformHashes(): Promise; + isLocked(): Promise; + cancelled(): Promise; + owner(): Promise
; + paused(): Promise; + // Writes + updateDeadline(deadline: bigint): Promise; + updateGoalAmount(goalAmount: bigint): Promise; + updateLaunchTime(launchTime: bigint): Promise; + updateSelectedPlatform(platformHash: Hex, selection: boolean, platformDataKey: readonly Hex[], platformDataValue: readonly Hex[]): Promise; + setImageURI(newImageURI: string): Promise; + updateContractURI(newContractURI: string): Promise; + /** Mints an NFT for a pledge; returns the tx hash (tokenId is in the receipt events). */ + mintNFTForPledge(backer: Address, reward: Hex, tokenAddress: Address, amount: bigint, shippingFee: bigint, tipAmount: bigint): Promise; + burn(tokenId: bigint): Promise; + pauseCampaign(message: Hex): Promise; + unpauseCampaign(message: Hex): Promise; + setPlatformInfo(platformBytes: Hex, platformTreasuryAddress: Address): Promise; + transferOwnership(newOwner: Address): Promise; + renounceOwnership(): Promise; +} + +/** + * PaymentTreasury entity — full reads and writes for a deployed PaymentTreasury contract. + */ +export interface PaymentTreasuryEntity { + // Reads + getplatformHash(): Promise; + getplatformFeePercent(): Promise; + getRaisedAmount(): Promise; + getAvailableRaisedAmount(): Promise; + getLifetimeRaisedAmount(): Promise; + getRefundedAmount(): Promise; + getExpectedAmount(): Promise; + getPaymentData(paymentId: Hex): Promise; + cancelled(): Promise; + // Writes + createPayment(paymentId: Hex, buyerId: Hex, itemId: Hex, paymentToken: Address, amount: bigint, expiration: bigint, lineItems: readonly LineItem[], externalFees: readonly ExternalFees[]): Promise; + createPaymentBatch(paymentIds: readonly Hex[], buyerIds: readonly Hex[], itemIds: readonly Hex[], paymentTokens: readonly Address[], amounts: readonly bigint[], expirations: readonly bigint[], lineItemsArray: readonly (readonly LineItem[])[], externalFeesArray: readonly (readonly ExternalFees[])[]): Promise; + processCryptoPayment(paymentId: Hex, itemId: Hex, buyerAddress: Address, paymentToken: Address, amount: bigint, lineItems: readonly LineItem[], externalFees: readonly ExternalFees[]): Promise; + cancelPayment(paymentId: Hex): Promise; + confirmPayment(paymentId: Hex, buyerAddress: Address): Promise; + confirmPaymentBatch(paymentIds: readonly Hex[], buyerAddresses: readonly Address[]): Promise; + disburseFees(): Promise; + withdraw(): Promise; + /** Claim refund to a specific address. */ + claimRefund(paymentId: Hex, refundAddress: Address): Promise; + /** Claim refund to the caller's address. */ + claimRefundSelf(paymentId: Hex): Promise; + claimExpiredFunds(): Promise; + claimNonGoalLineItems(token: Address): Promise; + pauseTreasury(message: Hex): Promise; + unpauseTreasury(message: Hex): Promise; + cancelTreasury(message: Hex): Promise; +} + +/** + * AllOrNothing treasury entity — full reads and writes including ERC721 and pledge operations. + */ +export interface AllOrNothingTreasuryEntity { + // Reads + getRaisedAmount(): Promise; + getLifetimeRaisedAmount(): Promise; + getRefundedAmount(): Promise; + getReward(rewardName: Hex): Promise; + getPlatformHash(): Promise; + getplatformFeePercent(): Promise; + paused(): Promise; + balanceOf(owner: Address): Promise; + ownerOf(tokenId: bigint): Promise
; + tokenURI(tokenId: bigint): Promise; + name(): Promise; + symbol(): Promise; + getApproved(tokenId: bigint): Promise
; + isApprovedForAll(owner: Address, operator: Address): Promise; + supportsInterface(interfaceId: Hex): Promise; + // Writes + pauseTreasury(message: Hex): Promise; + unpauseTreasury(message: Hex): Promise; + addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]): Promise; + removeReward(rewardName: Hex): Promise; + pledgeForAReward(backer: Address, pledgeToken: Address, shippingFee: bigint, rewardNames: readonly Hex[]): Promise; + pledgeWithoutAReward(backer: Address, pledgeToken: Address, pledgeAmount: bigint): Promise; + claimRefund(tokenId: bigint): Promise; + disburseFees(): Promise; + withdraw(): Promise; + burn(tokenId: bigint): Promise; + approve(to: Address, tokenId: bigint): Promise; + setApprovalForAll(operator: Address, approved: boolean): Promise; + safeTransferFrom(from: Address, to: Address, tokenId: bigint): Promise; + transferFrom(from: Address, to: Address, tokenId: bigint): Promise; +} + +/** + * KeepWhatsRaised treasury entity — full reads and writes including pledge-based operations. + */ +export interface KeepWhatsRaisedTreasuryEntity { + // Reads + getRaisedAmount(): Promise; + getLifetimeRaisedAmount(): Promise; + getRefundedAmount(): Promise; + getAvailableRaisedAmount(): Promise; + getReward(rewardName: Hex): Promise; + getPlatformHash(): Promise; + getplatformFeePercent(): Promise; + getWithdrawalApprovalStatus(): Promise; + getLaunchTime(): Promise; + getDeadline(): Promise; + getGoalAmount(): Promise; + getPaymentGatewayFee(pledgeId: Hex): Promise; + getFeeValue(feeKey: Hex): Promise; + paused(): Promise; + balanceOf(owner: Address): Promise; + ownerOf(tokenId: bigint): Promise
; + tokenURI(tokenId: bigint): Promise; + name(): Promise; + symbol(): Promise; + getApproved(tokenId: bigint): Promise
; + isApprovedForAll(owner: Address, operator: Address): Promise; + supportsInterface(interfaceId: Hex): Promise; + // Writes + pauseTreasury(message: Hex): Promise; + unpauseTreasury(message: Hex): Promise; + configureTreasury(config: KeepWhatsRaisedConfig, campaignData: CampaignData, feeKeys: KeepWhatsRaisedFeeKeys, feeValues: KeepWhatsRaisedFeeValues): Promise; + addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]): Promise; + removeReward(rewardName: Hex): Promise; + approveWithdrawal(): Promise; + setPaymentGatewayFee(pledgeId: Hex, fee: bigint): Promise; + setFeeAndPledge(pledgeId: Hex, backer: Address, pledgeToken: Address, pledgeAmount: bigint, tip: bigint, fee: bigint, reward: readonly Hex[], isPledgeForAReward: boolean): Promise; + pledgeForAReward(pledgeId: Hex, backer: Address, pledgeToken: Address, tip: bigint, rewardNames: readonly Hex[]): Promise; + pledgeWithoutAReward(pledgeId: Hex, backer: Address, pledgeToken: Address, pledgeAmount: bigint, tip: bigint): Promise; + claimRefund(tokenId: bigint): Promise; + claimTip(): Promise; + claimFund(): Promise; + disburseFees(): Promise; + updateDeadline(deadline: bigint): Promise; + updateGoalAmount(goalAmount: bigint): Promise; + approve(to: Address, tokenId: bigint): Promise; + setApprovalForAll(operator: Address, approved: boolean): Promise; + safeTransferFrom(from: Address, to: Address, tokenId: bigint): Promise; + transferFrom(from: Address, to: Address, tokenId: bigint): Promise; +} + +/** + * ItemRegistry entity — add and retrieve items. + */ +export interface ItemRegistryEntity { + getItem(owner: Address, itemId: Hex): Promise; + addItem(itemId: Hex, item: Item): Promise; + addItemsBatch(itemIds: readonly Hex[], items: readonly Item[]): Promise; +} + +// ─── Receipt type ────────────────────────────────────────────────────────────── + +/** + * Transaction receipt returned by waitForReceipt. + */ +export interface TransactionReceipt { + blockNumber: bigint; + gasUsed: bigint; + logs: readonly { topics: readonly Hex[]; data: Hex }[]; +} + +// ─── Main client interface ───────────────────────────────────────────────────── + /** - * Oak Contracts SDK Client interface + * Oak Contracts SDK Client interface. + * Supports both simple (chainId/rpcUrl/privateKey) and full (chain/provider/signer) config. */ export interface OakContractsClient { readonly config: PublicOakContractsClientConfig; readonly options: OakContractsClientOptions; + /** Viem public client for reads and waitForTransactionReceipt */ + readonly publicClient: PublicClient; + /** Viem wallet client (with account when using privateKey or signer) */ + readonly walletClient: WalletClient; + /** Wait for a transaction to be mined; returns receipt with blockNumber, gasUsed, logs */ + waitForReceipt(txHash: Hex): Promise; + /** Get a GlobalParams entity for the given contract address */ + globalParams(address: Address): GlobalParamsEntity; + /** Get a CampaignInfoFactory entity for the given contract address */ + campaignInfoFactory(address: Address): CampaignInfoFactoryEntity; + /** Get a TreasuryFactory entity for the given contract address */ + treasuryFactory(address: Address): TreasuryFactoryEntity; + /** Get a CampaignInfo entity for the given contract address */ + campaignInfo(address: Address): CampaignInfoEntity; + /** Get a PaymentTreasury entity for the given contract address */ + paymentTreasury(address: Address): PaymentTreasuryEntity; + /** Get an AllOrNothing treasury entity for the given contract address */ + allOrNothingTreasury(address: Address): AllOrNothingTreasuryEntity; + /** Get a KeepWhatsRaised treasury entity for the given contract address */ + keepWhatsRaisedTreasury(address: Address): KeepWhatsRaisedTreasuryEntity; + /** Get an ItemRegistry entity for the given contract address */ + itemRegistry(address: Address): ItemRegistryEntity; } diff --git a/packages/contracts/src/types/index.ts b/packages/contracts/src/types/index.ts index 91e65d3..8e4a487 100644 --- a/packages/contracts/src/types/index.ts +++ b/packages/contracts/src/types/index.ts @@ -1,98 +1,7 @@ /** - * Shared struct types derived from contract ABIs. - * All uint256 values are represented as bigint. + * All protocol types are defined in client.ts and re-exported here. + * Struct types (CampaignData, TieredReward, LineItem, etc.) live alongside + * the entity interfaces so they can reference each other without circular imports. */ - -import type { Address, Hex } from "viem"; - -/** ICampaignData.CampaignData -- used by CampaignInfo and CampaignInfoFactory */ -export interface CampaignData { - launchTime: bigint; - deadline: bigint; - goalAmount: bigint; - /** bytes32 currency identifier (e.g. keccak256("USD")) */ - currency: Hex; -} - -/** - * Reward struct for AllOrNothing and KeepWhatsRaised treasuries. - * Includes the `isRewardTier` flag to distinguish tiers from flat rewards. - */ -export interface TieredReward { - rewardValue: bigint; - isRewardTier: boolean; - itemId: readonly Hex[]; - itemValue: readonly bigint[]; - itemQuantity: readonly bigint[]; -} - -/** ICampaignPaymentTreasury.LineItem -- line item in a payment (typeId + amount). */ -export interface LineItem { - typeId: Hex; - amount: bigint; -} - -/** IItem.Item -- used by ItemRegistry */ -export interface Item { - actualWeight: bigint; - height: bigint; - width: bigint; - length: bigint; - /** bytes32 category identifier */ - category: Hex; - /** bytes32 declared currency identifier */ - declaredCurrency: Hex; -} - -/** - * ICampaignPaymentTreasury.PaymentLineItem -- stored with configuration snapshot. - * All uint256 values are bigint; bytes32 are hex strings. - */ -export interface PaymentLineItem { - typeId: Hex; - amount: bigint; - label: string; - countsTowardGoal: boolean; - applyProtocolFee: boolean; - canRefund: boolean; - instantTransfer: boolean; -} - -/** ICampaignPaymentTreasury.ExternalFees -- informational external fee metadata. */ -export interface ExternalFees { - feeType: Hex; - feeAmount: bigint; -} - -/** - * ICampaignPaymentTreasury.PaymentData -- comprehensive payment snapshot. - * Mirrors the on-chain struct; lineItems and externalFees include config snapshots. - */ -export interface PaymentData { - buyerAddress: Address; - buyerId: Hex; - itemId: Hex; - amount: bigint; - expiration: bigint; - isConfirmed: boolean; - isCryptoPayment: boolean; - lineItemCount: bigint; - paymentToken: Address; - lineItems: readonly PaymentLineItem[]; - externalFees: readonly ExternalFees[]; -} - -/** EIP-2612 permit parameters */ -export interface PermitParams { - owner: Address; - spender: Address; - value: bigint; - deadline: bigint; - v: number; - r: Hex; - s: Hex; -} - -// Re-export client types export * from "./client"; -export * from "./config-options"; \ No newline at end of file +export * from "./config-options"; From ea1faa75694c115aac4f623ac891629929fe6bbd Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:53:29 +0600 Subject: [PATCH 06/14] feat: add Celo Sepolia to chain registry and update imports - Introduced Celo Sepolia testnet to the chain registry, enhancing support for Celo networks. - Updated import paths for `defineChain`, `mainnet`, `sepolia`, and `goerli` to use the new structure from the `viem` package. - Re-exported `CHAIN_IDS` from constants for simplified client configuration. --- .../contracts/src/utils/chain-registry.ts | 19 +++++++++++++++---- packages/contracts/src/utils/index.ts | 10 +++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/contracts/src/utils/chain-registry.ts b/packages/contracts/src/utils/chain-registry.ts index 2d51aab..a989ace 100644 --- a/packages/contracts/src/utils/chain-registry.ts +++ b/packages/contracts/src/utils/chain-registry.ts @@ -1,15 +1,26 @@ -import { defineChain } from "../viem"; -import { mainnet, sepolia, goerli } from "../viem"; -import type { Chain } from "../viem"; +import { defineChain } from "viem"; +import { mainnet, sepolia, goerli } from "viem/chains"; +import type { Chain } from "viem/chains"; + +/** Celo Sepolia testnet */ +const celoSepolia = defineChain({ + id: 11142220, + name: "Celo Sepolia", + nativeCurrency: { decimals: 18, name: "CELO", symbol: "CELO" }, + rpcUrls: { + default: { http: ["https://forno.celo-sepolia.celo-testnet.org"] }, + }, +}); /** * Registry mapping chain IDs to Chain objects - * Contains common Ethereum chains + * Contains common Ethereum and Celo chains */ const CHAIN_REGISTRY: Record = { 1: mainnet, 11155111: sepolia, 5: goerli, + 11142220: celoSepolia, }; /** diff --git a/packages/contracts/src/utils/index.ts b/packages/contracts/src/utils/index.ts index 4877038..2a06802 100644 --- a/packages/contracts/src/utils/index.ts +++ b/packages/contracts/src/utils/index.ts @@ -6,7 +6,11 @@ export { isAddress, getAddress, stringToHex, -} from "../viem"; + toHex, +} from "viem"; + +// Re-export chain IDs for simple client config +export { CHAIN_IDS } from "../constants"; import { keccak256 as viemKeccak256, @@ -19,8 +23,8 @@ import { type Account, type PublicClient, type WalletClient, - type Chain, -} from "../viem"; +} from "viem"; +import type { Chain } from "viem/chains"; import type { JsonRpcProvider, Wallet } from "../types"; /** From 3c4ea02ac962e8d2ff618910005db489b5933acc Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 20:54:01 +0600 Subject: [PATCH 07/14] feat: refactor contracts and introduce new entities - Removed the `client.ts` file as part of the restructuring. - Added multiple new contract entities including `AllOrNothing`, `CampaignInfoFactory`, `CampaignInfo`, `GlobalParams`, `ItemRegistry`, `KeepWhatsRaised`, `PaymentTreasury`, and `TreasuryFactory` to enhance functionality and modularity. - Updated `index.ts` to export the new contract entities for easier access. - Improved type safety and clarity in contract interactions by defining specific entity functions for read/write operations. --- packages/contracts/src/client.ts | 80 ------- .../contracts/src/contracts/all-or-nothing.ts | 148 +++++++++++++ .../src/contracts/campaign-info-factory.ts | 121 +++++++++++ .../contracts/src/contracts/campaign-info.ts | 187 ++++++++++++++++ .../contracts/src/contracts/global-params.ts | 154 ++++++++++++++ packages/contracts/src/contracts/index.ts | 8 + .../contracts/src/contracts/item-registry.ts | 58 +++++ .../src/contracts/keep-whats-raised.ts | 201 ++++++++++++++++++ .../src/contracts/payment-treasury.ts | 140 ++++++++++++ .../src/contracts/treasury-factory.ts | 89 ++++++++ packages/contracts/src/index.ts | 11 +- packages/contracts/src/viem/index.ts | 27 --- 12 files changed, 1111 insertions(+), 113 deletions(-) delete mode 100644 packages/contracts/src/client.ts create mode 100644 packages/contracts/src/contracts/all-or-nothing.ts create mode 100644 packages/contracts/src/contracts/campaign-info-factory.ts create mode 100644 packages/contracts/src/contracts/campaign-info.ts create mode 100644 packages/contracts/src/contracts/global-params.ts create mode 100644 packages/contracts/src/contracts/index.ts create mode 100644 packages/contracts/src/contracts/item-registry.ts create mode 100644 packages/contracts/src/contracts/keep-whats-raised.ts create mode 100644 packages/contracts/src/contracts/payment-treasury.ts create mode 100644 packages/contracts/src/contracts/treasury-factory.ts delete mode 100644 packages/contracts/src/viem/index.ts diff --git a/packages/contracts/src/client.ts b/packages/contracts/src/client.ts deleted file mode 100644 index bd6eac3..0000000 --- a/packages/contracts/src/client.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { - ChainIdentifier, - OakContractsClient, - OakContractsClientConfig, - PublicOakContractsClientConfig, - Chain, -} from "./types"; -import { DEFAULT_CLIENT_OPTIONS, type OakContractsClientOptions } from "./types"; -import { getChainFromId } from "./utils/chain-registry"; - -/** - * Resolves chain identifier to Chain object - * Supports both Chain objects and chain ID numbers - */ -function resolveChain(chain: ChainIdentifier): Chain { - if (typeof chain === "number") { - return getChainFromId(chain); - } - return chain; -} - -/** - * Creates a new Oak Contracts SDK client instance. - * - * @param config - Client configuration including chain, provider, signer, and optional options - * @returns Configured OakContractsClient instance - * - * @example - * ```typescript - * import { - * createOakContractsClient, - * createJsonRpcProvider, - * createWallet, - * createBrowserProvider, - * getSigner, - * mainnet, - * type Chain - * } from '@oaknetwork/contracts' - * - * // Backend with default timeout (3000ms) - using Chain object - * const provider = createJsonRpcProvider(rpcUrl, mainnet) - * const signer = createWallet(privateKey, provider, rpcUrl) - * const contractSdk = createOakContractsClient({ chain: mainnet, provider, signer }) - * - * // Backend with chain ID number (automatically converted to Chain object) - * const contractSdk = createOakContractsClient({ chain: 1, provider, signer }) - * - * // Backend with custom timeout - * const contractSdk = createOakContractsClient({ - * chain: 1, - * provider, - * signer, - * options: { timeout: 5000 } - * }) - * - * // Frontend (MetaMask, or any wallet via Web3Modal) - * const provider = createBrowserProvider(window.ethereum, mainnet) - * const signer = await getSigner(window.ethereum, mainnet) - * const contractSdk = createOakContractsClient({ chain: mainnet, provider, signer }) - * ``` - */ -export function createOakContractsClient( - config: OakContractsClientConfig, -): OakContractsClient { - const resolvedChain = resolveChain(config.chain); - - const publicConfig: PublicOakContractsClientConfig = { - chain: resolvedChain, - }; - - const options: OakContractsClientOptions = { - ...DEFAULT_CLIENT_OPTIONS, - ...config?.options, - }; - - return { - config: publicConfig, - options, - }; -} diff --git a/packages/contracts/src/contracts/all-or-nothing.ts b/packages/contracts/src/contracts/all-or-nothing.ts new file mode 100644 index 0000000..c6e4f5e --- /dev/null +++ b/packages/contracts/src/contracts/all-or-nothing.ts @@ -0,0 +1,148 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { ALL_OR_NOTHING_ABI } from "../abis/all-or-nothing"; +import type { AllOrNothingTreasuryEntity, TieredReward } from "../types"; + +/** + * Creates an AllOrNothing treasury entity with full read/write access. + * + * @param address - Deployed AllOrNothing treasury contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns AllOrNothingTreasuryEntity + * + * @example + * ```typescript + * const aon = createAllOrNothingEntity(AON_ADDRESS, publicClient, walletClient, chain); + * const raised = await aon.getRaisedAmount(); + * await aon.pledgeForAReward(backer, token, shippingFee, rewardNames); + * ``` + */ +export function createAllOrNothingEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): AllOrNothingTreasuryEntity { + const contract = { address, abi: ALL_OR_NOTHING_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Reads ──────────────────────────────────────────────────────────────── + + async getRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRaisedAmount" }); + }, + async getLifetimeRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getLifetimeRaisedAmount" }); + }, + async getRefundedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRefundedAmount" }); + }, + async getReward(rewardName: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getReward", args: [rewardName] }); + return result as unknown as TieredReward; + }, + async getPlatformHash() { + return publicClient.readContract({ ...contract, functionName: "getPlatformHash" }); + }, + async getplatformFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); + }, + async paused() { + return publicClient.readContract({ ...contract, functionName: "paused" }); + }, + async balanceOf(owner: Address) { + return publicClient.readContract({ ...contract, functionName: "balanceOf", args: [owner] }); + }, + async ownerOf(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "ownerOf", args: [tokenId] }); + }, + async tokenURI(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "tokenURI", args: [tokenId] }); + }, + async name() { + return publicClient.readContract({ ...contract, functionName: "name" }); + }, + async symbol() { + return publicClient.readContract({ ...contract, functionName: "symbol" }); + }, + async getApproved(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "getApproved", args: [tokenId] }); + }, + async isApprovedForAll(owner: Address, operator: Address) { + return publicClient.readContract({ ...contract, functionName: "isApprovedForAll", args: [owner, operator] }); + }, + async supportsInterface(interfaceId: Hex) { + return publicClient.readContract({ ...contract, functionName: "supportsInterface", args: [interfaceId as `0x${string}`] }); + }, + + // ── Writes ─────────────────────────────────────────────────────────────── + + async pauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pauseTreasury", args: [message] }); + }, + async unpauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "unpauseTreasury", args: [message] }); + }, + async addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "addRewards", + args: [[...rewardNames], rewards.map((r) => ({ rewardValue: r.rewardValue, isRewardTier: r.isRewardTier, itemId: [...r.itemId], itemValue: [...r.itemValue], itemQuantity: [...r.itemQuantity] }))], + }); + }, + async removeReward(rewardName: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "removeReward", args: [rewardName] }); + }, + async pledgeForAReward(backer: Address, pledgeToken: Address, shippingFee: bigint, rewardNames: readonly Hex[]) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pledgeForAReward", args: [backer, pledgeToken, shippingFee, [...rewardNames]] }); + }, + async pledgeWithoutAReward(backer: Address, pledgeToken: Address, pledgeAmount: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pledgeWithoutAReward", args: [backer, pledgeToken, pledgeAmount] }); + }, + async claimRefund(tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimRefund", args: [tokenId] }); + }, + async disburseFees() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "disburseFees", args: [] }); + }, + async withdraw() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "withdraw", args: [] }); + }, + async burn(tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "burn", args: [tokenId] }); + }, + async approve(to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "approve", args: [to, tokenId] }); + }, + async setApprovalForAll(operator: Address, approved: boolean) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setApprovalForAll", args: [operator, approved] }); + }, + async safeTransferFrom(from: Address, to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "safeTransferFrom", args: [from, to, tokenId] }); + }, + async transferFrom(from: Address, to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "transferFrom", args: [from, to, tokenId] }); + }, + }; +} diff --git a/packages/contracts/src/contracts/campaign-info-factory.ts b/packages/contracts/src/contracts/campaign-info-factory.ts new file mode 100644 index 0000000..9807e7e --- /dev/null +++ b/packages/contracts/src/contracts/campaign-info-factory.ts @@ -0,0 +1,121 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { CAMPAIGN_INFO_FACTORY_ABI } from "../abis/campaign-info-factory"; +import type { CampaignInfoFactoryEntity, CreateCampaignParams } from "../types"; + +/** + * Creates a CampaignInfoFactory entity with full read/write access. + * + * @param address - Deployed CampaignInfoFactory contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns CampaignInfoFactoryEntity + * + * @example + * ```typescript + * const factory = createCampaignInfoFactoryEntity(FACTORY_ADDRESS, publicClient, walletClient, chain); + * const txHash = await factory.createCampaign({ creator, identifierHash, campaignData, ... }); + * const address = await factory.identifierToCampaignInfo(identifierHash); + * ``` + */ +export function createCampaignInfoFactoryEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): CampaignInfoFactoryEntity { + const contract = { address, abi: CAMPAIGN_INFO_FACTORY_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Writes ────────────────────────────────────────────────────────────── + + async createCampaign(params: CreateCampaignParams): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "createCampaign", + args: [ + params.creator, + params.identifierHash, + [...params.selectedPlatformHash], + [...(params.platformDataKey ?? [])], + [...(params.platformDataValue ?? [])], + { + launchTime: params.campaignData.launchTime, + deadline: params.campaignData.deadline, + goalAmount: params.campaignData.goalAmount, + currency: params.campaignData.currency, + }, + params.nftName, + params.nftSymbol, + params.nftImageURI, + params.contractURI, + ], + }); + }, + + async updateImplementation(newImplementation: Address): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "updateImplementation", + args: [newImplementation], + }); + }, + + async transferOwnership(newOwner: Address): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "transferOwnership", + args: [newOwner], + }); + }, + + async renounceOwnership(): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "renounceOwnership", + args: [], + }); + }, + + // ── Reads ──────────────────────────────────────────────────────────────── + + async identifierToCampaignInfo(identifierHash: Hex): Promise
{ + return publicClient.readContract({ + ...contract, + functionName: "identifierToCampaignInfo", + args: [identifierHash], + }); + }, + + async isValidCampaignInfo(campaignInfo: Address): Promise { + return publicClient.readContract({ + ...contract, + functionName: "isValidCampaignInfo", + args: [campaignInfo], + }); + }, + + async owner(): Promise
{ + return publicClient.readContract({ ...contract, functionName: "owner" }); + }, + }; +} diff --git a/packages/contracts/src/contracts/campaign-info.ts b/packages/contracts/src/contracts/campaign-info.ts new file mode 100644 index 0000000..6a26865 --- /dev/null +++ b/packages/contracts/src/contracts/campaign-info.ts @@ -0,0 +1,187 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { CAMPAIGN_INFO_ABI } from "../abis/campaign-info"; +import type { CampaignInfoEntity, LineItemTypeInfo, CampaignConfig } from "../types"; + +/** + * Creates a CampaignInfo entity with full read/write access. + * + * @param address - Deployed CampaignInfo contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns CampaignInfoEntity + * + * @example + * ```typescript + * const ci = createCampaignInfoEntity(CAMPAIGN_INFO_ADDRESS, publicClient, walletClient, chain); + * const deadline = await ci.getDeadline(); + * await ci.updateDeadline(newDeadline); + * ``` + */ +export function createCampaignInfoEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): CampaignInfoEntity { + const contract = { address, abi: CAMPAIGN_INFO_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Reads ──────────────────────────────────────────────────────────────── + + async getLaunchTime() { + return publicClient.readContract({ ...contract, functionName: "getLaunchTime" }); + }, + async getDeadline() { + return publicClient.readContract({ ...contract, functionName: "getDeadline" }); + }, + async getGoalAmount() { + return publicClient.readContract({ ...contract, functionName: "getGoalAmount" }); + }, + async getCampaignCurrency() { + return publicClient.readContract({ ...contract, functionName: "getCampaignCurrency" }); + }, + async getIdentifierHash() { + return publicClient.readContract({ ...contract, functionName: "getIdentifierHash" }); + }, + async checkIfPlatformSelected(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "checkIfPlatformSelected", args: [platformBytes] }); + }, + async checkIfPlatformApproved(platformHash: Hex) { + return publicClient.readContract({ ...contract, functionName: "checkIfPlatformApproved", args: [platformHash] }); + }, + async getPlatformAdminAddress(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformAdminAddress", args: [platformBytes] }); + }, + async getPlatformData(platformDataKey: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformData", args: [platformDataKey] }); + }, + async getPlatformFeePercent(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformFeePercent", args: [platformBytes] }); + }, + async getPlatformClaimDelay(platformHash: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformClaimDelay", args: [platformHash] }); + }, + async getProtocolAdminAddress() { + return publicClient.readContract({ ...contract, functionName: "getProtocolAdminAddress" }); + }, + async getProtocolFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getProtocolFeePercent" }); + }, + async getAcceptedTokens() { + return publicClient.readContract({ ...contract, functionName: "getAcceptedTokens" }); + }, + async isTokenAccepted(token: Address) { + return publicClient.readContract({ ...contract, functionName: "isTokenAccepted", args: [token] }); + }, + async getTotalRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalRaisedAmount" }); + }, + async getTotalLifetimeRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalLifetimeRaisedAmount" }); + }, + async getTotalRefundedAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalRefundedAmount" }); + }, + async getTotalAvailableRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalAvailableRaisedAmount" }); + }, + async getTotalCancelledAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalCancelledAmount" }); + }, + async getTotalExpectedAmount() { + return publicClient.readContract({ ...contract, functionName: "getTotalExpectedAmount" }); + }, + async getDataFromRegistry(key: Hex) { + return publicClient.readContract({ ...contract, functionName: "getDataFromRegistry", args: [key] }); + }, + async getBufferTime() { + return publicClient.readContract({ ...contract, functionName: "getBufferTime" }); + }, + async getLineItemType(platformHash: Hex, typeId: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getLineItemType", args: [platformHash, typeId] }); + return result as unknown as LineItemTypeInfo; + }, + async getCampaignConfig(): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getCampaignConfig" }); + return result as unknown as CampaignConfig; + }, + async getApprovedPlatformHashes() { + return publicClient.readContract({ ...contract, functionName: "getApprovedPlatformHashes" }); + }, + async isLocked() { + return publicClient.readContract({ ...contract, functionName: "isLocked" }); + }, + async cancelled() { + return publicClient.readContract({ ...contract, functionName: "cancelled" }); + }, + async owner() { + return publicClient.readContract({ ...contract, functionName: "owner" }); + }, + async paused() { + return publicClient.readContract({ ...contract, functionName: "paused" }); + }, + + // ── Writes ─────────────────────────────────────────────────────────────── + + async updateDeadline(deadline: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateDeadline", args: [deadline] }); + }, + async updateGoalAmount(goalAmount: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateGoalAmount", args: [goalAmount] }); + }, + async updateLaunchTime(launchTime: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateLaunchTime", args: [launchTime] }); + }, + async updateSelectedPlatform(platformHash: Hex, selection: boolean, platformDataKey: readonly Hex[], platformDataValue: readonly Hex[]) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateSelectedPlatform", args: [platformHash, selection, [...platformDataKey], [...platformDataValue]] }); + }, + async setImageURI(newImageURI: string) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setImageURI", args: [newImageURI] }); + }, + async updateContractURI(newContractURI: string) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateContractURI", args: [newContractURI] }); + }, + async mintNFTForPledge(backer: Address, reward: Hex, tokenAddress: Address, amount: bigint, shippingFee: bigint, tipAmount: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "mintNFTForPledge", args: [backer, reward, tokenAddress, amount, shippingFee, tipAmount] }); + }, + async burn(tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "burn", args: [tokenId] }); + }, + async pauseCampaign(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "_pauseCampaign", args: [message] }); + }, + async unpauseCampaign(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "_unpauseCampaign", args: [message] }); + }, + async setPlatformInfo(platformBytes: Hex, platformTreasuryAddress: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "_setPlatformInfo", args: [platformBytes, platformTreasuryAddress] }); + }, + async transferOwnership(newOwner: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "transferOwnership", args: [newOwner] }); + }, + async renounceOwnership() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "renounceOwnership", args: [] }); + }, + }; +} diff --git a/packages/contracts/src/contracts/global-params.ts b/packages/contracts/src/contracts/global-params.ts new file mode 100644 index 0000000..fb9fb3f --- /dev/null +++ b/packages/contracts/src/contracts/global-params.ts @@ -0,0 +1,154 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { GLOBAL_PARAMS_ABI } from "../abis/global-params"; +import type { GlobalParamsEntity, LineItemTypeInfo } from "../types"; + +/** + * Creates a GlobalParams entity with full read/write access. + * + * @param address - Deployed GlobalParams contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns GlobalParamsEntity + * + * @example + * ```typescript + * const gp = createGlobalParamsEntity(GP_ADDRESS, publicClient, walletClient, chain); + * const admin = await gp.getProtocolAdminAddress(); + * await gp.enlistPlatform(platformHash, adminAddr, 500n, adapterAddr); + * ``` + */ +export function createGlobalParamsEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): GlobalParamsEntity { + const contract = { address, abi: GLOBAL_PARAMS_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Reads ──────────────────────────────────────────────────────────────── + + async getProtocolAdminAddress() { + return publicClient.readContract({ ...contract, functionName: "getProtocolAdminAddress" }); + }, + async getProtocolFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getProtocolFeePercent" }); + }, + async getNumberOfListedPlatforms() { + return publicClient.readContract({ ...contract, functionName: "getNumberOfListedPlatforms" }); + }, + async checkIfPlatformIsListed(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "checkIfPlatformIsListed", args: [platformBytes] }); + }, + async checkIfPlatformDataKeyValid(platformDataKey: Hex) { + return publicClient.readContract({ ...contract, functionName: "checkIfPlatformDataKeyValid", args: [platformDataKey] }); + }, + async getPlatformAdminAddress(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformAdminAddress", args: [platformBytes] }); + }, + async getPlatformFeePercent(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformFeePercent", args: [platformBytes] }); + }, + async getPlatformClaimDelay(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformClaimDelay", args: [platformBytes] }); + }, + async getPlatformAdapter(platformBytes: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformAdapter", args: [platformBytes] }); + }, + async getPlatformDataOwner(platformDataKey: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPlatformDataOwner", args: [platformDataKey] }); + }, + async getPlatformLineItemType(platformHash: Hex, typeId: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getPlatformLineItemType", args: [platformHash, typeId] }); + // viem returns named tuple outputs as an object + return result as unknown as LineItemTypeInfo; + }, + async getTokensForCurrency(currency: Hex) { + return publicClient.readContract({ ...contract, functionName: "getTokensForCurrency", args: [currency] }); + }, + async getFromRegistry(key: Hex) { + return publicClient.readContract({ ...contract, functionName: "getFromRegistry", args: [key] }); + }, + async owner() { + return publicClient.readContract({ ...contract, functionName: "owner" }); + }, + async paused() { + return publicClient.readContract({ ...contract, functionName: "paused" }); + }, + + // ── Writes ─────────────────────────────────────────────────────────────── + + async enlistPlatform(platformHash: Hex, platformAdminAddress: Address, platformFeePercent: bigint, platformAdapter: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "enlistPlatform", args: [platformHash, platformAdminAddress, platformFeePercent, platformAdapter] }); + }, + async delistPlatform(platformBytes: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "delistPlatform", args: [platformBytes] }); + }, + async updatePlatformAdminAddress(platformBytes: Hex, platformAdminAddress: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updatePlatformAdminAddress", args: [platformBytes, platformAdminAddress] }); + }, + async updatePlatformClaimDelay(platformBytes: Hex, claimDelay: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updatePlatformClaimDelay", args: [platformBytes, claimDelay] }); + }, + async updateProtocolAdminAddress(protocolAdminAddress: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateProtocolAdminAddress", args: [protocolAdminAddress] }); + }, + async updateProtocolFeePercent(protocolFeePercent: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateProtocolFeePercent", args: [protocolFeePercent] }); + }, + async setPlatformAdapter(platformBytes: Hex, platformAdapter: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setPlatformAdapter", args: [platformBytes, platformAdapter] }); + }, + async setPlatformLineItemType(platformHash: Hex, typeId: Hex, label: string, countsTowardGoal: boolean, applyProtocolFee: boolean, canRefund: boolean, instantTransfer: boolean) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setPlatformLineItemType", args: [platformHash, typeId, label, countsTowardGoal, applyProtocolFee, canRefund, instantTransfer] }); + }, + async removePlatformLineItemType(platformHash: Hex, typeId: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "removePlatformLineItemType", args: [platformHash, typeId] }); + }, + async addTokenToCurrency(currency: Hex, token: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "addTokenToCurrency", args: [currency, token] }); + }, + async removeTokenFromCurrency(currency: Hex, token: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "removeTokenFromCurrency", args: [currency, token] }); + }, + async addPlatformData(platformBytes: Hex, platformDataKey: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "addPlatformData", args: [platformBytes, platformDataKey] }); + }, + async removePlatformData(platformBytes: Hex, platformDataKey: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "removePlatformData", args: [platformBytes, platformDataKey] }); + }, + async addToRegistry(key: Hex, value: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "addToRegistry", args: [key, value] }); + }, + async transferOwnership(newOwner: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "transferOwnership", args: [newOwner] }); + }, + async renounceOwnership() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "renounceOwnership", args: [] }); + }, + }; +} diff --git a/packages/contracts/src/contracts/index.ts b/packages/contracts/src/contracts/index.ts new file mode 100644 index 0000000..44a1f55 --- /dev/null +++ b/packages/contracts/src/contracts/index.ts @@ -0,0 +1,8 @@ +export { createGlobalParamsEntity } from "./global-params"; +export { createCampaignInfoFactoryEntity } from "./campaign-info-factory"; +export { createTreasuryFactoryEntity } from "./treasury-factory"; +export { createCampaignInfoEntity } from "./campaign-info"; +export { createPaymentTreasuryEntity } from "./payment-treasury"; +export { createAllOrNothingEntity } from "./all-or-nothing"; +export { createKeepWhatsRaisedEntity } from "./keep-whats-raised"; +export { createItemRegistryEntity } from "./item-registry"; diff --git a/packages/contracts/src/contracts/item-registry.ts b/packages/contracts/src/contracts/item-registry.ts new file mode 100644 index 0000000..306ea02 --- /dev/null +++ b/packages/contracts/src/contracts/item-registry.ts @@ -0,0 +1,58 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { ITEM_REGISTRY_ABI } from "../abis/item-registry"; +import type { ItemRegistryEntity, Item } from "../types"; + +/** + * Creates an ItemRegistry entity with full read/write access. + * + * @param address - Deployed ItemRegistry contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns ItemRegistryEntity + * + * @example + * ```typescript + * const ir = createItemRegistryEntity(IR_ADDRESS, publicClient, walletClient, chain); + * const item = await ir.getItem(ownerAddress, itemId); + * await ir.addItem(itemId, { actualWeight, height, width, length, category, declaredCurrency }); + * ``` + */ +export function createItemRegistryEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): ItemRegistryEntity { + const contract = { address, abi: ITEM_REGISTRY_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + async getItem(owner: Address, itemId: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getItem", args: [owner, itemId] }); + return result as unknown as Item; + }, + + async addItem(itemId: Hex, item: Item): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "addItem", + args: [itemId, { actualWeight: item.actualWeight, height: item.height, width: item.width, length: item.length, category: item.category, declaredCurrency: item.declaredCurrency }], + }); + }, + + async addItemsBatch(itemIds: readonly Hex[], items: readonly Item[]): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "addItemsBatch", + args: [[...itemIds], items.map((item) => ({ actualWeight: item.actualWeight, height: item.height, width: item.width, length: item.length, category: item.category, declaredCurrency: item.declaredCurrency }))], + }); + }, + }; +} diff --git a/packages/contracts/src/contracts/keep-whats-raised.ts b/packages/contracts/src/contracts/keep-whats-raised.ts new file mode 100644 index 0000000..9f5aff6 --- /dev/null +++ b/packages/contracts/src/contracts/keep-whats-raised.ts @@ -0,0 +1,201 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { KEEP_WHATS_RAISED_ABI } from "../abis/keep-whats-raised"; +import type { KeepWhatsRaisedTreasuryEntity, TieredReward, CampaignData, KeepWhatsRaisedConfig, KeepWhatsRaisedFeeKeys, KeepWhatsRaisedFeeValues } from "../types"; + +/** + * Creates a KeepWhatsRaised treasury entity with full read/write access. + * + * @param address - Deployed KeepWhatsRaised treasury contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns KeepWhatsRaisedTreasuryEntity + * + * @example + * ```typescript + * const kwr = createKeepWhatsRaisedEntity(KWR_ADDRESS, publicClient, walletClient, chain); + * await kwr.configureTreasury(config, campaignData, feeKeys, feeValues); + * await kwr.pledgeForAReward(pledgeId, backer, token, tip, rewardNames); + * ``` + */ +export function createKeepWhatsRaisedEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): KeepWhatsRaisedTreasuryEntity { + const contract = { address, abi: KEEP_WHATS_RAISED_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Reads ──────────────────────────────────────────────────────────────── + + async getRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRaisedAmount" }); + }, + async getLifetimeRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getLifetimeRaisedAmount" }); + }, + async getRefundedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRefundedAmount" }); + }, + async getAvailableRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getAvailableRaisedAmount" }); + }, + async getReward(rewardName: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getReward", args: [rewardName] }); + return result as unknown as TieredReward; + }, + async getPlatformHash() { + return publicClient.readContract({ ...contract, functionName: "getPlatformHash" }); + }, + async getplatformFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); + }, + async getWithdrawalApprovalStatus() { + return publicClient.readContract({ ...contract, functionName: "getWithdrawalApprovalStatus" }); + }, + async getLaunchTime() { + return publicClient.readContract({ ...contract, functionName: "getLaunchTime" }); + }, + async getDeadline() { + return publicClient.readContract({ ...contract, functionName: "getDeadline" }); + }, + async getGoalAmount() { + return publicClient.readContract({ ...contract, functionName: "getGoalAmount" }); + }, + async getPaymentGatewayFee(pledgeId: Hex) { + return publicClient.readContract({ ...contract, functionName: "getPaymentGatewayFee", args: [pledgeId] }); + }, + async getFeeValue(feeKey: Hex) { + return publicClient.readContract({ ...contract, functionName: "getFeeValue", args: [feeKey] }); + }, + async paused() { + return publicClient.readContract({ ...contract, functionName: "paused" }); + }, + async balanceOf(owner: Address) { + return publicClient.readContract({ ...contract, functionName: "balanceOf", args: [owner] }); + }, + async ownerOf(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "ownerOf", args: [tokenId] }); + }, + async tokenURI(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "tokenURI", args: [tokenId] }); + }, + async name() { + return publicClient.readContract({ ...contract, functionName: "name" }); + }, + async symbol() { + return publicClient.readContract({ ...contract, functionName: "symbol" }); + }, + async getApproved(tokenId: bigint) { + return publicClient.readContract({ ...contract, functionName: "getApproved", args: [tokenId] }); + }, + async isApprovedForAll(owner: Address, operator: Address) { + return publicClient.readContract({ ...contract, functionName: "isApprovedForAll", args: [owner, operator] }); + }, + async supportsInterface(interfaceId: Hex) { + return publicClient.readContract({ ...contract, functionName: "supportsInterface", args: [interfaceId as `0x${string}`] }); + }, + + // ── Writes ─────────────────────────────────────────────────────────────── + + async pauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pauseTreasury", args: [message] }); + }, + async unpauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "unpauseTreasury", args: [message] }); + }, + async configureTreasury(config: KeepWhatsRaisedConfig, campaignData: CampaignData, feeKeys: KeepWhatsRaisedFeeKeys, feeValues: KeepWhatsRaisedFeeValues) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "configureTreasury", + args: [ + { minimumWithdrawalForFeeExemption: config.minimumWithdrawalForFeeExemption, withdrawalDelay: config.withdrawalDelay, refundDelay: config.refundDelay, configLockPeriod: config.configLockPeriod, isColombianCreator: config.isColombianCreator }, + { launchTime: campaignData.launchTime, deadline: campaignData.deadline, goalAmount: campaignData.goalAmount, currency: campaignData.currency }, + { flatFeeKey: feeKeys.flatFeeKey, cumulativeFlatFeeKey: feeKeys.cumulativeFlatFeeKey, grossPercentageFeeKeys: [...feeKeys.grossPercentageFeeKeys] }, + { flatFeeValue: feeValues.flatFeeValue, cumulativeFlatFeeValue: feeValues.cumulativeFlatFeeValue, grossPercentageFeeValues: [...feeValues.grossPercentageFeeValues] }, + ], + }); + }, + async addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "addRewards", + args: [[...rewardNames], rewards.map((r) => ({ rewardValue: r.rewardValue, isRewardTier: r.isRewardTier, itemId: [...r.itemId], itemValue: [...r.itemValue], itemQuantity: [...r.itemQuantity] }))], + }); + }, + async removeReward(rewardName: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "removeReward", args: [rewardName] }); + }, + async approveWithdrawal() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "approveWithdrawal", args: [] }); + }, + async setPaymentGatewayFee(pledgeId: Hex, fee: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setPaymentGatewayFee", args: [pledgeId, fee] }); + }, + async setFeeAndPledge(pledgeId: Hex, backer: Address, pledgeToken: Address, pledgeAmount: bigint, tip: bigint, fee: bigint, reward: readonly Hex[], isPledgeForAReward: boolean) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setFeeAndPledge", args: [pledgeId, backer, pledgeToken, pledgeAmount, tip, fee, [...reward], isPledgeForAReward] }); + }, + async pledgeForAReward(pledgeId: Hex, backer: Address, pledgeToken: Address, tip: bigint, rewardNames: readonly Hex[]) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pledgeForAReward", args: [pledgeId, backer, pledgeToken, tip, [...rewardNames]] }); + }, + async pledgeWithoutAReward(pledgeId: Hex, backer: Address, pledgeToken: Address, pledgeAmount: bigint, tip: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pledgeWithoutAReward", args: [pledgeId, backer, pledgeToken, pledgeAmount, tip] }); + }, + async claimRefund(tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimRefund", args: [tokenId] }); + }, + async claimTip() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimTip", args: [] }); + }, + async claimFund() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimFund", args: [] }); + }, + async disburseFees() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "disburseFees", args: [] }); + }, + async updateDeadline(deadline: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateDeadline", args: [deadline] }); + }, + async updateGoalAmount(goalAmount: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "updateGoalAmount", args: [goalAmount] }); + }, + async approve(to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "approve", args: [to, tokenId] }); + }, + async setApprovalForAll(operator: Address, approved: boolean) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "setApprovalForAll", args: [operator, approved] }); + }, + async safeTransferFrom(from: Address, to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "safeTransferFrom", args: [from, to, tokenId] }); + }, + async transferFrom(from: Address, to: Address, tokenId: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "transferFrom", args: [from, to, tokenId] }); + }, + }; +} diff --git a/packages/contracts/src/contracts/payment-treasury.ts b/packages/contracts/src/contracts/payment-treasury.ts new file mode 100644 index 0000000..9e88606 --- /dev/null +++ b/packages/contracts/src/contracts/payment-treasury.ts @@ -0,0 +1,140 @@ +import type { Address, Hex, PublicClient, WalletClient, Chain } from "viem"; +import { PAYMENT_TREASURY_ABI } from "../abis/payment-treasury"; +import type { PaymentTreasuryEntity, PaymentData, LineItem, ExternalFees } from "../types"; + +/** + * Creates a PaymentTreasury entity with full read/write access. + * + * @param address - Deployed PaymentTreasury (or TimeConstrainedPaymentTreasury) contract address + * @param publicClient - Viem PublicClient for on-chain reads + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns PaymentTreasuryEntity + * + * @example + * ```typescript + * const pt = createPaymentTreasuryEntity(PT_ADDRESS, publicClient, walletClient, chain); + * const data = await pt.getPaymentData(paymentId); + * await pt.confirmPayment(paymentId, buyerAddress); + * ``` + */ +export function createPaymentTreasuryEntity( + address: Address, + publicClient: PublicClient, + walletClient: WalletClient, + chain: Chain, +): PaymentTreasuryEntity { + const contract = { address, abi: PAYMENT_TREASURY_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + // ── Reads ──────────────────────────────────────────────────────────────── + + async getplatformHash() { + return publicClient.readContract({ ...contract, functionName: "getplatformHash" }); + }, + async getplatformFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); + }, + async getRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRaisedAmount" }); + }, + async getAvailableRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getAvailableRaisedAmount" }); + }, + async getLifetimeRaisedAmount() { + return publicClient.readContract({ ...contract, functionName: "getLifetimeRaisedAmount" }); + }, + async getRefundedAmount() { + return publicClient.readContract({ ...contract, functionName: "getRefundedAmount" }); + }, + async getExpectedAmount() { + return publicClient.readContract({ ...contract, functionName: "getExpectedAmount" }); + }, + async getPaymentData(paymentId: Hex): Promise { + const result = await publicClient.readContract({ ...contract, functionName: "getPaymentData", args: [paymentId] }); + return result as unknown as PaymentData; + }, + async cancelled() { + return publicClient.readContract({ ...contract, functionName: "cancelled" }); + }, + + // ── Writes ─────────────────────────────────────────────────────────────── + + async createPayment(paymentId: Hex, buyerId: Hex, itemId: Hex, paymentToken: Address, amount: bigint, expiration: bigint, lineItems: readonly LineItem[], externalFees: readonly ExternalFees[]) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "createPayment", + args: [paymentId, buyerId, itemId, paymentToken, amount, expiration, [...lineItems] as { typeId: Hex; amount: bigint }[], [...externalFees] as { feeType: Hex; feeAmount: bigint }[]], + }); + }, + async createPaymentBatch(paymentIds: readonly Hex[], buyerIds: readonly Hex[], itemIds: readonly Hex[], paymentTokens: readonly Address[], amounts: readonly bigint[], expirations: readonly bigint[], lineItemsArray: readonly (readonly LineItem[])[], externalFeesArray: readonly (readonly ExternalFees[])[]) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "createPaymentBatch", + args: [[...paymentIds], [...buyerIds], [...itemIds], [...paymentTokens], [...amounts], [...expirations], lineItemsArray.map((li) => [...li]) as { typeId: Hex; amount: bigint }[][], externalFeesArray.map((ef) => [...ef]) as { feeType: Hex; feeAmount: bigint }[][]], + }); + }, + async processCryptoPayment(paymentId: Hex, itemId: Hex, buyerAddress: Address, paymentToken: Address, amount: bigint, lineItems: readonly LineItem[], externalFees: readonly ExternalFees[]) { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, chain, account, functionName: "processCryptoPayment", + args: [paymentId, itemId, buyerAddress, paymentToken, amount, [...lineItems] as { typeId: Hex; amount: bigint }[], [...externalFees] as { feeType: Hex; feeAmount: bigint }[]], + }); + }, + async cancelPayment(paymentId: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "cancelPayment", args: [paymentId] }); + }, + async confirmPayment(paymentId: Hex, buyerAddress: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "confirmPayment", args: [paymentId, buyerAddress] }); + }, + async confirmPaymentBatch(paymentIds: readonly Hex[], buyerAddresses: readonly Address[]) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "confirmPaymentBatch", args: [[...paymentIds], [...buyerAddresses]] }); + }, + async disburseFees() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "disburseFees", args: [] }); + }, + async withdraw() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "withdraw", args: [] }); + }, + async claimRefund(paymentId: Hex, refundAddress: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimRefund", args: [paymentId, refundAddress] }); + }, + async claimRefundSelf(paymentId: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimRefund", args: [paymentId] }); + }, + async claimExpiredFunds() { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimExpiredFunds", args: [] }); + }, + async claimNonGoalLineItems(token: Address) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "claimNonGoalLineItems", args: [token] }); + }, + async pauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "pauseTreasury", args: [message] }); + }, + async unpauseTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "unpauseTreasury", args: [message] }); + }, + async cancelTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "cancelTreasury", args: [message] }); + }, + }; +} diff --git a/packages/contracts/src/contracts/treasury-factory.ts b/packages/contracts/src/contracts/treasury-factory.ts new file mode 100644 index 0000000..93e2c7f --- /dev/null +++ b/packages/contracts/src/contracts/treasury-factory.ts @@ -0,0 +1,89 @@ +import type { Address, Hex, WalletClient, Chain } from "viem"; +import { TREASURY_FACTORY_ABI } from "../abis/treasury-factory"; +import type { TreasuryFactoryEntity } from "../types"; + +/** + * Creates a TreasuryFactory entity with full implementation management and deploy. + * + * @param address - Deployed TreasuryFactory contract address + * @param walletClient - Viem WalletClient for sending transactions + * @param chain - Chain object (required for writeContract) + * @returns TreasuryFactoryEntity + * + * @example + * ```typescript + * const tf = createTreasuryFactoryEntity(TF_ADDRESS, walletClient, chain); + * const txHash = await tf.deploy(platformHash, infoAddress, implementationId); + * ``` + */ +export function createTreasuryFactoryEntity( + address: Address, + walletClient: WalletClient, + chain: Chain, +): TreasuryFactoryEntity { + const contract = { address, abi: TREASURY_FACTORY_ABI } as const; + + function requireAccount() { + if (!walletClient.account) { + throw new Error("Wallet client has no account; cannot send transaction."); + } + return walletClient.account; + } + + return { + async deploy(platformHash: Hex, infoAddress: Address, implementationId: bigint): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "deploy", + args: [platformHash, infoAddress, implementationId], + }); + }, + + async registerTreasuryImplementation(platformHash: Hex, implementationId: bigint, implementation: Address): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "registerTreasuryImplementation", + args: [platformHash, implementationId, implementation], + }); + }, + + async approveTreasuryImplementation(platformHash: Hex, implementationId: bigint): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "approveTreasuryImplementation", + args: [platformHash, implementationId], + }); + }, + + async disapproveTreasuryImplementation(implementation: Address): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "disapproveTreasuryImplementation", + args: [implementation], + }); + }, + + async removeTreasuryImplementation(platformHash: Hex, implementationId: bigint): Promise { + const account = requireAccount(); + return walletClient.writeContract({ + ...contract, + chain, + account, + functionName: "removeTreasuryImplementation", + args: [platformHash, implementationId], + }); + }, + }; +} diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts index 072b653..a294270 100644 --- a/packages/contracts/src/index.ts +++ b/packages/contracts/src/index.ts @@ -9,8 +9,8 @@ export type { Hex, PublicClient, WalletClient, - Chain, -} from "./viem"; +} from "viem"; +export type { Chain } from "viem/chains"; export { createPublicClient, @@ -19,15 +19,14 @@ export { custom, keccak256, stringToHex, + toHex, parseEther, formatEther, parseUnits, isAddress, getAddress, - mainnet, - sepolia, - goerli, -} from "./viem"; +} from "viem"; +export { mainnet, sepolia, goerli } from "viem/chains"; export * from "./constants"; export * from "./errors"; diff --git a/packages/contracts/src/viem/index.ts b/packages/contracts/src/viem/index.ts deleted file mode 100644 index 4e5319d..0000000 --- a/packages/contracts/src/viem/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Re-export commonly used viem types and functions -export type { - Account, - Address, - Hex, - PublicClient, - WalletClient, -} from "viem"; - -export { - createPublicClient, - createWalletClient, - http, - custom, - keccak256, - stringToHex, - parseEther, - formatEther, - parseUnits, - isAddress, - getAddress, - defineChain, -} from "viem"; - -// Re-export Chain type and common chains -export type { Chain } from "viem/chains"; -export { mainnet, sepolia, goerli } from "viem/chains"; From 978d4ac8b202428b35cdd7f1386558c8ea9453d5 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Thu, 5 Mar 2026 21:02:19 +0600 Subject: [PATCH 08/14] feat: add README for Oak Network contracts SDK - Introduced a comprehensive README.md file for the @oaknetwork/contracts package. - Documented installation instructions, quick start guide, client configuration options, supported chain IDs, and detailed contract functionalities. - Enhanced clarity and usability for developers interacting with Oak Network smart contracts. --- packages/contracts/README.md | 417 +++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 packages/contracts/README.md diff --git a/packages/contracts/README.md b/packages/contracts/README.md new file mode 100644 index 0000000..0098d53 --- /dev/null +++ b/packages/contracts/README.md @@ -0,0 +1,417 @@ +# @oaknetwork/contracts + +TypeScript SDK for interacting with Oak Network smart contracts. Provides a type-safe client with full read/write access to all Oak protocol contracts. + +## Installation + +```bash +pnpm add @oaknetwork/contracts +``` + +## Quick Start + +```typescript +import { createOakContractsClient, CHAIN_IDS, toHex } from "@oaknetwork/contracts"; + +const oak = createOakContractsClient({ + chainId: CHAIN_IDS.CELO_SEPOLIA, + rpcUrl: "https://forno.celo-sepolia.celo-testnet.org", + privateKey: "0x...", +}); +``` + +## Client Configuration + +Two config shapes are supported: + +### Simple (chainId + rpcUrl + privateKey) + +```typescript +const oak = createOakContractsClient({ + chainId: CHAIN_IDS.CELO_SEPOLIA, + rpcUrl: "https://forno.celo-sepolia.celo-testnet.org", + privateKey: "0x...", +}); +``` + +### Full (bring your own clients) + +```typescript +import { + createOakContractsClient, + createPublicClient, + createWalletClient, + http, + getChainFromId, + CHAIN_IDS, +} from "@oaknetwork/contracts"; + +const chain = getChainFromId(CHAIN_IDS.CELO_SEPOLIA); +const provider = createPublicClient({ chain, transport: http(RPC_URL) }); +const signer = createWalletClient({ account, chain, transport: http(RPC_URL) }); + +const oak = createOakContractsClient({ chain, provider, signer }); +``` + +## Supported Chain IDs + +```typescript +import { CHAIN_IDS } from "@oaknetwork/contracts"; + +CHAIN_IDS.MAINNET // 1 +CHAIN_IDS.SEPOLIA // 11155111 +CHAIN_IDS.CELO_SEPOLIA // 11142220 +CHAIN_IDS.ALFAJORES // 44787 +``` + +## Contracts + +### GlobalParams + +Protocol-wide configuration registry. + +```typescript +const gp = oak.globalParams("0x..."); + +// Reads +const admin = await gp.getProtocolAdminAddress(); +const fee = await gp.getProtocolFeePercent(); // bigint bps (e.g. 100 = 1%) +const count = await gp.getNumberOfListedPlatforms(); +const isListed = await gp.checkIfPlatformIsListed(platformHash); +const platAdmin = await gp.getPlatformAdminAddress(platformHash); +const platFee = await gp.getPlatformFeePercent(platformHash); +const delay = await gp.getPlatformClaimDelay(platformHash); +const adapter = await gp.getPlatformAdapter(platformHash); +const tokens = await gp.getTokensForCurrency(currency); // Address[] +const lineItem = await gp.getPlatformLineItemType(platformHash, typeId); +const value = await gp.getFromRegistry(key); + +// Writes +await gp.enlistPlatform(platformHash, adminAddress, feePercent, adapterAddress); +await gp.delistPlatform(platformHash); +await gp.updatePlatformAdminAddress(platformHash, newAdmin); +await gp.updatePlatformClaimDelay(platformHash, delaySeconds); +await gp.updateProtocolAdminAddress(newAdmin); +await gp.updateProtocolFeePercent(newFeePercent); +await gp.setPlatformAdapter(platformHash, adapterAddress); +await gp.setPlatformLineItemType(platformHash, typeId, label, countsTowardGoal, applyProtocolFee, canRefund, instantTransfer); +await gp.removePlatformLineItemType(platformHash, typeId); +await gp.addTokenToCurrency(currency, tokenAddress); +await gp.removeTokenFromCurrency(currency, tokenAddress); +await gp.addPlatformData(platformHash, platformDataKey); +await gp.removePlatformData(platformHash, platformDataKey); +await gp.addToRegistry(key, value); +await gp.transferOwnership(newOwner); +``` + +--- + +### CampaignInfoFactory + +Deploys new CampaignInfo contracts. + +```typescript +import { + createOakContractsClient, + keccak256, + toHex, + getCurrentTimestamp, + addDays, + CHAIN_IDS, +} from "@oaknetwork/contracts"; + +const factory = oak.campaignInfoFactory("0x..."); + +const PLATFORM_HASH = keccak256(toHex("my-platform")); +const CURRENCY = toHex("USD", { size: 32 }); +const identifierHash = keccak256(toHex("my-campaign-slug")); +const now = getCurrentTimestamp(); + +// Reads +const infoAddress = await factory.identifierToCampaignInfo(identifierHash); +const isValid = await factory.isValidCampaignInfo(infoAddress); + +// Writes +const txHash = await factory.createCampaign({ + creator: "0x...", + identifierHash, + selectedPlatformHash: [PLATFORM_HASH], + campaignData: { + launchTime: now + 3_600n, // 1 hour from now + deadline: addDays(now, 30), // 30 days from now + goalAmount: 1_000_000n, + currency: CURRENCY, + }, + nftName: "My Campaign NFT", + nftSymbol: "MCN", + nftImageURI: "https://example.com/nft.png", + contractURI: "https://example.com/contract.json", +}); + +const receipt = await oak.waitForReceipt(txHash); +const campaignAddress = await factory.identifierToCampaignInfo(identifierHash); +``` + +--- + +### TreasuryFactory + +Deploys treasury contracts for a given CampaignInfo. + +```typescript +const tf = oak.treasuryFactory("0x..."); + +// Deploy +const txHash = await tf.deploy(platformHash, infoAddress, implementationId); + +// Implementation management +await tf.registerTreasuryImplementation(platformHash, implementationId, implAddress); +await tf.approveTreasuryImplementation(platformHash, implementationId); +await tf.disapproveTreasuryImplementation(implAddress); +await tf.removeTreasuryImplementation(platformHash, implementationId); +``` + +--- + +### CampaignInfo + +Per-campaign configuration and state. + +```typescript +const ci = oak.campaignInfo("0x..."); + +// Reads +const launchTime = await ci.getLaunchTime(); +const deadline = await ci.getDeadline(); +const goalAmount = await ci.getGoalAmount(); +const currency = await ci.getCampaignCurrency(); +const totalRaised = await ci.getTotalRaisedAmount(); +const available = await ci.getAvailableRaisedAmount(); +const isLocked = await ci.isLocked(); +const isCancelled = await ci.cancelled(); +const config = await ci.getCampaignConfig(); +const tokens = await ci.getAcceptedTokens(); + +// Writes +await ci.updateDeadline(newDeadline); +await ci.updateGoalAmount(newGoal); +await ci.cancelCampaign(); +await ci.lockCampaign(); +``` + +--- + +### PaymentTreasury + +Handles fiat-style payments via a payment gateway. + +```typescript +const pt = oak.paymentTreasury("0x..."); + +// Reads +const raised = await pt.getRaisedAmount(); +const refunded = await pt.getRefundedAmount(); +const payment = await pt.getPaymentData(paymentId); + +// Writes +const txHash = await pt.createPayment(paymentId, backer, token, amount, tip, lineItemIds, lineItemAmounts); +await pt.confirmPayment(paymentId); +await pt.claimRefund(paymentId, refundAddress); +await pt.claimRefundSelf(paymentId); +await pt.disburseFees(); +await pt.withdraw(); +await pt.pauseTreasury(message); +await pt.unpauseTreasury(message); +await pt.cancelTreasury(); +``` + +--- + +### AllOrNothing Treasury + +Crowdfunding treasury — funds only released if goal is met, otherwise backers can claim refunds. + +```typescript +const aon = oak.allOrNothingTreasury("0x..."); + +// Reads +const raised = await aon.getRaisedAmount(); +const reward = await aon.getReward(rewardName); + +// Writes +await aon.addRewards(rewardNames, rewards); +await aon.pledgeForAReward(pledgeId, backer, token, tip, rewardNames); +await aon.pledgeWithoutAReward(pledgeId, backer, token, amount, tip); +await aon.claimRefund(tokenId); +await aon.disburseFees(); +await aon.withdraw(); +await aon.pauseTreasury(message); +await aon.unpauseTreasury(message); + +// ERC-721 +const owner = await aon.ownerOf(tokenId); +const uri = await aon.tokenURI(tokenId); +await aon.safeTransferFrom(from, to, tokenId); +``` + +--- + +### KeepWhatsRaised Treasury + +Crowdfunding treasury — creator keeps all funds raised regardless of goal. + +```typescript +const kwr = oak.keepWhatsRaisedTreasury("0x..."); + +// Reads +const raised = await kwr.getRaisedAmount(); +const available = await kwr.getAvailableRaisedAmount(); +const reward = await kwr.getReward(rewardName); + +// Writes +await kwr.configureTreasury(config, campaignData, feeKeys, feeValues); +await kwr.addRewards(rewardNames, rewards); +await kwr.pledgeForAReward(pledgeId, backer, token, tip, rewardNames); +await kwr.pledgeWithoutAReward(pledgeId, backer, token, amount, tip); +await kwr.approveWithdrawal(); +await kwr.claimFund(); +await kwr.claimTip(); +await kwr.claimRefund(tokenId); +await kwr.disburseFees(); +await kwr.pauseTreasury(message); +await kwr.unpauseTreasury(message); +``` + +--- + +### ItemRegistry + +Manages items available for purchase in campaigns. + +```typescript +const ir = oak.itemRegistry("0x..."); + +// Read +const item = await ir.getItem(itemId); + +// Writes +await ir.addItem(itemId, name, price, quantity); +await ir.addItemsBatch(itemIds, names, prices, quantities); +``` + +--- + +## Error Handling + +Contract revert errors can be decoded into typed SDK errors: + +```typescript +import { parseContractError } from "@oaknetwork/contracts"; + +function handleError(err) { + // Walk the cause chain to find raw revert data + let current = err; + while (current) { + if (typeof current.data === "string" && current.data.startsWith("0x")) { + const parsed = parseContractError(current.data); + if (parsed) { + console.error("Reverted:", parsed.name); + console.error("Args:", parsed.args); + if (parsed.recoveryHint) console.error("Hint:", parsed.recoveryHint); + return; + } + } + current = current.cause; + } + console.error("Unknown error:", err.message); +} + +try { + const txHash = await factory.createCampaign({ ... }); +} catch (err) { + handleError(err); +} +``` + +Recognized error types: +- `GlobalParams*` — platform/protocol configuration errors +- `CampaignInfoFactory*` — campaign creation errors + +--- + +## Utility Functions + +```typescript +import { + keccak256, + id, + toHex, + stringToHex, + parseEther, + formatEther, + parseUnits, + isAddress, + getAddress, + getCurrentTimestamp, + addDays, + getChainFromId, + createJsonRpcProvider, + createWallet, + createBrowserProvider, + getSigner, + CHAIN_IDS, + BPS_DENOMINATOR, + BYTES32_ZERO, + DATA_REGISTRY_KEYS, + scopedToPlatform, +} from "@oaknetwork/contracts"; + +// Hash a string to bytes32 +const platformHash = keccak256(toHex("my-platform")); + +// Encode string to fixed bytes32 +const currency = toHex("USD", { size: 32 }); + +// Timestamp helpers +const now = getCurrentTimestamp(); // bigint seconds +const deadline = addDays(now, 30); // 30 days from now + +// Fee calculations (fees are in basis points, 10_000 = 100%) +const feeAmount = (raisedAmount * platformFee) / BPS_DENOMINATOR; + +// Browser wallet (frontend) +const chain = getChainFromId(CHAIN_IDS.CELO_SEPOLIA); +const provider = createBrowserProvider(window.ethereum, chain); +const signer = await getSigner(window.ethereum, chain); +``` + +--- + +## Exported Entry Points + +| Entry point | Contents | +|-------------------------------|--------------------------------------------| +| `@oaknetwork/contracts` | Everything — client, types, utils, errors | +| `@oaknetwork/contracts/utils` | Utility functions only (no client) | +| `@oaknetwork/contracts/contracts` | Contract entity factories only | +| `@oaknetwork/contracts/client` | `createOakContractsClient` only | + +--- + +## Local Development & Testing + +```bash +# Install dependencies +pnpm install + +# Build +pnpm build + +# Run smoke test (edit addresses in test-example.mjs first) +node test-example.mjs + +# Run unit tests +pnpm test +``` + +The `test-example.mjs` file at the package root contains runnable examples for all three contract groups (GlobalParams reads, CampaignInfoFactory, TreasuryFactory). Each section can be toggled by uncommenting the relevant block. From a6a9f54e910850a8d12bccccf855b2cc7fd1f5ca Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Fri, 6 Mar 2026 17:06:19 +0600 Subject: [PATCH 09/14] feat: update ABIs for various contracts - Enhanced `AllOrNothing` ABI by adding new functions `cancelTreasury` and `cancelled`, and modified event names and input types for better clarity. - Updated `CampaignInfo` ABI to include the `_cancelCampaign` function and removed outdated ownership transfer events. - Refined `KeepWhatsRaised` ABI by adding `cancelTreasury` and `cancelled` functions, and corrected event names for consistency. - Adjusted `PaymentTreasury` ABI to include an `initialize` function for contract setup. - Cleaned up `GlobalParams` ABI by removing redundant input parameters for error handling functions. --- packages/contracts/src/abis/all-or-nothing.ts | 32 ++++++++++++++----- packages/contracts/src/abis/campaign-info.ts | 25 ++++----------- packages/contracts/src/abis/global-params.ts | 5 +-- .../contracts/src/abis/keep-whats-raised.ts | 29 +++++++++-------- .../contracts/src/abis/payment-treasury.ts | 11 +++++++ 5 files changed, 59 insertions(+), 43 deletions(-) diff --git a/packages/contracts/src/abis/all-or-nothing.ts b/packages/contracts/src/abis/all-or-nothing.ts index cd8baa6..5861c7e 100644 --- a/packages/contracts/src/abis/all-or-nothing.ts +++ b/packages/contracts/src/abis/all-or-nothing.ts @@ -76,6 +76,7 @@ export const ALL_OR_NOTHING_ABI = [ { anonymous: false, inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, { indexed: false, internalType: "uint256", name: "protocolShare", type: "uint256" }, { indexed: false, internalType: "uint256", name: "platformShare", type: "uint256" }, ], @@ -118,16 +119,16 @@ export const ALL_OR_NOTHING_ABI = [ { anonymous: false, inputs: [ - { indexed: true, internalType: "bytes32", name: "rewardName", type: "bytes32" }, + { indexed: false, internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, { - components: REWARD_TIER_COMPONENTS, + components: [...REWARD_TIER_COMPONENTS], indexed: false, - internalType: "struct AllOrNothing.Reward", - name: "reward", - type: "tuple", + internalType: "struct AllOrNothing.Reward[]", + name: "rewards", + type: "tuple[]", }, ], - name: "RewardAdded", + name: "RewardsAdded", type: "event", }, { @@ -159,7 +160,8 @@ export const ALL_OR_NOTHING_ABI = [ { anonymous: false, inputs: [ - { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: false, internalType: "address", name: "to", type: "address" }, { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, ], name: "WithdrawalSuccessful", @@ -179,6 +181,20 @@ export const ALL_OR_NOTHING_ABI = [ stateMutability: "nonpayable", type: "function", }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "cancelTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "cancelled", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, { inputs: [ { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, @@ -294,7 +310,7 @@ export const ALL_OR_NOTHING_ABI = [ }, { inputs: [], - name: "getplatformFeePercent", + name: "getPlatformFeePercent", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", type: "function", diff --git a/packages/contracts/src/abis/campaign-info.ts b/packages/contracts/src/abis/campaign-info.ts index e8b9cbc..c79aa1d 100644 --- a/packages/contracts/src/abis/campaign-info.ts +++ b/packages/contracts/src/abis/campaign-info.ts @@ -70,15 +70,6 @@ export const CAMPAIGN_INFO_ABI = [ name: "CampaignInfoLaunchTimeUpdated", type: "event", }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: "address", name: "previousOwner", type: "address" }, - { indexed: true, internalType: "address", name: "newOwner", type: "address" }, - ], - name: "CampaignInfoOwnershipTransferred", - type: "event", - }, { anonymous: false, inputs: [ @@ -88,15 +79,6 @@ export const CAMPAIGN_INFO_ABI = [ name: "CampaignInfoPlatformInfoUpdated", type: "event", }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: "bytes32", name: "platformBytes", type: "bytes32" }, - { indexed: true, internalType: "address", name: "platformTreasury", type: "address" }, - ], - name: "CampaignInfoPlatformSelected", - type: "event", - }, { anonymous: false, inputs: [ @@ -133,6 +115,13 @@ export const CAMPAIGN_INFO_ABI = [ name: "Unpaused", type: "event", }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "_cancelCampaign", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, { inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], name: "_pauseCampaign", diff --git a/packages/contracts/src/abis/global-params.ts b/packages/contracts/src/abis/global-params.ts index 28d3b90..e60760e 100644 --- a/packages/contracts/src/abis/global-params.ts +++ b/packages/contracts/src/abis/global-params.ts @@ -19,10 +19,7 @@ export const GLOBAL_PARAMS_ABI = [ type: "error", }, { - inputs: [ - { internalType: "bytes32", name: "platformBytes", type: "bytes32" }, - { internalType: "address", name: "platformAdminAddress", type: "address" }, - ], + inputs: [{ internalType: "bytes32", name: "platformBytes", type: "bytes32" }], name: "GlobalParamsPlatformNotListed", type: "error", }, diff --git a/packages/contracts/src/abis/keep-whats-raised.ts b/packages/contracts/src/abis/keep-whats-raised.ts index 68b4669..b96ed30 100644 --- a/packages/contracts/src/abis/keep-whats-raised.ts +++ b/packages/contracts/src/abis/keep-whats-raised.ts @@ -84,9 +84,6 @@ export const KEEP_WHATS_RAISED_ABI = [ { inputs: [], name: "TreasuryCampaignInfoIsPaused", type: "error" }, { inputs: [], name: "TreasuryFeeNotDisbursed", type: "error" }, { inputs: [], name: "TreasuryTransferFailed", type: "error" }, - { inputs: [], name: "TreasuryCampaignInfoIsPaused", type: "error" }, - { inputs: [], name: "TreasuryFeeNotDisbursed", type: "error" }, - { inputs: [], name: "TreasuryTransferFailed", type: "error" }, { anonymous: false, inputs: [ @@ -110,6 +107,7 @@ export const KEEP_WHATS_RAISED_ABI = [ { anonymous: false, inputs: [ + { indexed: true, internalType: "address", name: "token", type: "address" }, { indexed: false, internalType: "uint256", name: "protocolShare", type: "uint256" }, { indexed: false, internalType: "uint256", name: "platformShare", type: "uint256" }, ], @@ -250,15 +248,6 @@ export const KEEP_WHATS_RAISED_ABI = [ name: "KeepWhatsRaisedPaymentGatewayFeeSet", type: "event", }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: "address", name: "to", type: "address" }, - { indexed: false, internalType: "uint256", name: "amount", type: "uint256" }, - ], - name: "WithdrawalSuccessful", - type: "event", - }, { anonymous: false, inputs: [ @@ -313,6 +302,20 @@ export const KEEP_WHATS_RAISED_ABI = [ stateMutability: "nonpayable", type: "function", }, + { + inputs: [{ internalType: "bytes32", name: "message", type: "bytes32" }], + name: "cancelTreasury", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "cancelled", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, { inputs: [ { internalType: "bytes32[]", name: "rewardNames", type: "bytes32[]" }, @@ -552,7 +555,7 @@ export const KEEP_WHATS_RAISED_ABI = [ }, { inputs: [], - name: "getplatformFeePercent", + name: "getPlatformFeePercent", outputs: [{ internalType: "uint256", name: "", type: "uint256" }], stateMutability: "view", type: "function", diff --git a/packages/contracts/src/abis/payment-treasury.ts b/packages/contracts/src/abis/payment-treasury.ts index 46f3e89..f8f9b08 100644 --- a/packages/contracts/src/abis/payment-treasury.ts +++ b/packages/contracts/src/abis/payment-treasury.ts @@ -189,6 +189,17 @@ export const PAYMENT_TREASURY_ABI = [ name: "ExpiredFundsClaimed", type: "event", }, + { + inputs: [ + { internalType: "bytes32", name: "_platformHash", type: "bytes32" }, + { internalType: "address", name: "_infoAddress", type: "address" }, + { internalType: "address", name: "_trustedForwarder", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, { inputs: [], name: "getplatformHash", From 81cabcd352b1ce8601167a7e57ed86c5f7f0bd06 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Fri, 6 Mar 2026 17:06:50 +0600 Subject: [PATCH 10/14] fix: correct function name casing in contract methods - Updated `getplatformFeePercent` to `getPlatformFeePercent` in both `AllOrNothing` and `KeepWhatsRaised` contracts for consistency and adherence to naming conventions. --- packages/contracts/src/contracts/all-or-nothing.ts | 4 ++-- packages/contracts/src/contracts/keep-whats-raised.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts/src/contracts/all-or-nothing.ts b/packages/contracts/src/contracts/all-or-nothing.ts index c6e4f5e..247d6da 100644 --- a/packages/contracts/src/contracts/all-or-nothing.ts +++ b/packages/contracts/src/contracts/all-or-nothing.ts @@ -52,8 +52,8 @@ export function createAllOrNothingEntity( async getPlatformHash() { return publicClient.readContract({ ...contract, functionName: "getPlatformHash" }); }, - async getplatformFeePercent() { - return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); + async getPlatformFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getPlatformFeePercent" }); }, async paused() { return publicClient.readContract({ ...contract, functionName: "paused" }); diff --git a/packages/contracts/src/contracts/keep-whats-raised.ts b/packages/contracts/src/contracts/keep-whats-raised.ts index 9f5aff6..fd4833d 100644 --- a/packages/contracts/src/contracts/keep-whats-raised.ts +++ b/packages/contracts/src/contracts/keep-whats-raised.ts @@ -55,8 +55,8 @@ export function createKeepWhatsRaisedEntity( async getPlatformHash() { return publicClient.readContract({ ...contract, functionName: "getPlatformHash" }); }, - async getplatformFeePercent() { - return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); + async getPlatformFeePercent() { + return publicClient.readContract({ ...contract, functionName: "getPlatformFeePercent" }); }, async getWithdrawalApprovalStatus() { return publicClient.readContract({ ...contract, functionName: "getWithdrawalApprovalStatus" }); From 226d1438e4c0579a02884811ad3ae8cdbf579bd0 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Fri, 6 Mar 2026 17:07:30 +0600 Subject: [PATCH 11/14] feat: introduce new error classes for contract handling - Added multiple error classes for `AllOrNothing`, `CampaignInfo`, `KeepWhatsRaised`, `ItemRegistry`, `PaymentTreasury`, `Shared`, and `TreasuryFactory` to enhance error handling and provide clearer recovery hints. - Updated `index.ts` to export the new error types for better accessibility across the contracts. - Improved type safety and clarity in error management for contract interactions. --- .../contracts/src/errors/all-or-nothing.ts | 127 +++++ .../contracts/src/errors/campaign-info.ts | 81 ++++ .../contracts/src/errors/global-params.ts | 8 +- packages/contracts/src/errors/index.ts | 95 ++++ .../contracts/src/errors/item-registry.ts | 15 + .../contracts/src/errors/keep-whats-raised.ts | 204 ++++++++ .../src/errors/parse-contract-error.ts | 445 ++++++++++++++++-- .../contracts/src/errors/payment-treasury.ts | 259 ++++++++++ packages/contracts/src/errors/shared.ts | 105 +++++ .../contracts/src/errors/treasury-factory.ts | 112 +++++ 10 files changed, 1400 insertions(+), 51 deletions(-) create mode 100644 packages/contracts/src/errors/all-or-nothing.ts create mode 100644 packages/contracts/src/errors/campaign-info.ts create mode 100644 packages/contracts/src/errors/item-registry.ts create mode 100644 packages/contracts/src/errors/keep-whats-raised.ts create mode 100644 packages/contracts/src/errors/payment-treasury.ts create mode 100644 packages/contracts/src/errors/shared.ts create mode 100644 packages/contracts/src/errors/treasury-factory.ts diff --git a/packages/contracts/src/errors/all-or-nothing.ts b/packages/contracts/src/errors/all-or-nothing.ts new file mode 100644 index 0000000..307ff50 --- /dev/null +++ b/packages/contracts/src/errors/all-or-nothing.ts @@ -0,0 +1,127 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class AllOrNothingFeeNotDisbursedError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingFeeNotDisbursed"; + readonly args: Record = {}; + readonly recoveryHint = "Fees have not been disbursed yet. Call disburseFees() before withdrawing."; + + constructor() { + super("AllOrNothingFeeNotDisbursed()"); + Object.setPrototypeOf(this, AllOrNothingFeeNotDisbursedError.prototype); + } +} + +export class AllOrNothingFeeAlreadyDisbursedError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingFeeAlreadyDisbursed"; + readonly args: Record = {}; + readonly recoveryHint = "Fees have already been disbursed for this campaign."; + + constructor() { + super("AllOrNothingFeeAlreadyDisbursed()"); + Object.setPrototypeOf(this, AllOrNothingFeeAlreadyDisbursedError.prototype); + } +} + +export class AllOrNothingInvalidInputError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = "One or more inputs are invalid. Check all provided parameters."; + + constructor() { + super("AllOrNothingInvalidInput()"); + Object.setPrototypeOf(this, AllOrNothingInvalidInputError.prototype); + } +} + +export class AllOrNothingNotClaimableError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingNotClaimable"; + readonly args: { tokenId: string }; + readonly recoveryHint = + "This pledge NFT is not claimable as a refund. The campaign may have succeeded or the refund window has not opened."; + + constructor(args: { tokenId: string }) { + super(`AllOrNothingNotClaimable(tokenId: ${args.tokenId})`); + this.args = args; + Object.setPrototypeOf(this, AllOrNothingNotClaimableError.prototype); + } +} + +export class AllOrNothingNotSuccessfulError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingNotSuccessful"; + readonly args: Record = {}; + readonly recoveryHint = "The campaign has not reached its goal. This operation requires a successful campaign."; + + constructor() { + super("AllOrNothingNotSuccessful()"); + Object.setPrototypeOf(this, AllOrNothingNotSuccessfulError.prototype); + } +} + +export class AllOrNothingRewardExistsError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingRewardExists"; + readonly args: Record = {}; + readonly recoveryHint = "A reward with this name already exists. Use a different reward name or remove the existing one first."; + + constructor() { + super("AllOrNothingRewardExists()"); + Object.setPrototypeOf(this, AllOrNothingRewardExistsError.prototype); + } +} + +export class AllOrNothingTransferFailedError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingTransferFailed"; + readonly args: Record = {}; + readonly recoveryHint = "Token transfer failed. Check token balances and allowances."; + + constructor() { + super("AllOrNothingTransferFailed()"); + Object.setPrototypeOf(this, AllOrNothingTransferFailedError.prototype); + } +} + +export class AllOrNothingUnAuthorizedError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingUnAuthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this operation on the AllOrNothing treasury."; + + constructor() { + super("AllOrNothingUnAuthorized()"); + Object.setPrototypeOf(this, AllOrNothingUnAuthorizedError.prototype); + } +} + +export class AllOrNothingTokenNotAcceptedError extends Error implements ContractErrorBase { + readonly name = "AllOrNothingTokenNotAccepted"; + readonly args: { token: string }; + readonly recoveryHint = "This token is not accepted for pledging. Use an accepted token for this campaign."; + + constructor(args: { token: string }) { + super(`AllOrNothingTokenNotAccepted(token: ${args.token})`); + this.args = args; + Object.setPrototypeOf(this, AllOrNothingTokenNotAcceptedError.prototype); + } +} + +export class TreasurySuccessConditionNotFulfilledError extends Error implements ContractErrorBase { + readonly name = "TreasurySuccessConditionNotFulfilled"; + readonly args: Record = {}; + readonly recoveryHint = + "The campaign success condition has not been fulfilled. The goal amount must be reached before withdrawing."; + + constructor() { + super("TreasurySuccessConditionNotFulfilled()"); + Object.setPrototypeOf(this, TreasurySuccessConditionNotFulfilledError.prototype); + } +} + +export type AllOrNothingError = + | AllOrNothingFeeNotDisbursedError + | AllOrNothingFeeAlreadyDisbursedError + | AllOrNothingInvalidInputError + | AllOrNothingNotClaimableError + | AllOrNothingNotSuccessfulError + | AllOrNothingRewardExistsError + | AllOrNothingTransferFailedError + | AllOrNothingUnAuthorizedError + | AllOrNothingTokenNotAcceptedError + | TreasurySuccessConditionNotFulfilledError; diff --git a/packages/contracts/src/errors/campaign-info.ts b/packages/contracts/src/errors/campaign-info.ts new file mode 100644 index 0000000..38632b1 --- /dev/null +++ b/packages/contracts/src/errors/campaign-info.ts @@ -0,0 +1,81 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class CampaignInfoInvalidInputError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = "One or more campaign info inputs are invalid. Check all provided parameters."; + + constructor() { + super("CampaignInfoInvalidInput()"); + Object.setPrototypeOf(this, CampaignInfoInvalidInputError.prototype); + } +} + +export class CampaignInfoInvalidPlatformUpdateError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoInvalidPlatformUpdate"; + readonly args: { platformBytes: string; selection: boolean }; + readonly recoveryHint = + "Invalid platform selection update. The platform may already be in the requested state."; + + constructor(args: { platformBytes: string; selection: boolean }) { + super( + `CampaignInfoInvalidPlatformUpdate(platformBytes: ${args.platformBytes}, selection: ${args.selection})`, + ); + this.args = args; + Object.setPrototypeOf(this, CampaignInfoInvalidPlatformUpdateError.prototype); + } +} + +export class CampaignInfoPlatformNotSelectedError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoPlatformNotSelected"; + readonly args: { platformBytes: string }; + readonly recoveryHint = "The platform is not selected for this campaign. Select the platform first."; + + constructor(args: { platformBytes: string }) { + super(`CampaignInfoPlatformNotSelected(platformBytes: ${args.platformBytes})`); + this.args = args; + Object.setPrototypeOf(this, CampaignInfoPlatformNotSelectedError.prototype); + } +} + +export class CampaignInfoPlatformAlreadyApprovedError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoPlatformAlreadyApproved"; + readonly args: { platformHash: string }; + readonly recoveryHint = "The platform is already approved for this campaign. No action required."; + + constructor(args: { platformHash: string }) { + super(`CampaignInfoPlatformAlreadyApproved(platformHash: ${args.platformHash})`); + this.args = args; + Object.setPrototypeOf(this, CampaignInfoPlatformAlreadyApprovedError.prototype); + } +} + +export class CampaignInfoUnauthorizedError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoUnauthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this campaign operation."; + + constructor() { + super("CampaignInfoUnauthorized()"); + Object.setPrototypeOf(this, CampaignInfoUnauthorizedError.prototype); + } +} + +export class CampaignInfoIsLockedError extends Error implements ContractErrorBase { + readonly name = "CampaignInfoIsLocked"; + readonly args: Record = {}; + readonly recoveryHint = "The campaign info is locked and cannot be modified."; + + constructor() { + super("CampaignInfoIsLocked()"); + Object.setPrototypeOf(this, CampaignInfoIsLockedError.prototype); + } +} + +export type CampaignInfoError = + | CampaignInfoInvalidInputError + | CampaignInfoInvalidPlatformUpdateError + | CampaignInfoPlatformNotSelectedError + | CampaignInfoPlatformAlreadyApprovedError + | CampaignInfoUnauthorizedError + | CampaignInfoIsLockedError; diff --git a/packages/contracts/src/errors/global-params.ts b/packages/contracts/src/errors/global-params.ts index e25eb03..f3d6659 100644 --- a/packages/contracts/src/errors/global-params.ts +++ b/packages/contracts/src/errors/global-params.ts @@ -84,14 +84,12 @@ export class GlobalParamsPlatformFeePercentIsZeroError extends Error implements export class GlobalParamsPlatformNotListedError extends Error implements ContractErrorBase { readonly name = "GlobalParamsPlatformNotListed"; - readonly args: { platformBytes: string; platformAdminAddress: string }; + readonly args: { platformBytes: string }; readonly recoveryHint = "Platform is not enlisted in GlobalParams. Enlist the platform first."; - constructor(args: { platformBytes: string; platformAdminAddress: string }) { - super( - `GlobalParamsPlatformNotListed(platformBytes: ${args.platformBytes}, platformAdminAddress: ${args.platformAdminAddress})`, - ); + constructor(args: { platformBytes: string }) { + super(`GlobalParamsPlatformNotListed(platformBytes: ${args.platformBytes})`); this.args = args; Object.setPrototypeOf(this, GlobalParamsPlatformNotListedError.prototype); } diff --git a/packages/contracts/src/errors/index.ts b/packages/contracts/src/errors/index.ts index 44cacc2..1d675c5 100644 --- a/packages/contracts/src/errors/index.ts +++ b/packages/contracts/src/errors/index.ts @@ -1,5 +1,6 @@ export type { ContractErrorBase } from "./contract-error.js"; export { parseContractError } from "./parse-contract-error.js"; + export { GlobalParamsCurrencyHasNoTokensError, GlobalParamsCurrencyTokenLengthMismatchError, @@ -16,6 +17,7 @@ export { GlobalParamsUnauthorizedError, } from "./global-params.js"; export type { GlobalParamsError } from "./global-params.js"; + export { CampaignInfoFactoryCampaignInitializationFailedError, CampaignInfoFactoryCampaignWithSameIdentifierExistsError, @@ -25,6 +27,99 @@ export { } from "./campaign-info-factory.js"; export type { CampaignInfoFactoryError } from "./campaign-info-factory.js"; +export { + CampaignInfoInvalidInputError, + CampaignInfoInvalidPlatformUpdateError, + CampaignInfoIsLockedError, + CampaignInfoPlatformAlreadyApprovedError, + CampaignInfoPlatformNotSelectedError, + CampaignInfoUnauthorizedError, +} from "./campaign-info.js"; +export type { CampaignInfoError } from "./campaign-info.js"; + +export { + AllOrNothingFeeAlreadyDisbursedError, + AllOrNothingFeeNotDisbursedError, + AllOrNothingInvalidInputError, + AllOrNothingNotClaimableError, + AllOrNothingNotSuccessfulError, + AllOrNothingRewardExistsError, + AllOrNothingTokenNotAcceptedError, + AllOrNothingTransferFailedError, + AllOrNothingUnAuthorizedError, + TreasurySuccessConditionNotFulfilledError, +} from "./all-or-nothing.js"; +export type { AllOrNothingError } from "./all-or-nothing.js"; + +export { + KeepWhatsRaisedAlreadyClaimedError, + KeepWhatsRaisedAlreadyEnabledError, + KeepWhatsRaisedAlreadyWithdrawnError, + KeepWhatsRaisedConfigLockedError, + KeepWhatsRaisedDisabledError, + KeepWhatsRaisedDisbursementBlockedError, + KeepWhatsRaisedInsufficientFundsForFeeError, + KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError, + KeepWhatsRaisedInvalidInputError, + KeepWhatsRaisedNotClaimableAdminError, + KeepWhatsRaisedNotClaimableError, + KeepWhatsRaisedPledgeAlreadyProcessedError, + KeepWhatsRaisedRewardExistsError, + KeepWhatsRaisedTokenNotAcceptedError, + KeepWhatsRaisedUnAuthorizedError, +} from "./keep-whats-raised.js"; +export type { KeepWhatsRaisedError } from "./keep-whats-raised.js"; + +export { ItemRegistryMismatchedArraysLengthError } from "./item-registry.js"; +export type { ItemRegistryError } from "./item-registry.js"; + +export { + PaymentTreasuryAlreadyWithdrawnError, + PaymentTreasuryCampaignInfoIsPausedError, + PaymentTreasuryClaimWindowNotReachedError, + PaymentTreasuryCryptoPaymentError, + PaymentTreasuryExpirationExceedsMaxError, + PaymentTreasuryFeeNotDisbursedError, + PaymentTreasuryInsufficientBalanceError, + PaymentTreasuryInsufficientFundsForFeeError, + PaymentTreasuryInvalidInputError, + PaymentTreasuryNoFundsToClaimError, + PaymentTreasuryPaymentAlreadyConfirmedError, + PaymentTreasuryPaymentAlreadyExpiredError, + PaymentTreasuryPaymentAlreadyExistError, + PaymentTreasuryPaymentNotClaimableError, + PaymentTreasuryPaymentNotConfirmedError, + PaymentTreasuryPaymentNotExistError, + PaymentTreasurySuccessConditionNotFulfilledError, + PaymentTreasuryTokenNotAcceptedError, + PaymentTreasuryUnAuthorizedError, +} from "./payment-treasury.js"; +export type { PaymentTreasuryError } from "./payment-treasury.js"; + +export { + TreasuryFactoryImplementationNotSetError, + TreasuryFactoryImplementationNotSetOrApprovedError, + TreasuryFactoryInvalidAddressError, + TreasuryFactoryInvalidKeyError, + TreasuryFactorySettingPlatformInfoFailedError, + TreasuryFactoryTreasuryCreationFailedError, + TreasuryFactoryTreasuryInitializationFailedError, + TreasuryFactoryUnauthorizedError, +} from "./treasury-factory.js"; +export type { TreasuryFactoryError } from "./treasury-factory.js"; + +export { + AccessCheckerUnauthorizedError, + AdminAccessCheckerUnauthorizedError, + CurrentTimeIsGreaterError, + CurrentTimeIsLessError, + CurrentTimeIsNotWithinRangeError, + TreasuryCampaignInfoIsPausedError, + TreasuryFeeNotDisbursedError, + TreasuryTransferFailedError, +} from "./shared.js"; +export type { SharedError } from "./shared.js"; + import type { ContractErrorBase } from "./contract-error.js"; /** diff --git a/packages/contracts/src/errors/item-registry.ts b/packages/contracts/src/errors/item-registry.ts new file mode 100644 index 0000000..c0f1d6b --- /dev/null +++ b/packages/contracts/src/errors/item-registry.ts @@ -0,0 +1,15 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class ItemRegistryMismatchedArraysLengthError extends Error implements ContractErrorBase { + readonly name = "ItemRegistryMismatchedArraysLength"; + readonly args: Record = {}; + readonly recoveryHint = + "The itemIds and items arrays must have the same length. Ensure both arrays are equal in size."; + + constructor() { + super("ItemRegistryMismatchedArraysLength()"); + Object.setPrototypeOf(this, ItemRegistryMismatchedArraysLengthError.prototype); + } +} + +export type ItemRegistryError = ItemRegistryMismatchedArraysLengthError; diff --git a/packages/contracts/src/errors/keep-whats-raised.ts b/packages/contracts/src/errors/keep-whats-raised.ts new file mode 100644 index 0000000..e8b3545 --- /dev/null +++ b/packages/contracts/src/errors/keep-whats-raised.ts @@ -0,0 +1,204 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class KeepWhatsRaisedUnAuthorizedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedUnAuthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this operation on the KeepWhatsRaised treasury."; + + constructor() { + super("KeepWhatsRaisedUnAuthorized()"); + Object.setPrototypeOf(this, KeepWhatsRaisedUnAuthorizedError.prototype); + } +} + +export class KeepWhatsRaisedInvalidInputError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = "One or more inputs are invalid. Check all provided parameters."; + + constructor() { + super("KeepWhatsRaisedInvalidInput()"); + Object.setPrototypeOf(this, KeepWhatsRaisedInvalidInputError.prototype); + } +} + +export class KeepWhatsRaisedTokenNotAcceptedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedTokenNotAccepted"; + readonly args: { token: string }; + readonly recoveryHint = "This token is not accepted for pledging. Use an accepted token for this campaign."; + + constructor(args: { token: string }) { + super(`KeepWhatsRaisedTokenNotAccepted(token: ${args.token})`); + this.args = args; + Object.setPrototypeOf(this, KeepWhatsRaisedTokenNotAcceptedError.prototype); + } +} + +export class KeepWhatsRaisedRewardExistsError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedRewardExists"; + readonly args: Record = {}; + readonly recoveryHint = "A reward with this name already exists. Use a different reward name or remove the existing one first."; + + constructor() { + super("KeepWhatsRaisedRewardExists()"); + Object.setPrototypeOf(this, KeepWhatsRaisedRewardExistsError.prototype); + } +} + +export class KeepWhatsRaisedDisabledError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedDisabled"; + readonly args: Record = {}; + readonly recoveryHint = "The KeepWhatsRaised treasury is disabled. Enable it before performing this operation."; + + constructor() { + super("KeepWhatsRaisedDisabled()"); + Object.setPrototypeOf(this, KeepWhatsRaisedDisabledError.prototype); + } +} + +export class KeepWhatsRaisedAlreadyEnabledError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedAlreadyEnabled"; + readonly args: Record = {}; + readonly recoveryHint = "The KeepWhatsRaised treasury is already enabled."; + + constructor() { + super("KeepWhatsRaisedAlreadyEnabled()"); + Object.setPrototypeOf(this, KeepWhatsRaisedAlreadyEnabledError.prototype); + } +} + +export class KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError + extends Error + implements ContractErrorBase +{ + readonly name = "KeepWhatsRaisedInsufficientFundsForWithdrawalAndFee"; + readonly args: { availableAmount: string; withdrawalAmount: string; fee: string }; + readonly recoveryHint = + "Insufficient funds to cover both the withdrawal amount and fee. Reduce the withdrawal amount or wait for more pledges."; + + constructor(args: { availableAmount: string; withdrawalAmount: string; fee: string }) { + super( + `KeepWhatsRaisedInsufficientFundsForWithdrawalAndFee(availableAmount: ${args.availableAmount}, withdrawalAmount: ${args.withdrawalAmount}, fee: ${args.fee})`, + ); + this.args = args; + Object.setPrototypeOf( + this, + KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError.prototype, + ); + } +} + +export class KeepWhatsRaisedInsufficientFundsForFeeError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedInsufficientFundsForFee"; + readonly args: { withdrawalAmount: string; fee: string }; + readonly recoveryHint = + "Insufficient funds to cover the withdrawal fee. Ensure the treasury has enough balance to pay the fee."; + + constructor(args: { withdrawalAmount: string; fee: string }) { + super( + `KeepWhatsRaisedInsufficientFundsForFee(withdrawalAmount: ${args.withdrawalAmount}, fee: ${args.fee})`, + ); + this.args = args; + Object.setPrototypeOf(this, KeepWhatsRaisedInsufficientFundsForFeeError.prototype); + } +} + +export class KeepWhatsRaisedAlreadyWithdrawnError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedAlreadyWithdrawn"; + readonly args: Record = {}; + readonly recoveryHint = "Funds have already been withdrawn from this treasury."; + + constructor() { + super("KeepWhatsRaisedAlreadyWithdrawn()"); + Object.setPrototypeOf(this, KeepWhatsRaisedAlreadyWithdrawnError.prototype); + } +} + +export class KeepWhatsRaisedAlreadyClaimedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedAlreadyClaimed"; + readonly args: Record = {}; + readonly recoveryHint = "This pledge has already been claimed or refunded."; + + constructor() { + super("KeepWhatsRaisedAlreadyClaimed()"); + Object.setPrototypeOf(this, KeepWhatsRaisedAlreadyClaimedError.prototype); + } +} + +export class KeepWhatsRaisedNotClaimableError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedNotClaimable"; + readonly args: { tokenId: string }; + readonly recoveryHint = + "This pledge NFT is not claimable for a refund. The campaign may still be active or refund conditions are not met."; + + constructor(args: { tokenId: string }) { + super(`KeepWhatsRaisedNotClaimable(tokenId: ${args.tokenId})`); + this.args = args; + Object.setPrototypeOf(this, KeepWhatsRaisedNotClaimableError.prototype); + } +} + +export class KeepWhatsRaisedNotClaimableAdminError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedNotClaimableAdmin"; + readonly args: Record = {}; + readonly recoveryHint = + "The admin claim conditions are not met. Ensure the campaign is in the correct state before claiming."; + + constructor() { + super("KeepWhatsRaisedNotClaimableAdmin()"); + Object.setPrototypeOf(this, KeepWhatsRaisedNotClaimableAdminError.prototype); + } +} + +export class KeepWhatsRaisedConfigLockedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedConfigLocked"; + readonly args: Record = {}; + readonly recoveryHint = + "The treasury configuration is locked and cannot be modified. Wait for the lock period to expire."; + + constructor() { + super("KeepWhatsRaisedConfigLocked()"); + Object.setPrototypeOf(this, KeepWhatsRaisedConfigLockedError.prototype); + } +} + +export class KeepWhatsRaisedDisbursementBlockedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedDisbursementBlocked"; + readonly args: Record = {}; + readonly recoveryHint = + "Fee disbursement is blocked. Ensure all required conditions are met before disbursing fees."; + + constructor() { + super("KeepWhatsRaisedDisbursementBlocked()"); + Object.setPrototypeOf(this, KeepWhatsRaisedDisbursementBlockedError.prototype); + } +} + +export class KeepWhatsRaisedPledgeAlreadyProcessedError extends Error implements ContractErrorBase { + readonly name = "KeepWhatsRaisedPledgeAlreadyProcessed"; + readonly args: { pledgeId: string }; + readonly recoveryHint = "This pledge ID has already been processed. Each pledge ID can only be used once."; + + constructor(args: { pledgeId: string }) { + super(`KeepWhatsRaisedPledgeAlreadyProcessed(pledgeId: ${args.pledgeId})`); + this.args = args; + Object.setPrototypeOf(this, KeepWhatsRaisedPledgeAlreadyProcessedError.prototype); + } +} + +export type KeepWhatsRaisedError = + | KeepWhatsRaisedUnAuthorizedError + | KeepWhatsRaisedInvalidInputError + | KeepWhatsRaisedTokenNotAcceptedError + | KeepWhatsRaisedRewardExistsError + | KeepWhatsRaisedDisabledError + | KeepWhatsRaisedAlreadyEnabledError + | KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError + | KeepWhatsRaisedInsufficientFundsForFeeError + | KeepWhatsRaisedAlreadyWithdrawnError + | KeepWhatsRaisedAlreadyClaimedError + | KeepWhatsRaisedNotClaimableError + | KeepWhatsRaisedNotClaimableAdminError + | KeepWhatsRaisedConfigLockedError + | KeepWhatsRaisedDisbursementBlockedError + | KeepWhatsRaisedPledgeAlreadyProcessedError; diff --git a/packages/contracts/src/errors/parse-contract-error.ts b/packages/contracts/src/errors/parse-contract-error.ts index 14a8d83..e92952d 100644 --- a/packages/contracts/src/errors/parse-contract-error.ts +++ b/packages/contracts/src/errors/parse-contract-error.ts @@ -1,6 +1,12 @@ import { decodeErrorResult, type Hex } from "viem"; import { GLOBAL_PARAMS_ABI } from "../abis/global-params.js"; import { CAMPAIGN_INFO_FACTORY_ABI } from "../abis/campaign-info-factory.js"; +import { CAMPAIGN_INFO_ABI } from "../abis/campaign-info.js"; +import { ALL_OR_NOTHING_ABI } from "../abis/all-or-nothing.js"; +import { KEEP_WHATS_RAISED_ABI } from "../abis/keep-whats-raised.js"; +import { ITEM_REGISTRY_ABI } from "../abis/item-registry.js"; +import { PAYMENT_TREASURY_ABI } from "../abis/payment-treasury.js"; +import { TREASURY_FACTORY_ABI } from "../abis/treasury-factory.js"; import type { ContractErrorBase } from "./contract-error.js"; import { GlobalParamsCurrencyHasNoTokensError, @@ -24,11 +30,139 @@ import { CampaignInfoFactoryPlatformNotListedError, CampaignInfoInvalidTokenListError, } from "./campaign-info-factory.js"; +import { + CampaignInfoInvalidInputError, + CampaignInfoInvalidPlatformUpdateError, + CampaignInfoIsLockedError, + CampaignInfoPlatformAlreadyApprovedError, + CampaignInfoPlatformNotSelectedError, + CampaignInfoUnauthorizedError, +} from "./campaign-info.js"; +import { + AllOrNothingFeeAlreadyDisbursedError, + AllOrNothingFeeNotDisbursedError, + AllOrNothingInvalidInputError, + AllOrNothingNotClaimableError, + AllOrNothingNotSuccessfulError, + AllOrNothingRewardExistsError, + AllOrNothingTokenNotAcceptedError, + AllOrNothingTransferFailedError, + AllOrNothingUnAuthorizedError, + TreasurySuccessConditionNotFulfilledError, +} from "./all-or-nothing.js"; +import { + KeepWhatsRaisedAlreadyClaimedError, + KeepWhatsRaisedAlreadyEnabledError, + KeepWhatsRaisedAlreadyWithdrawnError, + KeepWhatsRaisedConfigLockedError, + KeepWhatsRaisedDisabledError, + KeepWhatsRaisedDisbursementBlockedError, + KeepWhatsRaisedInsufficientFundsForFeeError, + KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError, + KeepWhatsRaisedInvalidInputError, + KeepWhatsRaisedNotClaimableAdminError, + KeepWhatsRaisedNotClaimableError, + KeepWhatsRaisedPledgeAlreadyProcessedError, + KeepWhatsRaisedRewardExistsError, + KeepWhatsRaisedTokenNotAcceptedError, + KeepWhatsRaisedUnAuthorizedError, +} from "./keep-whats-raised.js"; +import { ItemRegistryMismatchedArraysLengthError } from "./item-registry.js"; +import { + PaymentTreasuryAlreadyWithdrawnError, + PaymentTreasuryCampaignInfoIsPausedError, + PaymentTreasuryClaimWindowNotReachedError, + PaymentTreasuryCryptoPaymentError, + PaymentTreasuryExpirationExceedsMaxError, + PaymentTreasuryFeeNotDisbursedError, + PaymentTreasuryInsufficientBalanceError, + PaymentTreasuryInsufficientFundsForFeeError, + PaymentTreasuryInvalidInputError, + PaymentTreasuryNoFundsToClaimError, + PaymentTreasuryPaymentAlreadyConfirmedError, + PaymentTreasuryPaymentAlreadyExpiredError, + PaymentTreasuryPaymentAlreadyExistError, + PaymentTreasuryPaymentNotClaimableError, + PaymentTreasuryPaymentNotConfirmedError, + PaymentTreasuryPaymentNotExistError, + PaymentTreasurySuccessConditionNotFulfilledError, + PaymentTreasuryTokenNotAcceptedError, + PaymentTreasuryUnAuthorizedError, +} from "./payment-treasury.js"; +import { + TreasuryFactoryImplementationNotSetError, + TreasuryFactoryImplementationNotSetOrApprovedError, + TreasuryFactoryInvalidAddressError, + TreasuryFactoryInvalidKeyError, + TreasuryFactorySettingPlatformInfoFailedError, + TreasuryFactoryTreasuryCreationFailedError, + TreasuryFactoryTreasuryInitializationFailedError, + TreasuryFactoryUnauthorizedError, +} from "./treasury-factory.js"; +import { + AccessCheckerUnauthorizedError, + AdminAccessCheckerUnauthorizedError, + CurrentTimeIsGreaterError, + CurrentTimeIsLessError, + CurrentTimeIsNotWithinRangeError, + TreasuryCampaignInfoIsPausedError, + TreasuryFeeNotDisbursedError, + TreasuryTransferFailedError, +} from "./shared.js"; function isHex(data: string): data is Hex { return typeof data === "string" && data.startsWith("0x") && /^0x[0-9a-fA-F]*$/.test(data); } +function decodeArgs( + abi: readonly { type: string; name?: string; inputs?: readonly { name: string }[] }[], + errorName: string, + decodedArgs: readonly unknown[], +): Record { + const args: Record = {}; + const errorAbi = abi.find((item) => item.type === "error" && item.name === errorName); + if (errorAbi && "inputs" in errorAbi && errorAbi.inputs) { + errorAbi.inputs.forEach((input, i) => { + if (input.name && decodedArgs[i] !== undefined) { + args[input.name] = decodedArgs[i]; + } + }); + } + return args; +} + +function toSharedError(name: string, args: Record): ContractErrorBase | null { + switch (name) { + case "AccessCheckerUnauthorized": + return new AccessCheckerUnauthorizedError(); + case "AdminAccessCheckerUnauthorized": + return new AdminAccessCheckerUnauthorizedError(); + case "CurrentTimeIsGreater": + return new CurrentTimeIsGreaterError({ + inputTime: args["inputTime"] as string, + currentTime: args["currentTime"] as string, + }); + case "CurrentTimeIsLess": + return new CurrentTimeIsLessError({ + inputTime: args["inputTime"] as string, + currentTime: args["currentTime"] as string, + }); + case "CurrentTimeIsNotWithinRange": + return new CurrentTimeIsNotWithinRangeError({ + initialTime: args["initialTime"] as string, + finalTime: args["finalTime"] as string, + }); + case "TreasuryCampaignInfoIsPaused": + return new TreasuryCampaignInfoIsPausedError(); + case "TreasuryFeeNotDisbursed": + return new TreasuryFeeNotDisbursedError(); + case "TreasuryTransferFailed": + return new TreasuryTransferFailedError(); + default: + return null; + } +} + function toGlobalParamsError(name: string, args: Record): ContractErrorBase { switch (name) { case "GlobalParamsInvalidInput": @@ -54,7 +188,6 @@ function toGlobalParamsError(name: string, args: Record): Contr case "GlobalParamsPlatformNotListed": return new GlobalParamsPlatformNotListedError({ platformBytes: args["platformBytes"] as string, - platformAdminAddress: args["platformAdminAddress"] as string, }); case "GlobalParamsUnauthorized": return new GlobalParamsUnauthorizedError(); @@ -102,6 +235,211 @@ function toCampaignInfoFactoryError( }); case "CampaignInfoInvalidTokenList": return new CampaignInfoInvalidTokenListError(); + default: + return ( + toSharedError(name, args) ?? + new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`) + ); + } +} + +function toCampaignInfoError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "CampaignInfoInvalidInput": + return new CampaignInfoInvalidInputError(); + case "CampaignInfoInvalidPlatformUpdate": + return new CampaignInfoInvalidPlatformUpdateError({ + platformBytes: args["platformBytes"] as string, + selection: args["selection"] as boolean, + }); + case "CampaignInfoPlatformNotSelected": + return new CampaignInfoPlatformNotSelectedError({ + platformBytes: args["platformBytes"] as string, + }); + case "CampaignInfoPlatformAlreadyApproved": + return new CampaignInfoPlatformAlreadyApprovedError({ + platformHash: args["platformHash"] as string, + }); + case "CampaignInfoUnauthorized": + return new CampaignInfoUnauthorizedError(); + case "CampaignInfoIsLocked": + return new CampaignInfoIsLockedError(); + default: + return ( + toSharedError(name, args) ?? + new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`) + ); + } +} + +function toAllOrNothingError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "AllOrNothingFeeNotDisbursed": + return new AllOrNothingFeeNotDisbursedError(); + case "AllOrNothingFeeAlreadyDisbursed": + return new AllOrNothingFeeAlreadyDisbursedError(); + case "AllOrNothingInvalidInput": + return new AllOrNothingInvalidInputError(); + case "AllOrNothingNotClaimable": + return new AllOrNothingNotClaimableError({ tokenId: args["tokenId"] as string }); + case "AllOrNothingNotSuccessful": + return new AllOrNothingNotSuccessfulError(); + case "AllOrNothingRewardExists": + return new AllOrNothingRewardExistsError(); + case "AllOrNothingTransferFailed": + return new AllOrNothingTransferFailedError(); + case "AllOrNothingUnAuthorized": + return new AllOrNothingUnAuthorizedError(); + case "AllOrNothingTokenNotAccepted": + return new AllOrNothingTokenNotAcceptedError({ token: args["token"] as string }); + case "TreasurySuccessConditionNotFulfilled": + return new TreasurySuccessConditionNotFulfilledError(); + default: + return ( + toSharedError(name, args) ?? + new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`) + ); + } +} + +function toKeepWhatsRaisedError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "KeepWhatsRaisedUnAuthorized": + return new KeepWhatsRaisedUnAuthorizedError(); + case "KeepWhatsRaisedInvalidInput": + return new KeepWhatsRaisedInvalidInputError(); + case "KeepWhatsRaisedTokenNotAccepted": + return new KeepWhatsRaisedTokenNotAcceptedError({ token: args["token"] as string }); + case "KeepWhatsRaisedRewardExists": + return new KeepWhatsRaisedRewardExistsError(); + case "KeepWhatsRaisedDisabled": + return new KeepWhatsRaisedDisabledError(); + case "KeepWhatsRaisedAlreadyEnabled": + return new KeepWhatsRaisedAlreadyEnabledError(); + case "KeepWhatsRaisedInsufficientFundsForWithdrawalAndFee": + return new KeepWhatsRaisedInsufficientFundsForWithdrawalAndFeeError({ + availableAmount: args["availableAmount"] as string, + withdrawalAmount: args["withdrawalAmount"] as string, + fee: args["fee"] as string, + }); + case "KeepWhatsRaisedInsufficientFundsForFee": + return new KeepWhatsRaisedInsufficientFundsForFeeError({ + withdrawalAmount: args["withdrawalAmount"] as string, + fee: args["fee"] as string, + }); + case "KeepWhatsRaisedAlreadyWithdrawn": + return new KeepWhatsRaisedAlreadyWithdrawnError(); + case "KeepWhatsRaisedAlreadyClaimed": + return new KeepWhatsRaisedAlreadyClaimedError(); + case "KeepWhatsRaisedNotClaimable": + return new KeepWhatsRaisedNotClaimableError({ tokenId: args["tokenId"] as string }); + case "KeepWhatsRaisedNotClaimableAdmin": + return new KeepWhatsRaisedNotClaimableAdminError(); + case "KeepWhatsRaisedConfigLocked": + return new KeepWhatsRaisedConfigLockedError(); + case "KeepWhatsRaisedDisbursementBlocked": + return new KeepWhatsRaisedDisbursementBlockedError(); + case "KeepWhatsRaisedPledgeAlreadyProcessed": + return new KeepWhatsRaisedPledgeAlreadyProcessedError({ + pledgeId: args["pledgeId"] as string, + }); + default: + return ( + toSharedError(name, args) ?? + new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`) + ); + } +} + +function toItemRegistryError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "ItemRegistryMismatchedArraysLength": + return new ItemRegistryMismatchedArraysLengthError(); + default: + return new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`); + } +} + +function toPaymentTreasuryError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "PaymentTreasuryUnAuthorized": + return new PaymentTreasuryUnAuthorizedError(); + case "PaymentTreasuryInvalidInput": + return new PaymentTreasuryInvalidInputError(); + case "PaymentTreasuryPaymentAlreadyExist": + return new PaymentTreasuryPaymentAlreadyExistError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryPaymentAlreadyConfirmed": + return new PaymentTreasuryPaymentAlreadyConfirmedError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryPaymentAlreadyExpired": + return new PaymentTreasuryPaymentAlreadyExpiredError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryPaymentNotExist": + return new PaymentTreasuryPaymentNotExistError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryCampaignInfoIsPaused": + return new PaymentTreasuryCampaignInfoIsPausedError(); + case "PaymentTreasuryTokenNotAccepted": + return new PaymentTreasuryTokenNotAcceptedError({ token: args["token"] as string }); + case "PaymentTreasurySuccessConditionNotFulfilled": + return new PaymentTreasurySuccessConditionNotFulfilledError(); + case "PaymentTreasuryFeeNotDisbursed": + return new PaymentTreasuryFeeNotDisbursedError(); + case "PaymentTreasuryPaymentNotConfirmed": + return new PaymentTreasuryPaymentNotConfirmedError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryPaymentNotClaimable": + return new PaymentTreasuryPaymentNotClaimableError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryAlreadyWithdrawn": + return new PaymentTreasuryAlreadyWithdrawnError(); + case "PaymentTreasuryCryptoPayment": + return new PaymentTreasuryCryptoPaymentError({ + paymentId: args["paymentId"] as string, + }); + case "PaymentTreasuryInsufficientFundsForFee": + return new PaymentTreasuryInsufficientFundsForFeeError({ + withdrawalAmount: args["withdrawalAmount"] as string, + fee: args["fee"] as string, + }); + case "PaymentTreasuryInsufficientBalance": + return new PaymentTreasuryInsufficientBalanceError({ + required: args["required"] as string, + available: args["available"] as string, + }); + case "PaymentTreasuryExpirationExceedsMax": + return new PaymentTreasuryExpirationExceedsMaxError({ + expiration: args["expiration"] as string, + maxExpiration: args["maxExpiration"] as string, + }); + case "PaymentTreasuryClaimWindowNotReached": + return new PaymentTreasuryClaimWindowNotReachedError({ + claimableAt: args["claimableAt"] as string, + }); + case "PaymentTreasuryNoFundsToClaim": + return new PaymentTreasuryNoFundsToClaimError(); default: return new (class extends Error implements ContractErrorBase { readonly name = name; @@ -110,10 +448,57 @@ function toCampaignInfoFactoryError( } } +function toTreasuryFactoryError(name: string, args: Record): ContractErrorBase { + switch (name) { + case "TreasuryFactoryUnauthorized": + return new TreasuryFactoryUnauthorizedError(); + case "TreasuryFactoryInvalidKey": + return new TreasuryFactoryInvalidKeyError(); + case "TreasuryFactoryTreasuryCreationFailed": + return new TreasuryFactoryTreasuryCreationFailedError(); + case "TreasuryFactoryInvalidAddress": + return new TreasuryFactoryInvalidAddressError(); + case "TreasuryFactoryImplementationNotSet": + return new TreasuryFactoryImplementationNotSetError(); + case "TreasuryFactoryImplementationNotSetOrApproved": + return new TreasuryFactoryImplementationNotSetOrApprovedError(); + case "TreasuryFactoryTreasuryInitializationFailed": + return new TreasuryFactoryTreasuryInitializationFailedError(); + case "TreasuryFactorySettingPlatformInfoFailed": + return new TreasuryFactorySettingPlatformInfoFailedError(); + default: + return ( + toSharedError(name, args) ?? + new (class extends Error implements ContractErrorBase { + readonly name = name; + readonly args = args; + })(`${name}(${JSON.stringify(args)})`) + ); + } +} + +type AbiEntry = { type: string; name?: string; inputs?: readonly { name: string }[] }; + +function tryDecode( + abi: readonly AbiEntry[], + data: Hex, + toError: (name: string, args: Record) => ContractErrorBase, +): ContractErrorBase | null { + try { + const decoded = decodeErrorResult({ abi: abi as Parameters[0]["abi"], data }); + const decodedArgs = (decoded.args ?? []) as readonly unknown[]; + const args = decodeArgs(abi, decoded.errorName, decodedArgs); + return toError(decoded.errorName, args); + } catch { + return null; + } +} + /** * Parses raw revert data from a contract call and returns a typed SDK error if the error - * is recognized. Currently supports: GlobalParams, CampaignInfoFactory. Returns null if - * the data is not valid or not from a known contract. + * is recognized. Supports: GlobalParams, CampaignInfoFactory, CampaignInfo, AllOrNothing, + * KeepWhatsRaised, ItemRegistry, PaymentTreasury, TreasuryFactory. + * Returns null if the data is not valid or not from a known contract. * * Use this when you have raw revert data (e.g. from a provider or estimateGas) and want * to get a typed, discriminable error with decoded args and optional recovery hints. @@ -128,47 +513,15 @@ export function parseContractError(revertData: string): ContractErrorBase | null const data = revertData as Hex; - try { - const decoded = decodeErrorResult({ abi: GLOBAL_PARAMS_ABI, data }); - const args: Record = {}; - if (decoded.args) { - const decodedArgs = decoded.args as readonly unknown[]; - const errorAbi = GLOBAL_PARAMS_ABI.find( - (item) => item.type === "error" && item.name === decoded.errorName, - ); - if (errorAbi && "inputs" in errorAbi && errorAbi.inputs) { - errorAbi.inputs.forEach((input, i) => { - if (input.name && decodedArgs[i] !== undefined) { - args[input.name] = decodedArgs[i]; - } - }); - } - } - return toGlobalParamsError(decoded.errorName, args); - } catch { - // not a GlobalParams error, try next - } - - try { - const decoded = decodeErrorResult({ abi: CAMPAIGN_INFO_FACTORY_ABI, data }); - const args: Record = {}; - if (decoded.args) { - const decodedArgs = decoded.args as readonly unknown[]; - const errorAbi = CAMPAIGN_INFO_FACTORY_ABI.find( - (item) => item.type === "error" && item.name === decoded.errorName, - ); - if (errorAbi && "inputs" in errorAbi && errorAbi.inputs) { - errorAbi.inputs.forEach((input, i) => { - if (input.name && decodedArgs[i] !== undefined) { - args[input.name] = decodedArgs[i]; - } - }); - } - } - return toCampaignInfoFactoryError(decoded.errorName, args); - } catch { - // unknown error - } - - return null; + return ( + tryDecode(GLOBAL_PARAMS_ABI, data, toGlobalParamsError) ?? + tryDecode(CAMPAIGN_INFO_FACTORY_ABI, data, toCampaignInfoFactoryError) ?? + tryDecode(CAMPAIGN_INFO_ABI, data, toCampaignInfoError) ?? + tryDecode(ALL_OR_NOTHING_ABI, data, toAllOrNothingError) ?? + tryDecode(KEEP_WHATS_RAISED_ABI, data, toKeepWhatsRaisedError) ?? + tryDecode(ITEM_REGISTRY_ABI, data, toItemRegistryError) ?? + tryDecode(PAYMENT_TREASURY_ABI, data, toPaymentTreasuryError) ?? + tryDecode(TREASURY_FACTORY_ABI, data, toTreasuryFactoryError) ?? + null + ); } diff --git a/packages/contracts/src/errors/payment-treasury.ts b/packages/contracts/src/errors/payment-treasury.ts new file mode 100644 index 0000000..80fd23b --- /dev/null +++ b/packages/contracts/src/errors/payment-treasury.ts @@ -0,0 +1,259 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class PaymentTreasuryUnAuthorizedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryUnAuthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this operation on the PaymentTreasury."; + + constructor() { + super("PaymentTreasuryUnAuthorized()"); + Object.setPrototypeOf(this, PaymentTreasuryUnAuthorizedError.prototype); + } +} + +export class PaymentTreasuryInvalidInputError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryInvalidInput"; + readonly args: Record = {}; + readonly recoveryHint = "One or more inputs are invalid. Check all provided parameters."; + + constructor() { + super("PaymentTreasuryInvalidInput()"); + Object.setPrototypeOf(this, PaymentTreasuryInvalidInputError.prototype); + } +} + +export class PaymentTreasuryPaymentAlreadyExistError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentAlreadyExist"; + readonly args: { paymentId: string }; + readonly recoveryHint = "A payment with this ID already exists. Use a unique payment ID."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentAlreadyExist(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentAlreadyExistError.prototype); + } +} + +export class PaymentTreasuryPaymentAlreadyConfirmedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentAlreadyConfirmed"; + readonly args: { paymentId: string }; + readonly recoveryHint = "This payment has already been confirmed and cannot be confirmed again."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentAlreadyConfirmed(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentAlreadyConfirmedError.prototype); + } +} + +export class PaymentTreasuryPaymentAlreadyExpiredError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentAlreadyExpired"; + readonly args: { paymentId: string }; + readonly recoveryHint = "This payment has expired and can no longer be confirmed or modified."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentAlreadyExpired(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentAlreadyExpiredError.prototype); + } +} + +export class PaymentTreasuryPaymentNotExistError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentNotExist"; + readonly args: { paymentId: string }; + readonly recoveryHint = "No payment found with this ID. Check the payment ID and try again."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentNotExist(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentNotExistError.prototype); + } +} + +export class PaymentTreasuryCampaignInfoIsPausedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryCampaignInfoIsPaused"; + readonly args: Record = {}; + readonly recoveryHint = "The campaign is paused. Unpause the campaign before performing this operation."; + + constructor() { + super("PaymentTreasuryCampaignInfoIsPaused()"); + Object.setPrototypeOf(this, PaymentTreasuryCampaignInfoIsPausedError.prototype); + } +} + +export class PaymentTreasuryTokenNotAcceptedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryTokenNotAccepted"; + readonly args: { token: string }; + readonly recoveryHint = "This token is not accepted for payment. Use an accepted token for this campaign."; + + constructor(args: { token: string }) { + super(`PaymentTreasuryTokenNotAccepted(token: ${args.token})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryTokenNotAcceptedError.prototype); + } +} + +export class PaymentTreasurySuccessConditionNotFulfilledError + extends Error + implements ContractErrorBase +{ + readonly name = "PaymentTreasurySuccessConditionNotFulfilled"; + readonly args: Record = {}; + readonly recoveryHint = + "The campaign success condition has not been fulfilled. The goal amount must be reached before withdrawing."; + + constructor() { + super("PaymentTreasurySuccessConditionNotFulfilled()"); + Object.setPrototypeOf(this, PaymentTreasurySuccessConditionNotFulfilledError.prototype); + } +} + +export class PaymentTreasuryFeeNotDisbursedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryFeeNotDisbursed"; + readonly args: Record = {}; + readonly recoveryHint = "Fees have not been disbursed yet. Call disburseFees() before withdrawing."; + + constructor() { + super("PaymentTreasuryFeeNotDisbursed()"); + Object.setPrototypeOf(this, PaymentTreasuryFeeNotDisbursedError.prototype); + } +} + +export class PaymentTreasuryPaymentNotConfirmedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentNotConfirmed"; + readonly args: { paymentId: string }; + readonly recoveryHint = "This payment has not been confirmed yet. Confirm the payment before claiming."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentNotConfirmed(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentNotConfirmedError.prototype); + } +} + +export class PaymentTreasuryPaymentNotClaimableError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryPaymentNotClaimable"; + readonly args: { paymentId: string }; + readonly recoveryHint = + "This payment is not claimable. It may not be confirmed, may have expired, or the claim window has not been reached."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryPaymentNotClaimable(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryPaymentNotClaimableError.prototype); + } +} + +export class PaymentTreasuryAlreadyWithdrawnError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryAlreadyWithdrawn"; + readonly args: Record = {}; + readonly recoveryHint = "Funds have already been withdrawn from this treasury."; + + constructor() { + super("PaymentTreasuryAlreadyWithdrawn()"); + Object.setPrototypeOf(this, PaymentTreasuryAlreadyWithdrawnError.prototype); + } +} + +export class PaymentTreasuryCryptoPaymentError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryCryptoPayment"; + readonly args: { paymentId: string }; + readonly recoveryHint = + "This payment is a crypto payment and cannot be processed through this flow. Use processCryptoPayment() instead."; + + constructor(args: { paymentId: string }) { + super(`PaymentTreasuryCryptoPayment(paymentId: ${args.paymentId})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryCryptoPaymentError.prototype); + } +} + +export class PaymentTreasuryInsufficientFundsForFeeError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryInsufficientFundsForFee"; + readonly args: { withdrawalAmount: string; fee: string }; + readonly recoveryHint = + "Insufficient funds to cover the withdrawal fee. Ensure the treasury has enough balance to pay the fee."; + + constructor(args: { withdrawalAmount: string; fee: string }) { + super( + `PaymentTreasuryInsufficientFundsForFee(withdrawalAmount: ${args.withdrawalAmount}, fee: ${args.fee})`, + ); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryInsufficientFundsForFeeError.prototype); + } +} + +export class PaymentTreasuryInsufficientBalanceError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryInsufficientBalance"; + readonly args: { required: string; available: string }; + readonly recoveryHint = + "Insufficient balance in the treasury. The required amount exceeds the available funds."; + + constructor(args: { required: string; available: string }) { + super( + `PaymentTreasuryInsufficientBalance(required: ${args.required}, available: ${args.available})`, + ); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryInsufficientBalanceError.prototype); + } +} + +export class PaymentTreasuryExpirationExceedsMaxError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryExpirationExceedsMax"; + readonly args: { expiration: string; maxExpiration: string }; + readonly recoveryHint = + "The payment expiration exceeds the maximum allowed expiration. Use a shorter expiration time."; + + constructor(args: { expiration: string; maxExpiration: string }) { + super( + `PaymentTreasuryExpirationExceedsMax(expiration: ${args.expiration}, maxExpiration: ${args.maxExpiration})`, + ); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryExpirationExceedsMaxError.prototype); + } +} + +export class PaymentTreasuryClaimWindowNotReachedError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryClaimWindowNotReached"; + readonly args: { claimableAt: string }; + readonly recoveryHint = + "The claim window has not been reached yet. Wait until the claimableAt timestamp before claiming."; + + constructor(args: { claimableAt: string }) { + super(`PaymentTreasuryClaimWindowNotReached(claimableAt: ${args.claimableAt})`); + this.args = args; + Object.setPrototypeOf(this, PaymentTreasuryClaimWindowNotReachedError.prototype); + } +} + +export class PaymentTreasuryNoFundsToClaimError extends Error implements ContractErrorBase { + readonly name = "PaymentTreasuryNoFundsToClaim"; + readonly args: Record = {}; + readonly recoveryHint = "There are no funds available to claim at this time."; + + constructor() { + super("PaymentTreasuryNoFundsToClaim()"); + Object.setPrototypeOf(this, PaymentTreasuryNoFundsToClaimError.prototype); + } +} + +export type PaymentTreasuryError = + | PaymentTreasuryUnAuthorizedError + | PaymentTreasuryInvalidInputError + | PaymentTreasuryPaymentAlreadyExistError + | PaymentTreasuryPaymentAlreadyConfirmedError + | PaymentTreasuryPaymentAlreadyExpiredError + | PaymentTreasuryPaymentNotExistError + | PaymentTreasuryCampaignInfoIsPausedError + | PaymentTreasuryTokenNotAcceptedError + | PaymentTreasurySuccessConditionNotFulfilledError + | PaymentTreasuryFeeNotDisbursedError + | PaymentTreasuryPaymentNotConfirmedError + | PaymentTreasuryPaymentNotClaimableError + | PaymentTreasuryAlreadyWithdrawnError + | PaymentTreasuryCryptoPaymentError + | PaymentTreasuryInsufficientFundsForFeeError + | PaymentTreasuryInsufficientBalanceError + | PaymentTreasuryExpirationExceedsMaxError + | PaymentTreasuryClaimWindowNotReachedError + | PaymentTreasuryNoFundsToClaimError; diff --git a/packages/contracts/src/errors/shared.ts b/packages/contracts/src/errors/shared.ts new file mode 100644 index 0000000..51306d1 --- /dev/null +++ b/packages/contracts/src/errors/shared.ts @@ -0,0 +1,105 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class AccessCheckerUnauthorizedError extends Error implements ContractErrorBase { + readonly name = "AccessCheckerUnauthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized. Check access control permissions."; + + constructor() { + super("AccessCheckerUnauthorized()"); + Object.setPrototypeOf(this, AccessCheckerUnauthorizedError.prototype); + } +} + +export class AdminAccessCheckerUnauthorizedError extends Error implements ContractErrorBase { + readonly name = "AdminAccessCheckerUnauthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not an admin. Only admins can perform this operation."; + + constructor() { + super("AdminAccessCheckerUnauthorized()"); + Object.setPrototypeOf(this, AdminAccessCheckerUnauthorizedError.prototype); + } +} + +export class CurrentTimeIsGreaterError extends Error implements ContractErrorBase { + readonly name = "CurrentTimeIsGreater"; + readonly args: { inputTime: string; currentTime: string }; + readonly recoveryHint = "The input time is in the past. Provide a future timestamp."; + + constructor(args: { inputTime: string; currentTime: string }) { + super(`CurrentTimeIsGreater(inputTime: ${args.inputTime}, currentTime: ${args.currentTime})`); + this.args = args; + Object.setPrototypeOf(this, CurrentTimeIsGreaterError.prototype); + } +} + +export class CurrentTimeIsLessError extends Error implements ContractErrorBase { + readonly name = "CurrentTimeIsLess"; + readonly args: { inputTime: string; currentTime: string }; + readonly recoveryHint = "The operation is not yet available. Wait until the specified time has passed."; + + constructor(args: { inputTime: string; currentTime: string }) { + super(`CurrentTimeIsLess(inputTime: ${args.inputTime}, currentTime: ${args.currentTime})`); + this.args = args; + Object.setPrototypeOf(this, CurrentTimeIsLessError.prototype); + } +} + +export class CurrentTimeIsNotWithinRangeError extends Error implements ContractErrorBase { + readonly name = "CurrentTimeIsNotWithinRange"; + readonly args: { initialTime: string; finalTime: string }; + readonly recoveryHint = + "Current time is outside the allowed range. The operation is only valid between the initial and final times."; + + constructor(args: { initialTime: string; finalTime: string }) { + super( + `CurrentTimeIsNotWithinRange(initialTime: ${args.initialTime}, finalTime: ${args.finalTime})`, + ); + this.args = args; + Object.setPrototypeOf(this, CurrentTimeIsNotWithinRangeError.prototype); + } +} + +export class TreasuryCampaignInfoIsPausedError extends Error implements ContractErrorBase { + readonly name = "TreasuryCampaignInfoIsPaused"; + readonly args: Record = {}; + readonly recoveryHint = "The campaign is paused. Unpause the campaign before performing this operation."; + + constructor() { + super("TreasuryCampaignInfoIsPaused()"); + Object.setPrototypeOf(this, TreasuryCampaignInfoIsPausedError.prototype); + } +} + +export class TreasuryFeeNotDisbursedError extends Error implements ContractErrorBase { + readonly name = "TreasuryFeeNotDisbursed"; + readonly args: Record = {}; + readonly recoveryHint = "Fees have not been disbursed yet. Call disburseFees() before this operation."; + + constructor() { + super("TreasuryFeeNotDisbursed()"); + Object.setPrototypeOf(this, TreasuryFeeNotDisbursedError.prototype); + } +} + +export class TreasuryTransferFailedError extends Error implements ContractErrorBase { + readonly name = "TreasuryTransferFailed"; + readonly args: Record = {}; + readonly recoveryHint = "Token transfer failed. Check token balances and allowances."; + + constructor() { + super("TreasuryTransferFailed()"); + Object.setPrototypeOf(this, TreasuryTransferFailedError.prototype); + } +} + +export type SharedError = + | AccessCheckerUnauthorizedError + | AdminAccessCheckerUnauthorizedError + | CurrentTimeIsGreaterError + | CurrentTimeIsLessError + | CurrentTimeIsNotWithinRangeError + | TreasuryCampaignInfoIsPausedError + | TreasuryFeeNotDisbursedError + | TreasuryTransferFailedError; diff --git a/packages/contracts/src/errors/treasury-factory.ts b/packages/contracts/src/errors/treasury-factory.ts new file mode 100644 index 0000000..d881bc0 --- /dev/null +++ b/packages/contracts/src/errors/treasury-factory.ts @@ -0,0 +1,112 @@ +import type { ContractErrorBase } from "./contract-error.js"; + +export class TreasuryFactoryUnauthorizedError extends Error implements ContractErrorBase { + readonly name = "TreasuryFactoryUnauthorized"; + readonly args: Record = {}; + readonly recoveryHint = "Caller is not authorized for this operation on the TreasuryFactory."; + + constructor() { + super("TreasuryFactoryUnauthorized()"); + Object.setPrototypeOf(this, TreasuryFactoryUnauthorizedError.prototype); + } +} + +export class TreasuryFactoryInvalidKeyError extends Error implements ContractErrorBase { + readonly name = "TreasuryFactoryInvalidKey"; + readonly args: Record = {}; + readonly recoveryHint = "The provided implementation key is invalid. Check the platform hash and implementation ID."; + + constructor() { + super("TreasuryFactoryInvalidKey()"); + Object.setPrototypeOf(this, TreasuryFactoryInvalidKeyError.prototype); + } +} + +export class TreasuryFactoryTreasuryCreationFailedError extends Error implements ContractErrorBase { + readonly name = "TreasuryFactoryTreasuryCreationFailed"; + readonly args: Record = {}; + readonly recoveryHint = "Treasury clone creation failed. Check the implementation address and try again."; + + constructor() { + super("TreasuryFactoryTreasuryCreationFailed()"); + Object.setPrototypeOf(this, TreasuryFactoryTreasuryCreationFailedError.prototype); + } +} + +export class TreasuryFactoryInvalidAddressError extends Error implements ContractErrorBase { + readonly name = "TreasuryFactoryInvalidAddress"; + readonly args: Record = {}; + readonly recoveryHint = "One or more provided addresses are invalid. Ensure all addresses are non-zero."; + + constructor() { + super("TreasuryFactoryInvalidAddress()"); + Object.setPrototypeOf(this, TreasuryFactoryInvalidAddressError.prototype); + } +} + +export class TreasuryFactoryImplementationNotSetError extends Error implements ContractErrorBase { + readonly name = "TreasuryFactoryImplementationNotSet"; + readonly args: Record = {}; + readonly recoveryHint = + "No implementation is registered for this platform and implementation ID. Register the implementation first."; + + constructor() { + super("TreasuryFactoryImplementationNotSet()"); + Object.setPrototypeOf(this, TreasuryFactoryImplementationNotSetError.prototype); + } +} + +export class TreasuryFactoryImplementationNotSetOrApprovedError + extends Error + implements ContractErrorBase +{ + readonly name = "TreasuryFactoryImplementationNotSetOrApproved"; + readonly args: Record = {}; + readonly recoveryHint = + "The implementation is not registered or not approved. Register and approve the implementation before deploying."; + + constructor() { + super("TreasuryFactoryImplementationNotSetOrApproved()"); + Object.setPrototypeOf(this, TreasuryFactoryImplementationNotSetOrApprovedError.prototype); + } +} + +export class TreasuryFactoryTreasuryInitializationFailedError + extends Error + implements ContractErrorBase +{ + readonly name = "TreasuryFactoryTreasuryInitializationFailed"; + readonly args: Record = {}; + readonly recoveryHint = + "Treasury initialization failed after cloning. Check the implementation and initialization parameters."; + + constructor() { + super("TreasuryFactoryTreasuryInitializationFailed()"); + Object.setPrototypeOf(this, TreasuryFactoryTreasuryInitializationFailedError.prototype); + } +} + +export class TreasuryFactorySettingPlatformInfoFailedError + extends Error + implements ContractErrorBase +{ + readonly name = "TreasuryFactorySettingPlatformInfoFailed"; + readonly args: Record = {}; + readonly recoveryHint = + "Setting platform info on the deployed treasury failed. Check the treasury implementation and platform data."; + + constructor() { + super("TreasuryFactorySettingPlatformInfoFailed()"); + Object.setPrototypeOf(this, TreasuryFactorySettingPlatformInfoFailedError.prototype); + } +} + +export type TreasuryFactoryError = + | TreasuryFactoryUnauthorizedError + | TreasuryFactoryInvalidKeyError + | TreasuryFactoryTreasuryCreationFailedError + | TreasuryFactoryInvalidAddressError + | TreasuryFactoryImplementationNotSetError + | TreasuryFactoryImplementationNotSetOrApprovedError + | TreasuryFactoryTreasuryInitializationFailedError + | TreasuryFactorySettingPlatformInfoFailedError; From b70561760825ea9c52897885bf18faa87f6d2759 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Fri, 6 Mar 2026 17:07:42 +0600 Subject: [PATCH 12/14] fix: correct function name casing in client types - Updated `getplatformFeePercent` to `getPlatformFeePercent` in `AllOrNothingTreasuryEntity` and `KeepWhatsRaisedTreasuryEntity` interfaces for consistency and adherence to naming conventions. --- packages/contracts/src/types/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/types/client.ts b/packages/contracts/src/types/client.ts index ffee23d..a22eeda 100644 --- a/packages/contracts/src/types/client.ts +++ b/packages/contracts/src/types/client.ts @@ -404,7 +404,7 @@ export interface AllOrNothingTreasuryEntity { getRefundedAmount(): Promise; getReward(rewardName: Hex): Promise; getPlatformHash(): Promise; - getplatformFeePercent(): Promise; + getPlatformFeePercent(): Promise; paused(): Promise; balanceOf(owner: Address): Promise; ownerOf(tokenId: bigint): Promise
; @@ -442,7 +442,7 @@ export interface KeepWhatsRaisedTreasuryEntity { getAvailableRaisedAmount(): Promise; getReward(rewardName: Hex): Promise; getPlatformHash(): Promise; - getplatformFeePercent(): Promise; + getPlatformFeePercent(): Promise; getWithdrawalApprovalStatus(): Promise; getLaunchTime(): Promise; getDeadline(): Promise; From f2b6abdbbcca1396eda926d934c5ba39dd651d93 Mon Sep 17 00:00:00 2001 From: mahabubAlahi <32974385+mahabubAlahi@users.noreply.github.com> Date: Mon, 9 Mar 2026 15:13:05 +0600 Subject: [PATCH 13/14] Enhance contract functionalities and streamline client configuration (#74) * fix: add missing function implementations to contract entities - Introduced `cancelled` and `cancelTreasury` functions in `AllOrNothing` and `KeepWhatsRaised` contracts. - Added `cancelCampaign` function in `CampaignInfo` contract. - Updated corresponding types in `client.ts` to reflect the new functionalities. * fix: update account handling in wallet client creation - Refactored the account assignment in the `createWallet` function to utilize `privateKeyToAccount` for improved clarity and correctness. - Removed redundant account extraction from the wallet client, streamlining the wallet creation process. * fix: standardize function name casing in PaymentTreasuryEntity - Updated function names from `getplatformHash` and `getplatformFeePercent` to `getPlatformHash` and `getPlatformFeePercent` for consistency and adherence to naming conventions in both the contract and type definitions. * refactor: remove ResolvedOakContractsClientConfig interface - Eliminated the `ResolvedOakContractsClientConfig` interface from `client.ts` to streamline the type definitions and improve clarity in client configuration handling. * refactor: enhance client configuration with timeout options - Updated the `buildClients` function to accept a new `options` parameter, allowing for customizable request timeouts in HTTP transport calls and transaction receipt waits. - Adjusted the default timeout value in `OakContractsClientOptions` from 3000ms to 30000ms for improved reliability in client operations. * feat: add error module to contract package - Introduced a new module for error handling in the contracts package by adding `errors` to the package.json and tsup.config.ts files. - Updated the build configuration to include the new `errors/index.ts` entry point for better organization and accessibility of error-related functionalities. * refactor: remove keccak256 export from contracts index - Eliminated the `keccak256` export from the `index.ts` file in the contracts package to streamline the module exports and improve clarity. * refactor: improve type definitions in wallet client functions - Updated the `createBrowserProvider` and `getSigner` functions to use `EIP1193Provider` instead of `any` for the `ethereum` parameter, enhancing type safety and clarity in the wallet client implementation. - Adjusted the transport handling in `createWallet` to utilize the `custom` transport method for better compatibility with various providers. * feat: keep Jest config loadable after switching package to ESM * refactor: update chain ID naming and usage in client configuration - Changed the chain ID from `CHAIN_IDS.CELO_SEPOLIA` to `CHAIN_IDS.CELO_TESTNET_SEPOLIA` in the client example for clarity. - Updated the chain ID constants to follow a new naming convention, distinguishing between mainnet and testnet. - Added `Celo Mainnet` definition to the chain registry for improved clarity and organization. * refactor: update chain ID references in README for clarity - Changed all instances of `CHAIN_IDS.CELO_SEPOLIA` to `CHAIN_IDS.CELO_TESTNET_SEPOLIA` in the README to reflect the correct testnet configuration. - Updated chain ID constants to better differentiate between mainnet and testnet environments, enhancing documentation accuracy. * refactor: remove deprecated entities files - It's unreferenced dead code and its functionality is already covered by `contracts/` * refactor: simplify transport handling in createWallet function * refactor: streamline transport initialization in createWallet function * refactor: enhance configuration validation in isSimpleConfig function - Improved type checks for the `chainId`, `rpcUrl`, and `privateKey` properties in the `isSimpleConfig` function to ensure they meet specific criteria, enhancing type safety and configuration reliability. * refactor: remove legacy Celo testnet constant from chain IDs - Deleted the `CELO_TESTNET_ALFAJORES` constant from the `CHAIN_IDS` to eliminate outdated references and encourage the use of `CELO_TESTNET_SEPOLIA` for new development. --- packages/contracts/README.md | 16 ++++----- .../{jest.config.js => jest.config.cjs} | 0 packages/contracts/package.json | 4 +++ packages/contracts/src/client/index.ts | 21 ++++++++---- packages/contracts/src/constants/index.ts | 15 ++++---- .../contracts/src/contracts/all-or-nothing.ts | 7 ++++ .../contracts/src/contracts/campaign-info.ts | 4 +++ .../src/contracts/keep-whats-raised.ts | 11 ++++++ .../src/contracts/payment-treasury.ts | 4 +-- .../src/entities/all-or-nothing-treasury.ts | 15 -------- .../src/entities/campaign-info-factory.ts | 15 -------- .../contracts/src/entities/campaign-info.ts | 34 ------------------- .../contracts/src/entities/global-params.ts | 16 --------- .../contracts/src/entities/item-registry.ts | 15 -------- .../entities/keep-whats-raised-treasury.ts | 15 -------- .../src/entities/payment-treasury.ts | 15 -------- .../src/entities/treasuries/index.ts | 7 ---- .../src/entities/treasury-factory.ts | 15 -------- packages/contracts/src/index.ts | 1 - packages/contracts/src/types/client.ts | 19 +++++------ .../contracts/src/types/config-options.ts | 8 +++-- .../contracts/src/utils/chain-registry.ts | 11 ++++++ packages/contracts/src/utils/index.ts | 19 +++++------ packages/contracts/tsup.config.ts | 1 + 24 files changed, 94 insertions(+), 194 deletions(-) rename packages/contracts/{jest.config.js => jest.config.cjs} (100%) delete mode 100644 packages/contracts/src/entities/all-or-nothing-treasury.ts delete mode 100644 packages/contracts/src/entities/campaign-info-factory.ts delete mode 100644 packages/contracts/src/entities/campaign-info.ts delete mode 100644 packages/contracts/src/entities/global-params.ts delete mode 100644 packages/contracts/src/entities/item-registry.ts delete mode 100644 packages/contracts/src/entities/keep-whats-raised-treasury.ts delete mode 100644 packages/contracts/src/entities/payment-treasury.ts delete mode 100644 packages/contracts/src/entities/treasuries/index.ts delete mode 100644 packages/contracts/src/entities/treasury-factory.ts diff --git a/packages/contracts/README.md b/packages/contracts/README.md index 0098d53..c2b06d6 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -14,7 +14,7 @@ pnpm add @oaknetwork/contracts import { createOakContractsClient, CHAIN_IDS, toHex } from "@oaknetwork/contracts"; const oak = createOakContractsClient({ - chainId: CHAIN_IDS.CELO_SEPOLIA, + chainId: CHAIN_IDS.CELO_TESTNET_SEPOLIA, rpcUrl: "https://forno.celo-sepolia.celo-testnet.org", privateKey: "0x...", }); @@ -28,7 +28,7 @@ Two config shapes are supported: ```typescript const oak = createOakContractsClient({ - chainId: CHAIN_IDS.CELO_SEPOLIA, + chainId: CHAIN_IDS.CELO_TESTNET_SEPOLIA, rpcUrl: "https://forno.celo-sepolia.celo-testnet.org", privateKey: "0x...", }); @@ -46,7 +46,7 @@ import { CHAIN_IDS, } from "@oaknetwork/contracts"; -const chain = getChainFromId(CHAIN_IDS.CELO_SEPOLIA); +const chain = getChainFromId(CHAIN_IDS.CELO_TESTNET_SEPOLIA); const provider = createPublicClient({ chain, transport: http(RPC_URL) }); const signer = createWalletClient({ account, chain, transport: http(RPC_URL) }); @@ -58,10 +58,10 @@ const oak = createOakContractsClient({ chain, provider, signer }); ```typescript import { CHAIN_IDS } from "@oaknetwork/contracts"; -CHAIN_IDS.MAINNET // 1 -CHAIN_IDS.SEPOLIA // 11155111 -CHAIN_IDS.CELO_SEPOLIA // 11142220 -CHAIN_IDS.ALFAJORES // 44787 +CHAIN_IDS.ETHEREUM_MAINNET // 1 +CHAIN_IDS.ETHEREUM_TESTNET_SEPOLIA // 11155111 +CHAIN_IDS.CELO_TESTNET_SEPOLIA // 11142220 +CHAIN_IDS.CELO_TESTNET_ALFAJORES // 44787 ``` ## Contracts @@ -380,7 +380,7 @@ const deadline = addDays(now, 30); // 30 days from now const feeAmount = (raisedAmount * platformFee) / BPS_DENOMINATOR; // Browser wallet (frontend) -const chain = getChainFromId(CHAIN_IDS.CELO_SEPOLIA); +const chain = getChainFromId(CHAIN_IDS.CELO_TESTNET_SEPOLIA); const provider = createBrowserProvider(window.ethereum, chain); const signer = await getSigner(window.ethereum, chain); ``` diff --git a/packages/contracts/jest.config.js b/packages/contracts/jest.config.cjs similarity index 100% rename from packages/contracts/jest.config.js rename to packages/contracts/jest.config.cjs diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 3d90e55..1c44e71 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -24,6 +24,10 @@ "./client": { "types": "./dist/client/index.d.ts", "import": "./dist/client/index.js" + }, + "./errors": { + "types": "./dist/errors/index.d.ts", + "import": "./dist/errors/index.js" } }, "scripts": { diff --git a/packages/contracts/src/client/index.ts b/packages/contracts/src/client/index.ts index 339c3f9..609cbfd 100644 --- a/packages/contracts/src/client/index.ts +++ b/packages/contracts/src/client/index.ts @@ -36,7 +36,16 @@ import { createItemRegistryEntity } from "../contracts/item-registry"; function isSimpleConfig( config: OakContractsClientConfig, ): config is SimpleOakContractsClientConfig { - return "chainId" in config && "rpcUrl" in config && "privateKey" in config; + return ( + "chainId" in config && + "rpcUrl" in config && + "privateKey" in config && + typeof (config as SimpleOakContractsClientConfig).chainId === "number" && + typeof (config as SimpleOakContractsClientConfig).rpcUrl === "string" && + (config as SimpleOakContractsClientConfig).rpcUrl.length > 0 && + typeof (config as SimpleOakContractsClientConfig).privateKey === "string" && + (config as SimpleOakContractsClientConfig).privateKey.startsWith("0x") + ); } /** @@ -52,14 +61,14 @@ function resolveChain(chain: ChainIdentifier): Chain { /** * Builds viem publicClient and walletClient from the given config. */ -function buildClients(config: OakContractsClientConfig): { +function buildClients(config: OakContractsClientConfig, options: OakContractsClientOptions): { chain: Chain; publicClient: PublicClient; walletClient: WalletClient; } { if (isSimpleConfig(config)) { const chain = getChainFromId(config.chainId); - const transport = http(config.rpcUrl); + const transport = http(config.rpcUrl, { timeout: options.timeout }); const publicClient = createPublicClient({ chain, transport }); const account = privateKeyToAccount(config.privateKey); const walletClient = createWalletClient({ account, chain, transport }); @@ -85,7 +94,7 @@ function buildClients(config: OakContractsClientConfig): { * @example * ```typescript * const oak = createOakContractsClient({ - * chainId: CHAIN_IDS.CELO_SEPOLIA, + * chainId: CHAIN_IDS.CELO_TESTNET_SEPOLIA, * rpcUrl: "https://forno.celo-sepolia.org", * privateKey: "0x...", * }); @@ -105,11 +114,11 @@ export function createOakContractsClient( ...config?.options, }; - const { chain, publicClient, walletClient } = buildClients(config); + const { chain, publicClient, walletClient } = buildClients(config, options); const publicConfig: PublicOakContractsClientConfig = { chain }; async function waitForReceipt(txHash: Hex): Promise { - const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); + const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, timeout: options.timeout }); return { blockNumber: receipt.blockNumber, gasUsed: receipt.gasUsed, diff --git a/packages/contracts/src/constants/index.ts b/packages/contracts/src/constants/index.ts index 7236a30..2d8a2bb 100644 --- a/packages/contracts/src/constants/index.ts +++ b/packages/contracts/src/constants/index.ts @@ -2,15 +2,16 @@ import { keccak256, toHex, encodeAbiParameters, type Hex } from "viem"; /** * Common chain IDs for use with createOakContractsClient({ chainId, rpcUrl, privateKey }). - * CELO_SEPOLIA is the Celo Sepolia testnet (11142220). - * ALFAJORES is the legacy Celo testnet (44787); use CELO_SEPOLIA for new development. + * Naming convention: {CHAIN}_{MAINNET|TESTNET} */ export const CHAIN_IDS = { - MAINNET: 1, - SEPOLIA: 11155111, - GOERLI: 5, - CELO_SEPOLIA: 11142220, - ALFAJORES: 44787, + // Mainnets + ETHEREUM_MAINNET: 1, + CELO_MAINNET: 42220, + // Testnets + ETHEREUM_TESTNET_SEPOLIA: 11155111, + ETHEREUM_TESTNET_GOERLI: 5, + CELO_TESTNET_SEPOLIA: 11142220, } as const; /** Basis points denominator used for fee calculations (100% = 10_000 bps) */ diff --git a/packages/contracts/src/contracts/all-or-nothing.ts b/packages/contracts/src/contracts/all-or-nothing.ts index 247d6da..e7798bb 100644 --- a/packages/contracts/src/contracts/all-or-nothing.ts +++ b/packages/contracts/src/contracts/all-or-nothing.ts @@ -58,6 +58,9 @@ export function createAllOrNothingEntity( async paused() { return publicClient.readContract({ ...contract, functionName: "paused" }); }, + async cancelled() { + return publicClient.readContract({ ...contract, functionName: "cancelled" }); + }, async balanceOf(owner: Address) { return publicClient.readContract({ ...contract, functionName: "balanceOf", args: [owner] }); }, @@ -93,6 +96,10 @@ export function createAllOrNothingEntity( const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "unpauseTreasury", args: [message] }); }, + async cancelTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "cancelTreasury", args: [message] }); + }, async addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]) { const account = requireAccount(); return walletClient.writeContract({ diff --git a/packages/contracts/src/contracts/campaign-info.ts b/packages/contracts/src/contracts/campaign-info.ts index 6a26865..6bce90c 100644 --- a/packages/contracts/src/contracts/campaign-info.ts +++ b/packages/contracts/src/contracts/campaign-info.ts @@ -171,6 +171,10 @@ export function createCampaignInfoEntity( const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "_unpauseCampaign", args: [message] }); }, + async cancelCampaign(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "_cancelCampaign", args: [message] }); + }, async setPlatformInfo(platformBytes: Hex, platformTreasuryAddress: Address) { const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "_setPlatformInfo", args: [platformBytes, platformTreasuryAddress] }); diff --git a/packages/contracts/src/contracts/keep-whats-raised.ts b/packages/contracts/src/contracts/keep-whats-raised.ts index fd4833d..51a20ee 100644 --- a/packages/contracts/src/contracts/keep-whats-raised.ts +++ b/packages/contracts/src/contracts/keep-whats-raised.ts @@ -79,6 +79,9 @@ export function createKeepWhatsRaisedEntity( async paused() { return publicClient.readContract({ ...contract, functionName: "paused" }); }, + async cancelled() { + return publicClient.readContract({ ...contract, functionName: "cancelled" }); + }, async balanceOf(owner: Address) { return publicClient.readContract({ ...contract, functionName: "balanceOf", args: [owner] }); }, @@ -114,6 +117,10 @@ export function createKeepWhatsRaisedEntity( const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "unpauseTreasury", args: [message] }); }, + async cancelTreasury(message: Hex) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "cancelTreasury", args: [message] }); + }, async configureTreasury(config: KeepWhatsRaisedConfig, campaignData: CampaignData, feeKeys: KeepWhatsRaisedFeeKeys, feeValues: KeepWhatsRaisedFeeValues) { const account = requireAccount(); return walletClient.writeContract({ @@ -173,6 +180,10 @@ export function createKeepWhatsRaisedEntity( const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "disburseFees", args: [] }); }, + async withdraw(token: Address, amount: bigint) { + const account = requireAccount(); + return walletClient.writeContract({ ...contract, chain, account, functionName: "withdraw", args: [token, amount] }); + }, async updateDeadline(deadline: bigint) { const account = requireAccount(); return walletClient.writeContract({ ...contract, chain, account, functionName: "updateDeadline", args: [deadline] }); diff --git a/packages/contracts/src/contracts/payment-treasury.ts b/packages/contracts/src/contracts/payment-treasury.ts index 9e88606..ea51de5 100644 --- a/packages/contracts/src/contracts/payment-treasury.ts +++ b/packages/contracts/src/contracts/payment-treasury.ts @@ -36,10 +36,10 @@ export function createPaymentTreasuryEntity( return { // ── Reads ──────────────────────────────────────────────────────────────── - async getplatformHash() { + async getPlatformHash() { return publicClient.readContract({ ...contract, functionName: "getplatformHash" }); }, - async getplatformFeePercent() { + async getPlatformFeePercent() { return publicClient.readContract({ ...contract, functionName: "getplatformFeePercent" }); }, async getRaisedAmount() { diff --git a/packages/contracts/src/entities/all-or-nothing-treasury.ts b/packages/contracts/src/entities/all-or-nothing-treasury.ts deleted file mode 100644 index 0eec882..0000000 --- a/packages/contracts/src/entities/all-or-nothing-treasury.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { ALL_OR_NOTHING_ABI } from "../abis/all-or-nothing.js"; - -/** - * Returns a typed contract config for AllOrNothing treasury. - * - * @example - * const aon = allOrNothingContract('0x...'); - * const raised = await publicClient.readContract({ ...aon, functionName: 'getRaisedAmount' }); - */ -export function allOrNothingContract(address: Address) { - return { address, abi: ALL_OR_NOTHING_ABI } as const; -} - -export type AllOrNothingContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/campaign-info-factory.ts b/packages/contracts/src/entities/campaign-info-factory.ts deleted file mode 100644 index d584ec2..0000000 --- a/packages/contracts/src/entities/campaign-info-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { CAMPAIGN_INFO_FACTORY_ABI } from "../abis/campaign-info-factory.js"; - -/** - * Returns a typed contract config for CampaignInfoFactory. - * - * @example - * const factory = campaignInfoFactoryContract('0x...'); - * const isValid = await publicClient.readContract({ ...factory, functionName: 'isValidCampaignInfo', args: [addr] }); - */ -export function campaignInfoFactoryContract(address: Address) { - return { address, abi: CAMPAIGN_INFO_FACTORY_ABI } as const; -} - -export type CampaignInfoFactoryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/campaign-info.ts b/packages/contracts/src/entities/campaign-info.ts deleted file mode 100644 index bfb7a22..0000000 --- a/packages/contracts/src/entities/campaign-info.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Address, PublicClient } from "viem"; -import { CAMPAIGN_INFO_ABI } from "../abis/campaign-info.js"; -import type { CampaignData } from "../types/index.js"; - -/** - * Returns a typed contract config for CampaignInfo. - * - * @example - * const ci = campaignInfoContract('0x...'); - * const deadline = await publicClient.readContract({ ...ci, functionName: 'getDeadline' }); - */ -export function campaignInfoContract(address: Address) { - return { address, abi: CAMPAIGN_INFO_ABI } as const; -} - -export type CampaignInfoContractConfig = ReturnType; - -/** - * Convenience: fetch the core campaign data in one batched call set. - * Uses Promise.all over individual reads for simplicity. - */ -export async function getCampaignData( - publicClient: PublicClient, - address: Address, -): Promise { - const config = campaignInfoContract(address); - const [launchTime, deadline, goalAmount, currency] = await Promise.all([ - publicClient.readContract({ ...config, functionName: "getLaunchTime" }), - publicClient.readContract({ ...config, functionName: "getDeadline" }), - publicClient.readContract({ ...config, functionName: "getGoalAmount" }), - publicClient.readContract({ ...config, functionName: "getCampaignCurrency" }), - ]); - return { launchTime, deadline, goalAmount, currency }; -} diff --git a/packages/contracts/src/entities/global-params.ts b/packages/contracts/src/entities/global-params.ts deleted file mode 100644 index 6ac5c53..0000000 --- a/packages/contracts/src/entities/global-params.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Address } from "viem"; -import { GLOBAL_PARAMS_ABI } from "../abis/global-params.js"; - -/** - * Returns a typed contract config for GlobalParams that can be spread into - * viem's readContract, writeContract, simulateContract, etc. - * - * @example - * const gp = globalParamsContract('0x...'); - * const fee = await publicClient.readContract({ ...gp, functionName: 'getProtocolFeePercent' }); - */ -export function globalParamsContract(address: Address) { - return { address, abi: GLOBAL_PARAMS_ABI } as const; -} - -export type GlobalParamsContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/item-registry.ts b/packages/contracts/src/entities/item-registry.ts deleted file mode 100644 index 60c8677..0000000 --- a/packages/contracts/src/entities/item-registry.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { ITEM_REGISTRY_ABI } from "../abis/item-registry.js"; - -/** - * Returns a typed contract config for ItemRegistry. - * - * @example - * const ir = itemRegistryContract('0x...'); - * const item = await publicClient.readContract({ ...ir, functionName: 'getItem', args: [owner, itemId] }); - */ -export function itemRegistryContract(address: Address) { - return { address, abi: ITEM_REGISTRY_ABI } as const; -} - -export type ItemRegistryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/keep-whats-raised-treasury.ts b/packages/contracts/src/entities/keep-whats-raised-treasury.ts deleted file mode 100644 index f665189..0000000 --- a/packages/contracts/src/entities/keep-whats-raised-treasury.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { KEEP_WHATS_RAISED_ABI } from "../abis/keep-whats-raised.js"; - -/** - * Returns a typed contract config for KeepWhatsRaised treasury. - * - * @example - * const kwr = keepWhatsRaisedContract('0x...'); - * const raised = await publicClient.readContract({ ...kwr, functionName: 'getRaisedAmount' }); - */ -export function keepWhatsRaisedContract(address: Address) { - return { address, abi: KEEP_WHATS_RAISED_ABI } as const; -} - -export type KeepWhatsRaisedContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/payment-treasury.ts b/packages/contracts/src/entities/payment-treasury.ts deleted file mode 100644 index 9820a10..0000000 --- a/packages/contracts/src/entities/payment-treasury.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { PAYMENT_TREASURY_ABI } from "../abis/payment-treasury.js"; - -/** - * Returns a typed contract config for PaymentTreasury / TimeConstrainedPaymentTreasury. - * - * @example - * const pt = paymentTreasuryContract('0x...'); - * const data = await publicClient.readContract({ ...pt, functionName: 'getPaymentData', args: [paymentId] }); - */ -export function paymentTreasuryContract(address: Address) { - return { address, abi: PAYMENT_TREASURY_ABI } as const; -} - -export type PaymentTreasuryContractConfig = ReturnType; diff --git a/packages/contracts/src/entities/treasuries/index.ts b/packages/contracts/src/entities/treasuries/index.ts deleted file mode 100644 index c1a0d24..0000000 --- a/packages/contracts/src/entities/treasuries/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Treasury contract config factories. Use these for per-treasury instances (AllOrNothing, - * KeepWhatsRaised, PaymentTreasury, TimeConstrainedPaymentTreasury). - */ -export { allOrNothingContract, type AllOrNothingContractConfig } from "../all-or-nothing-treasury.js"; -export { keepWhatsRaisedContract, type KeepWhatsRaisedContractConfig } from "../keep-whats-raised-treasury.js"; -export { paymentTreasuryContract, type PaymentTreasuryContractConfig } from "../payment-treasury.js"; diff --git a/packages/contracts/src/entities/treasury-factory.ts b/packages/contracts/src/entities/treasury-factory.ts deleted file mode 100644 index 7179648..0000000 --- a/packages/contracts/src/entities/treasury-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Address } from "viem"; -import { TREASURY_FACTORY_ABI } from "../abis/treasury-factory.js"; - -/** - * Returns a typed contract config for TreasuryFactory. - * - * @example - * const tf = treasuryFactoryContract('0x...'); - * const hash = await walletClient.writeContract({ ...tf, functionName: 'deploy', args: [platformHash, infoAddr, implId] }); - */ -export function treasuryFactoryContract(address: Address) { - return { address, abi: TREASURY_FACTORY_ABI } as const; -} - -export type TreasuryFactoryContractConfig = ReturnType; diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts index a294270..c8fd6e4 100644 --- a/packages/contracts/src/index.ts +++ b/packages/contracts/src/index.ts @@ -17,7 +17,6 @@ export { createWalletClient, http, custom, - keccak256, stringToHex, toHex, parseEther, diff --git a/packages/contracts/src/types/client.ts b/packages/contracts/src/types/client.ts index a22eeda..34b153e 100644 --- a/packages/contracts/src/types/client.ts +++ b/packages/contracts/src/types/client.ts @@ -169,7 +169,7 @@ export interface Wallet extends WalletClient { * Use this for backend scripts or when you have a single signer. */ export interface SimpleOakContractsClientConfig { - /** Chain ID (e.g. CHAIN_IDS.CELO_SEPOLIA) */ + /** Chain ID (e.g. CHAIN_IDS.CELO_TESTNET_SEPOLIA) */ chainId: number; /** RPC URL for the chain */ rpcUrl: string; @@ -201,13 +201,6 @@ export type OakContractsClientConfig = | SimpleOakContractsClientConfig | FullOakContractsClientConfig; -/** - * Resolved client configuration with resolved chain - */ -export interface ResolvedOakContractsClientConfig extends Omit { - chain: Chain; -} - /** * Public client configuration (without sensitive data) */ @@ -355,6 +348,7 @@ export interface CampaignInfoEntity { burn(tokenId: bigint): Promise; pauseCampaign(message: Hex): Promise; unpauseCampaign(message: Hex): Promise; + cancelCampaign(message: Hex): Promise; setPlatformInfo(platformBytes: Hex, platformTreasuryAddress: Address): Promise; transferOwnership(newOwner: Address): Promise; renounceOwnership(): Promise; @@ -365,8 +359,8 @@ export interface CampaignInfoEntity { */ export interface PaymentTreasuryEntity { // Reads - getplatformHash(): Promise; - getplatformFeePercent(): Promise; + getPlatformHash(): Promise; + getPlatformFeePercent(): Promise; getRaisedAmount(): Promise; getAvailableRaisedAmount(): Promise; getLifetimeRaisedAmount(): Promise; @@ -406,6 +400,7 @@ export interface AllOrNothingTreasuryEntity { getPlatformHash(): Promise; getPlatformFeePercent(): Promise; paused(): Promise; + cancelled(): Promise; balanceOf(owner: Address): Promise; ownerOf(tokenId: bigint): Promise
; tokenURI(tokenId: bigint): Promise; @@ -417,6 +412,7 @@ export interface AllOrNothingTreasuryEntity { // Writes pauseTreasury(message: Hex): Promise; unpauseTreasury(message: Hex): Promise; + cancelTreasury(message: Hex): Promise; addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]): Promise; removeReward(rewardName: Hex): Promise; pledgeForAReward(backer: Address, pledgeToken: Address, shippingFee: bigint, rewardNames: readonly Hex[]): Promise; @@ -450,6 +446,7 @@ export interface KeepWhatsRaisedTreasuryEntity { getPaymentGatewayFee(pledgeId: Hex): Promise; getFeeValue(feeKey: Hex): Promise; paused(): Promise; + cancelled(): Promise; balanceOf(owner: Address): Promise; ownerOf(tokenId: bigint): Promise
; tokenURI(tokenId: bigint): Promise; @@ -461,6 +458,7 @@ export interface KeepWhatsRaisedTreasuryEntity { // Writes pauseTreasury(message: Hex): Promise; unpauseTreasury(message: Hex): Promise; + cancelTreasury(message: Hex): Promise; configureTreasury(config: KeepWhatsRaisedConfig, campaignData: CampaignData, feeKeys: KeepWhatsRaisedFeeKeys, feeValues: KeepWhatsRaisedFeeValues): Promise; addRewards(rewardNames: readonly Hex[], rewards: readonly TieredReward[]): Promise; removeReward(rewardName: Hex): Promise; @@ -473,6 +471,7 @@ export interface KeepWhatsRaisedTreasuryEntity { claimTip(): Promise; claimFund(): Promise; disburseFees(): Promise; + withdraw(token: Address, amount: bigint): Promise; updateDeadline(deadline: bigint): Promise; updateGoalAmount(goalAmount: bigint): Promise; approve(to: Address, tokenId: bigint): Promise; diff --git a/packages/contracts/src/types/config-options.ts b/packages/contracts/src/types/config-options.ts index b1184f1..e5ad101 100644 --- a/packages/contracts/src/types/config-options.ts +++ b/packages/contracts/src/types/config-options.ts @@ -2,10 +2,14 @@ * Client options configuration */ export interface OakContractsClientOptions { - /** Request timeout in milliseconds */ + /** + * Request timeout in milliseconds. + * Applied to HTTP transport calls (readContract, writeContract) and waitForTransactionReceipt. + * @default 30000 + */ timeout?: number; } export const DEFAULT_CLIENT_OPTIONS: OakContractsClientOptions = { - timeout: 3000, + timeout: 30000, }; diff --git a/packages/contracts/src/utils/chain-registry.ts b/packages/contracts/src/utils/chain-registry.ts index a989ace..4ac676d 100644 --- a/packages/contracts/src/utils/chain-registry.ts +++ b/packages/contracts/src/utils/chain-registry.ts @@ -2,6 +2,16 @@ import { defineChain } from "viem"; import { mainnet, sepolia, goerli } from "viem/chains"; import type { Chain } from "viem/chains"; +/** Celo Mainnet */ +const celoMainnet = defineChain({ + id: 42220, + name: "Celo", + nativeCurrency: { decimals: 18, name: "CELO", symbol: "CELO" }, + rpcUrls: { + default: { http: ["https://forno.celo.org"] }, + }, +}); + /** Celo Sepolia testnet */ const celoSepolia = defineChain({ id: 11142220, @@ -18,6 +28,7 @@ const celoSepolia = defineChain({ */ const CHAIN_REGISTRY: Record = { 1: mainnet, + 42220: celoMainnet, 11155111: sepolia, 5: goerli, 11142220: celoSepolia, diff --git a/packages/contracts/src/utils/index.ts b/packages/contracts/src/utils/index.ts index 2a06802..6cd077b 100644 --- a/packages/contracts/src/utils/index.ts +++ b/packages/contracts/src/utils/index.ts @@ -21,9 +21,11 @@ import { http, custom, type Account, + type EIP1193Provider, type PublicClient, type WalletClient, } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; import type { Chain } from "viem/chains"; import type { JsonRpcProvider, Wallet } from "../types"; @@ -118,21 +120,16 @@ export function createWallet( provider: PublicClient, rpcUrl?: string, ): Wallet { - // Use the provided RPC URL or try to extract from provider's transport - // For http transports, we need the URL; for custom transports, we reuse the transport - const transport = rpcUrl - ? http(rpcUrl) - : (provider as any).transport || http(); + const transport = rpcUrl ? http(rpcUrl) : custom(provider as unknown as EIP1193Provider); + + const account = privateKeyToAccount(privateKey); const walletClient = createWalletClient({ - account: privateKey as `0x${string}`, + account, chain: provider.chain, transport, }); - // Get the account from the wallet client - const account = walletClient.account as Account; - return { ...walletClient, account, @@ -154,7 +151,7 @@ export function createWallet( * ``` */ export function createBrowserProvider( - ethereum: any, + ethereum: EIP1193Provider, chain: Chain, ): JsonRpcProvider { return createPublicClient({ @@ -179,7 +176,7 @@ export function createBrowserProvider( * ``` */ export async function getSigner( - ethereum: any, + ethereum: EIP1193Provider, chain: Chain, ): Promise { // Request accounts from the provider diff --git a/packages/contracts/tsup.config.ts b/packages/contracts/tsup.config.ts index bf46cfb..4080a74 100644 --- a/packages/contracts/tsup.config.ts +++ b/packages/contracts/tsup.config.ts @@ -6,6 +6,7 @@ export default defineConfig({ "utils/index": "src/utils/index.ts", "contracts/index": "src/contracts/index.ts", "client/index": "src/client/index.ts", + "errors/index": "src/errors/index.ts", }, format: ["esm"], dts: true, From d6022b4899143bba925ea4561afd85c0dccda9a6 Mon Sep 17 00:00:00 2001 From: Mahabub Alahi Date: Mon, 9 Mar 2026 15:28:20 +0600 Subject: [PATCH 14/14] Update README and enhance contract methods for clarity and functionality - Revised chain ID documentation in README to include new mainnet and testnet identifiers for Ethereum and Celo. - Updated contract method calls to improve clarity, including renaming parameters for consistency and adding message handling for campaign and treasury functions. - Enhanced item registry methods to accept structured item data for better usability. --- packages/contracts/README.md | 46 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/contracts/README.md b/packages/contracts/README.md index c2b06d6..9dd5a96 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -58,10 +58,11 @@ const oak = createOakContractsClient({ chain, provider, signer }); ```typescript import { CHAIN_IDS } from "@oaknetwork/contracts"; -CHAIN_IDS.ETHEREUM_MAINNET // 1 -CHAIN_IDS.ETHEREUM_TESTNET_SEPOLIA // 11155111 -CHAIN_IDS.CELO_TESTNET_SEPOLIA // 11142220 -CHAIN_IDS.CELO_TESTNET_ALFAJORES // 44787 +CHAIN_IDS.ETHEREUM_MAINNET // 1 +CHAIN_IDS.CELO_MAINNET // 42220 +CHAIN_IDS.ETHEREUM_TESTNET_SEPOLIA // 11155111 +CHAIN_IDS.ETHEREUM_TESTNET_GOERLI // 5 +CHAIN_IDS.CELO_TESTNET_SEPOLIA // 11142220 ``` ## Contracts @@ -195,8 +196,9 @@ const tokens = await ci.getAcceptedTokens(); // Writes await ci.updateDeadline(newDeadline); await ci.updateGoalAmount(newGoal); -await ci.cancelCampaign(); -await ci.lockCampaign(); +await ci.pauseCampaign(message); +await ci.unpauseCampaign(message); +await ci.cancelCampaign(message); ``` --- @@ -214,15 +216,15 @@ const refunded = await pt.getRefundedAmount(); const payment = await pt.getPaymentData(paymentId); // Writes -const txHash = await pt.createPayment(paymentId, backer, token, amount, tip, lineItemIds, lineItemAmounts); -await pt.confirmPayment(paymentId); +const txHash = await pt.createPayment(paymentId, buyerId, itemId, paymentToken, amount, expiration, lineItems, externalFees); +await pt.confirmPayment(paymentId, buyerAddress); await pt.claimRefund(paymentId, refundAddress); await pt.claimRefundSelf(paymentId); await pt.disburseFees(); await pt.withdraw(); await pt.pauseTreasury(message); await pt.unpauseTreasury(message); -await pt.cancelTreasury(); +await pt.cancelTreasury(message); ``` --- @@ -240,13 +242,14 @@ const reward = await aon.getReward(rewardName); // Writes await aon.addRewards(rewardNames, rewards); -await aon.pledgeForAReward(pledgeId, backer, token, tip, rewardNames); -await aon.pledgeWithoutAReward(pledgeId, backer, token, amount, tip); +await aon.pledgeForAReward(backer, pledgeToken, shippingFee, rewardNames); +await aon.pledgeWithoutAReward(backer, pledgeToken, pledgeAmount); await aon.claimRefund(tokenId); await aon.disburseFees(); await aon.withdraw(); await aon.pauseTreasury(message); await aon.unpauseTreasury(message); +await aon.cancelTreasury(message); // ERC-721 const owner = await aon.ownerOf(tokenId); @@ -278,8 +281,10 @@ await kwr.claimFund(); await kwr.claimTip(); await kwr.claimRefund(tokenId); await kwr.disburseFees(); +await kwr.withdraw(token, amount); await kwr.pauseTreasury(message); await kwr.unpauseTreasury(message); +await kwr.cancelTreasury(message); ``` --- @@ -292,11 +297,11 @@ Manages items available for purchase in campaigns. const ir = oak.itemRegistry("0x..."); // Read -const item = await ir.getItem(itemId); +const item = await ir.getItem(ownerAddress, itemId); // Writes -await ir.addItem(itemId, name, price, quantity); -await ir.addItemsBatch(itemIds, names, prices, quantities); +await ir.addItem(itemId, item); +await ir.addItemsBatch(itemIds, items); ``` --- @@ -389,12 +394,13 @@ const signer = await getSigner(window.ethereum, chain); ## Exported Entry Points -| Entry point | Contents | -|-------------------------------|--------------------------------------------| -| `@oaknetwork/contracts` | Everything — client, types, utils, errors | -| `@oaknetwork/contracts/utils` | Utility functions only (no client) | -| `@oaknetwork/contracts/contracts` | Contract entity factories only | -| `@oaknetwork/contracts/client` | `createOakContractsClient` only | +| Entry point | Contents | +|-----------------------------------|--------------------------------------------| +| `@oaknetwork/contracts` | Everything — client, types, utils, errors | +| `@oaknetwork/contracts/utils` | Utility functions only (no client) | +| `@oaknetwork/contracts/contracts` | Contract entity factories only | +| `@oaknetwork/contracts/client` | `createOakContractsClient` only | +| `@oaknetwork/contracts/errors` | Error classes and `parseContractError` only | ---