Contract Name:
PeerToPlayFactory
Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title PeerToPlayFactory
* @dev Main Contract For PeerToPlay Smart Accounts. This is also a factory contract, which deploys new PeerToPlay Smart Accounts
* and serves as a registry for PeerToPlay Smart Accounts.
*/
/**
* @dev Interface for account functionality in PeerToPlay.
*/
interface AccountInterface {
/**
* @dev Returns the version of the account.
*/
function version() external view returns (uint);
/**
* @dev Enables an authority for the account.
* @param authority The address to be authorized.
*/
function enable(address authority) external;
/**
* @dev Executes multiple function calls within the account.
* @param _targets The target addresses to call.
* @param _datas The data (call data) for each target.
* @param _origin The origin address of the call.
* @return responses The responses from each call.
*/
function cast(
address[] calldata _targets,
bytes[] calldata _datas,
address _origin
) external payable returns (bytes32[] memory responses);
}
/**
* @dev Interface for list registry.
*/
interface ListInterface {
/**
* @dev Initializes the account in the list.
* @param _account The account address to initialize.
*/
function init(address _account) external;
}
/**
* @title AddressIndex
* @dev Contract to manage the master address, connectors, and account versions.
*/
contract AddressIndex {
event LogNewMaster(address indexed master);
event LogUpdateMaster(address indexed master);
event LogNewAccount(
address indexed _newAccount,
address indexed _connectors
);
// New master address.
address private newMaster;
// Current master address.
address public master;
// List registry address.
address public list;
// Connectors mapping for account versions.
mapping(uint => address) public connectors;
// Account modules mapping for versions.
mapping(uint => address) public account;
// Total version count of account modules.
uint public versionCount;
/**
* @dev Modifier to restrict function access to the master address.
*/
modifier isMaster() {
require(msg.sender == master, "not-master");
_;
}
/**
* @dev Initiates the master address change.
* @param _newMaster The new master address.
*/
function changeMaster(address _newMaster) external isMaster {
require(_newMaster != master, "already-a-master");
require(_newMaster != address(0), "not-valid-address");
require(newMaster != _newMaster, "already-a-new-master");
newMaster = _newMaster;
emit LogNewMaster(_newMaster);
}
/**
* @dev Finalizes the master address update.
*/
function updateMaster() external {
require(newMaster != address(0), "not-valid-address");
require(msg.sender == newMaster, "not-master");
master = newMaster;
newMaster = address(0);
emit LogUpdateMaster(master);
}
/**
* @dev Adds a new account module.
* @param _newAccount The new account module address.
* @param _connectors The connectors registry module address.
*/
function addNewAccount(
address _newAccount,
address _connectors
) external isMaster {
require(_newAccount != address(0), "not-valid-address");
versionCount++;
require(
AccountInterface(_newAccount).version() == versionCount,
"not-valid-version"
);
account[versionCount] = _newAccount;
if (_connectors != address(0)) connectors[versionCount] = _connectors;
emit LogNewAccount(_newAccount, _connectors);
}
}
/**
* @title CloneFactory
* @dev Contract to clone other contracts.
*/
contract CloneFactory is AddressIndex {
/**
* @dev Creates a new clone of the specified account version.
* @param version The account module version to clone.
* @return result The address of the created clone.
*/
function createClone(uint version) internal returns (address result) {
bytes20 targetBytes = bytes20(account[version]);
// solium-disable-next-line security/no-inline-assembly
assembly {
let clone := mload(0x40)
mstore(
clone,
0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
)
mstore(add(clone, 0x14), targetBytes)
mstore(
add(clone, 0x28),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
result := create(0, clone, 0x37)
}
}
/**
* @dev Checks if a specified address is a clone of a given account version.
* @param version The account module version.
* @param query The address to check.
* @return result Boolean indicating if the address is a clone.
*/
function isClone(
uint version,
address query
) external view returns (bool result) {
bytes20 targetBytes = bytes20(account[version]);
// solium-disable-next-line security/no-inline-assembly
assembly {
let clone := mload(0x40)
mstore(
clone,
0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
)
mstore(add(clone, 0xa), targetBytes)
mstore(
add(clone, 0x1e),
0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
)
let other := add(clone, 0x40)
extcodecopy(query, other, 0, 0x2d)
result := and(
eq(mload(clone), mload(other)),
eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
)
}
}
}
/**
* @title PeerToPlayFactory
* @dev Main contract for creating and managing PeerToPlay Smart Accounts.
*/
contract PeerToPlayFactory is CloneFactory {
event LogAccountCreated(
address sender,
address indexed owner,
address indexed account,
address indexed origin
);
/**
* @dev Creates a PeerToPlay Smart Account and performs a cast operation.
* @param _owner The owner of the PeerToPlay Smart Account.
* @param accountVersion The account module version.
* @param _targets Target addresses for the cast function.
* @param _datas Data (call data) for each target.
* @param _origin The origin of the account creation.
* @return _account The address of the created account.
*/
function buildWithCast(
address _owner,
uint accountVersion,
address[] calldata _targets,
bytes[] calldata _datas,
address _origin
) external payable returns (address _account) {
_account = build(_owner, accountVersion, _origin);
if (_targets.length > 0)
AccountInterface(_account).cast{value: msg.value}(
_targets,
_datas,
_origin
);
}
/**
* @dev Creates a PeerToPlay Smart Account.
* @param _owner The owner of the PeerToPlay Smart Account.
* @param accountVersion The account module version.
* @param _origin The origin of the account creation.
* @return _account The address of the created account.
*/
function build(
address _owner,
uint accountVersion,
address _origin
) public returns (address _account) {
require(
accountVersion != 0 && accountVersion <= versionCount,
"not-valid-account"
);
_account = createClone(accountVersion);
ListInterface(list).init(_account);
AccountInterface(_account).enable(_owner);
emit LogAccountCreated(msg.sender, _owner, _account, _origin);
}
/**
* @dev Sets up initial configuration for the PeerToPlayFactory contract.
* This function can only be called once.
* @param _master The master address.
* @param _list The list registry address.
* @param _account The initial account module address.
* @param _connectors The connectors registry module address.
*/
function setBasics(
address _master,
address _list,
address _account,
address _connectors
) external {
require(
master == address(0) &&
list == address(0) &&
account[1] == address(0) &&
connectors[1] == address(0) &&
versionCount == 0,
"already-defined"
);
master = _master;
list = _list;
versionCount++;
account[versionCount] = _account;
connectors[versionCount] = _connectors;
}
}