From 61631c322dd3fa7b753c15a6c86011e828ae4ba4 Mon Sep 17 00:00:00 2001 From: ross <92001561+z0r0z@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:18:27 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=AA=A1=20Multitoken=20Summoner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 8 +++++--- src/Summoner.sol | 26 ++++++++++++++------------ test/Summoner.t.sol | 34 ++++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index fd0d533..55f2e67 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -37,6 +37,8 @@ DagonTest:testSpoofSignatures(bytes) (runs: 256, μ: 16508, ~: 16437) DagonTest:testTransfer(address,address,uint88) (runs: 256, μ: 176031, ~: 176809) DagonTest:testTransferWithAuth(address,address,uint96) (runs: 256, μ: 179160, ~: 180278) DagonTest:testUserVoted() (gas: 194822) -SummonerTest:testSummoning(bytes12) (runs: 256, μ: 193633, ~: 193633) -SummonerTest:testSummoningForERC20(bytes12) (runs: 256, μ: 151767, ~: 151767) -SummonerTest:testSummoningForNFT(bytes12) (runs: 256, μ: 151789, ~: 151789) \ No newline at end of file +SummonerTest:testSummoning(bytes12) (runs: 256, μ: 192574, ~: 192574) +SummonerTest:testSummoningForERC1155(bytes12) (runs: 256, μ: 149821, ~: 149821) +SummonerTest:testSummoningForERC20(bytes12) (runs: 256, μ: 151708, ~: 151708) +SummonerTest:testSummoningForERC6909(bytes12) (runs: 256, μ: 149953, ~: 149953) +SummonerTest:testSummoningForERC721(bytes12) (runs: 256, μ: 151654, ~: 151654) \ No newline at end of file diff --git a/src/Summoner.sol b/src/Summoner.sol index 8aa3744..bbc0213 100644 --- a/src/Summoner.sol +++ b/src/Summoner.sol @@ -4,11 +4,14 @@ pragma solidity ^0.8.23; /// @notice Simple summoner for Dagon (𒀭) group accounts. /// @custom:version 0.0.0 contract Summoner { - // Constants: address internal constant DAGON = 0x0000000000001D4B1320bB3c47380a3D1C3A1A0C; IAccounts internal constant FACTORY = IAccounts(0x000000000000dD366cc2E4432bB998e41DFD47C7); - // Tokens: + struct Ownership { + address owner; + uint96 shares; + } + enum Standard { DAGON, ERC20, @@ -17,25 +20,24 @@ contract Summoner { ERC6909 } - // Dagon-native: - function summon(address summoner, uint88 shares, bool locked, bytes12 salt) public payable returns (IAccounts account) { - account = IAccounts(FACTORY.createAccount(address(this), bytes32(abi.encodePacked(address(this), salt)))); - account.execute(DAGON, 0, abi.encodeWithSignature("mint(address,uint96)", summoner, uint96(shares))); + function summon(Ownership[] calldata summoners, uint88 threshold, bool locked, bytes12 salt) public payable returns (IAccounts account) { + account = IAccounts(FACTORY.createAccount{value: msg.value}(address(this), bytes32(abi.encodePacked(this, salt)))); + for (uint256 i; i != summoners.length; ++i) + account.execute(DAGON, 0, abi.encodeWithSignature("mint(address,uint96)", summoners[i].owner, summoners[i].shares)); if (locked) account.execute(DAGON, 0, abi.encodeWithSignature("setAuth(address)", address(0xdead))); - account.execute(DAGON, 0, abi.encodeWithSignature("setThreshold(uint88)", shares)); + account.execute(DAGON, 0, abi.encodeWithSignature("setThreshold(uint88)", threshold)); account.execute(address(account), 0, abi.encodeWithSignature("transferOwnership(address)", DAGON)); } - // External token: - function summonForToken(address token, bool nft, uint88 threshold, bytes12 salt) public payable returns (IAccounts account) { - account = IAccounts(FACTORY.createAccount(address(this), bytes32(abi.encodePacked(address(this), salt)))); - account.execute(DAGON, 0,abi.encodeWithSignature("setToken(address,uint8)", token, nft ? Standard.ERC721 : Standard.ERC20)); + function summonForToken(address token, Standard standard, uint88 threshold, bytes12 salt) public payable returns (IAccounts account) { + account = IAccounts(FACTORY.createAccount{value: msg.value}(address(this), bytes32(abi.encodePacked(this, salt)))); + account.execute(DAGON, 0, abi.encodeWithSignature("setToken(address,uint8)", token, standard)); account.execute(DAGON, 0, abi.encodeWithSignature("setThreshold(uint88)", threshold)); account.execute(address(account), 0, abi.encodeWithSignature("transferOwnership(address)", DAGON)); } } -/// @dev Simple interface for Nani (𒀭) user account creation. +/// @dev Simple interface for Nani (𒀭) user account creation and setup. interface IAccounts { function createAccount(address, bytes32) external payable returns (address); function execute(address, uint256, bytes calldata) external payable returns (bytes memory); diff --git a/test/Summoner.t.sol b/test/Summoner.t.sol index 84e6693..162d252 100644 --- a/test/Summoner.t.sol +++ b/test/Summoner.t.sol @@ -8,6 +8,19 @@ import "@solady/test/utils/mocks/MockERC721.sol"; import {IAuth, Dagon} from "../src/Dagon.sol"; import {IAccounts, Summoner} from "../src/Summoner.sol"; +struct Ownership { + address owner; + uint96 shares; +} + +enum Standard { + DAGON, + ERC20, + ERC721, + ERC1155, + ERC6909 +} + contract SummonerTest is Test { Dagon internal constant DAGON = Dagon(0x0000000000001D4B1320bB3c47380a3D1C3A1A0C); address internal constant FACTORY = 0x000000000000dD366cc2E4432bB998e41DFD47C7; @@ -22,16 +35,25 @@ contract SummonerTest is Test { } function testSummoning(bytes12 salt) public payable { - IAccounts account = summoner.summon(address(this), 1 ether, false, salt); - assertEq(DAGON.totalSupply(uint256(uint160(address(account)))), 1 ether); - assertEq(DAGON.balanceOf(address(this), uint256(uint160(address(account)))), 1 ether); + Summoner.Ownership[] memory summoners = new Summoner.Ownership[](1); + summoners[0].owner = address(1); + summoners[0].shares = 1 ether; + summoner.summon(summoners, 1 ether, false, salt); } function testSummoningForERC20(bytes12 salt) public payable { - summoner.summonForToken(TOKEN, false, 1 ether, salt); + summoner.summonForToken(TOKEN, Summoner.Standard.ERC20, 1 ether, salt); + } + + function testSummoningForERC721(bytes12 salt) public payable { + summoner.summonForToken(NFT, Summoner.Standard.ERC721, 999, salt); + } + + function testSummoningForERC1155(bytes12 salt) public payable { + summoner.summonForToken(address(1), Summoner.Standard.ERC1155, 999, salt); } - function testSummoningForNFT(bytes12 salt) public payable { - summoner.summonForToken(NFT, true, 999, salt); + function testSummoningForERC6909(bytes12 salt) public payable { + summoner.summonForToken(address(1), Summoner.Standard.ERC6909, 999, salt); } }