Skip to content
This repository has been archived by the owner on Dec 26, 2024. It is now read-only.

Commit

Permalink
feat: Add key registration and removal functionality to PasskeyModule
Browse files Browse the repository at this point in the history
  • Loading branch information
imduchuyyy committed Jul 25, 2024
1 parent 52e6e75 commit dc12f3b
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 122 deletions.
3 changes: 3 additions & 0 deletions src/modules/Passkey.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ contract PasskeyModule is IModule {
event PasskeyRemoved(address indexed user, bytes32 indexed keyId);

function registerPublicKey(bytes32 keyId, uint256 x, uint256 y) external {
require(_wallets[keyId] == address(0), "PasskeyModule: keyId already registered");

_publicKeys[msg.sender][keyId] = PublicKey(x, y);
_wallets[keyId] = msg.sender;

emit PasskeyRegistered(msg.sender, keyId, x, y);
}

function removePublicKey(bytes32 keyId) external {
require(_wallets[keyId] == msg.sender, "PasskeyModule: Unauthorized");
delete _publicKeys[msg.sender][keyId];
delete _wallets[keyId];

Expand Down
253 changes: 131 additions & 122 deletions src/modules/Recovery.sol
Original file line number Diff line number Diff line change
@@ -1,155 +1,164 @@
// SPDX-License-Identifier: Apache
pragma solidity ^0.8.0;

import "../interfaces/IModule.sol";
import "../interfaces/IWallet.sol";

contract RecoveryModule is IModule {
uint256 internal constant SIG_VALIDATION_FAILED = 1;

struct WalletConfig {
uint256 threshold;
uint256 minPowerToOpenTicket;
uint256 delayTime;
}

enum TicketStatus {
Initial,
Pass
}

struct Ticket {
bool isCreated;
TicketStatus status;
uint256 totalVote;
uint256 startBlock;
address newKey;
}
// import "../interfaces/IModule.sol";
// import "../interfaces/IWallet.sol";

// contract RecoveryModuleFactory {
// event CreateRecoveryModule(address wallet, address module);
// function create() external returns (address) {
// RecoveryModule module = new RecoveryModule();
// module.init(msg.sender);
// return address(module);
// }
// }

// contract RecoveryModule is IModule {
// uint256 internal constant SIG_VALIDATION_FAILED = 1;

// struct WalletConfig {
// uint256 threshold;
// uint256 minPowerToOpenTicket;
// uint256 delayTime;
// }

// enum TicketStatus {
// Initial,
// Pass
// }

// struct Ticket {
// bool isCreated;
// TicketStatus status;
// uint256 totalVote;
// uint256 startBlock;
// address newKey;
// }

mapping(address => WalletConfig) private _configs;

mapping(address => mapping(address => uint256)) private _guardianPowers;
mapping(address => uint256) private _currentTicketNum;
mapping(address => mapping(uint256 => mapping(uint256 => Ticket))) private _tickets; // wallet => currentTicketNum => version => ticket
mapping(address => mapping(address => mapping(uint256 => bool))) private _isGuardianVoted;
// mapping(address => WalletConfig) private _configs;

// mapping(address => mapping(address => uint256)) private _guardianPowers;
// mapping(address => uint256) private _currentTicketNum;
// mapping(address => mapping(uint256 => mapping(uint256 => Ticket))) private _tickets; // wallet => currentTicketNum => version => ticket
// mapping(address => mapping(address => mapping(uint256 => bool))) private _isGuardianVoted;

event SetWalletConfig(address wallet, WalletConfig config);
event TicketOpened(address wallet, uint256 ticketNum, uint256 version, address creator, Ticket ticket);
event TicketClosed(address wallet, uint256 ticketNum);
event TicketVoted(address wallet, uint256 tickedNum, address voter);
event SetGuardianVotePower(address wallet, address guardian, uint256 votePower);
// event SetWalletConfig(address wallet, WalletConfig config);
// event TicketOpened(address wallet, uint256 ticketNum, uint256 version, address creator, Ticket ticket);
// event TicketClosed(address wallet, uint256 ticketNum);
// event TicketVoted(address wallet, uint256 tickedNum, address voter);
// event SetGuardianVotePower(address wallet, address guardian, uint256 votePower);

function _decodeTicketNum(bytes calldata signature) internal view returns (uint256) {
address module = address(bytes20(signature[:20]));
require(module == address(this), "Invalid module");
// function _decodeTicketNum(bytes calldata signature) internal view returns (uint256) {
// address module = address(bytes20(signature[:20]));
// require(module == address(this), "Invalid module");

bytes memory ticketNumEncoded = signature[20:];
uint256 ticketNum = abi.decode(ticketNumEncoded, (uint256));
return ticketNum;
}
// bytes memory ticketNumEncoded = signature[20:];
// uint256 ticketNum = abi.decode(ticketNumEncoded, (uint256));
// return ticketNum;
// }

function setWalletConfig(WalletConfig memory config) external {
_configs[msg.sender] = config;
// function setWalletConfig(WalletConfig memory config) external {
// _configs[msg.sender] = config;

emit SetWalletConfig(msg.sender, config);
}
// emit SetWalletConfig(msg.sender, config);
// }

function setGuardian(address guardian, uint256 votePower) external {
_guardianPowers[msg.sender][guardian] = votePower;
// function setGuardian(address guardian, uint256 votePower) external {
// _guardianPowers[msg.sender][guardian] = votePower;

emit SetGuardianVotePower(msg.sender, guardian, votePower);
}
// emit SetGuardianVotePower(msg.sender, guardian, votePower);
// }

function openTicket(address wallet, uint256 version, address newKey) external {
uint256 guardianPower = _guardianPowers[wallet][msg.sender];
require(guardianPower >= _configs[wallet].minPowerToOpenTicket, "Insufficient power");
require(!_tickets[wallet][_currentTicketNum[wallet]].isCreated, "Ticket is created");
// function openTicket(address wallet, uint256 version, address newKey) external {
// uint256 guardianPower = _guardianPowers[wallet][msg.sender];
// require(guardianPower >= _configs[wallet].minPowerToOpenTicket, "Insufficient power");
// require(!_tickets[wallet][_currentTicketNum[wallet]].isCreated, "Ticket is created");

uint256 currentTicketNum = _currentTicketNum[wallet];
require(!_tickets[wallet][currentTicketNum].isCreated, "Ticket is created");
// uint256 currentTicketNum = _currentTicketNum[wallet];
// require(!_tickets[wallet][currentTicketNum].isCreated, "Ticket is created");

Ticket storage ticket = _tickets[wallet][ticketNum][version];
require(ticket.totalVote == 0, "Ticket exited");
require(newKey != address(0), "Invalid new key");
// Ticket storage ticket = _tickets[wallet][ticketNum][version];
// require(ticket.totalVote == 0, "Ticket exited");
// require(newKey != address(0), "Invalid new key");

ticket.isCreated = true;
ticket.status = TicketStatus.Initial;
ticket.totalVote = 1;
ticket.startBlock = 0;
ticket.newKey = newKey;
// ticket.isCreated = true;
// ticket.status = TicketStatus.Initial;
// ticket.totalVote = 1;
// ticket.startBlock = 0;
// ticket.newKey = newKey;

_votedGuardians[ticketNum][msg.sender] = true;
// _votedGuardians[ticketNum][msg.sender] = true;

emit TicketOpened(wallet, ticketNum, version, msg.sender, ticket);
}
// emit TicketOpened(wallet, ticketNum, version, msg.sender, ticket);
// }

function closeTicket(address wallet) external {
if (wallet != msg.sender) {
require(_guardianPowers[wallet][msg.sender] >= _configs[wallet].minPowerToOpenTicket, "Insufficient power");
}
uint256 currentTicketNum = _currentTicketNum[wallet];
delete _tickets[wallet][_currentTicketNum[wallet]];
_currentTicketNum[wallet]++;
// function closeTicket(address wallet) external {
// if (wallet != msg.sender) {
// require(_guardianPowers[wallet][msg.sender] >= _configs[wallet].minPowerToOpenTicket, "Insufficient power");
// }
// uint256 currentTicketNum = _currentTicketNum[wallet];
// delete _tickets[wallet][_currentTicketNum[wallet]];
// _currentTicketNum[wallet]++;

emit TicketClosed(wallet, currentTicketNum);
}
// emit TicketClosed(wallet, currentTicketNum);
// }

function voteTicket(address wallet) external {
uint256 currentTicketNum = _currentTicketNum[wallet];
// function voteTicket(address wallet) external {
// uint256 currentTicketNum = _currentTicketNum[wallet];

Ticket storage ticket = _tickets[wallet][currentTicketNum];
require(ticket.isCreated, "Ticket not found");
require(ticket.status == TicketStatus.Initial, "Ticket not found");
require(ticket.newKey != address(0), "Invalid new key");
// Ticket storage ticket = _tickets[wallet][currentTicketNum];
// require(ticket.isCreated, "Ticket not found");
// require(ticket.status == TicketStatus.Initial, "Ticket not found");
// require(ticket.newKey != address(0), "Invalid new key");

uint256 votePower = _guardianPowers[wallet][msg.sender];
require(votePower > 0, "Invalid vote power");
// uint256 votePower = _guardianPowers[wallet][msg.sender];
// require(votePower > 0, "Invalid vote power");

require(!_votedGuardians[wallet][ticketNum][msg.sender], "Voted");
// require(!_votedGuardians[wallet][ticketNum][msg.sender], "Voted");

ticket.totalVote += votePower;
_votedGuardians[wallet][ticketNum][msg.sender] = true;
// ticket.totalVote += votePower;
// _votedGuardians[wallet][ticketNum][msg.sender] = true;

if (ticket.totalVote >= _config.threshold) {
ticket.status = TicketStatus.Pass;
ticket.startBlock = block.number;
}
// if (ticket.totalVote >= _config.threshold) {
// ticket.status = TicketStatus.Pass;
// ticket.startBlock = block.number;
// }

emit TicketVoted(ticketNum, msg.sender);
}
// emit TicketVoted(ticketNum, msg.sender);
// }

function validateUserOp(UserOperation calldata userOp, bytes32)
external
view
override
returns (uint256 validationData)
{
uint256 ticketNum = _decodeTicketNum(userOp.signature);
Ticket memory ticket = _tickets[ticketNum];
require(ticket.status == TicketStatus.Pass, "Ticket doesn't pass");
require(ticket.startBlock + _config.delayTime > block.number, "Ticket not start yet");

bytes memory expectCallData = abi.encodeWithSelector(IWallet.addKey.selector, ticket.newKey, true);
// function validateUserOp(UserOperation calldata userOp, bytes32)
// external
// view
// override
// returns (uint256 validationData)
// {
// uint256 ticketNum = _decodeTicketNum(userOp.signature);
// Ticket memory ticket = _tickets[ticketNum];
// require(ticket.status == TicketStatus.Pass, "Ticket doesn't pass");
// require(ticket.startBlock + _config.delayTime > block.number, "Ticket not start yet");

// bytes memory expectCallData = abi.encodeWithSelector(IWallet.addKey.selector, ticket.newKey, true);

require(keccak256(expectCallData) == keccak256(userOp.callData), "Invalid call data");
// require(keccak256(expectCallData) == keccak256(userOp.callData), "Invalid call data");

return 0;
}
// return 0;
// }

function callback(UserOperation calldata userOp, bytes32) external override onlyWallet {
uint256 ticketNum = _decodeTicketNum(userOp.signature);
delete _tickets[ticketNum];
}
// function callback(UserOperation calldata userOp, bytes32) external override onlyWallet {
// uint256 ticketNum = _decodeTicketNum(userOp.signature);
// delete _tickets[ticketNum];
// }

function isGuardian(address guardian) external view returns (bool) {
return _isGuardians[guardian];
}
// function isGuardian(address guardian) external view returns (bool) {
// return _isGuardians[guardian];
// }

function getTicket(uint256 ticketNum) external view returns (Ticket memory) {
return _tickets[ticketNum];
}
// function getTicket(uint256 ticketNum) external view returns (Ticket memory) {
// return _tickets[ticketNum];
// }

function isValidSignature(bytes32, bytes calldata) public view override onlyWallet returns (bytes4 magicValue) {
return 0x0000;
}
}
// function isValidSignature(bytes32, bytes calldata) public view override onlyWallet returns (bytes4 magicValue) {
// return 0x0000;
// }
// }

0 comments on commit dc12f3b

Please sign in to comment.