Skip to content

Commit

Permalink
Add wallet information
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelKim20 committed Jan 26, 2024
1 parent 6d1c5b0 commit 4418439
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 27 deletions.
21 changes: 18 additions & 3 deletions packages/contracts/contracts/IMultiSigWalletFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,32 @@ pragma solidity ^0.8.2;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface IMultiSigWalletFactory is IERC165 {
function create(address[] memory _owners, uint256 _required) external returns (address);
struct WalletInfo {
address creator;
address wallet;
string name;
string description;
uint256 time;
}
function create(
string calldata _name,
string calldata _description,
address[] memory _owners,
uint256 _required
) external returns (address);
function getNumberOfWalletsForCreator(address _creator) external view returns (uint256);
function getWalletsForCreator(
address _creator,
uint256 _from,
uint256 _to
) external view returns (address[] memory);
) external view returns (WalletInfo[] memory);
function getWalletInfo(address _wallet) external view returns (WalletInfo memory);
function changeName(address _wallet, string calldata _name) external;
function changeDescription(address _wallet, string calldata _description) external;

function addOwner(address _owner, address _wallet) external;
function removeOwner(address _owner, address _wallet) external;

function getNumberOfWalletsForOwner(address _owner) external view returns (uint256);
function getWalletsForOwner(address _owner, uint256 _from, uint256 _to) external view returns (address[] memory);
function getWalletsForOwner(address _owner, uint256 _from, uint256 _to) external view returns (WalletInfo[] memory);
}
2 changes: 1 addition & 1 deletion packages/contracts/contracts/MultiSigWallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ contract MultiSigWallet is ERC165, IMultiSigWallet {
// call has been separated into its own function in order to take advantage
// of the Solidity's code generator to produce a loop that copies tx.data into memory.
function external_call(address _destination, uint256 _value, bytes memory _data) internal returns (bool) {
(bool success, bytes memory data) = _destination.call{ value: _value }(_data);
(bool success, ) = _destination.call{ value: _value }(_data);
return success;
}

Expand Down
51 changes: 44 additions & 7 deletions packages/contracts/contracts/MultiSigWalletFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,36 @@ contract MultiSigWalletFactory is ERC165, IMultiSigWalletFactory {
*/
mapping(address => bool) internal hasWallets;
mapping(address => address[]) internal wallets;
mapping(address => WalletInfo) internal walletInfos;

/*
* Public functions
*/
/// @dev Allows verified creation of multi-signature wallet.
/// @param _name List of initial owners.
/// @param _description List of initial owners.
/// @param _owners List of initial owners.
/// @param _required Number of required confirmations.
/// @return wallet address.
function create(address[] memory _owners, uint256 _required) external override returns (address) {
function create(
string calldata _name,
string calldata _description,
address[] memory _owners,
uint256 _required
) external override returns (address) {
address wallet = address(new MultiSigWallet(address(this), _owners, _required));
for (uint256 idx = 0; idx < _owners.length; idx++) {
_addOwner(_owners[idx], wallet);
}
register(wallet);
WalletInfo memory walletInfo = WalletInfo({
creator: msg.sender,
wallet: wallet,
name: _name,
description: _description,
time: block.timestamp
});
walletInfos[wallet] = walletInfo;
return wallet;
}

Expand All @@ -59,14 +75,34 @@ contract MultiSigWalletFactory is ERC165, IMultiSigWalletFactory {
address _creator,
uint256 _from,
uint256 _to
) external view override returns (address[] memory) {
address[] memory values = new address[](_to - _from);
) external view override returns (WalletInfo[] memory) {
WalletInfo[] memory values = new WalletInfo[](_to - _from);
for (uint256 i = _from; i < _to; i++) {
values[i - _from] = wallets[_creator][i];
address wallet = wallets[_creator][i];
values[i - _from] = walletInfos[wallet];
}
return values;
}

/// @dev Returns information of the wallet
/// @param _wallet Address of wallet
/// @return information of wallet
function getWalletInfo(address _wallet) external view override returns (WalletInfo memory) {
return walletInfos[_wallet];
}

function changeName(address _wallet, string calldata _name) external override {
require(walletInfos[_wallet].creator == msg.sender, "Sender is not authorized to execute");

walletInfos[_wallet].name = _name;
}

function changeDescription(address _wallet, string calldata _description) external override {
require(walletInfos[_wallet].creator == msg.sender, "Sender is not authorized to execute");

walletInfos[_wallet].description = _description;
}

mapping(address => address[]) internal walletsForOwnerValues;
mapping(address => mapping(address => uint256)) internal walletsForOwnerIndexes;

Expand Down Expand Up @@ -98,10 +134,11 @@ contract MultiSigWalletFactory is ERC165, IMultiSigWalletFactory {
address _owner,
uint256 _from,
uint256 _to
) external view override returns (address[] memory) {
address[] memory values = new address[](_to - _from);
) external view override returns (WalletInfo[] memory) {
WalletInfo[] memory values = new WalletInfo[](_to - _from);
for (uint256 i = _from; i < _to; i++) {
values[i - _from] = walletsForOwnerValues[_owner][i];
address wallet = walletsForOwnerValues[_owner][i];
values[i - _from] = walletInfos[wallet];
}
return values;
}
Expand Down
6 changes: 5 additions & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
"lint": "tslint --config tslint.json \\\"{src,test}/**/*.ts\\\"",
"lint-fix": "tslint --fix --config tslint.json \\\"{src,test}/**/*.ts\\\"",
"formatting:check": "prettier '**/*.{json,sol,ts,js,md}' -c",
"formatting:write": "prettier '**/*.{json,sol,ts,js,md}' --write"
"formatting:write": "prettier '**/*.{json,sol,ts,js,md}' --write",
"test:ExecutionAfterRequirementsChanged": "hardhat test test/ExecutionAfterRequirementsChanged.test.ts",
"test:ExternalCalls": "hardhat test test/ExternalCalls.test.ts",
"test:Factory": "hardhat test test/Factory.test.ts",
"test:MultiSigToken": "hardhat test test/MultiSigToken.test.ts"
},
"repository": {
"type": "git",
Expand Down
110 changes: 97 additions & 13 deletions packages/contracts/test/Factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ async function deployMultiSigWalletFactory(deployer: Wallet): Promise<MultiSigWa
async function deployMultiSigWallet(
factoryAddress: string,
deployer: Wallet,
name: string,
description: string,
owners: string[],
required: number
): Promise<MultiSigWallet | undefined> {
const contractFactory = await ethers.getContractFactory("MultiSigWalletFactory");
const factoryContract = contractFactory.attach(factoryAddress);
const factoryContract = contractFactory.attach(factoryAddress) as MultiSigWalletFactory;

const address = await ContractUtils.getEventValueString(
await factoryContract.connect(deployer).create(owners, required),
await factoryContract.connect(deployer).create(name, description, owners, required),
factoryContract.interface,
"ContractInstantiation",
"wallet"
Expand All @@ -39,7 +41,6 @@ async function deployMultiSigWallet(
}

describe("Test for MultiSigWalletFactory", () => {
const provider = ethers.provider;
const raws = HardhatAccount.keys.map((m) => new Wallet(m, ethers.provider));
const [deployer, account0, account1, account2, account3, account4, account5, account6, account7] = raws;
const owners1 = [account0, account1, account2];
Expand All @@ -52,6 +53,25 @@ describe("Test for MultiSigWalletFactory", () => {
let multiSigWallet3: MultiSigWallet | undefined;
const requiredConfirmations = 2;

const walletInfos = [
{
name: "My Wallet 1",
description: "My first multi-sign wallet",
},
{
name: "My Wallet 2",
description: "My second multi-sign wallet",
},
{
name: "My Wallet 3",
description: "My third multi-sign wallet",
},
{
name: "Fund",
description: "Fund of develop",
},
];

before(async () => {
multiSigFactory = await deployMultiSigWalletFactory(deployer);
assert.ok(multiSigFactory);
Expand All @@ -61,6 +81,8 @@ describe("Test for MultiSigWalletFactory", () => {
multiSigWallet1 = await deployMultiSigWallet(
multiSigFactory.address,
deployer,
walletInfos[0].name,
walletInfos[0].description,
owners1.map((m) => m.address),
requiredConfirmations
);
Expand All @@ -72,6 +94,8 @@ describe("Test for MultiSigWalletFactory", () => {
multiSigWallet2 = await deployMultiSigWallet(
multiSigFactory.address,
deployer,
walletInfos[1].name,
walletInfos[1].description,
owners2.map((m) => m.address),
requiredConfirmations
);
Expand All @@ -83,17 +107,28 @@ describe("Test for MultiSigWalletFactory", () => {
multiSigWallet3 = await deployMultiSigWallet(
multiSigFactory.address,
deployer,
walletInfos[2].name,
walletInfos[2].description,
owners3.map((m) => m.address),
requiredConfirmations
);
assert.ok(multiSigWallet3);
assert.deepStrictEqual(await multiSigFactory.getNumberOfWalletsForOwner(account0.address), BigNumber.from(2));
assert.deepStrictEqual(await multiSigFactory.getNumberOfWalletsForOwner(account3.address), BigNumber.from(2));

assert.deepStrictEqual(await multiSigFactory.getWalletsForOwner(account0.address, 0, 2), [
multiSigWallet1.address,
multiSigWallet3.address,
]);
const res = await multiSigFactory.getWalletsForOwner(account0.address, 0, 2);
assert.deepStrictEqual(
res.map((m) => m.wallet),
[multiSigWallet1.address, multiSigWallet3.address]
);
assert.deepStrictEqual(
res.map((m) => m.name),
[walletInfos[0].name, walletInfos[2].name]
);
assert.deepStrictEqual(
res.map((m) => m.description),
[walletInfos[0].description, walletInfos[2].description]
);
});

it("Remove owner", async () => {
Expand Down Expand Up @@ -151,9 +186,19 @@ describe("Test for MultiSigWalletFactory", () => {
account6.address,
]);

assert.deepStrictEqual(await multiSigFactory.getWalletsForOwner(account6.address, 0, 1), [
multiSigWallet1.address,
]);
const res = await multiSigFactory.getWalletsForOwner(account6.address, 0, 1);
assert.deepStrictEqual(
res.map((m) => m.wallet),
[multiSigWallet1.address]
);
assert.deepStrictEqual(
res.map((m) => m.name),
[walletInfos[0].name]
);
assert.deepStrictEqual(
res.map((m) => m.description),
[walletInfos[0].description]
);
});

it("Replace owner", async () => {
Expand Down Expand Up @@ -188,8 +233,47 @@ describe("Test for MultiSigWalletFactory", () => {
account6.address,
]);

assert.deepStrictEqual(await multiSigFactory.getWalletsForOwner(account7.address, 0, 1), [
multiSigWallet1.address,
]);
const res = await multiSigFactory.getWalletsForOwner(account7.address, 0, 1);
assert.deepStrictEqual(
res.map((m) => m.wallet),
[multiSigWallet1.address]
);
assert.deepStrictEqual(
res.map((m) => m.name),
[walletInfos[0].name]
);
assert.deepStrictEqual(
res.map((m) => m.description),
[walletInfos[0].description]
);
});

it("getWalletInfo", async () => {
assert.ok(multiSigWallet1);

const res = await multiSigFactory.getWalletInfo(multiSigWallet1.address);
assert.deepStrictEqual(res.wallet, multiSigWallet1.address);
assert.deepStrictEqual(res.name, walletInfos[0].name);
assert.deepStrictEqual(res.description, walletInfos[0].description);
});

it("changeName", async () => {
assert.ok(multiSigWallet1);

await multiSigFactory.connect(deployer).changeName(multiSigWallet1.address, walletInfos[3].name);
const res = await multiSigFactory.getWalletInfo(multiSigWallet1.address);
assert.deepStrictEqual(res.wallet, multiSigWallet1.address);
assert.deepStrictEqual(res.name, walletInfos[3].name);
assert.deepStrictEqual(res.description, walletInfos[0].description);
});

it("changeDescription", async () => {
assert.ok(multiSigWallet1);

await multiSigFactory.connect(deployer).changeDescription(multiSigWallet1.address, walletInfos[3].description);
const res = await multiSigFactory.getWalletInfo(multiSigWallet1.address);
assert.deepStrictEqual(res.wallet, multiSigWallet1.address);
assert.deepStrictEqual(res.name, walletInfos[3].name);
assert.deepStrictEqual(res.description, walletInfos[3].description);
});
});
8 changes: 6 additions & 2 deletions packages/contracts/test/MultiSigToken.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ async function deployMultiSigWalletFactory(deployer: Wallet): Promise<MultiSigWa
async function deployMultiSigWallet(
factoryAddress: string,
deployer: Wallet,
name: string,
description: string,
owners: string[],
required: number
): Promise<MultiSigWallet | undefined> {
const contractFactory = await ethers.getContractFactory("MultiSigWalletFactory");
const factoryContract = contractFactory.attach(factoryAddress);
const factoryContract = contractFactory.attach(factoryAddress) as MultiSigWalletFactory;

const address = await ContractUtils.getEventValueString(
await factoryContract.connect(deployer).create(owners, required),
await factoryContract.connect(deployer).create(name, description, owners, required),
factoryContract.interface,
"ContractInstantiation",
"wallet"
Expand Down Expand Up @@ -67,6 +69,8 @@ describe("Test for MultiSigWalletFactory", () => {
multiSigWallet = await deployMultiSigWallet(
multiSigFactory.address,
deployer,
"My Wallet 1",
"My first multi-sign wallet",
owners1.map((m) => m.address),
requiredConfirmations
);
Expand Down

0 comments on commit 4418439

Please sign in to comment.