diff --git a/README.md b/README.md index 6b0eab5..fc4b134 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,19 @@ These solutions were combined with ideas from [Hats Protocol](https://www.hatspr ## Related Contract Addresses +### Sepolia + +| ContractAddress | Name | Memo | +| ------------------------------------------ | ----------------------- | ---- | +| 0x5d7a64Cc808294C516076d371685ed4E6aDd6337 | BigBang | | +| 0xb8f7ca7a5b1e457b8735884419e114f90d53e1d5 | FractionToken | | +| 0x8da1c0864962c5e26c99cf839b0dc48e39104568 | SplitsCreatorFactory | | +| 0xda9fbab4436e4124cd6ee6864d4b46d0dd412414 | SplitsCreatorIMPL | | +| 0xd4a66507ea8c8382fa8474ed6cae4163676a434a | HatsTimeFrameModuleIMPL | | +| 0x3bc1A0Ad72417f2d411118085256fC53CBdDd137 | Hats | | +| 0x0a3f85fa597B6a967271286aA0724811acDF5CD9 | HatsModuleFactory | | +| 0x80f1B766817D04870f115fEBbcCADF8DBF75E017 | PullSplitsFactory | | + ### Holesky | ContractAddress | Name | Memo | diff --git a/pkgs/cli/src/abi/bigbang.ts b/pkgs/cli/src/abi/bigbang.ts new file mode 100644 index 0000000..8db4a89 --- /dev/null +++ b/pkgs/cli/src/abi/bigbang.ts @@ -0,0 +1,228 @@ +export const BIGBANG_ABI = [ + { + inputs: [ + { + internalType: "address", + name: "_trustedForwarder", + type: "address", + }, + { + internalType: "address", + name: "_hatsAddress", + type: "address", + }, + { + internalType: "address", + name: "_hatsModuleFactory", + type: "address", + }, + { + internalType: "address", + name: "_hatsTimeFrameModule_IMPL", + type: "address", + }, + { + internalType: "address", + name: "_splitsCreatorFactory", + type: "address", + }, + { + internalType: "address", + name: "_splitFactoryV2", + type: "address", + }, + { + internalType: "address", + name: "_fractionToken", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "topHatId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "hatsTimeFrameModule", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "splitCreator", + type: "address", + }, + ], + name: "Executed", + type: "event", + }, + { + inputs: [], + name: "Hats", + outputs: [ + { + internalType: "contract IHats", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "HatsModuleFactory", + outputs: [ + { + internalType: "contract IHatsModuleFactory", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "HatsTimeFrameModule_IMPL", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "SplitsCreatorFactory", + outputs: [ + { + internalType: "contract ISplitsCreatorFactory", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_owner", + type: "address", + }, + { + internalType: "string", + name: "_topHatDetails", + type: "string", + }, + { + internalType: "string", + name: "_topHatImageURI", + type: "string", + }, + { + internalType: "string", + name: "_hatterHatDetails", + type: "string", + }, + { + internalType: "string", + name: "_hatterHatImageURI", + type: "string", + }, + { + internalType: "address", + name: "_trustedForwarder", + type: "address", + }, + ], + name: "bigbang", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "fractionToken", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "forwarder", + type: "address", + }, + ], + name: "isTrustedForwarder", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "splitFactoryV2", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "trustedForwarder", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/pkgs/cli/src/abi/hats.ts b/pkgs/cli/src/abi/hats.ts new file mode 100644 index 0000000..f7faf1a --- /dev/null +++ b/pkgs/cli/src/abi/hats.ts @@ -0,0 +1,924 @@ +export const HATS_ABI = [ + { + inputs: [ + { internalType: "string", name: "_name", type: "string" }, + { internalType: "string", name: "_baseImageURI", type: "string" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [{ internalType: "uint256", name: "hatId", type: "uint256" }], + name: "AllHatsWorn", + type: "error", + }, + { + inputs: [ + { internalType: "address", name: "wearer", type: "address" }, + { internalType: "uint256", name: "hatId", type: "uint256" }, + ], + name: "AlreadyWearingHat", + type: "error", + }, + { inputs: [], name: "BatchArrayLengthMismatch", type: "error" }, + { inputs: [], name: "CircularLinkage", type: "error" }, + { inputs: [], name: "CrossTreeLinkage", type: "error" }, + { + inputs: [{ internalType: "uint256", name: "hatId", type: "uint256" }], + name: "HatDoesNotExist", + type: "error", + }, + { inputs: [], name: "HatNotActive", type: "error" }, + { inputs: [], name: "Immutable", type: "error" }, + { inputs: [], name: "InvalidHatId", type: "error" }, + { inputs: [], name: "InvalidUnlink", type: "error" }, + { inputs: [], name: "LinkageNotRequested", type: "error" }, + { inputs: [], name: "MaxLevelsReached", type: "error" }, + { inputs: [], name: "MaxLevelsReached", type: "error" }, + { inputs: [], name: "NewMaxSupplyTooLow", type: "error" }, + { + inputs: [ + { internalType: "address", name: "user", type: "address" }, + { internalType: "uint256", name: "hatId", type: "uint256" }, + ], + name: "NotAdmin", + type: "error", + }, + { inputs: [], name: "NotAdminOrWearer", type: "error" }, + { inputs: [], name: "NotEligible", type: "error" }, + { inputs: [], name: "NotHatWearer", type: "error" }, + { inputs: [], name: "NotHatsEligibility", type: "error" }, + { inputs: [], name: "NotHatsToggle", type: "error" }, + { inputs: [], name: "StringTooLong", type: "error" }, + { inputs: [], name: "ZeroAddress", type: "error" }, + { + 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: "id", type: "uint256" }, + { + indexed: false, + internalType: "string", + name: "details", + type: "string", + }, + { + indexed: false, + internalType: "uint32", + name: "maxSupply", + type: "uint32", + }, + { + indexed: false, + internalType: "address", + name: "eligibility", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "toggle", + type: "address", + }, + { indexed: false, internalType: "bool", name: "mutable_", type: "bool" }, + { + indexed: false, + internalType: "string", + name: "imageURI", + type: "string", + }, + ], + name: "HatCreated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "newDetails", + type: "string", + }, + ], + name: "HatDetailsChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "newEligibility", + type: "address", + }, + ], + name: "HatEligibilityChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "string", + name: "newImageURI", + type: "string", + }, + ], + name: "HatImageURIChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "uint32", + name: "newMaxSupply", + type: "uint32", + }, + ], + name: "HatMaxSupplyChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + ], + name: "HatMutabilityChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { indexed: false, internalType: "bool", name: "newStatus", type: "bool" }, + ], + name: "HatStatusChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "newToggle", + type: "address", + }, + ], + name: "HatToggleChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "domain", + type: "uint32", + }, + { + indexed: false, + internalType: "uint256", + name: "newAdmin", + type: "uint256", + }, + ], + name: "TopHatLinkRequested", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint32", + name: "domain", + type: "uint32", + }, + { + indexed: false, + internalType: "uint256", + name: "newAdmin", + type: "uint256", + }, + ], + name: "TopHatLinked", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "operator", + type: "address", + }, + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256[]", + name: "ids", + type: "uint256[]", + }, + { + indexed: false, + internalType: "uint256[]", + name: "amounts", + type: "uint256[]", + }, + ], + name: "TransferBatch", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "operator", + type: "address", + }, + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { indexed: false, internalType: "uint256", name: "id", type: "uint256" }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "TransferSingle", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: "string", name: "value", type: "string" }, + { indexed: true, internalType: "uint256", name: "id", type: "uint256" }, + ], + name: "URI", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "wearer", + type: "address", + }, + { + indexed: false, + internalType: "bool", + name: "wearerStanding", + type: "bool", + }, + ], + name: "WearerStandingChanged", + type: "event", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "uint256", name: "_newAdminHat", type: "uint256" }, + { internalType: "address", name: "_eligibility", type: "address" }, + { internalType: "address", name: "_toggle", type: "address" }, + { internalType: "string", name: "_details", type: "string" }, + { internalType: "string", name: "_imageURI", type: "string" }, + ], + name: "approveLinkTopHatToTree", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "address", name: "", type: "address" }, + ], + name: "badStandings", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_wearer", type: "address" }, + { internalType: "uint256", name: "_hatId", type: "uint256" }, + ], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "balance", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "_wearers", type: "address[]" }, + { internalType: "uint256[]", name: "_hatIds", type: "uint256[]" }, + ], + name: "balanceOfBatch", + outputs: [ + { internalType: "uint256[]", name: "balances", type: "uint256[]" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "baseImageURI", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "_admins", type: "uint256[]" }, + { internalType: "string[]", name: "_details", type: "string[]" }, + { internalType: "uint32[]", name: "_maxSupplies", type: "uint32[]" }, + { + internalType: "address[]", + name: "_eligibilityModules", + type: "address[]", + }, + { internalType: "address[]", name: "_toggleModules", type: "address[]" }, + { internalType: "bool[]", name: "_mutables", type: "bool[]" }, + { internalType: "string[]", name: "_imageURIs", type: "string[]" }, + ], + name: "batchCreateHats", + outputs: [{ internalType: "bool", name: "success", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256[]", name: "_hatIds", type: "uint256[]" }, + { internalType: "address[]", name: "_wearers", type: "address[]" }, + ], + name: "batchMintHats", + outputs: [{ internalType: "bool", name: "success", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_admin", type: "uint256" }, + { internalType: "uint16", name: "_newHat", type: "uint16" }, + ], + name: "buildHatId", + outputs: [{ internalType: "uint256", name: "id", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "string", name: "_newDetails", type: "string" }, + ], + name: "changeHatDetails", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_newEligibility", type: "address" }, + ], + name: "changeHatEligibility", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "string", name: "_newImageURI", type: "string" }, + ], + name: "changeHatImageURI", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "uint32", name: "_newMaxSupply", type: "uint32" }, + ], + name: "changeHatMaxSupply", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_newToggle", type: "address" }, + ], + name: "changeHatToggle", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "checkHatStatus", + outputs: [{ internalType: "bool", name: "toggled", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_wearer", type: "address" }, + ], + name: "checkHatWearerStatus", + outputs: [{ internalType: "bool", name: "updated", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_admin", type: "uint256" }, + { internalType: "string", name: "_details", type: "string" }, + { internalType: "uint32", name: "_maxSupply", type: "uint32" }, + { internalType: "address", name: "_eligibility", type: "address" }, + { internalType: "address", name: "_toggle", type: "address" }, + { internalType: "bool", name: "_mutable", type: "bool" }, + { internalType: "string", name: "_imageURI", type: "string" }, + ], + name: "createHat", + outputs: [{ internalType: "uint256", name: "newHatId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "uint32", name: "_level", type: "uint32" }, + ], + name: "getAdminAtLevel", + outputs: [{ internalType: "uint256", name: "admin", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "uint32", name: "_level", type: "uint32" }, + ], + name: "getAdminAtLocalLevel", + outputs: [{ internalType: "uint256", name: "admin", type: "uint256" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getHatEligibilityModule", + outputs: [ + { internalType: "address", name: "eligibility", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getHatLevel", + outputs: [{ internalType: "uint32", name: "level", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getHatMaxSupply", + outputs: [{ internalType: "uint32", name: "maxSupply", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getHatToggleModule", + outputs: [{ internalType: "address", name: "toggle", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getImageURIForHat", + outputs: [{ internalType: "string", name: "_uri", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getLocalHatLevel", + outputs: [{ internalType: "uint32", name: "level", type: "uint32" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_admin", type: "uint256" }], + name: "getNextId", + outputs: [{ internalType: "uint256", name: "nextId", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint32", name: "_topHatDomain", type: "uint32" }], + name: "getTippyTopHatDomain", + outputs: [{ internalType: "uint32", name: "domain", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "getTopHatDomain", + outputs: [{ internalType: "uint32", name: "domain", type: "uint32" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "hatSupply", + outputs: [{ internalType: "uint32", name: "supply", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "isActive", + outputs: [{ internalType: "bool", name: "active", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_user", type: "address" }, + { internalType: "uint256", name: "_hatId", type: "uint256" }, + ], + name: "isAdminOfHat", + outputs: [{ internalType: "bool", name: "isAdmin", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + ], + name: "isApprovedForAll", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_wearer", type: "address" }, + { internalType: "uint256", name: "_hatId", type: "uint256" }, + ], + name: "isEligible", + outputs: [{ internalType: "bool", name: "eligible", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_wearer", type: "address" }, + { internalType: "uint256", name: "_hatId", type: "uint256" }, + ], + name: "isInGoodStanding", + outputs: [{ internalType: "bool", name: "standing", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "isLocalTopHat", + outputs: [{ internalType: "bool", name: "_isLocalTopHat", type: "bool" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "isTopHat", + outputs: [{ internalType: "bool", name: "_isTopHat", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "isValidHatId", + outputs: [{ internalType: "bool", name: "validHatId", type: "bool" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_user", type: "address" }, + { internalType: "uint256", name: "_hatId", type: "uint256" }, + ], + name: "isWearerOfHat", + outputs: [{ internalType: "bool", name: "isWearer", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "lastTopHatId", + outputs: [{ internalType: "uint32", name: "", type: "uint32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint32", name: "", type: "uint32" }], + name: "linkedTreeAdmins", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint32", name: "", type: "uint32" }], + name: "linkedTreeRequests", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "makeHatImmutable", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_wearer", type: "address" }, + ], + name: "mintHat", + outputs: [{ internalType: "bool", name: "success", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_target", type: "address" }, + { internalType: "string", name: "_details", type: "string" }, + { internalType: "string", name: "_imageURI", type: "string" }, + ], + name: "mintTopHat", + outputs: [{ internalType: "uint256", name: "topHatId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes[]", name: "data", type: "bytes[]" }], + name: "multicall", + outputs: [{ internalType: "bytes[]", name: "", type: "bytes[]" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "uint256", name: "_linkedAdmin", type: "uint256" }, + ], + name: "noCircularLinkage", + outputs: [{ internalType: "bool", name: "notCircular", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "uint256", name: "_newAdminHat", type: "uint256" }, + { internalType: "address", name: "_eligibility", type: "address" }, + { internalType: "address", name: "_toggle", type: "address" }, + { internalType: "string", name: "_details", type: "string" }, + { internalType: "string", name: "_imageURI", type: "string" }, + ], + name: "relinkTopHatWithinTree", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "renounceHat", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "uint256", name: "_requestedAdminHat", type: "uint256" }, + ], + name: "requestLinkTopHatToTree", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "uint256[]", name: "", type: "uint256[]" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "safeBatchTransferFrom", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "bytes", name: "", type: "bytes" }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "uint256", name: "_newAdminHat", type: "uint256" }, + ], + name: "sameTippyTopHatDomain", + outputs: [{ internalType: "bool", name: "sameDomain", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "bool", name: "", type: "bool" }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "bool", name: "_newStatus", type: "bool" }, + ], + name: "setHatStatus", + outputs: [{ internalType: "bool", name: "toggled", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_wearer", type: "address" }, + { internalType: "bool", name: "_eligible", type: "bool" }, + { internalType: "bool", name: "_standing", type: "bool" }, + ], + name: "setHatWearerStatus", + outputs: [{ internalType: "bool", name: "updated", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_hatId", type: "uint256" }, + { internalType: "address", name: "_from", type: "address" }, + { internalType: "address", name: "_to", type: "address" }, + ], + name: "transferHat", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint32", name: "_topHatDomain", type: "uint32" }, + { internalType: "address", name: "_wearer", type: "address" }, + ], + name: "unlinkTopHatFromTree", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "id", type: "uint256" }], + name: "uri", + outputs: [{ internalType: "string", name: "_uri", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "_hatId", type: "uint256" }], + name: "viewHat", + outputs: [ + { internalType: "string", name: "details", type: "string" }, + { internalType: "uint32", name: "maxSupply", type: "uint32" }, + { internalType: "uint32", name: "supply", type: "uint32" }, + { internalType: "address", name: "eligibility", type: "address" }, + { internalType: "address", name: "toggle", type: "address" }, + { internalType: "string", name: "imageURI", type: "string" }, + { internalType: "uint16", name: "lastHatId", type: "uint16" }, + { internalType: "bool", name: "mutable_", type: "bool" }, + { internalType: "bool", name: "active", type: "bool" }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/pkgs/cli/src/abi/hatsTimeFrameModule.ts b/pkgs/cli/src/abi/hatsTimeFrameModule.ts new file mode 100644 index 0000000..4a842b2 --- /dev/null +++ b/pkgs/cli/src/abi/hatsTimeFrameModule.ts @@ -0,0 +1,217 @@ +export const HATS_TIME_FRAME_MODULE_ABI = [ + { + inputs: [ + { + internalType: "address", + name: "_trustedForwarder", + type: "address", + }, + { + internalType: "string", + name: "_version", + type: "string", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "InvalidInitialization", + type: "error", + }, + { + inputs: [], + name: "NotInitializing", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint64", + name: "version", + type: "uint64", + }, + ], + name: "Initialized", + type: "event", + }, + { + inputs: [], + name: "HATS", + outputs: [ + { + internalType: "contract IHats", + name: "", + type: "address", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [], + name: "IMPLEMENTATION", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "wearer", + type: "address", + }, + { + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + ], + name: "getWearingElapsedTime", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "wearer", + type: "address", + }, + { + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + ], + name: "getWoreTime", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "hatId", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "pure", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "forwarder", + type: "address", + }, + ], + name: "isTrustedForwarder", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "hatId", + type: "uint256", + }, + { + internalType: "address", + name: "wearer", + type: "address", + }, + ], + name: "mintHat", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_initData", + type: "bytes", + }, + ], + name: "setUp", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "trustedForwarder", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "version", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "version_", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/pkgs/cli/src/commands/bigbang.ts b/pkgs/cli/src/commands/bigbang.ts new file mode 100644 index 0000000..4787f3b --- /dev/null +++ b/pkgs/cli/src/commands/bigbang.ts @@ -0,0 +1,35 @@ +import { Command } from "commander"; +import { bigbang } from "../modules/bigbang"; +import { zeroAddress } from "viem"; + +export const bigbangCommands = new Command(); + +bigbangCommands + .name("bigbang") + .description("This is a CLI bigbang for toban project") + .version("1.0.0"); + +bigbangCommands + .command("create") + .description("Create project") + .requiredOption("-o, --owner ", "Owner") + .requiredOption("-td, --topHatDetails ", "Top hat details") + .requiredOption("-ti, --topHatImageURI ", "Top hat image URI") + .option("-hd, --hatterHatDetails ", "Hatter hat details") + .option( + "-hi, --hatterHatImageURI ", + "Hatter hat image URI" + ) + .option("-f, --trustedForwarder ", "Trusted forwarder") + .action(async (options) => { + const hash = await bigbang({ + owner: options.owner, + topHatDetails: options.topHatDetails, + topHatImageURI: options.topHatImageURI, + hatterHatDetails: options.hatterHatDetails || "", + hatterHatImageURI: options.hatterHatImageURI || "", + trustedForwarder: options.trustedForwarder || zeroAddress, + }); + + console.log(`Transaction hash: ${hash}`); + }); diff --git a/pkgs/cli/src/commands/function.ts b/pkgs/cli/src/commands/function.ts deleted file mode 100644 index 5fda2d9..0000000 --- a/pkgs/cli/src/commands/function.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Command } from "commander"; - -export const functionCommands = new Command(); - -// ############################################################### -// CLI init setup -// ############################################################### - -functionCommands - .name("function") - .description("This is a CLI function for toban project") - .version("1.0.0"); - -// ############################################################### -// command setUp -// ############################################################### - -// シフトデータを保持するための簡易データ -let shifts = [ - { date: "2024-10-01", person: "Alice" }, - { date: "2024-10-02", person: "Bob" }, -]; - -/** - * シフトを一覧表示するコマンド - */ -functionCommands - .command("list") - .description("List all shifts") - .action(() => { - console.log("Current shifts:"); - shifts.forEach((shift, index) => { - console.log(`${index + 1}. ${shift.date} - ${shift.person}`); - }); - }); - -/** - * 新しいシフトを追加するコマンド - */ -functionCommands - .command("add ") - .description("Add a new shift") - .action((date, person) => { - shifts.push({ date, person }); - console.log(`Added new shift: ${date} - ${person}`); - }); - -/** - * ランダムで担当者を選ぶコマンド - */ -functionCommands - .command("random") - .description("Pick a random person for the shift") - .action(() => { - const randomIndex = Math.floor(Math.random() * shifts.length); - console.log( - `Selected: ${shifts[randomIndex].person} for ${shifts[randomIndex].date}` - ); - }); - -/** - * 引数を表示するだけのコマンド - */ -functionCommands - .command("show") - .description("Show the arguments") - .option("-t, --text ", "Show all arguments") - .action(async (options) => { - console.log("your args:", options.text); - }); diff --git a/pkgs/cli/src/commands/hats.ts b/pkgs/cli/src/commands/hats.ts index 2f2cbeb..3894934 100644 --- a/pkgs/cli/src/commands/hats.ts +++ b/pkgs/cli/src/commands/hats.ts @@ -3,9 +3,14 @@ import { getTreeInfo, getWearerInfo, getWearersInfo, + createHat, + mintHat, } from "../modules/hatsProtocol"; import { PinataSDK } from "pinata-web3"; import { getJwt, setJwt } from "../services/hats"; +import { getAccount } from "../services/wallet"; +import { publicClient, rootProgram, walletClient } from ".."; +import { Address } from "viem"; export const hatsCommands = new Command(); @@ -30,8 +35,9 @@ hatsCommands .description("Show all of the Hats that are associated with the tree ID") .option("-id, --treeId ", "Tree ID") .action(async (options) => { + const { chain } = rootProgram.opts(); // ツリー情報を全て取得する。 - const tree = await getTreeInfo(Number(options.treeId)); + const tree = await getTreeInfo(Number(options.treeId), chain); console.log(tree); }); @@ -44,8 +50,9 @@ hatsCommands .description("Show all of the wears that are associated with the hat ID") .option("-id, --hatId ", "Hat ID") .action(async (options) => { + const { chain } = rootProgram.opts(); // ツリー情報を全て取得する。 - const wearers = await getWearersInfo(options.hatId); + const wearers = await getWearersInfo(options.hatId, chain); console.log(wearers); }); @@ -59,7 +66,9 @@ hatsCommands .option("-addr, --address
", "Wallet Address") .action(async (options) => { // 特定のウォレットアドレスに紐づく情報を全て取得する。 - const wearer = await getWearerInfo(options.address); + const address = + options.address || getAccount(rootProgram.opts().profile).address; + const wearer = await getWearerInfo(address, rootProgram.opts().chain); console.log(wearer); }); @@ -152,4 +161,55 @@ hatsCommands }); console.log("CID:", upload.IpfsHash); - }); \ No newline at end of file + }); + +/** + * ロールを作成 + */ +hatsCommands + .command("createHat") + .description("Create Hat") + .requiredOption("-phid, --parentHatId ", "Parent Hat ID") + .requiredOption("-img, --imageURI ", "Image URI") + .option("-det , --details
", "Details") + .option("-max, --maxSupply ", "Max Supply") + .option("-el, --eligibility ", "Eligibility Address") + .option("-tgl, --toggle ", "Toggle") + .option("-mut, --mutable ", "Mutable") + .action( + async ({ + parentHatId, + details, + maxSupply, + eligibility, + toggle, + mutable, + imageURI, + }) => { + const transactionHash = await createHat({ + parentHatId: BigInt(parentHatId), + details, + maxSupply, + eligibility: eligibility as Address, + toggle: toggle as Address, + mutable: mutable == "true", + imageURI, + }); + + console.log("Transaction hash: ", transactionHash); + } + ); + +/** + * ロールを付与 + */ +hatsCommands + .command("mintHat") + .description("Mint Hat") + .requiredOption("-hid, --hatId ", "Hat ID") + .requiredOption("--wearer ", "Wearer address") + .action(async ({ hatId, wearer }) => { + const transactionHash = await mintHat({ hatId, wearer }); + + console.log("Transaction hash: ", transactionHash); + }); diff --git a/pkgs/cli/src/commands/wallet.ts b/pkgs/cli/src/commands/wallet.ts index 1699e19..a087141 100644 --- a/pkgs/cli/src/commands/wallet.ts +++ b/pkgs/cli/src/commands/wallet.ts @@ -1,11 +1,10 @@ import { Command } from "commander"; -import { getEthAddress, sendEth } from "../modules/viem"; +import { sendEth } from "../modules/viem"; import { listProfiles, saveProfile, deleteProfile } from "../services/wallet"; +import { walletClient } from ".."; export const walletCommands = new Command(); -const { TOBAN_PRIVATE_KEY } = process.env; - walletCommands .name("wallet") .description("This is a CLI function for toban project") @@ -50,11 +49,8 @@ walletCommands walletCommands .command("sendEth") .description("Send ETH") - .action(async () => { - console.log("Start send ETH"); - const address1 = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"; - - await sendEth(TOBAN_PRIVATE_KEY as `0x${string}`, address1); - - console.log("End send ETH"); + .requiredOption("--receiver ", "Receiver address") + .requiredOption("--amount ", "Amount") + .action(async ({ receiver, amount }) => { + await sendEth(walletClient, receiver, amount); }); diff --git a/pkgs/cli/src/config.ts b/pkgs/cli/src/config.ts new file mode 100644 index 0000000..0dbbe57 --- /dev/null +++ b/pkgs/cli/src/config.ts @@ -0,0 +1,20 @@ +import { Address } from "viem"; +import { HATS_ABI } from "./abi/hats"; +import { HATS_TIME_FRAME_MODULE_ABI } from "./abi/hatsTimeFrameModule"; +import { BIGBANG_ABI } from "./abi/bigbang"; + +export const skipPreActionCommands = ["wallet>add", "wallet>list"]; + +export const hatsContractBaseConfig = { + address: "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137" as Address, + abi: HATS_ABI, +}; + +export const hatsTimeFrameContractBaseConfig = { + abi: HATS_TIME_FRAME_MODULE_ABI, +}; + +export const bigbangContractBaseConfig = { + address: "0x5d7a64Cc808294C516076d371685ed4E6aDd6337" as Address, + abi: BIGBANG_ABI, +}; diff --git a/pkgs/cli/src/index.ts b/pkgs/cli/src/index.ts index 34e3516..30beafc 100755 --- a/pkgs/cli/src/index.ts +++ b/pkgs/cli/src/index.ts @@ -1,12 +1,37 @@ #!/usr/bin/env node -import { program } from "commander"; -import { functionCommands } from "./commands/function"; +import { Command } from "commander"; import { hatsCommands } from "./commands/hats"; import { walletCommands } from "./commands/wallet"; +import { PublicClient, WalletClient } from "viem"; +import { getPublicClient } from "./modules/viem"; +import { getWalletClient } from "./services/wallet"; +import { skipPreActionCommands } from "./config"; +import { bigbangCommands } from "./commands/bigbang"; -program.addCommand(functionCommands); -program.addCommand(hatsCommands); -program.addCommand(walletCommands); +export const rootProgram = new Command(); -program.parse(process.argv); +export let publicClient!: PublicClient; + +export let walletClient!: WalletClient; + +rootProgram + .version("0.0.1") + .option("--chain ", "chain id", "11155111") + .option("--profile ", "Wallet profile") + .hook("preAction", async (_, actionCommand) => { + const { chain, profile } = rootProgram.opts(); + const parentName = actionCommand.parent?.name(); + const commandName = actionCommand.name(); + + if (!skipPreActionCommands.includes(`${parentName}>${commandName}`)) { + publicClient = await getPublicClient(chain); + walletClient = await getWalletClient(profile, chain); + } + }); + +rootProgram.addCommand(bigbangCommands); +rootProgram.addCommand(hatsCommands); +rootProgram.addCommand(walletCommands); + +rootProgram.parse(process.argv); diff --git a/pkgs/cli/src/modules/bigbang.ts b/pkgs/cli/src/modules/bigbang.ts new file mode 100644 index 0000000..3bbc967 --- /dev/null +++ b/pkgs/cli/src/modules/bigbang.ts @@ -0,0 +1,37 @@ +// ############################################################### +// Write with viem +// ############################################################### + +import { Address } from "viem"; +import { publicClient, walletClient } from ".."; +import { bigbangContractBaseConfig } from "../config"; + +/** + * プロジェクト作成 + */ + +export const bigbang = async (params: { + owner: Address; + topHatDetails: string; + topHatImageURI: string; + hatterHatDetails: string; + hatterHatImageURI: string; + trustedForwarder: Address; +}) => { + const { request } = await publicClient.simulateContract({ + ...bigbangContractBaseConfig, + account: walletClient.account, + functionName: "bigbang", + args: [ + params.owner, + params.topHatDetails, + params.topHatImageURI, + params.hatterHatDetails, + params.hatterHatImageURI, + params.trustedForwarder, + ], + }); + const transactionHash = await walletClient.writeContract(request); + + return transactionHash; +}; diff --git a/pkgs/cli/src/modules/hatsProtocol.ts b/pkgs/cli/src/modules/hatsProtocol.ts index d0988e1..8097cff 100644 --- a/pkgs/cli/src/modules/hatsProtocol.ts +++ b/pkgs/cli/src/modules/hatsProtocol.ts @@ -1,5 +1,16 @@ import { HatsSubgraphClient } from "@hatsprotocol/sdk-v1-subgraph"; +import { Address } from "viem"; import { base, optimism, sepolia } from "viem/chains"; +import { + hatsContractBaseConfig, + hatsTimeFrameContractBaseConfig, +} from "../config"; +import { publicClient, walletClient } from ".."; +import { hatIdToTreeId } from "@hatsprotocol/sdk-v1-core"; + +// ############################################################### +// Read with subgraph +// ############################################################### // Subgraph用のインスタンスを生成 export const hatsSubgraphClient = new HatsSubgraphClient({ @@ -22,9 +33,9 @@ export const hatsSubgraphClient = new HatsSubgraphClient({ /** * ツリー情報を取得するメソッド */ -export const getTreeInfo = async (treeId: number) => { +export const getTreeInfo = async (treeId: number, chainId: number) => { const tree = await hatsSubgraphClient.getTree({ - chainId: optimism.id, + chainId, treeId: treeId, props: { hats: { @@ -50,10 +61,10 @@ export const getTreeInfo = async (treeId: number) => { /** * 帽子の着用者のウォレットアドレスを一覧を取得するメソッド */ -export const getWearersInfo = async (hatId: string) => { +export const getWearersInfo = async (hatId: string, chainId: number) => { // get the first 10 wearers of a given hat const wearers = await hatsSubgraphClient.getWearersOfHatPaginated({ - chainId: optimism.id, + chainId, props: {}, hatId: BigInt(hatId), page: 0, @@ -66,10 +77,10 @@ export const getWearersInfo = async (hatId: string) => { /** * 特定のウォレットアドレスが着用している全てのHats情報を取得するメソッド */ -export const getWearerInfo = async (walletAddress: string) => { +export const getWearerInfo = async (walletAddress: string, chainId: number) => { // get the wearer of a given hat const wearer = await hatsSubgraphClient.getWearer({ - chainId: optimism.id, + chainId, wearerAddress: walletAddress as `0x${string}`, props: { currentHats: { @@ -92,3 +103,77 @@ export const getWearerInfo = async (walletAddress: string) => { return wearer; }; + +export const getHatsTimeframeModuleAddress = async ( + hatId: string, + chainId: number +) => { + const treeId = hatIdToTreeId(BigInt(hatId)); + const { hats } = await getTreeInfo(treeId, chainId); + const hatterHat = hats?.find((hat) => hat.levelAtLocalTree === 1); + if (!hatterHat) { + throw new Error("Hatter hat not found"); + } + + const wearers = await getWearersInfo(hatterHat.id, chainId); + + if (wearers.length === 0) { + throw new Error("No wearers found for hatter hat"); + } + + return wearers[0].id; +}; + +// ############################################################### +// Write with viem +// ############################################################### + +/** + * 新規Hat作成 + */ +export const createHat = async (args: { + parentHatId: bigint; + details?: string; + maxSupply?: number; + eligibility?: Address; + toggle?: Address; + mutable?: boolean; + imageURI: string; +}) => { + const { request } = await publicClient.simulateContract({ + ...hatsContractBaseConfig, + account: walletClient.account, + functionName: "createHat", + args: [ + args.parentHatId, + args.details || "", + args.maxSupply || 5, + args.eligibility || "0x0000000000000000000000000000000000004a75", + args.toggle || "0x0000000000000000000000000000000000004a75", + args.mutable || true, + args.imageURI, + ], + }); + const transactionHash = walletClient.writeContract(request); + + return transactionHash; +}; + +/** + * ロール付与 + */ +export const mintHat = async (args: { hatId: bigint; wearer: Address }) => { + const { request } = await publicClient.simulateContract({ + ...hatsTimeFrameContractBaseConfig, + address: await getHatsTimeframeModuleAddress( + args.hatId.toString(), + Number(publicClient.chain?.id) + ), + account: walletClient.account, + functionName: "mintHat", + args: [args.hatId, args.wearer], + }); + const transactionHash = await walletClient.writeContract(request); + + return transactionHash; +}; diff --git a/pkgs/cli/src/modules/viem.ts b/pkgs/cli/src/modules/viem.ts index 0f703c6..267747b 100644 --- a/pkgs/cli/src/modules/viem.ts +++ b/pkgs/cli/src/modules/viem.ts @@ -1,28 +1,85 @@ -import { createWalletClient, http, parseEther } from "viem"; +import { + Chain, + createPublicClient, + createWalletClient, + http, + parseEther, + PrivateKeyAccount, + WalletClient, +} from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { hardhat } from "viem/chains"; +import { hardhat, sepolia, holesky } from "viem/chains"; -/** - * ETHを送金するためのメソッド - * @param secretKey - * @param to - * @returns - */ -export const sendEth = async (secretKey: `0x${string}`, to: `0x${string}`) => { - const account = privateKeyToAccount(secretKey); +const chains = [hardhat, holesky, sepolia]; + +export const getChainById = (chainId: number | string): Chain => { + const numericChainId = Number(chainId); + + const chain = chains.find((c) => c.id === numericChainId); + + if (!chain) { + throw new Error(`Chain with id ${numericChainId} not found`); + } + + return chain; +}; + +export const getChainOrDefault = ( + chainId: number | string | undefined +): Chain => { + return chainId ? getChainById(chainId) : sepolia; +}; - const client = createWalletClient({ +export const getPublicClient = async (chainId?: number | undefined) => { + const chain = getChainOrDefault(chainId); + + const publicClient = createPublicClient({ + chain, + transport: http(), + }); + + return publicClient; +}; + +export const setWallet = async ( + account: PrivateKeyAccount, + chainId?: number | undefined +) => { + const chain = getChainOrDefault(chainId); + + const wallet = createWalletClient({ account, - chain: hardhat, + chain, transport: http(), }); - const hash = await client.sendTransaction({ + return wallet; +}; + +export const sendEth = async ( + wallet: WalletClient, + to: `0x${string}`, + amount: string +) => { + const account = wallet.account; + + if (!account) { + throw new Error("Client account is not defined"); + } + + const hash = await wallet.sendTransaction({ account, - to: to, - value: parseEther("0.001"), + to, + value: parseEther(amount), + chain: wallet.chain, }); + console.log(`Transaction sent: ${hash}`); + console.log(`From: ${account.address}`); + console.log(`To: ${to}`); + console.log(`Amount: ${amount} ETH`); + console.log(`Chain ID: ${wallet.chain?.id}`); + return hash; }; diff --git a/pkgs/cli/src/services/wallet.ts b/pkgs/cli/src/services/wallet.ts index 3ed470f..e5b0408 100644 --- a/pkgs/cli/src/services/wallet.ts +++ b/pkgs/cli/src/services/wallet.ts @@ -2,13 +2,15 @@ import { existsSync, readFileSync, writeFileSync } from "fs"; import path from "path"; import { Hex } from "viem"; import { privateKeyToAccount, privateKeyToAddress } from "viem/accounts"; -const profilesPath = path.join(__dirname, "profiles.json"); +import { setWallet } from "../modules/viem"; export interface Profile { name: string; privateKey: Hex; } +const profilesPath = path.join(__dirname, "profiles.json"); + export const getProfiles = () => { if (!existsSync(profilesPath)) { writeFileSync(profilesPath, JSON.stringify([])); @@ -17,15 +19,25 @@ export const getProfiles = () => { return JSON.parse(data) as Profile[]; }; -export const getWallet = (name?: string) => { +export const getAccount = (name?: string) => { const profiles = getProfiles(); const profile = profiles.find((p) => p.name === name) || profiles[0]; - if (!profile) throw "Profile not found."; + if (!profile) + throw "Profile not found. Please add a profile with wallet add command."; return privateKeyToAccount(profile.privateKey); }; +export const getWalletClient = ( + name?: string, + chainId?: number | undefined +) => { + const account = getAccount(name); + + return setWallet(account, chainId); +}; + export const saveProfile = (params: Profile) => { if (!params.privateKey.match(/^0x[0-9a-f]{64}$/)) { console.log("Invalid private key."); @@ -59,7 +71,7 @@ export const deleteProfile = (params: { name: string }) => { writeFileSync(profilesPath, JSON.stringify(profiles, null, 2)); console.log(`Profile "${params.name}" with private key has been deleted.`); -} +}; export const listProfiles = () => { const profiles = getProfiles(); diff --git a/pkgs/contract/scripts/createSplit.ts b/pkgs/contract/scripts/createSplit.ts new file mode 100644 index 0000000..86844d5 --- /dev/null +++ b/pkgs/contract/scripts/createSplit.ts @@ -0,0 +1,25 @@ +import { viem } from "hardhat"; + +const create = async () => { + const contract = await viem.getContractAt( + "SplitsCreator", + "0xf7f536b25d3f1aEb84E32A35ca8E48b6fd0597A7" + ); + + const res = await contract.write.create([ + [ + { + hatId: BigInt( + "0x0000023900010001000000000000000000000000000000000000000000000000" + ), + multiplierBottom: 1n, + multiplierTop: 1n, + wearers: ["0x777EE5eeEd30c3712bEE6C83260D786857d9C556"], + }, + ], + ]); + + console.log(res); +}; + +create(); diff --git a/yarn.lock b/yarn.lock index efa562f..5a4538a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5504,7 +5504,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5521,15 +5521,6 @@ string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -5615,7 +5606,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5629,13 +5620,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -6174,16 +6158,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==