Address Contract Verified
Address
0x711c627735278C199DE2B5a97a97Ce75e2Bfc758
Balance
0 ETH
Nonce
1
Code Size
3576 bytes
Creator
0x01b2156C...28f9 at tx 0x468906ad...d9d35b
Indexed Transactions
0
Contract Bytecode
3576 bytes
0x608060405234801561001057600080fd5b50600436106100885760003560e01c80639dca31b61161005b5780639dca31b61461022f578063b817d52e146102e3578063bd66f5d714610409578063e93e1a7d1461052f57610088565b80632079fb9a1461008d57806322ca3886146100c65780632972351114610173578063408acd3314610227575b600080fd5b6100aa600480360360208110156100a357600080fd5b50356105da565b604080516001600160a01b039092168252519081900360200190f35b610171600480360360408110156100dc57600080fd5b81359190810190604081016020820135600160201b8111156100fd57600080fd5b82018360208201111561010f57600080fd5b803590602001918460018302840111600160201b8311171561013057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610604945050505050565b005b6101716004803603604081101561018957600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156101b357600080fd5b8201836020820111156101c557600080fd5b803590602001918460018302840111600160201b831117156101e657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610718945050505050565b6100aa610823565b6101716004803603604081101561024557600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561026f57600080fd5b82018360208201111561028157600080fd5b803590602001918460018302840111600160201b831117156102a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610832945050505050565b610171600480360360408110156102f957600080fd5b810190602081018135600160201b81111561031357600080fd5b82018360208201111561032557600080fd5b803590602001918460208302840111600160201b8311171561034657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561039557600080fd5b8201836020820111156103a757600080fd5b803590602001918460018302840111600160201b831117156103c857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610911945050505050565b6101716004803603604081101561041f57600080fd5b810190602081018135600160201b81111561043957600080fd5b82018360208201111561044b57600080fd5b803590602001918460208302840111600160201b8311171561046c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156104bb57600080fd5b8201836020820111156104cd57600080fd5b803590602001918460018302840111600160201b831117156104ee57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610a74945050505050565b6101716004803603604081101561054557600080fd5b81359190810190604081016020820135600160201b81111561056657600080fd5b82018360208201111561057857600080fd5b803590602001918460018302840111600160201b8311171561059957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610bb0945050505050565b600081815481106105ea57600080fd5b6000918252602090912001546001600160a01b0316905081565b600060028154811061061257fe5b6000918252602090912001546001600160a01b0316331461066c576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b60408051655245564f4b4560d01b602080830191909152602680830186905283518084039091018152604690920190925280519101206106ae81836000610ca6565b60015460408051635bae3ee360e11b81526004810186905290516001600160a01b039092169163b75c7dc69160248082019260009290919082900301818387803b1580156106fb57600080fd5b505af115801561070f573d6000803e3d6000fd5b50505050505050565b600060028154811061072657fe5b6000918252602090912001546001600160a01b03163314610780576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b60408051672a2920a729a322a960c11b6020808301919091526bffffffffffffffffffffffff19606086901b1660288301528251601c818403018152603c90920190925280519101206107d581836001610ca6565b6001546040805163f2fde38b60e01b81526001600160a01b0386811660048301529151919092169163f2fde38b91602480830192600092919082900301818387803b1580156106fb57600080fd5b6001546001600160a01b031681565b600060028154811061084057fe5b6000918252602090912001546001600160a01b0316331461089a576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b60408051654348414e474560d01b6020808301919091526bffffffffffffffffffffffff19606086901b1660268301528251601a818403018152603a90920190925280519101206108ed81836001610ca6565b5050600180546001600160a01b0319166001600160a01b0392909216919091179055565b600060028154811061091f57fe5b6000918252602090912001546001600160a01b03163314610979576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b60008260405160200180806842554c4b495353554560b81b815250600901828051906020019060200280838360005b838110156109c05781810151838201526020016109a8565b505050509050019150506040516020818303038152906040528051906020012090506109ee81836000610ca6565b600154604051633ef9041360e11b81526020600482018181528651602484015286516001600160a01b0390941693637df208269388938392604490920191818601910280838360005b83811015610a4f578181015183820152602001610a37565b5050505090500192505050600060405180830381600087803b1580156106fb57600080fd5b6000600281548110610a8257fe5b6000918252602090912001546001600160a01b03163314610adc576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b60008260405160200180806942554c4b5245564f4b4560b01b815250600a01828051906020019060200280838360005b83811015610b24578181015183820152602001610b0c565b50505050905001915050604051602081830303815290604052805190602001209050610b5281836000610ca6565b60015460405163256d403b60e11b81526020600482018181528651602484015286516001600160a01b0390941693634ada80769388938392604490920191858201910280838360008315610a4f578181015183820152602001610a37565b6000600281548110610bbe57fe5b6000918252602090912001546001600160a01b03163314610c18576040805162461bcd60e51b815260206004820152600f60248201526e2bb937b7339034b734ba34b0ba37b960891b604482015290519081900360640190fd5b6040805164495353554560d81b60208083019190915260258083018690528351808403909101815260459092019092528051910120610c5981836000610ca6565b60015460408051630f75e81f60e01b81526004810186905290516001600160a01b0390921691630f75e81f9160248082019260009290919082900301818387803b1580156106fb57600080fd5b6000610cb28484610d24565b905060008260ff1681548110610cc457fe5b6000918252602090912001546001600160a01b03828116911614610d1e576040805162461bcd60e51b815260206004820152600c60248201526b2bb937b7339039b4b3b732b960a11b604482015290519081900360640190fd5b50505050565b60008151604114610d3457600080fd5b60208201516040830151604184015160ff16601b811015610d5357601b015b60018682858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610dad573d6000803e3d6000fd5b5050604051601f19015197965050505050505056fea264697066735822122011cb236f187181f622465eebb482708b1a5ecd87a7fb83a42cc23657924b64b164736f6c63430007060033
Verified Source Code Full Match
Compiler: v0.7.6+commit.7338295f
EVM: istanbul
Optimization: Yes (200 runs)
AccredifyMultiSig.sol 408 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
// silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
/**
* @dev contract module that provides the OpenCerts DocumentStore contract to be used
* to issue and remoke certificates on the blockchain
*/
contract DocumentStore is Ownable {
string public name;
string public version = "2.3.0";
/// A mapping of the document hash to the block number that was issued
mapping(bytes32 => uint256) public documentIssued;
/// A mapping of the hash of the claim being revoked to the revocation block number
mapping(bytes32 => uint256) public documentRevoked;
event DocumentIssued(bytes32 indexed document);
event DocumentRevoked(bytes32 indexed document);
constructor(string memory _name) {
name = _name;
}
function issue(bytes32 document) public onlyOwner onlyNotIssued(document) {
documentIssued[document] = block.number;
emit DocumentIssued(document);
}
function bulkIssue(bytes32[] memory documents) public {
for (uint256 i = 0; i < documents.length; i++) {
issue(documents[i]);
}
}
function getIssuedBlock(bytes32 document)
public
view
onlyIssued(document)
returns (uint256)
{
return documentIssued[document];
}
function isIssued(bytes32 document) public view returns (bool) {
return (documentIssued[document] != 0);
}
function isIssuedBefore(bytes32 document, uint256 blockNumber)
public
view
returns (bool)
{
return
documentIssued[document] != 0 && documentIssued[document] <= blockNumber;
}
function revoke(bytes32 document)
public
onlyOwner
onlyNotRevoked(document)
{
documentRevoked[document] = block.number;
emit DocumentRevoked(document);
}
function bulkRevoke(bytes32[] memory documents) public {
for (uint256 i = 0; i < documents.length; i++) {
revoke(documents[i]);
}
}
function isRevoked(bytes32 document) public view returns (bool) {
return documentRevoked[document] != 0;
}
function isRevokedBefore(bytes32 document, uint256 blockNumber)
public
view
returns (bool)
{
return
documentRevoked[document] <= blockNumber && documentRevoked[document] != 0;
}
modifier onlyIssued(bytes32 document) {
require(
isIssued(document),
"Error: Only issued document hashes can be revoked"
);
_;
}
modifier onlyNotIssued(bytes32 document) {
require(
!isIssued(document),
"Error: Only hashes that have not been issued can be issued"
);
_;
}
modifier onlyNotRevoked(bytes32 claim) {
require(!isRevoked(claim), "Error: Hash has been revoked previously");
_;
}
}
/**
*
* AccredifyMultiSig
* ============
*
* Basic multi-signer wallet designed for use in a co-signing environment where
* 2 signatures are required to issue and revoke certificates.
* Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow
* for 2 signatures in a single transaction.
*
* The first signature is created on the operation hash (see Data Formats) and
* passed to the multiSig functions
* The signer is determined by verifyMultiSig().
*
* The second signature is created by the submitter of the transaction and determined
* by msg.signer.
*
* This wallet only allows for three signers that have to be set upon deployment.
* The signers cannot be changed/removed/added.
*
* This iteration of the wallet restricts the initiation of the different functions to
* specific signers, and removes the expiryTime param, does not deploy a docStore contract,
* and removes events.
*
* Signer Authorisation
* ====================
* All multisig transactions can only be initiated by the 3rd Signer AKA The Custodian
*
* Data Formats
* ============
*
* The signature is created with ethereumjs-util.ecsign(operationHash).
* Like the eth_sign RPC call, it packs the values as a 65-byte array of [r, s, v].
* Unlike eth_sign, the message is not prefixed.
*
* The operationHash the result of keccak256(prefix, hash).
* For Issue transactions, `prefix` is "ISSUE".
* For Bulk Issue transactions, `prefix` is "BULKISSUE".
* For Revoke transaction, `prefix` is "REVOKE".
* For Bulk Revoke transaction, `prefix` is "BULKREVOKE".
* For Transfer transaction, 'prefix' is "TRANSFER"
* For Change transaction, 'prefix' is "CHANGE"
*
*/
contract AccredifyMultiSigDocStore {
// Public fields
address[] public signers; // The addresses that can co-sign transactions on the wallet
DocumentStore public documentStore; //DocumentStore Contract
/**
* Constructor
* ============
*
* Deploys a new AccredifyMultiSig contract
* Takes in an array of 3 signers that will be used to approve transactions
*
*/
constructor(address[] memory _signers) {
require(_signers.length == 3, "3 signers required");
signers = _signers;
}
/**
* Modifier that will execute internal code block only if the sender is the Custodian
*/
modifier onlyCustodian {
require(msg.sender == signers[2], "Wrong initiator");
_;
}
/**
* Fallback function. Is called when a transaction is received without calling a method
*/
fallback() external {
revert();
// Reject any accidental Ether transfer
}
/**
* Execute a multi-signature issue transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
*
* @param hash the certificate batch's hash that will be appended to the blockchain
* @param signature second signer's signature
*/
function issue(
bytes32 hash,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("ISSUE", hash));
verify(operationHash, signature, 0);
documentStore.issue(hash);
}
/**
* Execute a multi-signature bulk issue transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
*
* @param hashes an array of certificate batch hashes that will be appended to the blockchain
* @param signature second signer's signature
*/
function bulkIssue(
bytes32[] memory hashes,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("BULKISSUE", hashes));
verify(operationHash, signature, 0);
documentStore.bulkIssue(hashes);
}
/**
* Execute a multi-signature revoke transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
*
* @param hash the certificate's hash that will be revoked on the blockchain
* @param signature second signer's signature
*/
function revoke(
bytes32 hash,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("REVOKE", hash));
verify(operationHash, signature, 0);
documentStore.revoke(hash);
}
/**
* Execute a multi-signature bulk revoke transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
*
* @param hashes an array of certificate hashes that will be revoked on the blockchain
* @param signature second signer's signature
*/
function bulkRevoke(
bytes32[] memory hashes,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("BULKREVOKE", hashes));
verify(operationHash, signature, 0);
documentStore.bulkRevoke(hashes);
}
/**
* Execute a multi-signature transfer transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
* This transaction transfers the ownership of the certificate store to a new owner.
*
* @param newOwner the new owner's address
* @param signature second signer's signature
*/
function transfer(
address newOwner,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("TRANSFER", newOwner));
verify(operationHash, signature, 1);
documentStore.transferOwnership(newOwner);
}
/**
* Execute a multi-signature change transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
* This transaction changes the address of the DocumentStore on this wallet contract.
*
* @param newStore the new owner's address
* @param signature second signer's signature
*/
function changeStore(
address newStore,
bytes memory signature
) public onlyCustodian {
bytes32 operationHash = keccak256(abi.encodePacked("CHANGE", newStore));
verify(operationHash, signature, 1);
documentStore = DocumentStore(newStore);
}
/**
* Do common multisig verification for both Issue and Revoke transactions
*
* @param operationHash keccak256(prefix, hash)
* @param signature second signer's signature
* @param signer order in singers array
* returns address that has created the signature
*/
function verify(
bytes32 operationHash,
bytes memory signature,
uint8 signer
) private view {
address otherSigner = recoverAddress(operationHash, signature);
require(otherSigner == signers[signer], "Wrong signer");
}
/**
* Gets signer's address using ecrecover
* @param operationHash see Data Formats
* @param signature see Data Formats
* returns address recovered from the signature
*/
function recoverAddress(
bytes32 operationHash,
bytes memory signature
) private pure returns (address) {
if (signature.length != 65) {
revert();
}
// We need to unpack the signature, which is given as an array of 65 bytes (like eth.sign)
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 32))
s := mload(add(signature, 64))
v := and(mload(add(signature, 65)), 255)
}
if (v < 27) {
v += 27;
// Ethereum versions are 27 or 28 as opposed to 0 or 1 which is submitted by some signing libs
}
return ecrecover(operationHash, v, r, s);
}
}
Read Contract
documentStore 0x408acd33 → address
signers 0x2079fb9a → address
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
bulkIssue 0xb817d52e
bytes32[] hashes
bytes signature
bulkRevoke 0xbd66f5d7
bytes32[] hashes
bytes signature
changeStore 0x9dca31b6
address newStore
bytes signature
issue 0xe93e1a7d
bytes32 hash
bytes signature
revoke 0x22ca3886
bytes32 hash
bytes signature
transfer 0x29723511
address newOwner
bytes signature
Recent Transactions
No transactions found for this address