This repository has been archived by the owner on Dec 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add key registration and removal functionality to PasskeyModule
- Loading branch information
1 parent
52e6e75
commit dc12f3b
Showing
2 changed files
with
134 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
// } | ||
// } |