Skip to content

feat(contract): Feature/issue 374 role hat integration via Hat protocol instead of authority in module contract #378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/puml/class-v2.puml
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ BigBang --|> OwnableUpgradeable
BigBang --|> UUPSUpgradeable

HatsTimeFrameModule --|> HatsModule
HatsTimeFrameModule --|> OwnableUpgradeable
HatsTimeFrameModule --|> Upgradeable

HatsHatCreatorModule --|> HatsModule
HatsHatCreatorModule --|> OwnableUpgradeable
HatsHatCreatorModule --|> Upgradeable

FractionToken --|> ERC1155Upgradeable
FractionToken --|> ERC1155SupplyUpgradeable
Expand Down
72 changes: 65 additions & 7 deletions pkgs/contract/contracts/bigbang/BigBang.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {

ISplitsCreatorFactory public SplitsCreatorFactory;

uint32 private maxTobanSupply = 10;

address public HatsTimeFrameModule_IMPL;

address public HatsHatCreatorModule_IMPL;
Expand All @@ -29,6 +31,9 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {
address indexed owner,
uint256 indexed topHatId,
uint256 hatterHatId,
uint256 operatorTobanId,
uint256 creatorTobanId,
uint256 timeFrameTobanId,
address hatsTimeFrameModule,
address hatsHatCreatorModule,
address splitCreator
Expand Down Expand Up @@ -64,6 +69,39 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {
FractionToken = _fractionToken;
}

/**
* @notice Creates a role hat with the given top hat ID and role name.
* and returns the id of the created role hat.
* @param _parentHatId The ID of the top hat to create the role hat under.
* @param _roleName The name of the role for the new hat.
* @param _hatterHatImageURI The image URI for the new hat.
*/
function createToban(
uint256 _parentHatId,
string memory _roleName,
string calldata _hatterHatImageURI
) internal returns (uint256) {
require(
_parentHatId != 0,
"BigBang: Parent hat ID must be greater than zero"
);
require(
bytes(_roleName).length > 0,
"BigBang: Role name must not be empty"
);

uint256 roleHatId = Hats.createHat(
_parentHatId,
_roleName,
maxTobanSupply,
0x0000000000000000000000000000000000004A75,
0x0000000000000000000000000000000000004A75,
true,
_hatterHatImageURI
);
return roleHatId;
}

/**
* @dev
* @param _owner The address of the user who will own the topHat.
Expand Down Expand Up @@ -100,25 +138,42 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {
_hatterHatImageURI
);

// 3. HatsHatCreatorModuleのデプロイ
// 3. Create Fixed Roles under TopHat
uint256 operatorTobanId = createToban(
topHatId,
"OperatorToban",
_hatterHatImageURI
);
uint256 creatorTobanId = createToban(
operatorTobanId,
"HatCreatorToban",
_hatterHatImageURI
);
uint256 timeFrameTobanId = createToban(
operatorTobanId,
"TimeFrameToban",
_hatterHatImageURI
);

// 4. HatsHatCreatorModuleのデプロイ
address hatsHatCreatorModule = HatsModuleFactory.createHatsModule(
HatsHatCreatorModule_IMPL,
topHatId,
"",
abi.encode(_owner), // ownerを初期化データとして渡す
abi.encode(creatorTobanId), // ownerを初期化データとして渡す
0
);

// 4. HatsTimeFrameModuleのデプロイ
// 5. HatsTimeFrameModuleのデプロイ
address hatsTimeFrameModule = HatsModuleFactory.createHatsModule(
HatsTimeFrameModule_IMPL,
topHatId,
"",
abi.encode(_owner), // ownerを初期化データとして渡す
abi.encode(timeFrameTobanId), // ownerを初期化データとして渡す
0
);

// 5. HatterHatにHatModuleをMint
// 6. HatterHatにHatModuleをMint
uint256[] memory hatIds = new uint256[](2);
hatIds[0] = hatterHatId;
hatIds[1] = hatterHatId;
Expand All @@ -129,10 +184,10 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {

Hats.batchMintHats(hatIds, modules);

// 6. TopHatIdの権限を_ownerに譲渡
// 7. TopHatIdの権限を_ownerに譲渡
Hats.transferHat(topHatId, address(this), _owner);

// 7. SplitCreatorをFactoryからデプロイ
// 8. SplitCreatorをFactoryからデプロイ
address splitCreator = SplitsCreatorFactory
.createSplitCreatorDeterministic(
topHatId,
Expand All @@ -148,6 +203,9 @@ contract BigBang is OwnableUpgradeable, UUPSUpgradeable {
_owner,
topHatId,
hatterHatId,
operatorTobanId,
creatorTobanId,
timeFrameTobanId,
hatsTimeFrameModule,
hatsHatCreatorModule,
splitCreator
Expand Down
64 changes: 58 additions & 6 deletions pkgs/contract/contracts/bigbang/mock/BigBang_Mock_v2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ contract BigBang_Mock_v2 is OwnableUpgradeable, UUPSUpgradeable {

ISplitsCreatorFactory public SplitsCreatorFactory;

uint32 private maxTobanSupply = 10;

address public HatsTimeFrameModule_IMPL;

address public HatsHatCreatorModule_IMPL;
Expand Down Expand Up @@ -64,6 +66,39 @@ contract BigBang_Mock_v2 is OwnableUpgradeable, UUPSUpgradeable {
FractionToken = _fractionToken;
}

/**
* @notice Creates a role hat with the given top hat ID and role name.
* and returns the id of the created role hat.
* @param _parentHatId The ID of the top hat to create the role hat under.
* @param _roleName The name of the role for the new hat.
* @param _hatterHatImageURI The image URI for the new hat.
*/
function createToban(
uint256 _parentHatId,
string memory _roleName,
string calldata _hatterHatImageURI
) internal returns (uint256) {
require(
_parentHatId != 0,
"BigBang: Parent hat ID must be greater than zero"
);
require(
bytes(_roleName).length > 0,
"BigBang: Role name must not be empty"
);

uint256 roleHatId = Hats.createHat(
_parentHatId,
_roleName,
maxTobanSupply,
0x0000000000000000000000000000000000004A75,
0x0000000000000000000000000000000000004A75,
true,
_hatterHatImageURI
);
return roleHatId;
}

/**
* @dev
* @param _owner The address of the user who will own the topHat.
Expand Down Expand Up @@ -100,25 +135,42 @@ contract BigBang_Mock_v2 is OwnableUpgradeable, UUPSUpgradeable {
_hatterHatImageURI
);

// 3. HatsHatCreatorModuleのデプロイ
// 3. Create Fixed Roles under TopHat
uint256 operatorTobanId = createToban(
topHatId,
"OperatorToban",
_hatterHatImageURI
);
uint256 creatorTobanId = createToban(
operatorTobanId,
"HatCreatorToban",
_hatterHatImageURI
);
uint256 timeFrameTobanId = createToban(
operatorTobanId,
"TimeFrameToban",
_hatterHatImageURI
);

// 4. HatsHatCreatorModuleのデプロイ
address hatsHatCreatorModule = HatsModuleFactory.createHatsModule(
HatsHatCreatorModule_IMPL,
topHatId,
"",
abi.encode(_owner), // ownerを初期化データとして渡す
abi.encode(creatorTobanId), // ownerを初期化データとして渡す
0
);

// 4. HatsTimeFrameModuleのデプロイ
// 5. HatsTimeFrameModuleのデプロイ
address hatsTimeFrameModule = HatsModuleFactory.createHatsModule(
HatsTimeFrameModule_IMPL,
topHatId,
"",
abi.encode(_owner),
abi.encode(timeFrameTobanId),
0
);

// 5. HatterHatにHatModuleをMint
// 6. HatterHatにHatModuleをMint
uint256[] memory hatIds = new uint256[](2);
hatIds[0] = hatterHatId;
hatIds[1] = hatterHatId;
Expand All @@ -132,7 +184,7 @@ contract BigBang_Mock_v2 is OwnableUpgradeable, UUPSUpgradeable {
// 6. TopHatIdの権限を_ownerに譲渡
Hats.transferHat(topHatId, address(this), _owner);

// 7. SplitCreatorをFactoryからデプロイ
// 8. SplitCreatorをFactoryからデプロイ
address splitCreator = SplitsCreatorFactory
.createSplitCreatorDeterministic(
topHatId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,47 @@ pragma solidity ^0.8.24;

import {IHatsHatCreatorModule} from "./IHatsHatCreatorModule.sol";
import {HatsModule} from "../../hats/module/HatsModule.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract HatsHatCreatorModule is HatsModule, Ownable, IHatsHatCreatorModule {
/// @dev Mapping to track addresses with hat creation authority
mapping(address => bool) public createHatAuthorities;
contract HatsHatCreatorModule is HatsModule, IHatsHatCreatorModule {
uint256 private creatorTobanId;

/**
* @dev Constructor to initialize the contract
* @param _version The version of the contract
* @param _tmpOwner The owner of the contract
*/
constructor(
string memory _version,
address _tmpOwner
) HatsModule(_version) Ownable(_tmpOwner) {}
constructor(string memory _version) HatsModule(_version) {}

/**
* @dev Initializes the contract, setting up the owner
* @param _initData The initialization data (encoded owner address)
* @dev Initializes the contract, hold creator toban ID
* @param _initData The initialization data (encoded creator toban ID)
*/
function _setUp(bytes calldata _initData) internal override {
address _owner = abi.decode(_initData, (address));
_grantCreateHatAuthority(_owner);
_transferOwnership(_owner);
uint256 _creatorTobanId = abi.decode(_initData, (uint256));
creatorTobanId = _creatorTobanId;
}

/**
* @notice Checks if an address has hat creation authority
* @notice Checks if an address is authorized to create hats
* @param authority The address to check
* @return bool Whether the address has authority
* @return bool Whether the address is authorized
*/
function hasCreateHatAuthority(
function _authorizedToCreateHat(
address authority
) public view returns (bool) {
return createHatAuthorities[authority];
}

/**
* @notice Grants hat creation authority to an address
* @param authority The address to grant authority to
*/
function grantCreateHatAuthority(address authority) external onlyOwner {
_grantCreateHatAuthority(authority);
) internal view returns (bool) {
return
HATS().isAdminOfHat(authority, creatorTobanId) ||
HATS().isWearerOfHat(authority, creatorTobanId);
}

/**
* @notice Revokes hat creation authority from an address
* @param authority The address to revoke authority from
* @notice Checks if an address has hat creation authority
* @param authority The address to check
* @return bool Whether the address has authority
*/
function revokeCreateHatAuthority(address authority) external onlyOwner {
_revokeCreateHatAuthority(authority);
function hasCreateHatAuthority(
address authority
) public view returns (bool) {
return _authorizedToCreateHat(authority);
}

/**
Expand Down Expand Up @@ -134,29 +124,4 @@ contract HatsHatCreatorModule is HatsModule, Ownable, IHatsHatCreatorModule {
HATS().changeHatMaxSupply(hatId, newMaxSupply);
emit HatMaxSupplyChanged(hatId, newMaxSupply);
}

// Internal Functions

/**
* @dev Grants hat creation authority to an address
* @param authority The address to grant authority to
*/
function _grantCreateHatAuthority(address authority) internal {
require(authority != address(0), "Invalid address");
require(!hasCreateHatAuthority(authority), "Already granted");

createHatAuthorities[authority] = true;
emit CreateHatAuthorityGranted(authority);
}

/**
* @dev Revokes hat creation authority from an address
* @param authority The address to revoke authority from
*/
function _revokeCreateHatAuthority(address authority) internal {
require(hasCreateHatAuthority(authority), "Not granted");

createHatAuthorities[authority] = false;
emit CreateHatAuthorityRevoked(authority);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@
pragma solidity ^0.8.24;

interface IHatsHatCreatorModule {
/**
* @notice Grants hat creation authority to an address
* @param authority The address to grant authority to
*/
function grantCreateHatAuthority(address authority) external;

/**
* @notice Revokes hat creation authority from an address
* @param authority The address to revoke authority from
*/
function revokeCreateHatAuthority(address authority) external;

/**
* @notice Checks if an address has hat creation authority
* @param authority The address to check
Expand Down
Loading
Loading