WalletLib
!!!DO NOT USE, IN THE PROCESS OF UPGRADING!!!
A wallet library family provided by Modular-Network composed of 3 libraries to use for multisig wallet contract deployment.
- Library Addresses
- License and Warranty
- How to install
- Functions
- Primary Functions
- init(WalletMainLib.WalletData storage, address[], uint256, uint256, uint256, uint256)
- serveTx(WalletMainLib.WalletData, address, uint256, bytes, bool, bytes)
- confirmTx(WalletMainLib.WalletData storage, bytes32)
- revokeConfirm(WalletMainLib.WalletData storage, bytes32)
- Administrative Functions
- changeOwner(WalletMainLib.WalletData storage, address, address, bool, bytes)
- addOwner(WalletMainLib.WalletData storage, address, bool, bytes)
- removeOwner(WalletMainLib.WalletData storage, address, bool, bytes)
- changeRequiredAdmin(WalletMainLib.WalletData storage, uint256, bool, bytes)
- changeRequiredMajor(WalletMainLib.WalletData storage, uint256, bool, bytes)
- changeRequiredMinor(WalletMainLib.WalletData storage, uint256, bool, bytes)
- changeMajorThreshold(WalletMainLib.WalletData storage, address, address, bool, bytes)
- Getter Functions
Library Addresses
WalletMainLib
Main Ethereum Network:
Rinkeby Test Network:
WalletAdminLib
Main Ethereum Network:
Rinkeby Test Network:
WalletGetterLib
Main Ethereum Network:
Rinkeby Test Network:
License and Warranty
Be advised that while we strive to provide professional grade, tested code we cannot guarantee its fitness for your application. This is released under The MIT License (MIT) and as such we will not be held liable for lost funds, etc. Please use your best judgment and note the following:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Installation and Usage
How to install
npm install ethereum-libraries-wallet
How to link
Amend the deployment .js file in your truffle migrations/
directory as follows:
var WalletMainLib = artifacts.require("ethereum-libraries-wallet/contracts/WalletMainLib.sol");
var WalletAdminLib = artifacts.require("ethereum-libraries-wallet/contracts/WalletAdminLib.sol");
var WalletGetterLib = artifacts.require("ethereum-libraries-wallet/contracts/WalletGetterLib.sol");
var YourWalletContract = artifacts.require("./YourWalletContract.sol");
...
module.exports = function(deployer) {
deployer.deploy(WalletMainLib, {overwrite: false});
deployer.deploy(WalletAdminLib, {overwrite: false});
deployer.deploy(WalletGetterLib, {overwrite: false});
deployer.link(WalletMainLib, YourWalletContract);
deployer.link(WalletAdminLib, YourWalletContract);
deployer.link(WalletGetterLib, YourWalletContract);
deployer.deploy(YourWalletContract);
};
Note: If you have not created a second deployment .js file in the migrations/
directory, this needs to be done first. You cannot use the 1_initial_migration.js file for your migrations.
Note: The .link()
function should be called before you .deploy(YourWalletContract)
. Also, be sure to include the {overwrite: false}
when writing the deployer i.e. .deploy(WalletMainLib, {overwrite: false})
. This prevents deploying the library onto the main network at your cost and uses the library already on the blockchain. The function should still be called however because it allows you to use it in your development environment. See below
Testing
Test: npm run test
Test Coverage: Solidity coverage is not currently emitting events properly for Solidity v0.4.21
solc Installation
version 0.4.21
For direction and instructions on how the Solidity command line compiler works see the documentation.
With standard JSON input
The Standard JSON Input provides an easy interface to include libraries. Include the following as part of your JSON input file:
{
"language": "Solidity",
"sources":
{
"YourContract.sol": {
...
...
},
"WalletMainLib.sol": {
"content": "[Contents of WalletMainLib.sol]"
},
"WalletAdminLib.sol": {
"content": "[Contents of WalletAdminLib.sol]"
},
"WalletGetterLib.sol": {
"content": "[Contents of WalletGetterLib.sol]"
}
},
"settings":
{
...
"libraries": {
"YourContract.sol": {
"WalletMainLib": "",
"WalletAdminLib": "",
"WalletGetterLib": "",
}
}
}
}
solc without standard JSON input
When creating unlinked binary, the compiler currently leaves special substrings in the compiled bytecode in the form of 'LibraryName' which leaves a 20 byte space for the library's address. In order to include the deployed libraries in your bytecode create a file with one library string per line and include these libraries as follows:
"WalletMainLib:"
"WalletAdminLib:"
"WalletGetterLib:"
then add the following flag to your command:
--libraries filename
Finally, if you have an unlinked binary already stored with the 'LibraryName' placeholder, you can run the compiler with the --link flag and include each library with the following flag:
--libraries "WalletMainLib:"
solc documentation
See the solc documentation for further information.
solc-js Installation
version 0.4.21
Solc-js provides javascript bindings for the Solidity compiler and can be found here. Please refer to their documentation for detailed use.
This version of Solc-js also uses the standard JSON input to compile a contract. The entry function is compileStandardWrapper()
and you can create a standard JSON object explained under the solc section and incorporate it as follows:
var solc = require('solc');
var fs = require('fs');
var file = fs.readFileSync('/path/to/YourWalletContract.sol','utf8');
var mainLib = fs.readFileSync('./path/to/WalletMainLib.sol','utf8');
var adminLib = fs.readFileSync('./path/to/WalletAdminLib.sol','utf8');
var getterLib = fs.readFileSync('./path/to/WalletGetterLib.sol','utf8');
var input = {
"language": "Solidity",
"sources":
{
"YourContract.sol": {
"content": file
},
"WalletMainLib.sol": {
"content": mainLib
},
"WalletAdminLib.sol": {
"content": adminLib
},
"WalletGetterLib.sol": {
"content": getterLib
}
},
"settings":
{
...
"libraries": {
"YourContract.sol": {
"WalletMainLib": "",
"WalletAdminLib": "",
"WalletGetterLib": "",
}
}
...
}
}
var output = JSON.parse(solc.compileStandardWrapper(JSON.stringify(input)));
Solc-js Installation via Linking
Solc-js also provides a linking method if you have compiled binary code already with the placeholder. To link each library the call would be:
bytecode = solc.linkBytecode(bytecode, { 'WalletMainLib': '' });
Solc-js documentation
See the Solc-js documentation for further information.
Basic Usage
The Wallet Libraries provide all of the functionality needed to generate a fully functional multisig wallet. Functionality is split into 3 different libraries. Each library serves the following purposes:
-
WalletMainLib: This is the main library used to create a wallet and initialize parameters. It contains the WalletData struct which should be placed in the storage of your wallet contract. This library also contains the primary transaction initiating, confirming, and revocation code.
-
WalletAdminLib: This library contains all of the functionality to change the parameters of your multisig wallet such as adding owners, changing signature requirements, etc.
-
WalletGetterLib: This library contains all of the getter functions for your wallet data.
The wallet generated will have some of these benefits and characteristics:
- Can have up to 50 wallet owners.
- Allows for signature requirements to be defined for three types of operations: administrative, minor transactions, and major transactions.
Administrative: These are transactions that change signature requirements, add owners, remove owners, etc.
Minor Transactions: These are ether or token transfers below a set daily threshold.
Major Transactions: These are ether or token transfers at or above a set daily threshold. - Allows a major transaction threshold to be set individually for any token.
- Provides a transaction hash for any pending transaction such as is implemented in Gav's wallet, allowing subsequent signatures to be submitted by hash.
- Can create other contracts from within the wallet.
- Any new token will automatically have a major threshold of 0 until a threshold is defined by the wallet owners.
- Allows signatures to be revoked at any point in time prior to the transaction confirming.
The wallet contract should put the init
function from the WalletMainLib in the constructor with the required parameters given. Once deployed, owners can initiate any transaction by calling the appropriate function with the required data for admin functions, transfer or value data for token or ether transactions, or contract data for deploying new contracts. Most transaction requests end with a bool
and bytes
parameter. The bool
parameter should be true for any transaction being initiated or confirmed and false for any signature revocation. The bytes
parameter should be the msg.data passed automatically by the wallet contract. See our example wallet contract to get a better idea of its implementation.
Most functions return two parameters, a bool
and a bytes32
. The transaction and admin functions will generally return false and log an error event when submitted parameters are either wrong or the call will not work. In the case of a non-owner attempting to submit a transaction or any failure during actual execution, the function will throw a standard out of gas error with no reason in order to successfully revert changes. These functions will return true if any confirm or revocation call is successful. The functions that return a bytes32
will also log this value in an event. Owners may choose to use the generic confirmTx
or revokeConfirm
functions by providing the id for any transaction already initiated, a concept artfully developed by Gav of York himself.
DISCLAIMER: As always, please ensure you review this code thoroughly for your team's use. We strive to make our code as solid, clean, and well documented as possible but will not accept liability for unforeseen circumstances in which value is lost or stolen. This includes but not limited to any inability to meet signature requirements to move funds, loss of private keys, transactions you deem unauthorized from an owner's account, a non-owners ability to gain access to your wallet, etc. The library code has been thoroughly tested by our team and believe it to be suitable enough to be posted in our open source repository, however, you are still responsible for its implementation and security in your smart contract. Please use your best judgment. Please let us know immediately if you have discovered any issues or vulnerabilities with this library.
Usage Example
pragma solidity ^0.4.21;
import "ethereum-libraries-wallet/contracts/WalletMainLib.sol";
import "ethereum-libraries-wallet/contracts/WalletAdminLib.sol";
import "ethereum-libraries-wallet/contracts/WalletGetterLib.sol";
contract YourWalletContract {
using WalletMainLib for WalletMainLib.WalletData;
WalletMainLib.WalletData public wallet;
event Deposit(uint value);
function YourWalletContract() {
address[] memory _owners = new address[](5);//Define initial account owners with your owners
_owners[0] = 0xb4e205cd196bbe4b1b3767a5e32e15f50eb79623;
_owners[1] = 0x40333d950b4c682e8aad143c216af52877d828bf;
_owners[2] = 0x0a1f4fcde83ba12ee8343488964811218da3e00e;
_owners[3] = 0x79b63228ff63659248b7c688870de388bdcf0c14;
_owners[4] = 0x36994c7cff11859ba8b9715120a68aa9499329ee;
wallet.init(_owners,4,3,1,100000000000000000000);
}
//Payable fallback function
function() payable {
Deposit(msg.value);
}
/*Getters*/
function owners() constant returns (address[51]) {//Returns fixed array until fork
return wallet.getOwners();
}
function ownerIndex(address _owner) constant returns (uint) {
return wallet.getOwnerIndex(_owner);
}
...
}
Functions
The following is the list of functions available to use in your smart contract.
Primary Functions
init(WalletMainLib.WalletData storage, address[], uint256, uint256, uint256, uint256)
(WalletMainLib.sol, line 88)
Constructor. Initializes the wallet in the calling contract's storage. Caller passes in owners and signature settings for the wallet. Owners must be valid ethereum addresses and signature requirements must be greater than zero and less than or equal to the number of owners. _majorThreshold
parameter should set the daily spend limit for minor ether transactions in wei.
Arguments
WalletMainLib.WalletData self The storage wallet in the calling contract.
address[] _owners
Array of initial wallet owner addresses
uint256 _requiredAdmin
The number of signatures required for administrative changes
uint256 _requiredMajor
The number of signatures required for major transactions
uint256 _requiredMinor
The number of signatures required for minor transactions
uint256 _majorThreshold
The daily Ether spend threshold for transactions to become major, in units of wei
Returns
bool
serveTx(WalletMainLib.WalletData, address, uint256, bytes, bool, bytes)
(WalletMainLib.sol, line 261)
Sends the specified amount of Ether or tokens from the Wallet to an address. This function requires a certain number of signatures from the wallet owners, indicated by requiredMinor for minor transactions and requiredMajor for major transactions. If it is the first call with the given parameters, the transaction is created and a confirmation from the sender is recorded. Additional calls sent from different owners but with the same parameters act as confirmations of the transaction. If a previously confirmed owner calls this function with the same arguments for the pending transaction, but with the confirm flag set to false, their confirmation for the transaction will be revoked. When the confirmations reach the required number, the transaction is executed.
Arguments
WalletMainLib.WalletData self The storage wallet in the calling contract.
address _to
Intended recipient of transaction.
uint256 _value
Amount of Ether to be sent.
bytes _txData
Any transaction data to be sent to recipient.
bool _confirm
True if initiaing or confirming a transaction, false if revoking a signature.
bytes _data
Data for this call sent automatically by the calling contract.
Returns
bool True if transaction confirmed or revoked successfully
bytes32 The transaction id which can be provided to confirmTx
or revokeConfirm
.
confirmTx(WalletMainLib.WalletData storage, bytes32)
(WalletMainLib.sol, line 351)
Confirms the specified pending transaction with the sender's signature. If the transaction does not exist, the call will fail. If the callers signature is the final signature needed for the transaction to succeed, the transaction will execute.
Arguments
WalletMainLib.WalletData self
bytes32 _id
Returns
bool
revokeConfirm(WalletMainLib.WalletData storage, bytes32)
(WalletMainLib.sol, line 391)
Revokes the sender's confirmation from a pending transaction. If the transaction does not exist or has already succeeded, the call will fail. The caller also needs to have already confirmed the transaction.
Arguments
WalletMainLib.WalletData self
bytes32 _id
Returns
bool
Administrative Functions
These functions are for performing actions that change the administrative settings of the Wallet contract such as owners, major/minor transaction threshholds, and number of signatures required. They behave almost exactly like ServeTx behaves above, but with requiredAdmin number of signatures required to execute changes.
changeOwner(WalletMainLib.WalletData storage, address, address, bool, bytes)
(WalletAdminLib.sol, line 139)
Changes owner address to a new address. bool should be true if confirming or initiating the transaction and false if revoking a confirmation. bytes parameter should be passed as msg.data from wallet contract.
Arguments
WalletMainLib.WalletData self
adress _from
address _to
bool _confirm
bytes _data
Returns
bool
bytes32
addOwner(WalletMainLib.WalletData storage, address, bool, bytes)
(WalletAdminLib.sol, line 209)
Adds a new user as an owner of the wallet.
Arguments
WalletMainLib.WalletData self
adress _newOwner
bool _confirm
bytes _data
Returns
bool
bytes32
removeOwner(WalletMainLib.WalletData storage, address, bool, bytes)
(WalletAdminLib.sol, line 280)
Removes an existing owner from the wallet.
Arguments
WalletMainLib.WalletData self
adress _ownerRemoving
bool _confirm
bytes _data
Returns
bool
bytes32
changeRequiredAdmin(WalletMainLib.WalletData storage, uint256, bool, bytes)
(WalletAdminLib.sol, line 351)
Changes the number of signatures required to confirm administrative changes.
Arguments
WalletMainLib.WalletData self
uint256 _requiredAdmin
bool _confirm
bytes _data
Returns
bool
bytes32
changeRequiredMajor(WalletMainLib.WalletData storage, uint256, bool, bytes)
(WalletAdminLib.sol, line 418)
Changes the number of signatures required to confirm major transactions.
Arguments
WalletMainLib.WalletData self
uint256 _requiredMajor
bool _confirm
bytes _data
Returns
bool
bytes32
changeRequiredMinor(WalletMainLib.WalletData storage, uint256, bool, bytes)
(WalletAdminLib.sol, line 485)
Changes the number of signatures required to confirm minor transactions.
Arguments
WalletMainLib.WalletData self
uint256 _requiredMinor
bool _confirm
bytes _data
Returns
bool
bytes32
changeMajorThreshold(WalletMainLib.WalletData storage, address, address, bool, bytes)
(WalletAdminLib.sol, line 553)
Changes the threshold of tokens or wei spent per day that needs to be crossed for the transaction to be considered major.
Arguments
WalletMainLib.WalletData self
adress _from
address _to
bool _confirm
bytes _data
Returns
bool
bytes32
Getter Functions
getOwners(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 40)
Get list of wallet owners, will return fixed 50 item array until Metro fork.
Arguments
WalletMainLib.WalletData self
Returns
address[51]
getOwnerIndex(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 52)
Get index of an owner.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getMaxOwners(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 59)
Get max number of wallet owners.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getOwnerCount(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 66)
Get number of wallet owners.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getRequiredAdmin(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 73)
Get sig requirements for administrative changes.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getRequiredMinor(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 80)
Get sig requirements for minor tx spends.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getRequiredMajor(WalletMainLib.WalletData storage)
(WalletGetterLib.sol, line 87)
Get sig requirements for major tx spends.
Arguments
WalletMainLib.WalletData self
Returns
uint256
getCurrentSpend(WalletMainLib.WalletData storage, address)
(WalletGetterLib.sol, line 95)
Get current day spend for token.
Arguments
WalletMainLib.WalletData self
address _token
Address of the token contract, use 0 for ether.
Returns
uint256[2] 0-index is day timestamp, 1-index is the day spend
getMajorThreshold(WalletMainLib.WalletData storage, address)
(WalletGetterLib.sol, line 106)
Get major tx threshold per token.
Arguments
WalletMainLib.WalletData self
address _token
Returns
uint256
getTransactionLength(WalletMainLib.WalletData storage, bytes32)
(WalletGetterLib.sol, line 114)
Get the number of tx's with the same id.
Arguments
WalletMainLib.WalletData self
bytes32 _id
Returns
uint256 Number of transactions with this id, can be used to query for specific tx, see getTransactionConfirms
getTransactionConfirms(WalletMainLib.WalletData storage, bytes32, uint256)
(WalletGetterLib.sol, line 123)
Get list of confirmations for a tx, use getTransactionLength
to get latest number.
Arguments
WalletMainLib.WalletData self
bytes32 _id
uint256 _number
Returns
uint256[50] List of confirmations, fixed at 50 items until Metro fork
getTransactionConfirmCount(WalletMainLib.WalletData storage, bytes32, uint256)
(WalletGetterLib.sol, line 140)
Retrieve tx confirmation count.
Arguments
WalletMainLib.WalletData self
bytes32 _id
uint256 _number
Returns
uint256 The current number of tx confirmations.
getTransactionSuccess(WalletMainLib.WalletData storage, bytes32, uint256)
(WalletGetterLib.sol, line 153)
Retrieve if transaction was successful.
Arguments
WalletMainLib.WalletData self
bytes32 _id
uint256 _number
Returns
bool