7 |
8 |
Please enter your password to securely decrypt your wallet.
9 |
10 |
19 |
20 |
30 |
--------------------------------------------------------------------------------
/contracts/TestCalls.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.15;
2 |
3 |
4 | /// @title Contract for testing low-level calls issued from the multisig wallet
5 | contract TestCalls {
6 |
7 | // msg.data.length of the latest call to "receive" methods
8 | uint public lastMsgDataLength;
9 |
10 | // msg.value of the latest call to "receive" methods
11 | uint public lastMsgValue;
12 |
13 | uint public uint1;
14 | uint public uint2;
15 | bytes public byteArray1;
16 |
17 | modifier setMsgFields {
18 | lastMsgDataLength = msg.data.length;
19 | lastMsgValue = msg.value;
20 | _;
21 | }
22 |
23 | function TestCalls() setMsgFields public {
24 | // This constructor will be used to test the creation via multisig wallet
25 | }
26 |
27 | function receive1uint(uint a) setMsgFields payable public {
28 | uint1 = a;
29 | }
30 |
31 | function receive2uints(uint a, uint b) setMsgFields payable public {
32 | uint1 = a;
33 | uint2 = b;
34 | }
35 |
36 | function receive1bytes(bytes c) setMsgFields payable public {
37 | byteArray1 = c;
38 | }
39 |
40 | function nonPayable() setMsgFields public {
41 | }
42 |
43 | }
--------------------------------------------------------------------------------
/dapp/less/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | padding-left: 0;
8 | margin: @line-height-computed 0;
9 | list-style: none;
10 | text-align: center;
11 | &:extend(.clearfix all);
12 | li {
13 | display: inline;
14 | > a,
15 | > span {
16 | display: inline-block;
17 | padding: 5px 14px;
18 | background-color: @pager-bg;
19 | border: 1px solid @pager-border;
20 | border-radius: @pager-border-radius;
21 | }
22 |
23 | > a:hover,
24 | > a:focus {
25 | text-decoration: none;
26 | background-color: @pager-hover-bg;
27 | }
28 | }
29 |
30 | .next {
31 | > a,
32 | > span {
33 | float: right;
34 | }
35 | }
36 |
37 | .previous {
38 | > a,
39 | > span {
40 | float: left;
41 | }
42 | }
43 |
44 | .disabled {
45 | > a,
46 | > a:hover,
47 | > a:focus,
48 | > span {
49 | color: @pager-disabled-color;
50 | background-color: @pager-bg;
51 | cursor: @cursor-disabled;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Basics
2 | *.py[cod]
3 | *.pyc
4 | __pycache__
5 |
6 | # Logs
7 | *.log
8 | pip-log.txt
9 |
10 | # Unit test / coverage reports
11 | .coverage
12 | .tox
13 | nosetests.xml
14 |
15 | # Translations
16 | *.mo
17 | *.pot
18 |
19 | # Pycharm
20 | .idea
21 |
22 | # Vagrant
23 | .vagrant
24 |
25 | # Vim
26 |
27 | *~
28 | *.swp
29 | *.swo
30 |
31 | # npm
32 | node_modules/
33 | # package-lock.json
34 | # dapp/package-lock.json
35 |
36 | # Compass
37 | .sass-cache
38 |
39 | # sqlite
40 | *.sqlite
41 |
42 | CACHE
43 |
44 | # OS generated files #
45 | ######################
46 | .DS_Store
47 | .DS_Store?
48 | ._*
49 | .Spotlight-V100
50 | .Trashes
51 | ehthumbs.db
52 | Thumbs.db
53 |
54 | # pip
55 | /src
56 |
57 | # Collected static files via Django's staticfiles app
58 | /staticfiles
59 |
60 | # custom multisig folders
61 | /contracts/abi
62 | /dapp/partials.js
63 | multisigWallet.zip
64 | /dapp/dist
65 |
66 | # Truffle
67 | /build
68 |
69 | # Bower
70 | dapp/bower_components
71 |
72 | # Keys
73 | dapp/localhost.crt
74 | dapp/localhost.key
75 |
76 | # Travis
77 | .travis/deploy_key
78 |
79 | # built package.json
80 | dapp/src/package.json
--------------------------------------------------------------------------------
/dapp/src/partials/modals/removeWallet.html:
--------------------------------------------------------------------------------
1 |
6 |
23 |
33 |
--------------------------------------------------------------------------------
/dapp/src/partials/modals/chooseWeb3Wallet.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 | Ledger wallet
13 |
14 |
15 |
16 |
17 |
18 |
19 | Light wallet
20 |
21 |
22 |
23 |
24 |
25 |
26 | Trezor wallet
27 |
28 |
29 |
30 |
31 |
32 |
33 | Remote node
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/dapp/src/partials/modals/withdrawToken.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | For using the application, you have to agree with our Terms of Use and Privacy Policy.
9 |
10 |
11 | All smart contracts have been audited carefully multiple times.
12 | However, all contracts are WITHOUT ANY WARRANTY; without even
13 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
14 |
15 |
16 | Use at your own risk.
17 |
18 |
19 |
20 |
21 | I have read and understood the Terms of Use
22 |
23 |
24 |
25 |
26 |
27 | I have read and understood the Privacy Policy
28 |
29 |
30 |
31 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/dapp/src/controllers/replaceOwnerCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("replaceOwnerCtrl", function ($scope, Web3Service, Wallet, Utils, Transaction, wallet, owner, $uibModalInstance) {
6 | $scope.owner = owner;
7 | $scope.send = function () {
8 | // Convert owner address to checksum address
9 | $scope.newOwner = Web3Service.toChecksumAddress($scope.newOwner);
10 |
11 | Wallet.replaceOwner(wallet.address, $scope.owner.address, $scope.newOwner, {onlySimulate: false}, function (e, tx) {
12 | if (e) {
13 | Utils.dangerAlert(e);
14 | }
15 | else {
16 | wallet.owners[$scope.newOwner] = {
17 | name: wallet.owners[$scope.owner.address].name,
18 | address: $scope.newOwner
19 | };
20 | delete wallet.owners[$scope.owner.address];
21 |
22 | // Update owners array
23 | Wallet.updateWallet(wallet);
24 | Utils.notification("Replace owner transaction was sent.");
25 | Transaction.add({txHash: tx, callback: function (){
26 | Utils.success("Replace owner transaction was mined.");
27 | }});
28 | $uibModalInstance.close();
29 | }
30 | });
31 | };
32 |
33 | $scope.cancel = function () {
34 | $uibModalInstance.dismiss();
35 | };
36 |
37 | });
38 | }
39 | )();
40 |
--------------------------------------------------------------------------------
/dapp/src/partials/modals/askLightWalletPassword.html:
--------------------------------------------------------------------------------
1 |
6 |
23 |
24 |
41 |
--------------------------------------------------------------------------------
/dapp/less/badges.less:
--------------------------------------------------------------------------------
1 | //
2 | // Badges
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .badge {
8 | display: inline-block;
9 | min-width: 10px;
10 | padding: 3px 7px;
11 | font-size: @font-size-small;
12 | font-weight: @badge-font-weight;
13 | color: @badge-color;
14 | line-height: @badge-line-height;
15 | vertical-align: middle;
16 | white-space: nowrap;
17 | text-align: center;
18 | background-color: @badge-bg;
19 | border-radius: @badge-border-radius;
20 |
21 | // Empty badges collapse automatically (not available in IE8)
22 | &:empty {
23 | display: none;
24 | }
25 |
26 | // Quick fix for badges in buttons
27 | .btn & {
28 | position: relative;
29 | top: -1px;
30 | }
31 |
32 | .btn-xs &,
33 | .btn-group-xs > .btn & {
34 | top: 0;
35 | padding: 1px 5px;
36 | }
37 |
38 | // Hover state, but only for links
39 | a& {
40 | &:hover,
41 | &:focus {
42 | color: @badge-link-hover-color;
43 | text-decoration: none;
44 | cursor: pointer;
45 | }
46 | }
47 |
48 | // Account for badges in navs
49 | .list-group-item.active > &,
50 | .nav-pills > .active > a > & {
51 | color: @badge-active-color;
52 | background-color: @badge-active-bg;
53 | }
54 |
55 | .list-group-item > & {
56 | float: right;
57 | }
58 |
59 | .list-group-item > & + & {
60 | margin-right: 5px;
61 | }
62 |
63 | .nav-pills > li > a > & {
64 | margin-left: 3px;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/dapp/src/routes.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module('multiSigWeb')
5 | .config(function($routeProvider, NotificationProvider){
6 | $routeProvider
7 | .when("/wallets", {
8 | controller: 'walletCtrl',
9 | templateUrl: 'partials/wallets.html'
10 | })
11 | .when("/transactions", {
12 | controller: 'transactionCtrl',
13 | templateUrl: 'partials/transactions.html'
14 | })
15 | .when("/wallet/:address", {
16 | controller: 'walletDetailCtrl',
17 | templateUrl: 'partials/wallet.html'
18 | })
19 | .when("/settings", {
20 | controller: 'settingsCtrl',
21 | templateUrl: 'partials/settings.html'
22 | })
23 | .when("/signup", {
24 | controller: 'notificationsSignupConfirmationCtrl',
25 | templateUrl: 'partials/wallets.html'
26 | })
27 | .when("/accounts", {
28 | // Only for Electron
29 | controller: 'accountCtrl',
30 | templateUrl: 'partials/accounts.html'
31 | })
32 | .when("/address-book", {
33 | controller: 'addressBookCtrl',
34 | templateUrl: 'partials/addressBook.html'
35 | })
36 | .when("/404", {
37 | templateUrl: 'partials/404.html'
38 | })
39 | .otherwise({
40 | redirectTo: '/wallets'
41 | });
42 |
43 | NotificationProvider.setOptions({
44 | delay: 3000,
45 | horizontalSpacing: 60
46 | });
47 | });
48 | }
49 | )();
50 |
--------------------------------------------------------------------------------
/dapp/less/bootstrap.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.3.7 (http://getbootstrap.com)
3 | * Copyright 2011-2016 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 |
7 | // Core variables and mixins
8 | @import "variables.less";
9 | @import "mixins.less";
10 |
11 | // Reset and dependencies
12 | @import "normalize.less";
13 | @import "print.less";
14 | @import "glyphicons.less";
15 |
16 | // Core CSS
17 | @import "scaffolding.less";
18 | @import "type.less";
19 | @import "code.less";
20 | @import "grid.less";
21 | @import "tables.less";
22 | @import "forms.less";
23 | @import "buttons.less";
24 |
25 | // Components
26 | @import "component-animations.less";
27 | @import "dropdowns.less";
28 | @import "button-groups.less";
29 | @import "input-groups.less";
30 | @import "navs.less";
31 | @import "navbar.less";
32 | @import "breadcrumbs.less";
33 | @import "pagination.less";
34 | @import "pager.less";
35 | @import "labels.less";
36 | @import "badges.less";
37 | @import "jumbotron.less";
38 | @import "thumbnails.less";
39 | @import "alerts.less";
40 | @import "progress-bars.less";
41 | @import "media.less";
42 | @import "list-group.less";
43 | @import "panels.less";
44 | @import "responsive-embed.less";
45 | @import "wells.less";
46 | @import "close.less";
47 |
48 | // Components w/ JavaScript
49 | @import "modals.less";
50 | @import "tooltip.less";
51 | @import "popovers.less";
52 | @import "carousel.less";
53 |
54 | // Utility classes
55 | @import "utilities.less";
56 | @import "responsive-utilities.less";
57 |
--------------------------------------------------------------------------------
/dapp/src/controllers/confirmMultisigTransactionOfflineCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("confirmMultisigTransactionOfflineCtrl", function ($scope, address, Wallet, $uibModalInstance, Utils) {
6 |
7 | $scope.transactionId = null;
8 |
9 | $scope.signOffline = function () {
10 | Wallet.confirmTransactionOffline(address, $scope.transactionId, function (e, tx){
11 | if (e) {
12 | Utils.dangerAlert(e);
13 | }
14 | else {
15 | Utils.signed(tx);
16 | $uibModalInstance.close();
17 | }
18 | });
19 | };
20 |
21 | $scope.revokeOffline = function () {
22 |
23 | Wallet.revokeConfirmationOffline(address, $scope.transactionId, function (e, tx) {
24 | if (e) {
25 | Utils.dangerAlert(e);
26 | }
27 | else{
28 | Utils.signed(tx);
29 | $uibModalInstance.close();
30 | }
31 | });
32 |
33 | };
34 |
35 | $scope.executeOffline = function () {
36 |
37 | Wallet.executeTransactionOffline(address, $scope.transactionId, function (e, tx) {
38 | if (e) {
39 | Utils.dangerAlert(e);
40 | }
41 | else{
42 | Utils.signed(tx);
43 | $uibModalInstance.close();
44 | }
45 | });
46 |
47 | };
48 |
49 | $scope.cancel = function () {
50 | $uibModalInstance.dismiss();
51 | };
52 | });
53 | }
54 | )();
55 |
--------------------------------------------------------------------------------
/dapp/src/services/ABI.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .service("ABI", function () {
6 | var factory = {
7 | saved: JSON.parse(localStorage.getItem("abis")) || {},
8 | };
9 |
10 | factory.get = function () {
11 | return JSON.parse(localStorage.getItem("abis")) || {};
12 | };
13 |
14 | factory.update = function (abi, to, name) {
15 | abiDecoder.addABI(abi);
16 | factory.saved[to] = { abi: abi, name: name};
17 |
18 | localStorage.setItem("abis", JSON.stringify(factory.saved));
19 | };
20 |
21 | factory.remove = function (to) {
22 | abiDecoder.removeABI(factory.saved[to].abi);
23 | delete factory.saved[to];
24 | localStorage.setItem("abis", JSON.stringify(factory.saved));
25 | };
26 |
27 | factory.decode = function (data) {
28 | var decoded = abiDecoder.decodeMethod(data);
29 | if (!decoded) {
30 | if (data.length > 20) {
31 | return {
32 | title: data.slice(0, 20) + "...",
33 | notDecoded: true
34 | };
35 | }
36 | else {
37 | return {
38 | title: data.slice(0, 20),
39 | notDecoded: true
40 | };
41 | }
42 | }
43 | else {
44 | return {
45 | title: decoded.name,
46 | params: decoded.params
47 | };
48 | }
49 | };
50 |
51 | return factory;
52 | });
53 | }
54 | )();
55 |
--------------------------------------------------------------------------------
/dapp/src/partials/modals/editToken.html:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
11 |
12 | In order to use the multisig with your Ledger wallet you need to:
13 |
14 |
15 | Connect your Ledger wallet to your USB port
16 |
17 |
18 | Enter your Ledger wallet pin code
19 |
20 |
21 | Update ledger firmware if version < 1.2
22 |
23 |
24 | Install the Ethereum app on your Ledger wallet
25 |
26 |
27 | Enable Browser support and contract data on settings
28 |
29 |
30 | Disable Browser support and enable contract data on settings
31 |
32 |
33 | Allow the multisig DApp to access your accounts on the Ledger wallet
34 |
35 |
36 |
37 |
38 |
39 |
40 | Connect
41 | Approve on Ledger
42 |
43 |
44 |
45 |
46 | Your Ledger is now connected to Multisig.
47 |
48 |
49 |
50 |
55 |
--------------------------------------------------------------------------------
/dapp/less/alerts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Alerts
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // -------------------------
8 |
9 | .alert {
10 | padding: @alert-padding;
11 | margin-bottom: @line-height-computed;
12 | border: 1px solid transparent;
13 | border-radius: @alert-border-radius;
14 |
15 | // Headings for larger alerts
16 | h4 {
17 | margin-top: 0;
18 | // Specified for the h4 to prevent conflicts of changing @headings-color
19 | color: inherit;
20 | }
21 |
22 | // Provide class for links that match alerts
23 | .alert-link {
24 | font-weight: @alert-link-font-weight;
25 | }
26 |
27 | // Improve alignment and spacing of inner content
28 | > p,
29 | > ul {
30 | margin-bottom: 0;
31 | }
32 |
33 | > p + p {
34 | margin-top: 5px;
35 | }
36 | }
37 |
38 | // Dismissible alerts
39 | //
40 | // Expand the right padding and account for the close button's positioning.
41 |
42 | .alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
43 | .alert-dismissible {
44 | padding-right: (@alert-padding + 20);
45 |
46 | // Adjust close link position
47 | .close {
48 | position: relative;
49 | top: -2px;
50 | right: -21px;
51 | color: inherit;
52 | }
53 | }
54 |
55 | // Alternate styles
56 | //
57 | // Generate contextual modifier classes for colorizing the alert.
58 |
59 | .alert-success {
60 | .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
61 | }
62 |
63 | .alert-info {
64 | .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
65 | }
66 |
67 | .alert-warning {
68 | .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
69 | }
70 |
71 | .alert-danger {
72 | .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
73 | }
74 |
--------------------------------------------------------------------------------
/dapp/src/controllers/removeOwnerCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("removeOwnerCtrl", function ($scope, Wallet, Utils, Transaction, wallet, owner, $uibModalInstance) {
6 | $scope.owner = owner;
7 | $scope.send = function () {
8 | Wallet.removeOwner(wallet.address, $scope.owner, {onlySimulate: false}, function (e, tx) {
9 | if (e) {
10 | Utils.dangerAlert(e);
11 | }
12 | else {
13 | // Update owners array
14 | Wallet.updateWallet(wallet);
15 | Utils.notification("Remove owner transaction was sent.");
16 | Transaction.add({txHash: tx, callback: function (){
17 | Utils.success("Remove owner transaction was mined.");
18 | }});
19 | $uibModalInstance.close();
20 | }
21 | });
22 | };
23 |
24 | $scope.simulate = function () {
25 | Wallet.removeOwner(wallet.address, $scope.owner, {onlySimulate: true}, function (e, tx) {
26 | if (e) {
27 | Utils.dangerAlert(e);
28 | }
29 | else {
30 | Utils.simulatedTransaction(tx);
31 | }
32 | });
33 | };
34 |
35 | $scope.getNonce = function () {
36 | var data = Wallet.getRemoveOwnerData(wallet.address, $scope.owner);
37 | Wallet.getNonce(wallet.address, wallet.address, "0x0", data, function (e, nonce) {
38 | if (e) {
39 | Utils.dangerAlert(e);
40 | }
41 | else {
42 | // Open modal
43 | $uibModalInstance.close();
44 | Utils.nonce(nonce);
45 | }
46 | }).call();
47 | };
48 |
49 | $scope.cancel = function () {
50 | $uibModalInstance.dismiss();
51 | };
52 |
53 | });
54 | }
55 | )();
56 |
--------------------------------------------------------------------------------
/dapp/src/partials/addressBook.html:
--------------------------------------------------------------------------------
1 |
7 |
8 | For using the application, you have to agree with our Terms of Use and Privacy Policy .
9 |
10 |
11 | Don't use the wallet hosted at
12 | {{ websites.wallet }} to sign transactions.
13 | Use {{ websites.wallet }} only to
14 | check the status of your wallet. Use a locally installed version for signing.
15 | A version can be obtained here .
16 |
17 |
18 | All smart contracts have been audited carefully multiple times.
19 | However, all contracts are WITHOUT ANY WARRANTY; without even
20 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
21 |
22 |
23 | Use at your own risk.
24 |
25 |
26 |
27 |
28 | I have read and understood the Terms of Use
29 |
30 |
31 |
32 |
33 |
34 | I have read and understood the Privacy Policy
35 |
36 |
37 |
38 |
39 |
40 |
45 |
--------------------------------------------------------------------------------
/dapp/src/controllers/updateRequiredCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("updateRequiredCtrl", function ($scope, Wallet, Transaction, Utils, $uibModalInstance, wallet) {
6 | $scope.address = wallet.address;
7 |
8 |
9 | Wallet
10 | .getRequired($scope.address, function (e, required) {
11 | $scope.required = required.toNumber();
12 | $scope.$apply();
13 | }).call();
14 |
15 |
16 | $scope.update = function () {
17 | Wallet.updateRequired($scope.address, $scope.required, {onlySimulate: false}, function (e, tx) {
18 | if (e) {
19 | Utils.dangerAlert(e);
20 | }
21 | else {
22 | $uibModalInstance.close();
23 | Utils.notification("Update required confirmations transaction was sent.");
24 | Transaction.add({txHash: tx, callback: function () {
25 | Utils.success("Update required confirmations transaction was mined.");
26 | }});
27 | }
28 | });
29 | };
30 |
31 | $scope.signOffline = function () {
32 | Wallet.signUpdateRequired($scope.address, $scope.required, function (e, tx) {
33 | if (e) {
34 | Utils.dangerAlert(e);
35 | }
36 | else {
37 | $uibModalInstance.close();
38 | Utils.signed(tx);
39 | }
40 | });
41 | };
42 |
43 | $scope.getNonce = function () {
44 | var data = Wallet.getUpdateRequiredData($scope.address, $scope.required);
45 | Wallet.getNonce($scope.address, $scope.address, "0x0", data, function (e, nonce) {
46 | // Open modal
47 | $uibModalInstance.close();
48 | Utils.nonce(nonce);
49 | }).call();
50 | };
51 |
52 | $scope.cancel = function () {
53 | $uibModalInstance.dismiss();
54 | };
55 | });
56 | }
57 | )();
58 |
--------------------------------------------------------------------------------
/test/javascript/utils.js:
--------------------------------------------------------------------------------
1 | function getParamFromTxEvent(transaction, paramName, contractFactory, eventName) {
2 | assert.isObject(transaction)
3 | let logs = transaction.logs
4 | if(eventName != null) {
5 | logs = logs.filter((l) => l.event === eventName)
6 | }
7 | assert.equal(logs.length, 1, 'too many logs found!')
8 | let param = logs[0].args[paramName]
9 | if(contractFactory != null) {
10 | let contract = contractFactory.at(param)
11 | assert.isObject(contract, `getting ${paramName} failed for ${param}`)
12 | return contract
13 | } else {
14 | return param
15 | }
16 | }
17 |
18 | function mineBlock(web3, reject, resolve) {
19 | web3.currentProvider.sendAsync({
20 | method: "evm_mine",
21 | jsonrpc: "2.0",
22 | id: new Date().getTime()
23 | }, (e) => (e ? reject(e) : resolve()))
24 | }
25 |
26 | function increaseTimestamp(web3, increase) {
27 | return new Promise((resolve, reject) => {
28 | web3.currentProvider.sendAsync({
29 | method: "evm_increaseTime",
30 | params: [increase],
31 | jsonrpc: "2.0",
32 | id: new Date().getTime()
33 | }, (e) => (e ? reject(e) : mineBlock(web3, reject, resolve)))
34 | })
35 | }
36 |
37 | function balanceOf(web3, account) {
38 | return new Promise((resolve, reject) => web3.eth.getBalance(account, (e, balance) => (e ? reject(e) : resolve(balance))))
39 | }
40 |
41 | async function assertThrowsAsynchronously(test, error) {
42 | try {
43 | await test();
44 | } catch(e) {
45 | if (!error || e instanceof error)
46 | return "everything is fine";
47 | }
48 | throw new Error("Missing rejection" + (error ? " with "+error.name : ""));
49 | }
50 |
51 | Object.assign(exports, {
52 | getParamFromTxEvent,
53 | increaseTimestamp,
54 | balanceOf,
55 | assertThrowsAsynchronously,
56 | })
--------------------------------------------------------------------------------
/dapp/src/controllers/setLimitCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("setLimitCtrl", function ($scope, $uibModalInstance, Utils, Transaction, wallet, Wallet) {
6 | $scope.address = wallet.address;
7 |
8 | Wallet
9 | .getLimit($scope.address, function (e, required) {
10 | if (required ) {
11 | $scope.limit = required.div('1e18').toNumber();
12 | $scope.$apply();
13 | }
14 | }).call();
15 |
16 | $scope.setLimit = function () {
17 | Wallet.updateLimit($scope.address, new Web3().toBigNumber($scope.limit).mul('1e18'), {onlySimulate: false}, function (e, tx){
18 | if (e) {
19 | Utils.dangerAlert(e);
20 | }
21 | else {
22 | $uibModalInstance.close();
23 | Utils.notification("Update daily limit transaction was sent.");
24 | Transaction.add({txHash: tx, callback: function () {
25 | Utils.success("Update daily limit transaction was mined.");
26 | }});
27 | }
28 | });
29 | };
30 |
31 | $scope.sign = function () {
32 | Wallet.signLimit($scope.address, new Web3().toBigNumber($scope.limit).mul('1e18'), function (e, tx) {
33 | if (e) {
34 | Utils.dangerAlert(e);
35 | }
36 | else {
37 | $uibModalInstance.close();
38 | Utils.signed(tx);
39 | }
40 | });
41 | };
42 |
43 | $scope.getNonce = function () {
44 | var data = Wallet.getUpdateLimitData($scope.address, new Web3().toBigNumber($scope.limit).mul('1e18'));
45 | Wallet.getNonce($scope.address, $scope.address, "0x0", data, function (e, nonce) {
46 | // Open modal
47 | $uibModalInstance.close();
48 | Utils.nonce(nonce);
49 | }).call();
50 | };
51 |
52 | $scope.cancel = function () {
53 | $uibModalInstance.dismiss();
54 | };
55 | });
56 | }
57 | )();
58 |
--------------------------------------------------------------------------------
/dapp/src/controllers/withdrawLimitCtrl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This controller manages submit new multisig transaction under daily limit
3 | * using submitTransaction function.
4 | */
5 | (
6 | function () {
7 | angular
8 | .module("multiSigWeb")
9 | .controller("withdrawLimitCtrl", function ($scope, Wallet, Transaction, Utils, wallet, $uibModalInstance, Web3Service) {
10 |
11 | $scope.wallet = wallet;
12 | $scope.tx = {
13 | value: 0,
14 | to: Web3Service.coinbase,
15 | data: '0x0'
16 | };
17 |
18 | $scope.send = function () {
19 | var tx = {};
20 | Object.assign(tx, $scope.tx);
21 | tx.value = new Web3().toBigNumber($scope.tx.value).mul('1e18');
22 |
23 | Wallet.submitTransaction(
24 | $scope.wallet.address,
25 | tx,
26 | null,
27 | null,
28 | null,
29 | {onlySimulate: false},
30 | function (e, tx) {
31 | if (e) {
32 | Utils.dangerAlert(e);
33 | }
34 | else {
35 | Utils.notification("Multisig transaction was sent.");
36 | Transaction.add(
37 | {
38 | txHash: tx,
39 | callback: function () {
40 | Utils.success("Multisig transaction was mined");
41 | }
42 | }
43 | );
44 | $uibModalInstance.close();
45 | }
46 | }
47 | );
48 | };
49 |
50 | $scope.signOff = function () {
51 | var tx = {};
52 | Object.assign(tx, $scope.tx);
53 | tx.value = new Web3().toBigNumber($scope.tx.value).mul('1e18');
54 |
55 | Wallet.signTransaction(
56 | $scope.wallet.address,
57 | tx,
58 | null,
59 | null,
60 | null,
61 | function (e, tx) {
62 | if (e) {
63 | Utils.dangerAlert(e);
64 | }
65 | else{
66 | $uibModalInstance.close();
67 | Utils.signed(tx);
68 | }
69 | }
70 | );
71 | };
72 |
73 | $scope.cancel = function () {
74 | $uibModalInstance.dismiss();
75 | };
76 | });
77 | }
78 | )();
79 |
--------------------------------------------------------------------------------
/dapp/less/progress-bars.less:
--------------------------------------------------------------------------------
1 | //
2 | // Progress bars
3 | // --------------------------------------------------
4 |
5 |
6 | // Bar animations
7 | // -------------------------
8 |
9 | // WebKit
10 | @-webkit-keyframes progress-bar-stripes {
11 | from { background-position: 40px 0; }
12 | to { background-position: 0 0; }
13 | }
14 |
15 | // Spec and IE10+
16 | @keyframes progress-bar-stripes {
17 | from { background-position: 40px 0; }
18 | to { background-position: 0 0; }
19 | }
20 |
21 |
22 | // Bar itself
23 | // -------------------------
24 |
25 | // Outer container
26 | .progress {
27 | overflow: hidden;
28 | height: @line-height-computed;
29 | margin-bottom: @line-height-computed;
30 | background-color: @progress-bg;
31 | border-radius: @progress-border-radius;
32 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
33 | }
34 |
35 | // Bar of progress
36 | .progress-bar {
37 | float: left;
38 | width: 0%;
39 | height: 100%;
40 | font-size: @font-size-small;
41 | line-height: @line-height-computed;
42 | color: @progress-bar-color;
43 | text-align: center;
44 | background-color: @progress-bar-bg;
45 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
46 | .transition(width .6s ease);
47 | }
48 |
49 | // Striped bars
50 | //
51 | // `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the
52 | // `.progress-bar-striped` class, which you just add to an existing
53 | // `.progress-bar`.
54 | .progress-striped .progress-bar,
55 | .progress-bar-striped {
56 | #gradient > .striped();
57 | background-size: 40px 40px;
58 | }
59 |
60 | // Call animation for the active one
61 | //
62 | // `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the
63 | // `.progress-bar.active` approach.
64 | .progress.active .progress-bar,
65 | .progress-bar.active {
66 | .animation(progress-bar-stripes 2s linear infinite);
67 | }
68 |
69 |
70 | // Variations
71 | // -------------------------
72 |
73 | .progress-bar-success {
74 | .progress-bar-variant(@progress-bar-success-bg);
75 | }
76 |
77 | .progress-bar-info {
78 | .progress-bar-variant(@progress-bar-info-bg);
79 | }
80 |
81 | .progress-bar-warning {
82 | .progress-bar-variant(@progress-bar-warning-bg);
83 | }
84 |
85 | .progress-bar-danger {
86 | .progress-bar-variant(@progress-bar-danger-bg);
87 | }
88 |
--------------------------------------------------------------------------------
/dapp/src/controllers/depositTokenCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("depositTokenCtrl", function ($scope, Transaction, Token, $uibModalInstance, Utils, wallet, token) {
6 | $scope.wallet = wallet;
7 | $scope.token = token;
8 | $scope.amount = 10;
9 | $scope.deposit = function () {
10 | Token.transfer(
11 | $scope.token.address,
12 | $scope.wallet.address,
13 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals),
14 | {onlySimulate: false},
15 | function(e, tx){
16 | if (e) {
17 | Utils.dangerAlert(e);
18 | }
19 | else {
20 | Utils.notification("Deposit transaction was sent.");
21 | $uibModalInstance.close();
22 | Transaction.add({
23 | txHash: tx,
24 | callback: function () {
25 | Utils.success("Deposit transaction was mined.");
26 | }
27 | });
28 | }
29 | }
30 | );
31 | };
32 |
33 | $scope.simulate = function () {
34 | Token.transfer(
35 | $scope.token.address,
36 | $scope.wallet.address,
37 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals),
38 | {onlySimulate: true},
39 | function(e, tx){
40 | if (e) {
41 | Utils.dangerAlert(e);
42 | }
43 | else {
44 | Utils.simulatedTransaction(tx);
45 | }
46 | }
47 | );
48 | };
49 |
50 | $scope.sign = function () {
51 | Token.transferOffline(
52 | $scope.token.address,
53 | $scope.wallet.address,
54 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals),
55 | function(e, signed){
56 | if (e) {
57 | Utils.dangerAlert(e);
58 | }
59 | else {
60 | $uibModalInstance.close();
61 | Utils.signed(signed);
62 | }
63 | }
64 | );
65 | };
66 |
67 | $scope.cancel = function () {
68 | $uibModalInstance.dismiss();
69 | };
70 | });
71 | }
72 | )();
73 |
--------------------------------------------------------------------------------
/dapp/src/partials/accounts.html:
--------------------------------------------------------------------------------
1 |
7 |
8 | Gnosis Safe Multisig is a successor to the Multisig Wallet.
9 | Migrate your old Multisig and enjoy new benefits:
10 |
11 |
12 |
13 |
14 |
15 | Future Proof
16 | The upgradable and modular design allows you to be ready for future use-cases and asset-types
17 |
18 |
19 | Formally Verified
20 | While our code is always audited, we've gone one step further and formally
21 | verified the Gnosis Safe smart contracts
22 |
23 |
24 |
25 |
26 | DeFi-Compatible
27 | You will soon be able to interact with various protocols right from the Safe Multisig interface
28 |
29 |
30 | User Experience
31 | Interacting with a Multisignature Wallet has never been easier
32 |
33 |
34 |
35 |
36 |
Upgrading couldn't be easier:
37 |
38 |
39 | Click the button below to create a new Safe. The owner and signature policies of your existing
40 | Multisig will be applied to it automatically.
41 |
42 |
43 | Try out the new interface and learn about the many benefits.
44 |
45 |
46 | As soon as you feel comfortable, start moving funds to your new Safe. read more
47 |
48 |
49 |
50 | Create new Safe
51 |
52 |
55 |
56 |
62 |
--------------------------------------------------------------------------------
/dapp/src/controllers/signedTransactionCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("signedTransactionCtrl", function (Web3Service, $scope, Wallet, Utils, Transaction, $uibModalInstance) {
6 | $scope.sendRawTransaction = function () {
7 | Transaction.sendRawTransaction($scope.tx, function (e, txHash) {
8 | if (e) {
9 | Utils.dangerAlert(e);
10 | }
11 | else {
12 | $uibModalInstance.close();
13 | Utils.notification("Transaction was sent.");
14 | // Wait for transaction receipt to get contract address
15 | Transaction.add({txHash: txHash, callback: function (receipt) {
16 |
17 | if (receipt.contractAddress) {
18 | Web3Service.web3.eth.getCode(receipt.contractAddress, function (e, code){
19 | if (code.length > 100 && Wallet.json.multiSigDailyLimit.binHex.slice(-992) == code.slice(-992)){
20 | Utils.success("Wallet deployed at address: " + receipt.contractAddress);
21 | Wallet.updateWallet({name: "Offline wallet", address: receipt.contractAddress, owners: {}});
22 | Transaction.update(txHash, {multisig: receipt.contractAddress});
23 | }
24 | else {
25 | Utils.success("Contract deployed at address: " + receipt.contractAddress);
26 | }
27 | });
28 | }
29 | else if( receipt.decodedLogs.length && receipt.decodedLogs[0] && receipt.decodedLogs[0].events && receipt.decodedLogs[0].events.length > 1 && receipt.decodedLogs[0].events[1].name == "instantiation"){
30 | var walletAddress = receipt.decodedLogs[0].events[1].value;
31 | Utils.success("Wallet deployed at address:" + walletAddress);
32 | Wallet.updateWallet({name: "Factory wallet", address: walletAddress, owners: {}});
33 | Transaction.update(txHash, {multisig: walletAddress});
34 | }
35 | else {
36 | Utils.success("Transaction was mined.");
37 | }
38 | }});
39 |
40 | }
41 | });
42 | };
43 |
44 | $scope.cancel = function () {
45 | $uibModalInstance.dismiss();
46 | };
47 | });
48 | }
49 | )();
50 |
--------------------------------------------------------------------------------
/dapp/src/controllers/addTokenCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("addTokenCtrl", function (Web3Service, $scope, $uibModalInstance, Wallet, Token, token, wallet) {
6 |
7 | $scope.wallet = wallet;
8 |
9 | if (!$scope.wallet.tokens) {
10 | $scope.wallet.tokens = {};
11 | }
12 |
13 | if (Object.keys(token).length) {
14 | $scope.editMode = true;
15 | token.address = Web3Service.toChecksumAddress(token.address);
16 | }
17 |
18 | $scope.editToken = {}; // Used for editing data
19 | $scope.token = token;
20 | Object.assign($scope.editToken, $scope.token);
21 |
22 | // Refresh token info when address changes
23 | $scope.updateInfo = function () {
24 | var batchInfo = Web3Service.web3.createBatch();
25 |
26 | batchInfo.add(
27 | Token.name(
28 | $scope.editToken.address,
29 | function (e, name) {
30 | if (!e) {
31 | $scope.editToken.name = name;
32 | $scope.$apply();
33 | }
34 | }
35 | )
36 | );
37 |
38 | batchInfo.add(
39 | Token.symbol(
40 | $scope.editToken.address,
41 | function (e, symbol) {
42 | if (!e) {
43 | $scope.editToken.symbol = symbol;
44 | $scope.$apply();
45 | }
46 | }
47 | )
48 | );
49 |
50 | batchInfo.add(
51 | Token.decimals(
52 | $scope.editToken.address,
53 | function (e, decimals) {
54 | if (!e) {
55 | $scope.editToken.decimals = decimals.toNumber();
56 | $scope.$apply();
57 | }
58 | }
59 | )
60 | );
61 |
62 | batchInfo.execute();
63 | };
64 |
65 | $scope.ok = function () {
66 | // Convert token address to checksum address
67 | $scope.editToken.address = Web3Service.toChecksumAddress($scope.editToken.address);
68 |
69 | $scope.wallet.tokens[$scope.editToken.address] = $scope.editToken;
70 | Wallet.updateWallet($scope.wallet);
71 | $uibModalInstance.close();
72 | };
73 |
74 | $scope.cancel = function () {
75 | $uibModalInstance.dismiss();
76 | };
77 | });
78 | }
79 | )();
80 |
--------------------------------------------------------------------------------
/dapp/less/pagination.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination (multiple pages)
3 | // --------------------------------------------------
4 | .pagination {
5 | display: inline-block;
6 | padding-left: 0;
7 | margin: @line-height-computed 0;
8 | border-radius: @border-radius-base;
9 |
10 | > li {
11 | display: inline; // Remove list-style and block-level defaults
12 | > a,
13 | > span {
14 | position: relative;
15 | float: left; // Collapse white-space
16 | padding: @padding-base-vertical @padding-base-horizontal;
17 | line-height: @line-height-base;
18 | text-decoration: none;
19 | color: @pagination-color;
20 | background-color: @pagination-bg;
21 | border: 1px solid @pagination-border;
22 | margin-left: -1px;
23 | }
24 | &:first-child {
25 | > a,
26 | > span {
27 | margin-left: 0;
28 | .border-left-radius(@border-radius-base);
29 | }
30 | }
31 | &:last-child {
32 | > a,
33 | > span {
34 | .border-right-radius(@border-radius-base);
35 | }
36 | }
37 | }
38 |
39 | > li > a,
40 | > li > span {
41 | &:hover,
42 | &:focus {
43 | z-index: 2;
44 | color: @pagination-hover-color;
45 | background-color: @pagination-hover-bg;
46 | border-color: @pagination-hover-border;
47 | }
48 | }
49 |
50 | > .active > a,
51 | > .active > span {
52 | &,
53 | &:hover,
54 | &:focus {
55 | z-index: 3;
56 | color: @pagination-active-color;
57 | background-color: @pagination-active-bg;
58 | border-color: @pagination-active-border;
59 | cursor: default;
60 | }
61 | }
62 |
63 | > .disabled {
64 | > span,
65 | > span:hover,
66 | > span:focus,
67 | > a,
68 | > a:hover,
69 | > a:focus {
70 | color: @pagination-disabled-color;
71 | background-color: @pagination-disabled-bg;
72 | border-color: @pagination-disabled-border;
73 | cursor: @cursor-disabled;
74 | }
75 | }
76 | }
77 |
78 | // Sizing
79 | // --------------------------------------------------
80 |
81 | // Large
82 | .pagination-lg {
83 | .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);
84 | }
85 |
86 | // Small
87 | .pagination-sm {
88 | .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);
89 | }
90 |
--------------------------------------------------------------------------------
/dapp/src/controllers/withdrawTokenCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("withdrawTokenCtrl", function ($scope, Wallet, Token, Transaction, Utils, wallet, token, $uibModalInstance, Web3Service) {
6 |
7 | $scope.wallet = wallet;
8 | $scope.token = token;
9 | $scope.amount = 10;
10 | $scope.to = Web3Service.coinbase;
11 |
12 | $scope.send = function () {
13 | Token.withdraw(
14 | $scope.token.address,
15 | $scope.wallet.address,
16 | $scope.to,
17 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals),
18 | function (e, tx) {
19 | if (e) {
20 | Utils.dangerAlert(e);
21 | }
22 | else {
23 | Utils.notification("Withdraw token transaction was sent.");
24 | $uibModalInstance.close();
25 | Transaction.add({
26 | txHash: tx,
27 | callback: function () {
28 | Utils.success("Withdraw token transaction was mined.");
29 | }
30 | });
31 | }
32 | }
33 | );
34 | };
35 |
36 | $scope.signOff = function () {
37 | Token.withdrawOffline(
38 | $scope.token.address,
39 | $scope.wallet.address,
40 | $scope.to,
41 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals),
42 | function (e, signed) {
43 | $uibModalInstance.close();
44 | Utils.signed(signed);
45 | }
46 | );
47 | };
48 |
49 | $scope.getNonce = function () {
50 | var value = new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals);
51 | var data = Token.withdrawData(
52 | $scope.token.address,
53 | $scope.to,
54 | new Web3().toBigNumber($scope.amount).mul('1e' + $scope.token.decimals)
55 | );
56 | Wallet.getNonce($scope.wallet.address, $scope.token.address, "0x0", data, function (e, nonce) {
57 | if (e) {
58 | Utils.dangerAlert(e);
59 | }
60 | else{
61 | $uibModalInstance.close();
62 | Utils.nonce(nonce);
63 | }
64 | }).call();
65 |
66 | };
67 |
68 | $scope.cancel = function () {
69 | $uibModalInstance.dismiss();
70 | };
71 | });
72 | }
73 | )();
74 |
--------------------------------------------------------------------------------
/dapp/src/controllers/addOwnerCtrl.js:
--------------------------------------------------------------------------------
1 | (
2 | function () {
3 | angular
4 | .module("multiSigWeb")
5 | .controller("addOwnerCtrl", function ($scope, Wallet, Utils, Transaction, wallet, $uibModalInstance) {
6 | $scope.send = function () {
7 | try{
8 | Wallet.addOwner(wallet.address, $scope.owner, {onlySimulate: false}, function (e, tx) {
9 | if (e) {
10 | Utils.dangerAlert(e);
11 | }
12 | else {
13 | // Update owners array
14 | wallet.owners[$scope.owner.address] = $scope.owner;
15 | Wallet.updateWallet(wallet);
16 | Utils.notification("Add owner transaction was sent.");
17 | Transaction.add({txHash: tx, callback: function () {
18 | Utils.success("Add owner transaction was mined.");
19 | }});
20 | $uibModalInstance.close();
21 | }
22 | });
23 | } catch (error) {
24 | Utils.dangerAlert(error);
25 | }
26 | };
27 |
28 | $scope.simulate = function () {
29 | try{
30 | Wallet.addOwner(wallet.address, $scope.owner, {onlySimulate: true}, function (e, tx) {
31 | if (e) {
32 | Utils.dangerAlert(e);
33 | }
34 | else {
35 | Utils.simulatedTransaction(tx);
36 | }
37 | });
38 | } catch (error) {
39 | Utils.dangerAlert(error);
40 | }
41 | };
42 |
43 | $scope.sign = function () {
44 | Wallet.addOwnerOffline(wallet.address, $scope.owner, function (e, tx) {
45 | if (e) {
46 | Utils.dangerAlert(e);
47 | }
48 | else {
49 | $uibModalInstance.close();
50 | Utils.signed(tx);
51 | }
52 | });
53 | };
54 |
55 | $scope.getNonce = function () {
56 | var data = Wallet.getAddOwnerData(wallet.address, $scope.owner);
57 | Wallet.getNonce(wallet.address, wallet.address, "0x0", data, function (e, nonce) {
58 | if (e) {
59 | Utils.dangerAlert(e);
60 | }
61 | else {
62 | // Open modal
63 | $uibModalInstance.close();
64 | Utils.nonce(nonce);
65 | }
66 | }).call();
67 | };
68 |
69 | $scope.cancel = function () {
70 | $uibModalInstance.dismiss();
71 | };
72 |
73 | });
74 | }
75 | )();
76 |
--------------------------------------------------------------------------------
/dapp/less/print.less:
--------------------------------------------------------------------------------
1 | /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
2 |
3 | // ==========================================================================
4 | // Print styles.
5 | // Inlined to avoid the additional HTTP request: h5bp.com/r
6 | // ==========================================================================
7 |
8 | @media print {
9 | *,
10 | *:before,
11 | *:after {
12 | background: transparent !important;
13 | color: #000 !important; // Black prints faster: h5bp.com/s
14 | box-shadow: none !important;
15 | text-shadow: none !important;
16 | }
17 |
18 | a,
19 | a:visited {
20 | text-decoration: underline;
21 | }
22 |
23 | a[href]:after {
24 | content: " (" attr(href) ")";
25 | }
26 |
27 | abbr[title]:after {
28 | content: " (" attr(title) ")";
29 | }
30 |
31 | // Don't show links that are fragment identifiers,
32 | // or use the `javascript:` pseudo protocol
33 | a[href^="#"]:after,
34 | a[href^="javascript:"]:after {
35 | content: "";
36 | }
37 |
38 | pre,
39 | blockquote {
40 | border: 1px solid #999;
41 | page-break-inside: avoid;
42 | }
43 |
44 | thead {
45 | display: table-header-group; // h5bp.com/t
46 | }
47 |
48 | tr,
49 | img {
50 | page-break-inside: avoid;
51 | }
52 |
53 | img {
54 | max-width: 100% !important;
55 | }
56 |
57 | p,
58 | h2,
59 | h3 {
60 | orphans: 3;
61 | widows: 3;
62 | }
63 |
64 | h2,
65 | h3 {
66 | page-break-after: avoid;
67 | }
68 |
69 | // Bootstrap specific changes start
70 |
71 | // Bootstrap components
72 | .navbar {
73 | display: none;
74 | }
75 | .btn,
76 | .dropup > .btn {
77 | > .caret {
78 | border-top-color: #000 !important;
79 | }
80 | }
81 | .label {
82 | border: 1px solid #000;
83 | }
84 |
85 | .table {
86 | border-collapse: collapse !important;
87 |
88 | td,
89 | th {
90 | background-color: #fff !important;
91 | }
92 | }
93 | .table-bordered {
94 | th,
95 | td {
96 | border: 1px solid #ddd !important;
97 | }
98 | }
99 |
100 | // Bootstrap specific changes end
101 | }
102 |
--------------------------------------------------------------------------------
/dapp/src/partials/modals/importLightWalletAccount.html:
--------------------------------------------------------------------------------
1 |
6 |