-
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.
- Loading branch information
1 parent
5011c0e
commit fc416de
Showing
11 changed files
with
673 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
import {SignatureRSV, EthereumUtils} from "@oasisprotocol/sapphire-contracts/contracts/EthereumUtils.sol"; | ||
import {Sapphire} from "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol"; | ||
import {EIP155Signer} from "@oasisprotocol/sapphire-contracts/contracts/EIP155Signer.sol"; | ||
import {AccountBase, AccountFactoryBase} from "./AccountBase.sol"; | ||
|
||
|
||
// A contract to create per-identity account. | ||
contract AccountFactory is AccountFactoryBase { | ||
event AccountCreated(address contractAddress); | ||
|
||
function clone (address starterOwner) | ||
public virtual override | ||
returns (AccountBase acct) { | ||
AccountBase acc = new Account(starterOwner); | ||
emit AccountCreated(address(acc)); | ||
return acc; | ||
} | ||
} | ||
|
||
// A base class for a per-identity account. | ||
// It can be extended to include additional data, for example a symmetric | ||
// key for encrypting and decryption off-chain data. | ||
contract Account is AccountBase { | ||
address private controller; | ||
bytes32 private privateKey; | ||
uint64 nonce; | ||
|
||
constructor(address starterOwner) { | ||
controller = starterOwner; | ||
// Generate the private / public keypair | ||
bytes memory pubKey; | ||
bytes memory privKey; | ||
(pubKey, privKey) = Sapphire.generateSigningKeyPair(Sapphire.SigningAlg.Secp256k1PrehashedKeccak256, Sapphire.randomBytes(32, "")); | ||
publicKey = EthereumUtils.k256PubkeyToEthereumAddress(pubKey); | ||
privateKey = bytes32(privKey); | ||
nonce = 0; | ||
} | ||
|
||
// Update the controller of this account. Useful when a different | ||
// type of credential is to be used and a validator contract is needed. | ||
function updateController(address _controller) external override authorized { | ||
// I'm not sure if this is the correct way to do access control | ||
require(hasPermission(msg.sender), "Message sender doesn't have permission to access this account"); | ||
controller = _controller; | ||
} | ||
|
||
// Functions to check and update permissions. | ||
function hasPermission(address grantee) public view override | ||
returns (bool) { | ||
// Check that there's an entry for the grantee and that the expiration is greater than the current timestamp | ||
return (grantee == controller || (permission[grantee] != 0 && permission[grantee] >= block.timestamp)); | ||
} | ||
|
||
modifier authorized { | ||
require(hasPermission(msg.sender) || msg.sender == address(this), | ||
"Message sender doesn't have permission to access this account"); | ||
_; | ||
} | ||
|
||
function grantPermission(address grantee, uint256 expiry) public virtual override authorized { | ||
permission[grantee] = expiry; | ||
} | ||
|
||
function revokePermission(address grantee) public virtual override authorized { | ||
permission[grantee] = 0; | ||
} | ||
|
||
// The remaining functions use the key pair for normal contract operations. | ||
function signEIP155(EIP155Signer.EthTx calldata txToSign) | ||
public view override authorized | ||
returns (bytes memory) { | ||
return EIP155Signer.sign(publicKey, privateKey, txToSign); | ||
} | ||
|
||
// Sign a digest. | ||
function sign(bytes32 digest) | ||
public view override authorized | ||
returns (SignatureRSV memory) { | ||
return EthereumUtils.sign(publicKey, privateKey, digest); | ||
} | ||
|
||
// Taken from https://github.com/oasisprotocol/sapphire-paratime/blob/main/examples/onchain-signer/contracts/Gasless.sol#L23 | ||
function makeProxyTx( | ||
address in_contract, | ||
bytes memory in_data | ||
) external view authorized | ||
returns (bytes memory output) { | ||
bytes memory data = abi.encode(in_contract, in_data); | ||
|
||
return | ||
EIP155Signer.sign( | ||
publicKey, | ||
privateKey, | ||
EIP155Signer.EthTx({ | ||
nonce: nonce, | ||
gasPrice: 100_000_000_000, | ||
gasLimit: 250000, | ||
to: address(this), | ||
value: 0, | ||
data: abi.encodeCall(this.proxy, data), | ||
chainId: block.chainid | ||
}) | ||
); | ||
} | ||
|
||
function proxy(bytes memory data) external authorized payable { | ||
(address addr, bytes memory subcallData) = abi.decode( | ||
data, | ||
(address, bytes) | ||
); | ||
(bool success, bytes memory outData) = addr.call{value: msg.value}( | ||
subcallData | ||
); | ||
if (!success) { | ||
// Add inner-transaction meaningful data in case of error. | ||
assembly { | ||
revert(add(outData, 32), mload(outData)) | ||
} | ||
} | ||
|
||
nonce += 1; | ||
} | ||
|
||
|
||
// Call another contract. | ||
function call(address in_contract, bytes memory in_data) | ||
public payable override authorized | ||
returns (bool success, bytes memory out_data) { | ||
|
||
(success, out_data) = in_contract.call{value: msg.value, gas: gasleft()}(in_data); | ||
if (!success) { | ||
assembly { | ||
revert(add(out_data, 32), mload(out_data)) | ||
} | ||
} | ||
nonce++; | ||
} | ||
|
||
// Call another contract. | ||
function staticcall(address in_contract, bytes memory in_data) | ||
public override view authorized | ||
returns (bool success, bytes memory out_data) { | ||
|
||
(success, out_data) = in_contract.staticcall{gas: gasleft()}(in_data); | ||
if (!success) { | ||
assembly { | ||
revert(add(out_data, 32), mload(out_data)) | ||
} | ||
} | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
import {SignatureRSV, EthereumUtils} from "@oasisprotocol/sapphire-contracts/contracts/EthereumUtils.sol"; | ||
import {EIP155Signer} from "@oasisprotocol/sapphire-contracts/contracts/EIP155Signer.sol"; | ||
|
||
// A contract to create per-identity account. | ||
abstract contract AccountFactoryBase { | ||
function clone (address starterOwner) | ||
public virtual | ||
returns (AccountBase acct); | ||
} | ||
|
||
// A base class for a per-identity account. | ||
// It can be extended to include additional data, for example a symmetric | ||
// key for encrypting and decryption off-chain data. | ||
abstract contract AccountBase { | ||
// Address of the controller of this account. It can either be | ||
// an EOA (externally owned account), or a validator contract | ||
// (defined below). | ||
address private controller; | ||
|
||
// Update the controller of this account. Useful when a different | ||
// type of credential is to be used and a validator contract is needed. | ||
function updateController(address _controller) external virtual; | ||
|
||
// A key pair for the account. | ||
address public publicKey; | ||
bytes32 private privateKey; | ||
|
||
// Grant permission for another address to act as owner for this account | ||
// until expiry. | ||
mapping (address => uint256) permission; | ||
|
||
// Functions to check and update permissions. | ||
function hasPermission(address grantee) public virtual view | ||
returns (bool); | ||
|
||
function grantPermission(address grantee, uint256 expiry) | ||
public virtual; | ||
function revokePermission(address grantee) public virtual; | ||
|
||
// The remaining functions use the key pair for normal contract operations. | ||
|
||
// Sign a transaction. | ||
function signEIP155(EIP155Signer.EthTx calldata txToSign) | ||
public view virtual | ||
returns (bytes memory); | ||
|
||
// Sign a digest. | ||
function sign(bytes32 digest) | ||
public virtual view | ||
returns (SignatureRSV memory); | ||
|
||
// Call another contract. | ||
function call(address in_contract, bytes memory in_data) | ||
public payable virtual | ||
returns (bool success, bytes memory out_data); | ||
|
||
// Call another contract. | ||
function staticcall(address in_contract, bytes memory in_data) | ||
public virtual view | ||
returns (bool success, bytes memory out_data); | ||
} |
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 |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
import "./Account.sol"; | ||
import "./AccountBase.sol"; | ||
import {Sapphire} from "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol"; | ||
|
||
// A contract to create per-identity account. | ||
contract AccountWithSymKeyFactory is AccountFactory { | ||
function clone (address starterOwner) | ||
public override | ||
returns (AccountBase acct) { | ||
AccountBase acc = new AccountWithSymKey(starterOwner); | ||
emit AccountCreated(address(acc)); | ||
return acc; | ||
} | ||
} | ||
|
||
contract AccountWithSymKey is Account { | ||
type Key is bytes32; | ||
|
||
constructor(address starterOwner) Account(starterOwner) {} | ||
|
||
// Named symmetric keys. name -> key | ||
mapping (string => Key) keys; | ||
|
||
// Generate a named symmetric key. | ||
function generateSymKey(string calldata name, bool overwrite) | ||
public authorized { | ||
require(overwrite || Key.unwrap(keys[name]) == bytes32(0), "Key already exists and overwrite is false"); | ||
|
||
bytes memory domainSep = bytes(name); | ||
(Sapphire.Curve25519PublicKey pubKey, Sapphire.Curve25519SecretKey privKey) = Sapphire.generateCurve25519KeyPair(domainSep); | ||
Key symKey = Key.wrap(Sapphire.deriveSymmetricKey(pubKey, privKey)); | ||
keys[name] = symKey; | ||
} | ||
|
||
// Retrieve a named symmetric key. | ||
function getSymKey(string calldata name) | ||
public view authorized | ||
returns (Key key) { | ||
key = keys[name]; | ||
} | ||
|
||
// Delete a named symmetric key. | ||
function deleteSymKey(string calldata name) | ||
external virtual authorized { | ||
keys[name] = Key.wrap(bytes32(0)); | ||
} | ||
|
||
// Encrypt in_data with the named symmetric key. | ||
function encryptSymKey(string calldata name, bytes memory in_data) | ||
public virtual view authorized | ||
returns (bytes memory out_data) { | ||
require(Key.unwrap(keys[name]) != bytes32(0), "Requested key doesn't exist"); | ||
bytes32 nonce = bytes32(Sapphire.randomBytes(32, "")); | ||
bytes memory ciphertext = Sapphire.encrypt(Key.unwrap(keys[name]), nonce, in_data, ""); | ||
out_data = abi.encode(nonce, ciphertext); | ||
} | ||
|
||
function decryptSymKey(string calldata name, bytes memory in_data) | ||
public view authorized | ||
returns (bytes memory out_data) { | ||
(bytes32 nonce, bytes memory ciphertext) = abi.decode(in_data, (bytes32, bytes)); | ||
out_data = Sapphire.decrypt(Key.unwrap(keys[name]), nonce, ciphertext, ""); | ||
} | ||
|
||
// Some key rotation stuff here? | ||
} |
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 |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
contract Sender { | ||
event CheckSender(address sender); | ||
|
||
function emitSender() public returns (address){ | ||
emit CheckSender(msg.sender); | ||
return msg.sender; | ||
} | ||
|
||
} |
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 |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.9; | ||
|
||
contract Test { | ||
uint256 counter; | ||
|
||
constructor() { | ||
counter = 0; | ||
} | ||
|
||
function incrementCounter() public { | ||
counter++; | ||
} | ||
} |
Oops, something went wrong.