Merge pull request #69 from gnosis/feature/create-safe-ui-process

Feature - Create Safe [design & 0.0.2 safe-contracts]
This commit is contained in:
Adolfo Panizo 2018-10-17 10:08:32 +02:00 committed by GitHub
commit eb1c6fd123
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
151 changed files with 109254 additions and 48915 deletions

View File

@ -34,6 +34,8 @@ before_script:
# Give some time to docker to enable all services
- sleep 15
- cd ..
script:
- yarn build
after_success:
- cd safe-transaction-history
- docker-compose stop

View File

@ -68,7 +68,6 @@ Add additional notes about how to deploy this on a live system
* [Material UI 1.X](https://material-ui-next.com/) - React components that implement Google's Material Design
* [redux, immutable, reselect, final-form](https://redux.js.org/) - React ecosystem libraries
* [Flow](https://flow.org/) - Sttic Type Checker
* [Surge](https://surge.sh/) - Static web publishing for generating staging links on GitHub
## Contributing

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -50,40 +50,40 @@
"type": "fallback"
}
],
"bytecode": "0x608060405234801561001057600080fd5b506040516102fc3803806102fc83398101806040528101908080519060200190929190805182019291905050508160008173ffffffffffffffffffffffffffffffffffffffff16141515156100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506000815111156101805773ffffffffffffffffffffffffffffffffffffffff60005416600080835160208501846127105a03f46040513d6000823e600082141561017c573d81fd5b5050505b505061016b806101916000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634555d5c91461008b5780635c60da1b146100b6575b73ffffffffffffffffffffffffffffffffffffffff600054163660008037600080366000845af43d6000803e6000811415610086573d6000fd5b3d6000f35b34801561009757600080fd5b506100a061010d565b6040518082815260200191505060405180910390f35b3480156100c257600080fd5b506100cb610116565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60006002905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050905600a165627a7a72305820bab5357556c704bffef0f96326dd27742408be175057ffd8f4f58237314cfd520029",
"deployedBytecode": "0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634555d5c91461008b5780635c60da1b146100b6575b73ffffffffffffffffffffffffffffffffffffffff600054163660008037600080366000845af43d6000803e6000811415610086573d6000fd5b3d6000f35b34801561009757600080fd5b506100a061010d565b6040518082815260200191505060405180910390f35b3480156100c257600080fd5b506100cb610116565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60006002905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050905600a165627a7a72305820bab5357556c704bffef0f96326dd27742408be175057ffd8f4f58237314cfd520029",
"sourceMap": "355:882:0:-;;;610:625;8:9:-1;5:2;;;30:1;27;20:12;5:2;610:625:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;668:11;593:1:13;578:11;:16;;;;570:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;658:11;645:10;;:24;;;;;;;;;;;;;;;;;;508:168;735:1:0;714:11;:18;:22;710:519;;;879:42;875:1;869:8;865:57;1043:1;1040;1026:11;1020:18;1013:4;1000:11;996:22;984:10;976:5;971:3;967:15;954:91;1079:4;1073:11;1124:14;1121:1;1116:3;1101:38;1171:1;1162:7;1159:14;1156:2;;;1188:14;1183:3;1176:27;1156:2;829:390;;;;610:625;;355:882;;;;;;",
"deployedSourceMap": "355:882:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;955:42:13;951:1;945:8;941:57;1030:14;1027:1;1024;1011:34;1125:1;1122;1106:14;1103:1;1091:10;1086:3;1073:54;1161:16;1158:1;1155;1140:38;1206:1;1197:7;1194:14;1191:2;;;1221:16;1218:1;1211:27;1191:2;1263:16;1260:1;1253:27;1426:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1426:104:13;;;;;;;;;;;;;;;;;;;;;;;1302:118;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1302:118:13;;;;;;;;;;;;;;;;;;;;;;;;;;;1426:104;1492:7;1522:1;1515:8;;1426:104;:::o;1302:118::-;1373:7;1403:10;;;;;;;;;;;1396:17;;1302:118;:::o",
"bytecode": "0x608060405234801561001057600080fd5b506040516102fc3803806102fc83398101806040528101908080519060200190929190805182019291905050508160008173ffffffffffffffffffffffffffffffffffffffff16141515156100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506000815111156101805773ffffffffffffffffffffffffffffffffffffffff60005416600080835160208501846127105a03f46040513d6000823e600082141561017c573d81fd5b5050505b505061016b806101916000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634555d5c91461008b5780635c60da1b146100b6575b73ffffffffffffffffffffffffffffffffffffffff600054163660008037600080366000845af43d6000803e6000811415610086573d6000fd5b3d6000f35b34801561009757600080fd5b506100a061010d565b6040518082815260200191505060405180910390f35b3480156100c257600080fd5b506100cb610116565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60006002905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050905600a165627a7a72305820b2de5726e0943c0fae0f20300b651ccee9090eab24beaf21fd7dbc55f5eef5970029",
"deployedBytecode": "0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634555d5c91461008b5780635c60da1b146100b6575b73ffffffffffffffffffffffffffffffffffffffff600054163660008037600080366000845af43d6000803e6000811415610086573d6000fd5b3d6000f35b34801561009757600080fd5b506100a061010d565b6040518082815260200191505060405180910390f35b3480156100c257600080fd5b506100cb610116565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60006002905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050905600a165627a7a72305820b2de5726e0943c0fae0f20300b651ccee9090eab24beaf21fd7dbc55f5eef5970029",
"sourceMap": "355:882:21:-;;;610:625;8:9:-1;5:2;;;30:1;27;20:12;5:2;610:625:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;668:11;593:1:23;578:11;:16;;;;570:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;658:11;645:10;;:24;;;;;;;;;;;;;;;;;;508:168;735:1:21;714:11;:18;:22;710:519;;;879:42;875:1;869:8;865:57;1043:1;1040;1026:11;1020:18;1013:4;1000:11;996:22;984:10;976:5;971:3;967:15;954:91;1079:4;1073:11;1124:14;1121:1;1116:3;1101:38;1171:1;1162:7;1159:14;1156:2;;;1188:14;1183:3;1176:27;1156:2;829:390;;;;610:625;;355:882;;;;;;",
"deployedSourceMap": "355:882:21:-;;;;;;;;;;;;;;;;;;;;;;;;;;955:42:23;951:1;945:8;941:57;1030:14;1027:1;1024;1011:34;1125:1;1122;1106:14;1103:1;1091:10;1086:3;1073:54;1161:16;1158:1;1155;1140:38;1206:1;1197:7;1194:14;1191:2;;;1221:16;1218:1;1211:27;1191:2;1263:16;1260:1;1253:27;1426:104;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1426:104:23;;;;;;;;;;;;;;;;;;;;;;;1302:118;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1302:118:23;;;;;;;;;;;;;;;;;;;;;;;;;;;1426:104;1492:7;1522:1;1515:8;;1426:104;:::o;1302:118::-;1373:7;1403:10;;;;;;;;;;;1396:17;;1302:118;:::o",
"source": "pragma solidity 0.4.24;\nimport \"./Proxy.sol\";\n\n\n/// @title Delegate Constructor Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. It is possible to send along initialization data with the constructor.\n/// @author Stefan George - <stefan@gnosis.pm>\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract DelegateConstructorProxy is Proxy {\n\n /// @dev Constructor function sets address of master copy contract.\n /// @param _masterCopy Master copy address.\n /// @param initializer Data used for a delegate call to initialize the contract.\n constructor(address _masterCopy, bytes initializer) Proxy(_masterCopy)\n public\n {\n if (initializer.length > 0) {\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)\n let success := delegatecall(sub(gas, 10000), masterCopy, add(initializer, 0x20), mload(initializer), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize)\n if eq(success, 0) { revert(ptr, returndatasize) }\n }\n }\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/DelegateConstructorProxy.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/proxies/DelegateConstructorProxy.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/DelegateConstructorProxy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/proxies/DelegateConstructorProxy.sol",
"exportedSymbols": {
"DelegateConstructorProxy": [
23
2740
]
},
"id": 24,
"id": 2741,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1,
"id": 2718,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:0"
"src": "0:23:21"
},
{
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/Proxy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/proxies/Proxy.sol",
"file": "./Proxy.sol",
"id": 2,
"id": 2719,
"nodeType": "ImportDirective",
"scope": 24,
"sourceUnit": 1689,
"src": "24:21:0",
"scope": 2741,
"sourceUnit": 2841,
"src": "24:21:21",
"symbolAliases": [],
"unitAlias": ""
},
@ -93,40 +93,40 @@
"arguments": null,
"baseName": {
"contractScope": null,
"id": 3,
"id": 2720,
"name": "Proxy",
"nodeType": "UserDefinedTypeName",
"referencedDeclaration": 1688,
"src": "392:5:0",
"referencedDeclaration": 2840,
"src": "392:5:21",
"typeDescriptions": {
"typeIdentifier": "t_contract$_Proxy_$1688",
"typeIdentifier": "t_contract$_Proxy_$2840",
"typeString": "contract Proxy"
}
},
"id": 4,
"id": 2721,
"nodeType": "InheritanceSpecifier",
"src": "392:5:0"
"src": "392:5:21"
}
],
"contractDependencies": [
1688
2840
],
"contractKind": "contract",
"documentation": "@title Delegate Constructor Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. It is possible to send along initialization data with the constructor.\n @author Stefan George - <stefan@gnosis.pm>\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 23,
"id": 2740,
"linearizedBaseContracts": [
23,
1688
2740,
2840
],
"name": "DelegateConstructorProxy",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 21,
"id": 2738,
"nodeType": "Block",
"src": "700:535:0",
"src": "700:535:21",
"statements": [
{
"condition": {
@ -135,7 +135,7 @@
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"id": 17,
"id": 2734,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -144,18 +144,18 @@
"argumentTypes": null,
"expression": {
"argumentTypes": null,
"id": 14,
"id": 2731,
"name": "initializer",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 8,
"src": "714:11:0",
"referencedDeclaration": 2725,
"src": "714:11:21",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes memory"
}
},
"id": 15,
"id": 2732,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -163,7 +163,7 @@
"memberName": "length",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "714:18:0",
"src": "714:18:21",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -174,14 +174,14 @@
"rightExpression": {
"argumentTypes": null,
"hexValue": "30",
"id": 16,
"id": 2733,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "number",
"lValueRequested": false,
"nodeType": "Literal",
"src": "735:1:0",
"src": "735:1:21",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_rational_0_by_1",
@ -189,46 +189,46 @@
},
"value": "0"
},
"src": "714:22:0",
"src": "714:22:21",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"falseBody": null,
"id": 20,
"id": 2737,
"nodeType": "IfStatement",
"src": "710:519:0",
"src": "710:519:21",
"trueBody": {
"id": 19,
"id": 2736,
"nodeType": "Block",
"src": "738:491:0",
"src": "738:491:21",
"statements": [
{
"externalReferences": [
{
"initializer": {
"declaration": 8,
"declaration": 2725,
"isOffset": false,
"isSlot": false,
"src": "1000:11:0",
"src": "1026:11:21",
"valueSize": 1
}
},
{
"initializer": {
"declaration": 8,
"declaration": 2725,
"isOffset": false,
"isSlot": false,
"src": "1026:11:0",
"src": "1000:11:21",
"valueSize": 1
}
}
],
"id": 18,
"id": 2735,
"nodeType": "InlineAssembly",
"operations": "{\n let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)\n let success := delegatecall(sub(gas(), 10000), masterCopy, add(initializer, 0x20), mload(initializer), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n if eq(success, 0)\n {\n revert(ptr, returndatasize())\n }\n}",
"src": "820:409:0"
"src": "820:409:21"
}
]
}
@ -236,7 +236,7 @@
]
},
"documentation": "@dev Constructor function sets address of master copy contract.\n @param _masterCopy Master copy address.\n @param initializer Data used for a delegate call to initialize the contract.",
"id": 22,
"id": 2739,
"implemented": true,
"isConstructor": true,
"isDeclaredConst": false,
@ -245,49 +245,49 @@
"arguments": [
{
"argumentTypes": null,
"id": 11,
"id": 2728,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 6,
"src": "668:11:0",
"referencedDeclaration": 2723,
"src": "668:11:21",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
}
],
"id": 12,
"id": 2729,
"modifierName": {
"argumentTypes": null,
"id": 10,
"id": 2727,
"name": "Proxy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1688,
"src": "662:5:0",
"referencedDeclaration": 2840,
"src": "662:5:21",
"typeDescriptions": {
"typeIdentifier": "t_type$_t_contract$_Proxy_$1688_$",
"typeIdentifier": "t_type$_t_contract$_Proxy_$2840_$",
"typeString": "type(contract Proxy)"
}
},
"nodeType": "ModifierInvocation",
"src": "662:18:0"
"src": "662:18:21"
}
],
"name": "",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 9,
"id": 2726,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 6,
"id": 2723,
"name": "_masterCopy",
"nodeType": "VariableDeclaration",
"scope": 22,
"src": "622:19:0",
"scope": 2739,
"src": "622:19:21",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -295,10 +295,10 @@
"typeString": "address"
},
"typeName": {
"id": 5,
"id": 2722,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "622:7:0",
"src": "622:7:21",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -309,11 +309,11 @@
},
{
"constant": false,
"id": 8,
"id": 2725,
"name": "initializer",
"nodeType": "VariableDeclaration",
"scope": 22,
"src": "643:17:0",
"scope": 2739,
"src": "643:17:21",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -321,10 +321,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 7,
"id": 2724,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "643:5:0",
"src": "643:5:21",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -334,56 +334,56 @@
"visibility": "internal"
}
],
"src": "621:40:0"
"src": "621:40:21"
},
"payable": false,
"returnParameters": {
"id": 13,
"id": 2730,
"nodeType": "ParameterList",
"parameters": [],
"src": "700:0:0"
"src": "700:0:21"
},
"scope": 23,
"src": "610:625:0",
"scope": 2740,
"src": "610:625:21",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 24,
"src": "355:882:0"
"scope": 2741,
"src": "355:882:21"
}
],
"src": "0:1238:0"
"src": "0:1238:21"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/DelegateConstructorProxy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/proxies/DelegateConstructorProxy.sol",
"exportedSymbols": {
"DelegateConstructorProxy": [
23
2740
]
},
"id": 24,
"id": 2741,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1,
"id": 2718,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:0"
"src": "0:23:21"
},
{
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/Proxy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/proxies/Proxy.sol",
"file": "./Proxy.sol",
"id": 2,
"id": 2719,
"nodeType": "ImportDirective",
"scope": 24,
"sourceUnit": 1689,
"src": "24:21:0",
"scope": 2741,
"sourceUnit": 2841,
"src": "24:21:21",
"symbolAliases": [],
"unitAlias": ""
},
@ -393,40 +393,40 @@
"arguments": null,
"baseName": {
"contractScope": null,
"id": 3,
"id": 2720,
"name": "Proxy",
"nodeType": "UserDefinedTypeName",
"referencedDeclaration": 1688,
"src": "392:5:0",
"referencedDeclaration": 2840,
"src": "392:5:21",
"typeDescriptions": {
"typeIdentifier": "t_contract$_Proxy_$1688",
"typeIdentifier": "t_contract$_Proxy_$2840",
"typeString": "contract Proxy"
}
},
"id": 4,
"id": 2721,
"nodeType": "InheritanceSpecifier",
"src": "392:5:0"
"src": "392:5:21"
}
],
"contractDependencies": [
1688
2840
],
"contractKind": "contract",
"documentation": "@title Delegate Constructor Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. It is possible to send along initialization data with the constructor.\n @author Stefan George - <stefan@gnosis.pm>\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 23,
"id": 2740,
"linearizedBaseContracts": [
23,
1688
2740,
2840
],
"name": "DelegateConstructorProxy",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 21,
"id": 2738,
"nodeType": "Block",
"src": "700:535:0",
"src": "700:535:21",
"statements": [
{
"condition": {
@ -435,7 +435,7 @@
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"id": 17,
"id": 2734,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -444,18 +444,18 @@
"argumentTypes": null,
"expression": {
"argumentTypes": null,
"id": 14,
"id": 2731,
"name": "initializer",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 8,
"src": "714:11:0",
"referencedDeclaration": 2725,
"src": "714:11:21",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes memory"
}
},
"id": 15,
"id": 2732,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -463,7 +463,7 @@
"memberName": "length",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "714:18:0",
"src": "714:18:21",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -474,14 +474,14 @@
"rightExpression": {
"argumentTypes": null,
"hexValue": "30",
"id": 16,
"id": 2733,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "number",
"lValueRequested": false,
"nodeType": "Literal",
"src": "735:1:0",
"src": "735:1:21",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_rational_0_by_1",
@ -489,46 +489,46 @@
},
"value": "0"
},
"src": "714:22:0",
"src": "714:22:21",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"falseBody": null,
"id": 20,
"id": 2737,
"nodeType": "IfStatement",
"src": "710:519:0",
"src": "710:519:21",
"trueBody": {
"id": 19,
"id": 2736,
"nodeType": "Block",
"src": "738:491:0",
"src": "738:491:21",
"statements": [
{
"externalReferences": [
{
"initializer": {
"declaration": 8,
"declaration": 2725,
"isOffset": false,
"isSlot": false,
"src": "1000:11:0",
"src": "1026:11:21",
"valueSize": 1
}
},
{
"initializer": {
"declaration": 8,
"declaration": 2725,
"isOffset": false,
"isSlot": false,
"src": "1026:11:0",
"src": "1000:11:21",
"valueSize": 1
}
}
],
"id": 18,
"id": 2735,
"nodeType": "InlineAssembly",
"operations": "{\n let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)\n let success := delegatecall(sub(gas(), 10000), masterCopy, add(initializer, 0x20), mload(initializer), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n if eq(success, 0)\n {\n revert(ptr, returndatasize())\n }\n}",
"src": "820:409:0"
"src": "820:409:21"
}
]
}
@ -536,7 +536,7 @@
]
},
"documentation": "@dev Constructor function sets address of master copy contract.\n @param _masterCopy Master copy address.\n @param initializer Data used for a delegate call to initialize the contract.",
"id": 22,
"id": 2739,
"implemented": true,
"isConstructor": true,
"isDeclaredConst": false,
@ -545,49 +545,49 @@
"arguments": [
{
"argumentTypes": null,
"id": 11,
"id": 2728,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 6,
"src": "668:11:0",
"referencedDeclaration": 2723,
"src": "668:11:21",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
}
],
"id": 12,
"id": 2729,
"modifierName": {
"argumentTypes": null,
"id": 10,
"id": 2727,
"name": "Proxy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1688,
"src": "662:5:0",
"referencedDeclaration": 2840,
"src": "662:5:21",
"typeDescriptions": {
"typeIdentifier": "t_type$_t_contract$_Proxy_$1688_$",
"typeIdentifier": "t_type$_t_contract$_Proxy_$2840_$",
"typeString": "type(contract Proxy)"
}
},
"nodeType": "ModifierInvocation",
"src": "662:18:0"
"src": "662:18:21"
}
],
"name": "",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 9,
"id": 2726,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 6,
"id": 2723,
"name": "_masterCopy",
"nodeType": "VariableDeclaration",
"scope": 22,
"src": "622:19:0",
"scope": 2739,
"src": "622:19:21",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -595,10 +595,10 @@
"typeString": "address"
},
"typeName": {
"id": 5,
"id": 2722,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "622:7:0",
"src": "622:7:21",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -609,11 +609,11 @@
},
{
"constant": false,
"id": 8,
"id": 2725,
"name": "initializer",
"nodeType": "VariableDeclaration",
"scope": 22,
"src": "643:17:0",
"scope": 2739,
"src": "643:17:21",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -621,10 +621,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 7,
"id": 2724,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "643:5:0",
"src": "643:5:21",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -634,27 +634,27 @@
"visibility": "internal"
}
],
"src": "621:40:0"
"src": "621:40:21"
},
"payable": false,
"returnParameters": {
"id": 13,
"id": 2730,
"nodeType": "ParameterList",
"parameters": [],
"src": "700:0:0"
"src": "700:0:21"
},
"scope": 23,
"src": "610:625:0",
"scope": 2740,
"src": "610:625:21",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 24,
"src": "355:882:0"
"scope": 2741,
"src": "355:882:21"
}
],
"src": "0:1238:0"
"src": "0:1238:21"
},
"compiler": {
"name": "solc",
@ -662,5 +662,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.083Z"
"updatedAt": "2018-10-05T14:25:58.944Z"
}

View File

@ -1,31 +1,31 @@
{
"contractName": "Enum",
"abi": [],
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820641ab8b295edfaa2b1c8a8e0ae7d17ea2f4c8b95ea27e45d8947ed9a4799ca1f0029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a72305820641ab8b295edfaa2b1c8a8e0ae7d17ea2f4c8b95ea27e45d8947ed9a4799ca1f0029",
"sourceMap": "115:95:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115:95:1;;;;;;;",
"deployedSourceMap": "115:95:1:-;;;;;",
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820e8f35ac07bd2a835eacbee7ba38b086a012b371f6bdc0da93abfb72fe3b38ec20029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a72305820e8f35ac07bd2a835eacbee7ba38b086a012b371f6bdc0da93abfb72fe3b38ec20029",
"sourceMap": "115:95:7:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;115:95:7;;;;;;;",
"deployedSourceMap": "115:95:7:-;;;;;",
"source": "pragma solidity 0.4.24;\n\n\n/// @title Enum - Collection of enums\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract Enum {\n enum Operation {\n Call,\n DelegateCall,\n Create\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/Enum.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/Enum.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/Enum.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/Enum.sol",
"exportedSymbols": {
"Enum": [
30
1659
]
},
"id": 31,
"id": 1660,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 25,
"id": 1654,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:1"
"src": "0:23:7"
},
{
"baseContracts": [],
@ -33,66 +33,66 @@
"contractKind": "contract",
"documentation": "@title Enum - Collection of enums\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 30,
"id": 1659,
"linearizedBaseContracts": [
30
1659
],
"name": "Enum",
"nodeType": "ContractDefinition",
"nodes": [
{
"canonicalName": "Enum.Operation",
"id": 29,
"id": 1658,
"members": [
{
"id": 26,
"id": 1655,
"name": "Call",
"nodeType": "EnumValue",
"src": "160:4:1"
"src": "160:4:7"
},
{
"id": 27,
"id": 1656,
"name": "DelegateCall",
"nodeType": "EnumValue",
"src": "174:12:1"
"src": "174:12:7"
},
{
"id": 28,
"id": 1657,
"name": "Create",
"nodeType": "EnumValue",
"src": "196:6:1"
"src": "196:6:7"
}
],
"name": "Operation",
"nodeType": "EnumDefinition",
"src": "135:73:1"
"src": "135:73:7"
}
],
"scope": 31,
"src": "115:95:1"
"scope": 1660,
"src": "115:95:7"
}
],
"src": "0:211:1"
"src": "0:211:7"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/Enum.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/Enum.sol",
"exportedSymbols": {
"Enum": [
30
1659
]
},
"id": 31,
"id": 1660,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 25,
"id": 1654,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:1"
"src": "0:23:7"
},
{
"baseContracts": [],
@ -100,46 +100,46 @@
"contractKind": "contract",
"documentation": "@title Enum - Collection of enums\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 30,
"id": 1659,
"linearizedBaseContracts": [
30
1659
],
"name": "Enum",
"nodeType": "ContractDefinition",
"nodes": [
{
"canonicalName": "Enum.Operation",
"id": 29,
"id": 1658,
"members": [
{
"id": 26,
"id": 1655,
"name": "Call",
"nodeType": "EnumValue",
"src": "160:4:1"
"src": "160:4:7"
},
{
"id": 27,
"id": 1656,
"name": "DelegateCall",
"nodeType": "EnumValue",
"src": "174:12:1"
"src": "174:12:7"
},
{
"id": 28,
"id": 1657,
"name": "Create",
"nodeType": "EnumValue",
"src": "196:6:1"
"src": "196:6:7"
}
],
"name": "Operation",
"nodeType": "EnumDefinition",
"src": "135:73:1"
"src": "135:73:7"
}
],
"scope": 31,
"src": "115:95:1"
"scope": 1660,
"src": "115:95:7"
}
],
"src": "0:211:1"
"src": "0:211:7"
},
"compiler": {
"name": "solc",
@ -147,5 +147,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.083Z"
"updatedAt": "2018-10-05T14:25:58.921Z"
}

View File

@ -7,31 +7,31 @@
"type": "fallback"
}
],
"bytecode": "0x6080604052348015600f57600080fd5b50603280601d6000396000f30060806040520000a165627a7a723058208226d93ca47e5b6cb455362823a9ae7ae1ffe3fb79b732dd39f124670f780a070029",
"deployedBytecode": "0x60806040520000a165627a7a723058208226d93ca47e5b6cb455362823a9ae7ae1ffe3fb79b732dd39f124670f780a070029",
"sourceMap": "167:155:2:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;167:155:2;;;;;;;",
"deployedSourceMap": "167:155:2:-;;;",
"bytecode": "0x6080604052348015600f57600080fd5b50603280601d6000396000f30060806040520000a165627a7a723058200c4d2e3a714c9a462ec30383030f16e7035d8647c8e18373ebc02f115b5a1d690029",
"deployedBytecode": "0x60806040520000a165627a7a723058200c4d2e3a714c9a462ec30383030f16e7035d8647c8e18373ebc02f115b5a1d690029",
"sourceMap": "167:155:8:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;167:155:8;;;;;;;",
"deployedSourceMap": "167:155:8:-;;;",
"source": "pragma solidity 0.4.24;\n\n\n/// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract EtherPaymentFallback {\n\n /// @dev Fallback function accepts Ether transactions.\n function ()\n external\n payable\n {\n\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/EtherPaymentFallback.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/EtherPaymentFallback.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/EtherPaymentFallback.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/EtherPaymentFallback.sol",
"exportedSymbols": {
"EtherPaymentFallback": [
37
1666
]
},
"id": 38,
"id": 1667,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 32,
"id": 1661,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:2"
"src": "0:23:8"
},
{
"baseContracts": [],
@ -39,22 +39,22 @@
"contractKind": "contract",
"documentation": "@title EtherPaymentFallback - A contract that has a fallback to accept ether payments\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 37,
"id": 1666,
"linearizedBaseContracts": [
37
1666
],
"name": "EtherPaymentFallback",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 35,
"id": 1664,
"nodeType": "Block",
"src": "312:8:2",
"src": "312:8:8",
"statements": []
},
"documentation": "@dev Fallback function accepts Ether transactions.",
"id": 36,
"id": 1665,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -62,50 +62,50 @@
"name": "",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 33,
"id": 1662,
"nodeType": "ParameterList",
"parameters": [],
"src": "272:2:2"
"src": "272:2:8"
},
"payable": true,
"returnParameters": {
"id": 34,
"id": 1663,
"nodeType": "ParameterList",
"parameters": [],
"src": "312:0:2"
"src": "312:0:8"
},
"scope": 37,
"src": "263:57:2",
"scope": 1666,
"src": "263:57:8",
"stateMutability": "payable",
"superFunction": null,
"visibility": "external"
}
],
"scope": 38,
"src": "167:155:2"
"scope": 1667,
"src": "167:155:8"
}
],
"src": "0:323:2"
"src": "0:323:8"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/EtherPaymentFallback.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/EtherPaymentFallback.sol",
"exportedSymbols": {
"EtherPaymentFallback": [
37
1666
]
},
"id": 38,
"id": 1667,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 32,
"id": 1661,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:2"
"src": "0:23:8"
},
{
"baseContracts": [],
@ -113,22 +113,22 @@
"contractKind": "contract",
"documentation": "@title EtherPaymentFallback - A contract that has a fallback to accept ether payments\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 37,
"id": 1666,
"linearizedBaseContracts": [
37
1666
],
"name": "EtherPaymentFallback",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 35,
"id": 1664,
"nodeType": "Block",
"src": "312:8:2",
"src": "312:8:8",
"statements": []
},
"documentation": "@dev Fallback function accepts Ether transactions.",
"id": 36,
"id": 1665,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -136,30 +136,30 @@
"name": "",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 33,
"id": 1662,
"nodeType": "ParameterList",
"parameters": [],
"src": "272:2:2"
"src": "272:2:8"
},
"payable": true,
"returnParameters": {
"id": 34,
"id": 1663,
"nodeType": "ParameterList",
"parameters": [],
"src": "312:0:2"
"src": "312:0:8"
},
"scope": 37,
"src": "263:57:2",
"scope": 1666,
"src": "263:57:8",
"stateMutability": "payable",
"superFunction": null,
"visibility": "external"
}
],
"scope": 38,
"src": "167:155:2"
"scope": 1667,
"src": "167:155:8"
}
],
"src": "0:323:2"
"src": "0:323:8"
},
"compiler": {
"name": "solc",
@ -167,5 +167,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.083Z"
"updatedAt": "2018-10-05T14:25:58.922Z"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,339 @@
{
"contractName": "ISignatureValidator",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_data",
"type": "bytes"
},
{
"name": "_signature",
"type": "bytes"
}
],
"name": "isValidSignature",
"outputs": [
{
"name": "isValid",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"sourceMap": "",
"deployedSourceMap": "",
"source": "pragma solidity 0.4.24;\n\ncontract ISignatureValidator {\n /**\n * @dev Should return whether the signature provided is valid for the provided data\n * @param _data Arbitrary length data signed on the behalf of address(this)\n * @param _signature Signature byte array associated with _data\n *\n * MUST return a bool upon valid or invalid signature with corresponding _data\n * MUST take (bytes, bytes) as arguments\n */ \n function isValidSignature(\n bytes _data, \n bytes _signature)\n public\n returns (bool isValid); \n}",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/interfaces/ISignatureValidator.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/interfaces/ISignatureValidator.sol",
"exportedSymbols": {
"ISignatureValidator": [
1803
]
},
"id": 1804,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1793,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:13"
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": false,
"id": 1803,
"linearizedBaseContracts": [
1803
],
"name": "ISignatureValidator",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": null,
"documentation": "@dev Should return whether the signature provided is valid for the provided data\n@param _data Arbitrary length data signed on the behalf of address(this)\n@param _signature Signature byte array associated with _data\n * MUST return a bool upon valid or invalid signature with corresponding _data\nMUST take (bytes, bytes) as arguments",
"id": 1802,
"implemented": false,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [],
"name": "isValidSignature",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1798,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1795,
"name": "_data",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "476:11:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes"
},
"typeName": {
"id": 1794,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "476:5:13",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
}
},
"value": null,
"visibility": "internal"
},
{
"constant": false,
"id": 1797,
"name": "_signature",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "498:16:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes"
},
"typeName": {
"id": 1796,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "498:5:13",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "466:49:13"
},
"payable": false,
"returnParameters": {
"id": 1801,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1800,
"name": "isValid",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "548:12:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
},
"typeName": {
"id": 1799,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "548:4:13",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "547:14:13"
},
"scope": 1803,
"src": "441:121:13",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1804,
"src": "25:540:13"
}
],
"src": "0:565:13"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/interfaces/ISignatureValidator.sol",
"exportedSymbols": {
"ISignatureValidator": [
1803
]
},
"id": 1804,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1793,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:13"
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": false,
"id": 1803,
"linearizedBaseContracts": [
1803
],
"name": "ISignatureValidator",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": null,
"documentation": "@dev Should return whether the signature provided is valid for the provided data\n@param _data Arbitrary length data signed on the behalf of address(this)\n@param _signature Signature byte array associated with _data\n * MUST return a bool upon valid or invalid signature with corresponding _data\nMUST take (bytes, bytes) as arguments",
"id": 1802,
"implemented": false,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [],
"name": "isValidSignature",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1798,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1795,
"name": "_data",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "476:11:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes"
},
"typeName": {
"id": 1794,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "476:5:13",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
}
},
"value": null,
"visibility": "internal"
},
{
"constant": false,
"id": 1797,
"name": "_signature",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "498:16:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes"
},
"typeName": {
"id": 1796,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "498:5:13",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "466:49:13"
},
"payable": false,
"returnParameters": {
"id": 1801,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1800,
"name": "isValid",
"nodeType": "VariableDeclaration",
"scope": 1802,
"src": "548:12:13",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
},
"typeName": {
"id": 1799,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "548:4:13",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "547:14:13"
},
"scope": 1803,
"src": "441:121:13",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1804,
"src": "25:540:13"
}
],
"src": "0:565:13"
},
"compiler": {
"name": "solc",
"version": "0.4.24+commit.e67f0147.Emscripten.clang"
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-10-05T14:25:58.938Z"
}

View File

@ -16,40 +16,40 @@
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b50610276806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637de7edef14610046575b600080fd5b34801561005257600080fd5b50610087600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610089565b005b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610152576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001807f4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207481526020017f68697320636f6e7472616374000000000000000000000000000000000000000081525060400191505060405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1614151515610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a72305820243ca7a44eb0464a47c14309cc3a29e407df6e966674981a787df22c0d9280220029",
"deployedBytecode": "0x608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637de7edef14610046575b600080fd5b34801561005257600080fd5b50610087600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610089565b005b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610152576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001807f4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207481526020017f68697320636f6e7472616374000000000000000000000000000000000000000081525060400191505060405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1614151515610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a72305820243ca7a44eb0464a47c14309cc3a29e407df6e966674981a787df22c0d9280220029",
"sourceMap": "203:673:7:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;203:673:7;;;;;;;",
"deployedSourceMap": "203:673:7:-;;;;;;;;;;;;;;;;;;;;;;;;626:248;;8:9:-1;5:2;;;30:1;27;20:12;5:2;626:248:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;244:4:16;222:27;;:10;:27;;;214:84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;791:1:7;776:11;:16;;;;768:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;856:11;843:10;;:24;;;;;;;;;;;;;;;;;;626:248;:::o",
"bytecode": "0x608060405234801561001057600080fd5b50610276806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637de7edef14610046575b600080fd5b34801561005257600080fd5b50610087600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610089565b005b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610152576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001807f4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207481526020017f68697320636f6e7472616374000000000000000000000000000000000000000081525060400191505060405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1614151515610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a7230582035e9d5d611938f796affd4397aed671c5c4079783e0a67a874440cb154a411440029",
"deployedBytecode": "0x608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637de7edef14610046575b600080fd5b34801561005257600080fd5b50610087600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610089565b005b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610152576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602c8152602001807f4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207481526020017f68697320636f6e7472616374000000000000000000000000000000000000000081525060400191505060405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1614151515610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001807f496e76616c6964206d617374657220636f707920616464726573732070726f7681526020017f696465640000000000000000000000000000000000000000000000000000000081525060400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a7230582035e9d5d611938f796affd4397aed671c5c4079783e0a67a874440cb154a411440029",
"sourceMap": "203:673:9:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;203:673:9;;;;;;;",
"deployedSourceMap": "203:673:9:-;;;;;;;;;;;;;;;;;;;;;;;;626:248;;8:9:-1;5:2;;;30:1;27;20:12;5:2;626:248:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;244:4:11;222:27;;:10;:27;;;214:84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;791:1:9;776:11;:16;;;;768:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;856:11;843:10;;:24;;;;;;;;;;;;;;;;;;626:248;:::o",
"source": "pragma solidity 0.4.24;\nimport \"./SelfAuthorized.sol\";\n\n\n/// @title MasterCopy - Base for master copy contracts (should always be first super contract)\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract MasterCopy is SelfAuthorized {\n // masterCopy always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.\n // It should also always be ensured that the address is stored alone (uses a full word)\n address masterCopy;\n\n /// @dev Allows to upgrade the contract. This can only be done via a Safe transaction.\n /// @param _masterCopy New contract address.\n function changeMasterCopy(address _masterCopy)\n public\n authorized\n {\n // Master copy address cannot be null.\n require(_masterCopy != 0, \"Invalid master copy address provided\");\n masterCopy = _masterCopy;\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/MasterCopy.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/MasterCopy.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/MasterCopy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/MasterCopy.sol",
"exportedSymbols": {
"MasterCopy": [
813
1693
]
},
"id": 814,
"id": 1694,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 788,
"id": 1668,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:7"
"src": "0:23:9"
},
{
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SelfAuthorized.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SelfAuthorized.sol",
"file": "./SelfAuthorized.sol",
"id": 789,
"id": 1669,
"nodeType": "ImportDirective",
"scope": 814,
"sourceUnit": 1766,
"src": "24:30:7",
"scope": 1694,
"sourceUnit": 1736,
"src": "24:30:9",
"symbolAliases": [],
"unitAlias": ""
},
@ -59,42 +59,42 @@
"arguments": null,
"baseName": {
"contractScope": null,
"id": 790,
"id": 1670,
"name": "SelfAuthorized",
"nodeType": "UserDefinedTypeName",
"referencedDeclaration": 1765,
"src": "226:14:7",
"referencedDeclaration": 1735,
"src": "226:14:9",
"typeDescriptions": {
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
},
"id": 791,
"id": 1671,
"nodeType": "InheritanceSpecifier",
"src": "226:14:7"
"src": "226:14:9"
}
],
"contractDependencies": [
1765
1735
],
"contractKind": "contract",
"documentation": "@title MasterCopy - Base for master copy contracts (should always be first super contract)\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 813,
"id": 1693,
"linearizedBaseContracts": [
813,
1765
1693,
1735
],
"name": "MasterCopy",
"nodeType": "ContractDefinition",
"nodes": [
{
"constant": false,
"id": 793,
"id": 1673,
"name": "masterCopy",
"nodeType": "VariableDeclaration",
"scope": 813,
"src": "465:18:7",
"scope": 1693,
"src": "465:18:9",
"stateVariable": true,
"storageLocation": "default",
"typeDescriptions": {
@ -102,10 +102,10 @@
"typeString": "address"
},
"typeName": {
"id": 792,
"id": 1672,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "465:7:7",
"src": "465:7:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -116,9 +116,9 @@
},
{
"body": {
"id": 811,
"id": 1691,
"nodeType": "Block",
"src": "711:163:7",
"src": "711:163:9",
"statements": [
{
"expression": {
@ -130,19 +130,19 @@
"typeIdentifier": "t_address",
"typeString": "address"
},
"id": 803,
"id": 1683,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftExpression": {
"argumentTypes": null,
"id": 801,
"id": 1681,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 795,
"src": "776:11:7",
"referencedDeclaration": 1675,
"src": "776:11:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -153,14 +153,14 @@
"rightExpression": {
"argumentTypes": null,
"hexValue": "30",
"id": 802,
"id": 1682,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "number",
"lValueRequested": false,
"nodeType": "Literal",
"src": "791:1:7",
"src": "791:1:9",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_rational_0_by_1",
@ -168,7 +168,7 @@
},
"value": "0"
},
"src": "776:16:7",
"src": "776:16:9",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -177,14 +177,14 @@
{
"argumentTypes": null,
"hexValue": "496e76616c6964206d617374657220636f707920616464726573732070726f7669646564",
"id": 804,
"id": 1684,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "794:38:7",
"src": "794:38:9",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_108d84599042957b954e89d43b52f80be89321dfc114a37800028eba58dafc87",
@ -204,21 +204,21 @@
"typeString": "literal_string \"Invalid master copy address provided\""
}
],
"id": 800,
"id": 1680,
"name": "require",
"nodeType": "Identifier",
"overloadedDeclarations": [
3831,
3832
4018,
4019
],
"referencedDeclaration": 3832,
"src": "768:7:7",
"referencedDeclaration": 4019,
"src": "768:7:9",
"typeDescriptions": {
"typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$",
"typeString": "function (bool,string memory) pure"
}
},
"id": 805,
"id": 1685,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -226,32 +226,32 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "768:65:7",
"src": "768:65:9",
"typeDescriptions": {
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 806,
"id": 1686,
"nodeType": "ExpressionStatement",
"src": "768:65:7"
"src": "768:65:9"
},
{
"expression": {
"argumentTypes": null,
"id": 809,
"id": 1689,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftHandSide": {
"argumentTypes": null,
"id": 807,
"id": 1687,
"name": "masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 793,
"src": "843:10:7",
"referencedDeclaration": 1673,
"src": "843:10:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -261,68 +261,68 @@
"operator": "=",
"rightHandSide": {
"argumentTypes": null,
"id": 808,
"id": 1688,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 795,
"src": "856:11:7",
"referencedDeclaration": 1675,
"src": "856:11:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"src": "843:24:7",
"src": "843:24:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"id": 810,
"id": 1690,
"nodeType": "ExpressionStatement",
"src": "843:24:7"
"src": "843:24:9"
}
]
},
"documentation": "@dev Allows to upgrade the contract. This can only be done via a Safe transaction.\n @param _masterCopy New contract address.",
"id": 812,
"id": 1692,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [
{
"arguments": null,
"id": 798,
"id": 1678,
"modifierName": {
"argumentTypes": null,
"id": 797,
"id": 1677,
"name": "authorized",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1764,
"src": "696:10:7",
"referencedDeclaration": 1734,
"src": "696:10:9",
"typeDescriptions": {
"typeIdentifier": "t_modifier$__$",
"typeString": "modifier ()"
}
},
"nodeType": "ModifierInvocation",
"src": "696:10:7"
"src": "696:10:9"
}
],
"name": "changeMasterCopy",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 796,
"id": 1676,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 795,
"id": 1675,
"name": "_masterCopy",
"nodeType": "VariableDeclaration",
"scope": 812,
"src": "652:19:7",
"scope": 1692,
"src": "652:19:9",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -330,10 +330,10 @@
"typeString": "address"
},
"typeName": {
"id": 794,
"id": 1674,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "652:7:7",
"src": "652:7:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -343,56 +343,56 @@
"visibility": "internal"
}
],
"src": "651:21:7"
"src": "651:21:9"
},
"payable": false,
"returnParameters": {
"id": 799,
"id": 1679,
"nodeType": "ParameterList",
"parameters": [],
"src": "711:0:7"
"src": "711:0:9"
},
"scope": 813,
"src": "626:248:7",
"scope": 1693,
"src": "626:248:9",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 814,
"src": "203:673:7"
"scope": 1694,
"src": "203:673:9"
}
],
"src": "0:877:7"
"src": "0:877:9"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/MasterCopy.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/MasterCopy.sol",
"exportedSymbols": {
"MasterCopy": [
813
1693
]
},
"id": 814,
"id": 1694,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 788,
"id": 1668,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:7"
"src": "0:23:9"
},
{
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SelfAuthorized.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SelfAuthorized.sol",
"file": "./SelfAuthorized.sol",
"id": 789,
"id": 1669,
"nodeType": "ImportDirective",
"scope": 814,
"sourceUnit": 1766,
"src": "24:30:7",
"scope": 1694,
"sourceUnit": 1736,
"src": "24:30:9",
"symbolAliases": [],
"unitAlias": ""
},
@ -402,42 +402,42 @@
"arguments": null,
"baseName": {
"contractScope": null,
"id": 790,
"id": 1670,
"name": "SelfAuthorized",
"nodeType": "UserDefinedTypeName",
"referencedDeclaration": 1765,
"src": "226:14:7",
"referencedDeclaration": 1735,
"src": "226:14:9",
"typeDescriptions": {
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
},
"id": 791,
"id": 1671,
"nodeType": "InheritanceSpecifier",
"src": "226:14:7"
"src": "226:14:9"
}
],
"contractDependencies": [
1765
1735
],
"contractKind": "contract",
"documentation": "@title MasterCopy - Base for master copy contracts (should always be first super contract)\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 813,
"id": 1693,
"linearizedBaseContracts": [
813,
1765
1693,
1735
],
"name": "MasterCopy",
"nodeType": "ContractDefinition",
"nodes": [
{
"constant": false,
"id": 793,
"id": 1673,
"name": "masterCopy",
"nodeType": "VariableDeclaration",
"scope": 813,
"src": "465:18:7",
"scope": 1693,
"src": "465:18:9",
"stateVariable": true,
"storageLocation": "default",
"typeDescriptions": {
@ -445,10 +445,10 @@
"typeString": "address"
},
"typeName": {
"id": 792,
"id": 1672,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "465:7:7",
"src": "465:7:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -459,9 +459,9 @@
},
{
"body": {
"id": 811,
"id": 1691,
"nodeType": "Block",
"src": "711:163:7",
"src": "711:163:9",
"statements": [
{
"expression": {
@ -473,19 +473,19 @@
"typeIdentifier": "t_address",
"typeString": "address"
},
"id": 803,
"id": 1683,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftExpression": {
"argumentTypes": null,
"id": 801,
"id": 1681,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 795,
"src": "776:11:7",
"referencedDeclaration": 1675,
"src": "776:11:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -496,14 +496,14 @@
"rightExpression": {
"argumentTypes": null,
"hexValue": "30",
"id": 802,
"id": 1682,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "number",
"lValueRequested": false,
"nodeType": "Literal",
"src": "791:1:7",
"src": "791:1:9",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_rational_0_by_1",
@ -511,7 +511,7 @@
},
"value": "0"
},
"src": "776:16:7",
"src": "776:16:9",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -520,14 +520,14 @@
{
"argumentTypes": null,
"hexValue": "496e76616c6964206d617374657220636f707920616464726573732070726f7669646564",
"id": 804,
"id": 1684,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "794:38:7",
"src": "794:38:9",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_108d84599042957b954e89d43b52f80be89321dfc114a37800028eba58dafc87",
@ -547,21 +547,21 @@
"typeString": "literal_string \"Invalid master copy address provided\""
}
],
"id": 800,
"id": 1680,
"name": "require",
"nodeType": "Identifier",
"overloadedDeclarations": [
3831,
3832
4018,
4019
],
"referencedDeclaration": 3832,
"src": "768:7:7",
"referencedDeclaration": 4019,
"src": "768:7:9",
"typeDescriptions": {
"typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$",
"typeString": "function (bool,string memory) pure"
}
},
"id": 805,
"id": 1685,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -569,32 +569,32 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "768:65:7",
"src": "768:65:9",
"typeDescriptions": {
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 806,
"id": 1686,
"nodeType": "ExpressionStatement",
"src": "768:65:7"
"src": "768:65:9"
},
{
"expression": {
"argumentTypes": null,
"id": 809,
"id": 1689,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftHandSide": {
"argumentTypes": null,
"id": 807,
"id": 1687,
"name": "masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 793,
"src": "843:10:7",
"referencedDeclaration": 1673,
"src": "843:10:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -604,68 +604,68 @@
"operator": "=",
"rightHandSide": {
"argumentTypes": null,
"id": 808,
"id": 1688,
"name": "_masterCopy",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 795,
"src": "856:11:7",
"referencedDeclaration": 1675,
"src": "856:11:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"src": "843:24:7",
"src": "843:24:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"id": 810,
"id": 1690,
"nodeType": "ExpressionStatement",
"src": "843:24:7"
"src": "843:24:9"
}
]
},
"documentation": "@dev Allows to upgrade the contract. This can only be done via a Safe transaction.\n @param _masterCopy New contract address.",
"id": 812,
"id": 1692,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [
{
"arguments": null,
"id": 798,
"id": 1678,
"modifierName": {
"argumentTypes": null,
"id": 797,
"id": 1677,
"name": "authorized",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1764,
"src": "696:10:7",
"referencedDeclaration": 1734,
"src": "696:10:9",
"typeDescriptions": {
"typeIdentifier": "t_modifier$__$",
"typeString": "modifier ()"
}
},
"nodeType": "ModifierInvocation",
"src": "696:10:7"
"src": "696:10:9"
}
],
"name": "changeMasterCopy",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 796,
"id": 1676,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 795,
"id": 1675,
"name": "_masterCopy",
"nodeType": "VariableDeclaration",
"scope": 812,
"src": "652:19:7",
"scope": 1692,
"src": "652:19:9",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -673,10 +673,10 @@
"typeString": "address"
},
"typeName": {
"id": 794,
"id": 1674,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "652:7:7",
"src": "652:7:9",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -686,27 +686,27 @@
"visibility": "internal"
}
],
"src": "651:21:7"
"src": "651:21:9"
},
"payable": false,
"returnParameters": {
"id": 799,
"id": 1679,
"nodeType": "ParameterList",
"parameters": [],
"src": "711:0:7"
"src": "711:0:9"
},
"scope": 813,
"src": "626:248:7",
"scope": 1693,
"src": "626:248:9",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 814,
"src": "203:673:7"
"scope": 1694,
"src": "203:673:9"
}
],
"src": "0:877:7"
"src": "0:877:9"
},
"compiler": {
"name": "solc",
@ -714,5 +714,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.087Z"
"updatedAt": "2018-10-05T14:25:58.937Z"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -18,29 +18,29 @@
],
"bytecode": "0x608060405234801561001057600080fd5b50610169806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680638d80ff0a14610046575b600080fd5b34801561005257600080fd5b506100ad600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506100af565b005b805160205b81811015610138578083015160208201840151604083018501516080840186015160a085018701600085600081146100f357600181146101035761010e565b6000808585888a5af1915061010e565b6000808585895af491505b50600081141561011d57600080fd5b602080601f8501040260a001870196505050505050506100b4565b5050505600a165627a7a72305820c1abf4988401674d6d6a5ceca56de123817c61305360ceffe26ebab59a828b7d0029",
"deployedBytecode": "0x608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680638d80ff0a14610046575b600080fd5b34801561005257600080fd5b506100ad600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506100af565b005b805160205b81811015610138578083015160208201840151604083018501516080840186015160a085018701600085600081146100f357600181146101035761010e565b6000808585888a5af1915061010e565b6000808585895af491505b50600081141561011d57600080fd5b602080601f8501040260a001870196505050505050506100b4565b5050505600a165627a7a72305820c1abf4988401674d6d6a5ceca56de123817c61305360ceffe26ebab59a828b7d0029",
"sourceMap": "253:1424:19:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;253:1424:19;;;;;;;",
"deployedSourceMap": "253:1424:19:-;;;;;;;;;;;;;;;;;;;;;;;;695:980;;8:9:-1;5:2;;;30:1;27;20:12;5:2;695:980:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;870:12;864:19;905:4;922:737;936:6;933:1;930:13;922:737;;;1007:1;993:12;989:20;983:27;1068:4;1065:1;1061:12;1047;1043:31;1037:38;1136:4;1133:1;1129:12;1115;1111:31;1105:38;1209:4;1206:1;1202:12;1188;1184:31;1178:38;1270:4;1267:1;1263:12;1249;1245:31;1308:1;1333:9;1365:1;1360:66;;;;1448:1;1443:67;;;;1326:184;;1360:66;1422:1;1419;1407:10;1401:4;1394:5;1390:2;1385:3;1380:44;1369:55;;1360:66;;1443:67;1506:1;1503;1491:10;1485:4;1481:2;1476:3;1463:45;1452:56;;1326:184;;1542:1;1533:7;1530:14;1527:2;;;1557:1;1554;1547:12;1527:2;1638:4;1631;1624;1612:10;1608:21;1604:32;1600:43;1594:4;1590:54;1587:1;1583:62;1578:67;;948:711;;;;;;922:737;;;836:833;;;:::o",
"sourceMap": "253:1424:15:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;253:1424:15;;;;;;;",
"deployedSourceMap": "253:1424:15:-;;;;;;;;;;;;;;;;;;;;;;;;695:980;;8:9:-1;5:2;;;30:1;27;20:12;5:2;695:980:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;870:12;864:19;905:4;922:737;936:6;933:1;930:13;922:737;;;1007:1;993:12;989:20;983:27;1068:4;1065:1;1061:12;1047;1043:31;1037:38;1136:4;1133:1;1129:12;1115;1111:31;1105:38;1209:4;1206:1;1202:12;1188;1184:31;1178:38;1270:4;1267:1;1263:12;1249;1245:31;1308:1;1333:9;1365:1;1360:66;;;;1448:1;1443:67;;;;1326:184;;1360:66;1422:1;1419;1407:10;1401:4;1394:5;1390:2;1385:3;1380:44;1369:55;;1360:66;;1443:67;1506:1;1503;1491:10;1485:4;1481:2;1476:3;1463:45;1452:56;;1326:184;;1542:1;1533:7;1530:14;1527:2;;;1557:1;1554;1547:12;1527:2;1638:4;1631;1624;1612:10;1608:21;1604:32;1600:43;1594:4;1590:54;1587:1;1583:62;1578:67;;948:711;;;;;;922:737;;;836:833;;;:::o",
"source": "pragma solidity 0.4.24;\n\n\n/// @title Multi Send - Allows to batch multiple transactions into one.\n/// @author Nick Dodson - <nick.dodson@consensys.net>\n/// @author Gonçalo Sá - <goncalo.sa@consensys.net>\n/// @author Stefan George - <stefan@gnosis.pm>\ncontract MultiSend {\n\n /// @dev Sends multiple transactions and reverts all if one fails.\n /// @param transactions Encoded transactions. Each transaction is encoded as a \n /// tuple(operation,address,uint256,bytes), where operation \n /// can be 0 for a call or 1 for a delegatecall. The bytes \n /// of all encoded transactions are concatenated to form the input.\n function multiSend(bytes transactions)\n public\n {\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let length := mload(transactions)\n let i := 0x20\n for { } lt(i, length) { } {\n let operation := mload(add(transactions, i))\n let to := mload(add(transactions, add(i, 0x20)))\n let value := mload(add(transactions, add(i, 0x40)))\n let dataLength := mload(add(transactions, add(i, 0x80)))\n let data := add(transactions, add(i, 0xa0))\n let success := 0\n switch operation \n case 0 { success := call(gas, to, value, data, dataLength, 0, 0) }\n case 1 { success := delegatecall(gas, to, data, dataLength, 0, 0) }\n if eq(success, 0) { revert(0, 0) }\n i := add(i, add(0xa0, mul(div(add(dataLength, 0x1f), 0x20), 0x20)))\n }\n }\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/libraries/MultiSend.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/libraries/MultiSend.sol",
"exportedSymbols": {
"MultiSend": [
1876
1858
]
},
"id": 1877,
"id": 1859,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1868,
"id": 1850,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:19"
"src": "0:23:15"
},
{
"baseContracts": [],
@ -48,85 +48,85 @@
"contractKind": "contract",
"documentation": "@title Multi Send - Allows to batch multiple transactions into one.\n @author Nick Dodson - <nick.dodson@consensys.net>\n @author Gonçalo Sá - <goncalo.sa@consensys.net>\n @author Stefan George - <stefan@gnosis.pm>",
"fullyImplemented": true,
"id": 1876,
"id": 1858,
"linearizedBaseContracts": [
1876
1858
],
"name": "MultiSend",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1874,
"id": 1856,
"nodeType": "Block",
"src": "753:922:19",
"src": "753:922:15",
"statements": [
{
"externalReferences": [
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "870:12:19",
"src": "870:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "993:12:19",
"src": "993:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1047:12:19",
"src": "1047:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1188:12:19",
"src": "1188:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1115:12:19",
"src": "1115:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1249:12:19",
"src": "1249:12:15",
"valueSize": 1
}
}
],
"id": 1873,
"id": 1855,
"nodeType": "InlineAssembly",
"operations": "{\n let length := mload(transactions)\n let i := 0x20\n for {\n }\n lt(i, length)\n {\n }\n {\n let operation := mload(add(transactions, i))\n let to := mload(add(transactions, add(i, 0x20)))\n let value := mload(add(transactions, add(i, 0x40)))\n let dataLength := mload(add(transactions, add(i, 0x80)))\n let data := add(transactions, add(i, 0xa0))\n let success := 0\n switch operation\n case 0 {\n success := call(gas(), to, value, data, dataLength, 0, 0)\n }\n case 1 {\n success := delegatecall(gas(), to, data, dataLength, 0, 0)\n }\n if eq(success, 0)\n {\n revert(0, 0)\n }\n i := add(i, add(0xa0, mul(div(add(dataLength, 0x1f), 0x20), 0x20)))\n }\n}",
"src": "827:848:19"
"src": "827:848:15"
}
]
},
"documentation": "@dev Sends multiple transactions and reverts all if one fails.\n @param transactions Encoded transactions. Each transaction is encoded as a \n tuple(operation,address,uint256,bytes), where operation \n can be 0 for a call or 1 for a delegatecall. The bytes \n of all encoded transactions are concatenated to form the input.",
"id": 1875,
"id": 1857,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -134,16 +134,16 @@
"name": "multiSend",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1871,
"id": 1853,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1870,
"id": 1852,
"name": "transactions",
"nodeType": "VariableDeclaration",
"scope": 1875,
"src": "714:18:19",
"scope": 1857,
"src": "714:18:15",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -151,10 +151,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 1869,
"id": 1851,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "714:5:19",
"src": "714:5:15",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -164,47 +164,47 @@
"visibility": "internal"
}
],
"src": "713:20:19"
"src": "713:20:15"
},
"payable": false,
"returnParameters": {
"id": 1872,
"id": 1854,
"nodeType": "ParameterList",
"parameters": [],
"src": "753:0:19"
"src": "753:0:15"
},
"scope": 1876,
"src": "695:980:19",
"scope": 1858,
"src": "695:980:15",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1877,
"src": "253:1424:19"
"scope": 1859,
"src": "253:1424:15"
}
],
"src": "0:1678:19"
"src": "0:1678:15"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/libraries/MultiSend.sol",
"exportedSymbols": {
"MultiSend": [
1876
1858
]
},
"id": 1877,
"id": 1859,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1868,
"id": 1850,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:19"
"src": "0:23:15"
},
{
"baseContracts": [],
@ -212,85 +212,85 @@
"contractKind": "contract",
"documentation": "@title Multi Send - Allows to batch multiple transactions into one.\n @author Nick Dodson - <nick.dodson@consensys.net>\n @author Gonçalo Sá - <goncalo.sa@consensys.net>\n @author Stefan George - <stefan@gnosis.pm>",
"fullyImplemented": true,
"id": 1876,
"id": 1858,
"linearizedBaseContracts": [
1876
1858
],
"name": "MultiSend",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1874,
"id": 1856,
"nodeType": "Block",
"src": "753:922:19",
"src": "753:922:15",
"statements": [
{
"externalReferences": [
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "870:12:19",
"src": "870:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "993:12:19",
"src": "993:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1047:12:19",
"src": "1047:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1188:12:19",
"src": "1188:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1115:12:19",
"src": "1115:12:15",
"valueSize": 1
}
},
{
"transactions": {
"declaration": 1870,
"declaration": 1852,
"isOffset": false,
"isSlot": false,
"src": "1249:12:19",
"src": "1249:12:15",
"valueSize": 1
}
}
],
"id": 1873,
"id": 1855,
"nodeType": "InlineAssembly",
"operations": "{\n let length := mload(transactions)\n let i := 0x20\n for {\n }\n lt(i, length)\n {\n }\n {\n let operation := mload(add(transactions, i))\n let to := mload(add(transactions, add(i, 0x20)))\n let value := mload(add(transactions, add(i, 0x40)))\n let dataLength := mload(add(transactions, add(i, 0x80)))\n let data := add(transactions, add(i, 0xa0))\n let success := 0\n switch operation\n case 0 {\n success := call(gas(), to, value, data, dataLength, 0, 0)\n }\n case 1 {\n success := delegatecall(gas(), to, data, dataLength, 0, 0)\n }\n if eq(success, 0)\n {\n revert(0, 0)\n }\n i := add(i, add(0xa0, mul(div(add(dataLength, 0x1f), 0x20), 0x20)))\n }\n}",
"src": "827:848:19"
"src": "827:848:15"
}
]
},
"documentation": "@dev Sends multiple transactions and reverts all if one fails.\n @param transactions Encoded transactions. Each transaction is encoded as a \n tuple(operation,address,uint256,bytes), where operation \n can be 0 for a call or 1 for a delegatecall. The bytes \n of all encoded transactions are concatenated to form the input.",
"id": 1875,
"id": 1857,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -298,16 +298,16 @@
"name": "multiSend",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1871,
"id": 1853,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1870,
"id": 1852,
"name": "transactions",
"nodeType": "VariableDeclaration",
"scope": 1875,
"src": "714:18:19",
"scope": 1857,
"src": "714:18:15",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -315,10 +315,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 1869,
"id": 1851,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "714:5:19",
"src": "714:5:15",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -328,27 +328,27 @@
"visibility": "internal"
}
],
"src": "713:20:19"
"src": "713:20:15"
},
"payable": false,
"returnParameters": {
"id": 1872,
"id": 1854,
"nodeType": "ParameterList",
"parameters": [],
"src": "753:0:19"
"src": "753:0:15"
},
"scope": 1876,
"src": "695:980:19",
"scope": 1858,
"src": "695:980:15",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1877,
"src": "253:1424:19"
"scope": 1859,
"src": "253:1424:15"
}
],
"src": "0:1678:19"
"src": "0:1678:15"
},
"compiler": {
"name": "solc",
@ -358,16 +358,16 @@
"4": {
"events": {},
"links": {},
"address": "0x3a29cf32d22f38b7338874b689a88f185663a1c3",
"transactionHash": "0x86b6895207dff0b3e19c202e140dc9cf823cbfc02672e02636af23a1b580e7e7"
"address": "0x6f6f431429fb15bb2ca4bb55bf353c15f044df9e",
"transactionHash": "0xeaf5db265940b81d6fe881ebf0b05aa9dde905851a966a9cda08dcabd7dc10bd"
},
"1534750848541": {
"1538739975997": {
"events": {},
"links": {},
"address": "0x5b9b42d6e4b2e4bf8d42eba32d46918e10899b66",
"transactionHash": "0xaf733882096b301ccf5bf4a12ebf84616b88927c71cc656cc037fbd892a24104"
"address": "0x26b4afb60d6c903165150c6f0aa14f8016be4aec",
"transactionHash": "0x4a85e63a3968cc7f7aaa5303f6ed331cf782929fc758645b44145286ad4076a6"
}
},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:50:29.677Z"
"updatedAt": "2018-10-05T14:43:41.420Z"
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,31 @@
{
"contractName": "SecuredTokenTransfer",
"abi": [],
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a723058203704d691dd103c6cda573e69dcd48a2de4d0edf672da44096a50180687c79a770029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a723058203704d691dd103c6cda573e69dcd48a2de4d0edf672da44096a50180687c79a770029",
"sourceMap": "133:1051:15:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;133:1051:15;;;;;;;",
"deployedSourceMap": "133:1051:15:-;;;;;",
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820ba27992b3b19c83b563b2634ef4e6e4b21311676e3d2a13b83cfd34834dfb8510029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a72305820ba27992b3b19c83b563b2634ef4e6e4b21311676e3d2a13b83cfd34834dfb8510029",
"sourceMap": "133:1051:10:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;133:1051:10;;;;;;;",
"deployedSourceMap": "133:1051:10:-;;;;;",
"source": "pragma solidity 0.4.24;\n\n\n/// @title SecuredTokenTransfer - Secure token transfer\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract SecuredTokenTransfer {\n\n /// @dev Transfers a token and returns if it was a success\n /// @param token Token that should be transferred\n /// @param receiver Receiver to whom the token should be transferred\n /// @param amount The amount of tokens that should be transferred\n function transferToken (\n address token, \n address receiver,\n uint256 amount\n )\n internal\n returns (bool transferred)\n {\n bytes memory data = abi.encodeWithSignature(\"transfer(address,uint256)\", receiver, amount);\n // solium-disable-next-line security/no-inline-assembly\n assembly {\n let success := call(sub(gas, 10000), token, 0, add(data, 0x20), mload(data), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize)\n switch returndatasize \n case 0 { transferred := success }\n case 0x20 { transferred := iszero(or(iszero(success), iszero(mload(ptr)))) }\n default { transferred := 0 }\n }\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SecuredTokenTransfer.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SecuredTokenTransfer.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SecuredTokenTransfer.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SecuredTokenTransfer.sol",
"exportedSymbols": {
"SecuredTokenTransfer": [
1748
1718
]
},
"id": 1749,
"id": 1719,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1725,
"id": 1695,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:15"
"src": "0:23:10"
},
{
"baseContracts": [],
@ -33,31 +33,31 @@
"contractKind": "contract",
"documentation": "@title SecuredTokenTransfer - Secure token transfer\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 1748,
"id": 1718,
"linearizedBaseContracts": [
1748
1718
],
"name": "SecuredTokenTransfer",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1746,
"id": 1716,
"nodeType": "Block",
"src": "590:592:15",
"src": "590:592:10",
"statements": [
{
"assignments": [
1737
1707
],
"declarations": [
{
"constant": false,
"id": 1737,
"id": 1707,
"name": "data",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "600:17:15",
"scope": 1717,
"src": "600:17:10",
"stateVariable": false,
"storageLocation": "memory",
"typeDescriptions": {
@ -65,10 +65,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 1736,
"id": 1706,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "600:5:15",
"src": "600:5:10",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -78,21 +78,21 @@
"visibility": "internal"
}
],
"id": 1744,
"id": 1714,
"initialValue": {
"argumentTypes": null,
"arguments": [
{
"argumentTypes": null,
"hexValue": "7472616e7366657228616464726573732c75696e7432353629",
"id": 1740,
"id": 1710,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "644:27:15",
"src": "644:27:10",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b",
@ -102,12 +102,12 @@
},
{
"argumentTypes": null,
"id": 1741,
"id": 1711,
"name": "receiver",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1729,
"src": "673:8:15",
"referencedDeclaration": 1699,
"src": "673:8:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -115,12 +115,12 @@
},
{
"argumentTypes": null,
"id": 1742,
"id": 1712,
"name": "amount",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1731,
"src": "683:6:15",
"referencedDeclaration": 1701,
"src": "683:6:10",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -144,18 +144,18 @@
],
"expression": {
"argumentTypes": null,
"id": 1738,
"id": 1708,
"name": "abi",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3815,
"src": "620:3:15",
"referencedDeclaration": 4002,
"src": "620:3:10",
"typeDescriptions": {
"typeIdentifier": "t_magic_abi",
"typeString": "abi"
}
},
"id": 1739,
"id": 1709,
"isConstant": false,
"isLValue": false,
"isPure": true,
@ -163,13 +163,13 @@
"memberName": "encodeWithSignature",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "620:23:15",
"src": "620:23:10",
"typeDescriptions": {
"typeIdentifier": "t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$",
"typeString": "function (string memory) pure returns (bytes memory)"
}
},
"id": 1743,
"id": 1713,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -177,81 +177,81 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "620:70:15",
"src": "620:70:10",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes memory"
}
},
"nodeType": "VariableDeclarationStatement",
"src": "600:90:15"
"src": "600:90:10"
},
{
"externalReferences": [
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1061:11:15",
"src": "1061:11:10",
"valueSize": 1
}
},
{
"data": {
"declaration": 1737,
"declaration": 1707,
"isOffset": false,
"isSlot": false,
"src": "857:4:15",
"src": "857:4:10",
"valueSize": 1
}
},
{
"token": {
"declaration": 1727,
"declaration": 1697,
"isOffset": false,
"isSlot": false,
"src": "824:5:15",
"src": "824:5:10",
"valueSize": 1
}
},
{
"data": {
"declaration": 1737,
"declaration": 1707,
"isOffset": false,
"isSlot": false,
"src": "838:4:15",
"src": "838:4:10",
"valueSize": 1
}
},
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1012:11:15",
"src": "1012:11:10",
"valueSize": 1
}
},
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1148:11:15",
"src": "1148:11:10",
"valueSize": 1
}
}
],
"id": 1745,
"id": 1715,
"nodeType": "InlineAssembly",
"operations": "{\n let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n switch returndatasize()\n case 0 {\n transferred := success\n }\n case 0x20 {\n transferred := iszero(or(iszero(success), iszero(mload(ptr))))\n }\n default {\n transferred := 0\n }\n}",
"src": "764:418:15"
"src": "764:418:10"
}
]
},
"documentation": "@dev Transfers a token and returns if it was a success\n @param token Token that should be transferred\n @param receiver Receiver to whom the token should be transferred\n @param amount The amount of tokens that should be transferred",
"id": 1747,
"id": 1717,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -259,16 +259,16 @@
"name": "transferToken",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1732,
"id": 1702,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1727,
"id": 1697,
"name": "token",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "463:13:15",
"scope": 1717,
"src": "463:13:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -276,10 +276,10 @@
"typeString": "address"
},
"typeName": {
"id": 1726,
"id": 1696,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "463:7:15",
"src": "463:7:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -290,11 +290,11 @@
},
{
"constant": false,
"id": 1729,
"id": 1699,
"name": "receiver",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "487:16:15",
"scope": 1717,
"src": "487:16:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -302,10 +302,10 @@
"typeString": "address"
},
"typeName": {
"id": 1728,
"id": 1698,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "487:7:15",
"src": "487:7:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -316,11 +316,11 @@
},
{
"constant": false,
"id": 1731,
"id": 1701,
"name": "amount",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "513:14:15",
"scope": 1717,
"src": "513:14:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -328,10 +328,10 @@
"typeString": "uint256"
},
"typeName": {
"id": 1730,
"id": 1700,
"name": "uint256",
"nodeType": "ElementaryTypeName",
"src": "513:7:15",
"src": "513:7:10",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -341,20 +341,20 @@
"visibility": "internal"
}
],
"src": "453:80:15"
"src": "453:80:10"
},
"payable": false,
"returnParameters": {
"id": 1735,
"id": 1705,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1734,
"id": 1704,
"name": "transferred",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "568:16:15",
"scope": 1717,
"src": "568:16:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -362,10 +362,10 @@
"typeString": "bool"
},
"typeName": {
"id": 1733,
"id": 1703,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "568:4:15",
"src": "568:4:10",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -375,40 +375,40 @@
"visibility": "internal"
}
],
"src": "567:18:15"
"src": "567:18:10"
},
"scope": 1748,
"src": "430:752:15",
"scope": 1718,
"src": "430:752:10",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "internal"
}
],
"scope": 1749,
"src": "133:1051:15"
"scope": 1719,
"src": "133:1051:10"
}
],
"src": "0:1185:15"
"src": "0:1185:10"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SecuredTokenTransfer.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SecuredTokenTransfer.sol",
"exportedSymbols": {
"SecuredTokenTransfer": [
1748
1718
]
},
"id": 1749,
"id": 1719,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1725,
"id": 1695,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:15"
"src": "0:23:10"
},
{
"baseContracts": [],
@ -416,31 +416,31 @@
"contractKind": "contract",
"documentation": "@title SecuredTokenTransfer - Secure token transfer\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 1748,
"id": 1718,
"linearizedBaseContracts": [
1748
1718
],
"name": "SecuredTokenTransfer",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1746,
"id": 1716,
"nodeType": "Block",
"src": "590:592:15",
"src": "590:592:10",
"statements": [
{
"assignments": [
1737
1707
],
"declarations": [
{
"constant": false,
"id": 1737,
"id": 1707,
"name": "data",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "600:17:15",
"scope": 1717,
"src": "600:17:10",
"stateVariable": false,
"storageLocation": "memory",
"typeDescriptions": {
@ -448,10 +448,10 @@
"typeString": "bytes"
},
"typeName": {
"id": 1736,
"id": 1706,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "600:5:15",
"src": "600:5:10",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
@ -461,21 +461,21 @@
"visibility": "internal"
}
],
"id": 1744,
"id": 1714,
"initialValue": {
"argumentTypes": null,
"arguments": [
{
"argumentTypes": null,
"hexValue": "7472616e7366657228616464726573732c75696e7432353629",
"id": 1740,
"id": 1710,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "644:27:15",
"src": "644:27:10",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_a9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b",
@ -485,12 +485,12 @@
},
{
"argumentTypes": null,
"id": 1741,
"id": 1711,
"name": "receiver",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1729,
"src": "673:8:15",
"referencedDeclaration": 1699,
"src": "673:8:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -498,12 +498,12 @@
},
{
"argumentTypes": null,
"id": 1742,
"id": 1712,
"name": "amount",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 1731,
"src": "683:6:15",
"referencedDeclaration": 1701,
"src": "683:6:10",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -527,18 +527,18 @@
],
"expression": {
"argumentTypes": null,
"id": 1738,
"id": 1708,
"name": "abi",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3815,
"src": "620:3:15",
"referencedDeclaration": 4002,
"src": "620:3:10",
"typeDescriptions": {
"typeIdentifier": "t_magic_abi",
"typeString": "abi"
}
},
"id": 1739,
"id": 1709,
"isConstant": false,
"isLValue": false,
"isPure": true,
@ -546,13 +546,13 @@
"memberName": "encodeWithSignature",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "620:23:15",
"src": "620:23:10",
"typeDescriptions": {
"typeIdentifier": "t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$",
"typeString": "function (string memory) pure returns (bytes memory)"
}
},
"id": 1743,
"id": 1713,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -560,81 +560,81 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "620:70:15",
"src": "620:70:10",
"typeDescriptions": {
"typeIdentifier": "t_bytes_memory_ptr",
"typeString": "bytes memory"
}
},
"nodeType": "VariableDeclarationStatement",
"src": "600:90:15"
"src": "600:90:10"
},
{
"externalReferences": [
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1061:11:15",
"src": "1061:11:10",
"valueSize": 1
}
},
{
"data": {
"declaration": 1737,
"declaration": 1707,
"isOffset": false,
"isSlot": false,
"src": "857:4:15",
"src": "857:4:10",
"valueSize": 1
}
},
{
"token": {
"declaration": 1727,
"declaration": 1697,
"isOffset": false,
"isSlot": false,
"src": "824:5:15",
"src": "824:5:10",
"valueSize": 1
}
},
{
"data": {
"declaration": 1737,
"declaration": 1707,
"isOffset": false,
"isSlot": false,
"src": "838:4:15",
"src": "838:4:10",
"valueSize": 1
}
},
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1012:11:15",
"src": "1012:11:10",
"valueSize": 1
}
},
{
"transferred": {
"declaration": 1734,
"declaration": 1704,
"isOffset": false,
"isSlot": false,
"src": "1148:11:15",
"src": "1148:11:10",
"valueSize": 1
}
}
],
"id": 1745,
"id": 1715,
"nodeType": "InlineAssembly",
"operations": "{\n let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0)\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n switch returndatasize()\n case 0 {\n transferred := success\n }\n case 0x20 {\n transferred := iszero(or(iszero(success), iszero(mload(ptr))))\n }\n default {\n transferred := 0\n }\n}",
"src": "764:418:15"
"src": "764:418:10"
}
]
},
"documentation": "@dev Transfers a token and returns if it was a success\n @param token Token that should be transferred\n @param receiver Receiver to whom the token should be transferred\n @param amount The amount of tokens that should be transferred",
"id": 1747,
"id": 1717,
"implemented": true,
"isConstructor": false,
"isDeclaredConst": false,
@ -642,16 +642,16 @@
"name": "transferToken",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1732,
"id": 1702,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1727,
"id": 1697,
"name": "token",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "463:13:15",
"scope": 1717,
"src": "463:13:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -659,10 +659,10 @@
"typeString": "address"
},
"typeName": {
"id": 1726,
"id": 1696,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "463:7:15",
"src": "463:7:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -673,11 +673,11 @@
},
{
"constant": false,
"id": 1729,
"id": 1699,
"name": "receiver",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "487:16:15",
"scope": 1717,
"src": "487:16:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -685,10 +685,10 @@
"typeString": "address"
},
"typeName": {
"id": 1728,
"id": 1698,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "487:7:15",
"src": "487:7:10",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -699,11 +699,11 @@
},
{
"constant": false,
"id": 1731,
"id": 1701,
"name": "amount",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "513:14:15",
"scope": 1717,
"src": "513:14:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -711,10 +711,10 @@
"typeString": "uint256"
},
"typeName": {
"id": 1730,
"id": 1700,
"name": "uint256",
"nodeType": "ElementaryTypeName",
"src": "513:7:15",
"src": "513:7:10",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
@ -724,20 +724,20 @@
"visibility": "internal"
}
],
"src": "453:80:15"
"src": "453:80:10"
},
"payable": false,
"returnParameters": {
"id": 1735,
"id": 1705,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1734,
"id": 1704,
"name": "transferred",
"nodeType": "VariableDeclaration",
"scope": 1747,
"src": "568:16:15",
"scope": 1717,
"src": "568:16:10",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
@ -745,10 +745,10 @@
"typeString": "bool"
},
"typeName": {
"id": 1733,
"id": 1703,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "568:4:15",
"src": "568:4:10",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -758,20 +758,20 @@
"visibility": "internal"
}
],
"src": "567:18:15"
"src": "567:18:10"
},
"scope": 1748,
"src": "430:752:15",
"scope": 1718,
"src": "430:752:10",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "internal"
}
],
"scope": 1749,
"src": "133:1051:15"
"scope": 1719,
"src": "133:1051:10"
}
],
"src": "0:1185:15"
"src": "0:1185:10"
},
"compiler": {
"name": "solc",
@ -779,5 +779,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.093Z"
"updatedAt": "2018-10-05T14:25:58.937Z"
}

View File

@ -1,31 +1,31 @@
{
"contractName": "SelfAuthorized",
"abi": [],
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820ec80f1b4520aa5197e4181778f1e2e4fc460002d4a40e2e8e6709c8986067c220029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a72305820ec80f1b4520aa5197e4181778f1e2e4fc460002d4a40e2e8e6709c8986067c220029",
"sourceMap": "152:166:16:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152:166:16;;;;;;;",
"deployedSourceMap": "152:166:16:-;;;;;",
"bytecode": "0x6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a7230582089be6830aa63b2ce4480c1565e02c1d4e7d28bdf01f3f1cfbca1af4fc2fd06f50029",
"deployedBytecode": "0x6080604052600080fd00a165627a7a7230582089be6830aa63b2ce4480c1565e02c1d4e7d28bdf01f3f1cfbca1af4fc2fd06f50029",
"sourceMap": "152:166:11:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;152:166:11;;;;;;;",
"deployedSourceMap": "152:166:11:-;;;;;",
"source": "pragma solidity 0.4.24;\n\n\n/// @title SelfAuthorized - authorizes current contract to perform actions\n/// @author Richard Meissner - <richard@gnosis.pm>\ncontract SelfAuthorized {\n modifier authorized() {\n require(msg.sender == address(this), \"Method can only be called from this contract\");\n _;\n }\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SelfAuthorized.sol",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SelfAuthorized.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SelfAuthorized.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SelfAuthorized.sol",
"exportedSymbols": {
"SelfAuthorized": [
1765
1735
]
},
"id": 1766,
"id": 1736,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1750,
"id": 1720,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:16"
"src": "0:23:11"
},
{
"baseContracts": [],
@ -33,18 +33,18 @@
"contractKind": "contract",
"documentation": "@title SelfAuthorized - authorizes current contract to perform actions\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 1765,
"id": 1735,
"linearizedBaseContracts": [
1765
1735
],
"name": "SelfAuthorized",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1763,
"id": 1733,
"nodeType": "Block",
"src": "204:112:16",
"src": "204:112:11",
"statements": [
{
"expression": {
@ -56,7 +56,7 @@
"typeIdentifier": "t_address",
"typeString": "address"
},
"id": 1758,
"id": 1728,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -65,18 +65,18 @@
"argumentTypes": null,
"expression": {
"argumentTypes": null,
"id": 1753,
"id": 1723,
"name": "msg",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3828,
"src": "222:3:16",
"referencedDeclaration": 4015,
"src": "222:3:11",
"typeDescriptions": {
"typeIdentifier": "t_magic_message",
"typeString": "msg"
}
},
"id": 1754,
"id": 1724,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -84,7 +84,7 @@
"memberName": "sender",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "222:10:16",
"src": "222:10:11",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -97,14 +97,14 @@
"arguments": [
{
"argumentTypes": null,
"id": 1756,
"id": 1726,
"name": "this",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3851,
"src": "244:4:16",
"referencedDeclaration": 4028,
"src": "244:4:11",
"typeDescriptions": {
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
}
@ -112,24 +112,24 @@
"expression": {
"argumentTypes": [
{
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
],
"id": 1755,
"id": 1725,
"isConstant": false,
"isLValue": false,
"isPure": true,
"lValueRequested": false,
"nodeType": "ElementaryTypeNameExpression",
"src": "236:7:16",
"src": "236:7:11",
"typeDescriptions": {
"typeIdentifier": "t_type$_t_address_$",
"typeString": "type(address)"
},
"typeName": "address"
},
"id": 1757,
"id": 1727,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -137,13 +137,13 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "236:13:16",
"src": "236:13:11",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"src": "222:27:16",
"src": "222:27:11",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -152,14 +152,14 @@
{
"argumentTypes": null,
"hexValue": "4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207468697320636f6e7472616374",
"id": 1759,
"id": 1729,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "251:46:16",
"src": "251:46:11",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_c4780ef0a1d41d59bac8c510cf9ada421bccf2b90f75a8e4ba2e8c09e8d72733",
@ -179,21 +179,21 @@
"typeString": "literal_string \"Method can only be called from this contract\""
}
],
"id": 1752,
"id": 1722,
"name": "require",
"nodeType": "Identifier",
"overloadedDeclarations": [
3831,
3832
4018,
4019
],
"referencedDeclaration": 3832,
"src": "214:7:16",
"referencedDeclaration": 4019,
"src": "214:7:11",
"typeDescriptions": {
"typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$",
"typeString": "function (bool,string memory) pure"
}
},
"id": 1760,
"id": 1730,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -201,62 +201,62 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "214:84:16",
"src": "214:84:11",
"typeDescriptions": {
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 1761,
"id": 1731,
"nodeType": "ExpressionStatement",
"src": "214:84:16"
"src": "214:84:11"
},
{
"id": 1762,
"id": 1732,
"nodeType": "PlaceholderStatement",
"src": "308:1:16"
"src": "308:1:11"
}
]
},
"documentation": null,
"id": 1764,
"id": 1734,
"name": "authorized",
"nodeType": "ModifierDefinition",
"parameters": {
"id": 1751,
"id": 1721,
"nodeType": "ParameterList",
"parameters": [],
"src": "201:2:16"
"src": "201:2:11"
},
"src": "182:134:16",
"src": "182:134:11",
"visibility": "internal"
}
],
"scope": 1766,
"src": "152:166:16"
"scope": 1736,
"src": "152:166:11"
}
],
"src": "0:319:16"
"src": "0:319:11"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/SelfAuthorized.sol",
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/common/SelfAuthorized.sol",
"exportedSymbols": {
"SelfAuthorized": [
1765
1735
]
},
"id": 1766,
"id": 1736,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1750,
"id": 1720,
"literals": [
"solidity",
"0.4",
".24"
],
"nodeType": "PragmaDirective",
"src": "0:23:16"
"src": "0:23:11"
},
{
"baseContracts": [],
@ -264,18 +264,18 @@
"contractKind": "contract",
"documentation": "@title SelfAuthorized - authorizes current contract to perform actions\n @author Richard Meissner - <richard@gnosis.pm>",
"fullyImplemented": true,
"id": 1765,
"id": 1735,
"linearizedBaseContracts": [
1765
1735
],
"name": "SelfAuthorized",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": {
"id": 1763,
"id": 1733,
"nodeType": "Block",
"src": "204:112:16",
"src": "204:112:11",
"statements": [
{
"expression": {
@ -287,7 +287,7 @@
"typeIdentifier": "t_address",
"typeString": "address"
},
"id": 1758,
"id": 1728,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -296,18 +296,18 @@
"argumentTypes": null,
"expression": {
"argumentTypes": null,
"id": 1753,
"id": 1723,
"name": "msg",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3828,
"src": "222:3:16",
"referencedDeclaration": 4015,
"src": "222:3:11",
"typeDescriptions": {
"typeIdentifier": "t_magic_message",
"typeString": "msg"
}
},
"id": 1754,
"id": 1724,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -315,7 +315,7 @@
"memberName": "sender",
"nodeType": "MemberAccess",
"referencedDeclaration": null,
"src": "222:10:16",
"src": "222:10:11",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
@ -328,14 +328,14 @@
"arguments": [
{
"argumentTypes": null,
"id": 1756,
"id": 1726,
"name": "this",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 3851,
"src": "244:4:16",
"referencedDeclaration": 4028,
"src": "244:4:11",
"typeDescriptions": {
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
}
@ -343,24 +343,24 @@
"expression": {
"argumentTypes": [
{
"typeIdentifier": "t_contract$_SelfAuthorized_$1765",
"typeIdentifier": "t_contract$_SelfAuthorized_$1735",
"typeString": "contract SelfAuthorized"
}
],
"id": 1755,
"id": 1725,
"isConstant": false,
"isLValue": false,
"isPure": true,
"lValueRequested": false,
"nodeType": "ElementaryTypeNameExpression",
"src": "236:7:16",
"src": "236:7:11",
"typeDescriptions": {
"typeIdentifier": "t_type$_t_address_$",
"typeString": "type(address)"
},
"typeName": "address"
},
"id": 1757,
"id": 1727,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -368,13 +368,13 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "236:13:16",
"src": "236:13:11",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"src": "222:27:16",
"src": "222:27:11",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
@ -383,14 +383,14 @@
{
"argumentTypes": null,
"hexValue": "4d6574686f642063616e206f6e6c792062652063616c6c65642066726f6d207468697320636f6e7472616374",
"id": 1759,
"id": 1729,
"isConstant": false,
"isLValue": false,
"isPure": true,
"kind": "string",
"lValueRequested": false,
"nodeType": "Literal",
"src": "251:46:16",
"src": "251:46:11",
"subdenomination": null,
"typeDescriptions": {
"typeIdentifier": "t_stringliteral_c4780ef0a1d41d59bac8c510cf9ada421bccf2b90f75a8e4ba2e8c09e8d72733",
@ -410,21 +410,21 @@
"typeString": "literal_string \"Method can only be called from this contract\""
}
],
"id": 1752,
"id": 1722,
"name": "require",
"nodeType": "Identifier",
"overloadedDeclarations": [
3831,
3832
4018,
4019
],
"referencedDeclaration": 3832,
"src": "214:7:16",
"referencedDeclaration": 4019,
"src": "214:7:11",
"typeDescriptions": {
"typeIdentifier": "t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$",
"typeString": "function (bool,string memory) pure"
}
},
"id": 1760,
"id": 1730,
"isConstant": false,
"isLValue": false,
"isPure": false,
@ -432,42 +432,42 @@
"lValueRequested": false,
"names": [],
"nodeType": "FunctionCall",
"src": "214:84:16",
"src": "214:84:11",
"typeDescriptions": {
"typeIdentifier": "t_tuple$__$",
"typeString": "tuple()"
}
},
"id": 1761,
"id": 1731,
"nodeType": "ExpressionStatement",
"src": "214:84:16"
"src": "214:84:11"
},
{
"id": 1762,
"id": 1732,
"nodeType": "PlaceholderStatement",
"src": "308:1:16"
"src": "308:1:11"
}
]
},
"documentation": null,
"id": 1764,
"id": 1734,
"name": "authorized",
"nodeType": "ModifierDefinition",
"parameters": {
"id": 1751,
"id": 1721,
"nodeType": "ParameterList",
"parameters": [],
"src": "201:2:16"
"src": "201:2:11"
},
"src": "182:134:16",
"src": "182:134:11",
"visibility": "internal"
}
],
"scope": 1766,
"src": "152:166:16"
"scope": 1736,
"src": "152:166:11"
}
],
"src": "0:319:16"
"src": "0:319:11"
},
"compiler": {
"name": "solc",
@ -475,5 +475,5 @@
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-08-20T07:44:41.093Z"
"updatedAt": "2018-10-05T14:25:58.938Z"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,363 @@
{
"contractName": "Token",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"sourceMap": "",
"deployedSourceMap": "",
"source": "pragma solidity ^0.4.23;\nimport \"@gnosis.pm/mock-contract/contracts/MockContract.sol\";\ncontract Token {\n\tfunction transfer(address _to, uint value) public returns (bool);\n}\n",
"sourcePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/mocks/Token.sol",
"ast": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/mocks/Token.sol",
"exportedSymbols": {
"Token": [
1871
]
},
"id": 1872,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1860,
"literals": [
"solidity",
"^",
"0.4",
".23"
],
"nodeType": "PragmaDirective",
"src": "0:24:16"
},
{
"absolutePath": "@gnosis.pm/mock-contract/contracts/MockContract.sol",
"file": "@gnosis.pm/mock-contract/contracts/MockContract.sol",
"id": 1861,
"nodeType": "ImportDirective",
"scope": 1872,
"sourceUnit": 4001,
"src": "25:61:16",
"symbolAliases": [],
"unitAlias": ""
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": false,
"id": 1871,
"linearizedBaseContracts": [
1871
],
"name": "Token",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": null,
"documentation": null,
"id": 1870,
"implemented": false,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [],
"name": "transfer",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1866,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1863,
"name": "_to",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "123:11:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
},
"typeName": {
"id": 1862,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "123:7:16",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"value": null,
"visibility": "internal"
},
{
"constant": false,
"id": 1865,
"name": "value",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "136:10:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 1864,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "136:4:16",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "122:25:16"
},
"payable": false,
"returnParameters": {
"id": 1869,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1868,
"name": "",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "164:4:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
},
"typeName": {
"id": 1867,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "164:4:16",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "163:6:16"
},
"scope": 1871,
"src": "105:65:16",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1872,
"src": "87:85:16"
}
],
"src": "0:173:16"
},
"legacyAST": {
"absolutePath": "/Users/apanizo/git/gnosis/safe-contracts/contracts/mocks/Token.sol",
"exportedSymbols": {
"Token": [
1871
]
},
"id": 1872,
"nodeType": "SourceUnit",
"nodes": [
{
"id": 1860,
"literals": [
"solidity",
"^",
"0.4",
".23"
],
"nodeType": "PragmaDirective",
"src": "0:24:16"
},
{
"absolutePath": "@gnosis.pm/mock-contract/contracts/MockContract.sol",
"file": "@gnosis.pm/mock-contract/contracts/MockContract.sol",
"id": 1861,
"nodeType": "ImportDirective",
"scope": 1872,
"sourceUnit": 4001,
"src": "25:61:16",
"symbolAliases": [],
"unitAlias": ""
},
{
"baseContracts": [],
"contractDependencies": [],
"contractKind": "contract",
"documentation": null,
"fullyImplemented": false,
"id": 1871,
"linearizedBaseContracts": [
1871
],
"name": "Token",
"nodeType": "ContractDefinition",
"nodes": [
{
"body": null,
"documentation": null,
"id": 1870,
"implemented": false,
"isConstructor": false,
"isDeclaredConst": false,
"modifiers": [],
"name": "transfer",
"nodeType": "FunctionDefinition",
"parameters": {
"id": 1866,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1863,
"name": "_to",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "123:11:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
},
"typeName": {
"id": 1862,
"name": "address",
"nodeType": "ElementaryTypeName",
"src": "123:7:16",
"typeDescriptions": {
"typeIdentifier": "t_address",
"typeString": "address"
}
},
"value": null,
"visibility": "internal"
},
{
"constant": false,
"id": 1865,
"name": "value",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "136:10:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 1864,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "136:4:16",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "122:25:16"
},
"payable": false,
"returnParameters": {
"id": 1869,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 1868,
"name": "",
"nodeType": "VariableDeclaration",
"scope": 1870,
"src": "164:4:16",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
},
"typeName": {
"id": 1867,
"name": "bool",
"nodeType": "ElementaryTypeName",
"src": "164:4:16",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"value": null,
"visibility": "internal"
}
],
"src": "163:6:16"
},
"scope": 1871,
"src": "105:65:16",
"stateMutability": "nonpayable",
"superFunction": null,
"visibility": "public"
}
],
"scope": 1872,
"src": "87:85:16"
}
],
"src": "0:173:16"
},
"compiler": {
"name": "solc",
"version": "0.4.24+commit.e67f0147.Emscripten.clang"
},
"networks": {},
"schemaVersion": "2.0.0",
"updatedAt": "2018-10-05T14:25:58.939Z"
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -39,11 +39,12 @@ const styles = () => ({
logo: {
padding: `${sm} ${md}`,
flexBasis: '95px',
flexGrow: 0,
},
})
const Layout = openHoc(({
open, toggle, classes, providerInfo, providerDetails,
open, toggle, clickAway, classes, providerInfo, providerDetails,
}: Props) => (
<React.Fragment>
<Row className={classes.summary}>
@ -60,7 +61,7 @@ const Layout = openHoc(({
<Grow
{...TransitionProps}
>
<ClickAwayListener onClickAway={toggle}>
<ClickAwayListener onClickAway={clickAway} mouseEvent="onClick" touchEvent={false}>
<List className={classes.root} component="div">
{providerDetails}
</List>

View File

@ -54,10 +54,9 @@ class Provider extends React.Component<Props> {
return (
<React.Fragment>
<div ref={this.myRef} className={classes.root}>
<Col end="sm" middle="xs" className={classes.provider}>
<Col end="sm" middle="xs" className={classes.provider} onClick={toggle}>
{ info }
<IconButton
onClick={toggle}
disableRipple
className={classes.expand}
>

View File

@ -11,10 +11,10 @@ import Img from '~/components/layout/Img'
import Row from '~/components/layout/Row'
import Block from '~/components/layout/Block'
import Spacer from '~/components/Spacer'
import { xs, sm, md, lg, background } from '~/theme/variables'
import { xs, sm, md, lg, background, secondary } from '~/theme/variables'
import { upperFirst } from '~/utils/css'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { openInEtherScan } from '~/logic/wallets/getWeb3'
import { openAddressInEtherScan } from '~/logic/wallets/getWeb3'
const metamask = require('../../assets/metamask.svg')
const connectedLogo = require('../../assets/connected.svg')
@ -32,7 +32,7 @@ type Props = {
const openIconStyle = {
height: '16px',
color: '#467ee5',
color: secondary,
}
const styles = () => ({
@ -97,7 +97,11 @@ const UserDetails = ({
<Block align="center" className={classes.user}>
<Paragraph className={classes.address} size="sm" noMargin>{address}</Paragraph>
{ userAddress &&
<OpenInNew className={classes.open} style={openIconStyle} onClick={openInEtherScan(userAddress, network)} />
<OpenInNew
className={classes.open}
style={openIconStyle}
onClick={openAddressInEtherScan(userAddress, network)}
/>
}
</Block>
</Block>

View File

@ -53,7 +53,7 @@ const ProviderInfo = ({
<React.Fragment>
<Identicon address={identiconAddress} diameter={30} />
<Img className={classes.logo} src={logo} height={20} alt="Connection status" />
<Col end="sm" middle="xs" layout="column" className={classes.account}>
<Col start="sm" layout="column" className={classes.account}>
<Paragraph size="sm" transform="capitalize" className={classes.network} noMargin weight="bold">{providerText}</Paragraph>
<Paragraph size="sm" className={classes.address} noMargin color={color}>{cutAddress}</Paragraph>
</Col>

View File

@ -2,6 +2,8 @@
import * as React from 'react'
import { connect } from 'react-redux'
import { logComponentStack, type Info } from '~/utils/logBoundaries'
import { SharedSnackbarConsumer, type Variant } from '~/components/SharedSnackBar/Context'
import { WALLET_ERROR_MSG } from '~/logic/wallets/store/actions'
import ProviderInfo from './component/ProviderInfo'
import ProviderDetails from './component/ProviderInfo/UserDetails'
import ProviderDisconnected from './component/ProviderDisconnected'
@ -10,33 +12,36 @@ import Layout from './component/Layout'
import actions, { type Actions } from './actions'
import selector, { type SelectorProps } from './selector'
type Props = Actions & SelectorProps
type Props = Actions & SelectorProps & {
openSnackbar: (message: string, variant: Variant) => void,
}
type State = {
hasError: boolean,
}
class Header extends React.PureComponent<Props, State> {
class HeaderComponent extends React.PureComponent<Props, State> {
state = {
hasError: false,
}
componentDidMount() {
this.props.fetchProvider()
this.props.fetchProvider(this.props.openSnackbar)
}
componentDidCatch(error: Error, info: Info) {
this.setState({ hasError: true })
this.props.openSnackbar(WALLET_ERROR_MSG, 'error')
logComponentStack(error, info)
}
onDisconnect = () => {
this.props.removeProvider()
this.props.removeProvider(this.props.openSnackbar)
}
onConnect = () => {
this.props.fetchProvider()
this.props.fetchProvider(this.props.openSnackbar)
}
getProviderInfoBased = () => {
@ -79,4 +84,14 @@ class Header extends React.PureComponent<Props, State> {
}
}
export default connect(selector, actions)(Header)
const Header = connect(selector, actions)(HeaderComponent)
const HeaderSnack = () => (
<SharedSnackbarConsumer>
{({ openSnackbar }) => (
<Header openSnackbar={openSnackbar} />
)}
</SharedSnackbarConsumer>
)
export default HeaderSnack

View File

@ -0,0 +1,67 @@
// @flow
import * as React from 'react'
import SharedSnackBar from './index'
const SharedSnackbarContext = React.createContext({
openSnackbar: undefined,
closeSnackbar: undefined,
snackbarIsOpen: false,
message: '',
variant: 'info',
})
type Props = {
children: React$Node,
}
export type Variant = 'success' | 'error' | 'warning' | 'info'
type State = {
isOpen: boolean,
message: string,
variant: Variant,
}
export class SharedSnackbarProvider extends React.Component<Props, State> {
state = {
isOpen: false,
message: '',
variant: 'info',
}
openSnackbar = (message: string, variant: Variant) => {
this.setState({
message,
variant,
isOpen: true,
})
}
closeSnackbar = () => {
this.setState({
message: '',
isOpen: false,
})
}
render() {
const { children } = this.props
return (
<SharedSnackbarContext.Provider
value={{
openSnackbar: this.openSnackbar,
closeSnackbar: this.closeSnackbar,
snackbarIsOpen: this.state.isOpen,
message: this.state.message,
variant: this.state.variant,
}}
>
<SharedSnackBar />
{children}
</SharedSnackbarContext.Provider>
)
}
}
export const SharedSnackbarConsumer = SharedSnackbarContext.Consumer

View File

@ -0,0 +1,35 @@
// @flow
import * as React from 'react'
import { Snackbar } from '@material-ui/core'
import SnackbarContent from '~/components/SnackbarContent'
import { SharedSnackbarConsumer } from './Context'
const SharedSnackbar = () => (
<SharedSnackbarConsumer>
{(value) => {
const {
snackbarIsOpen, message, closeSnackbar, variant,
} = value
return (
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
open={snackbarIsOpen}
autoHideDuration={4000}
onClose={closeSnackbar}
>
<SnackbarContent
onClose={closeSnackbar}
message={message}
variant={variant}
/>
</Snackbar>
)
}}
</SharedSnackbarConsumer>
)
export default SharedSnackbar

View File

@ -2,8 +2,6 @@
import SnackbarContent from '@material-ui/core/SnackbarContent'
import classNames from 'classnames/bind'
import * as React from 'react'
import green from '@material-ui/core/colors/green'
import amber from '@material-ui/core/colors/amber'
import CloseIcon from '@material-ui/icons/Close'
import CheckCircleIcon from '@material-ui/icons/CheckCircle'
import ErrorIcon from '@material-ui/icons/Error'
@ -12,6 +10,7 @@ import IconButton from '@material-ui/core/IconButton'
import { withStyles } from '@material-ui/core/styles'
import WarningIcon from '@material-ui/icons/Warning'
import { type WithStyles } from '~/theme/mui'
import { secondary } from '~/theme/variables'
type Variant = 'success' | 'error' | 'warning' | 'info'
@ -37,16 +36,28 @@ const variantIcon = {
const styles = theme => ({
success: {
backgroundColor: green[600],
backgroundColor: '#ffffff',
},
error: {
backgroundColor: theme.palette.error.dark,
},
info: {
backgroundColor: theme.palette.primary.dark,
successIcon: {
color: '#00c4c4',
},
warning: {
backgroundColor: amber[700],
backgroundColor: '#fff3e2',
},
warningIcon: {
color: '#ffc05f',
},
error: {
backgroundColor: '#ffe6ea',
},
errorIcon: {
color: '#fd7890',
},
info: {
backgroundColor: '#ffffff',
},
infoIcon: {
color: secondary,
},
icon: {
fontSize: 20,
@ -78,7 +89,7 @@ const Message = ({ classes, message, variant }: MessageProps) => {
return (
<span id="client-snackbar" className={classes.message}>
<Icon className={classNames(classes.icon, classes.iconVariant)} />
<Icon className={classNames(classes.icon, classes.iconVariant, classes[`${variant}Icon`])} />
{message}
</span>
)
@ -87,7 +98,7 @@ const Message = ({ classes, message, variant }: MessageProps) => {
const GnoSnackbarContent = ({
variant, classes, message, onClose,
}: Props) => {
const action = onClose ? [<Close onClose={onClose} classes={classes} />] : undefined
const action = onClose ? [<Close key="close" onClose={onClose} classes={classes} />] : undefined
const messageComponent = <Message classes={classes} message={message} variant={variant} />
return (

View File

@ -1,26 +1,47 @@
// @flow
import * as React from 'react'
import Button from '~/components/layout/Button'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import { sm } from '~/theme/variables'
type ControlProps = {
next: string,
onPrevious: () => void,
firstPage: boolean,
disabled: boolean,
const controlStyle = {
backgroundColor: 'white',
padding: sm,
}
const ControlButtons = ({
next, firstPage, onPrevious, disabled,
}: ControlProps) => (
<React.Fragment>
const firstButtonStyle = {
marginRight: sm,
}
type Props = {
onPrevious: () => void,
firstPage: boolean,
lastPage: boolean,
disabled: boolean,
penultimate: boolean,
}
const Controls = ({
onPrevious, firstPage, penultimate, lastPage, disabled,
}: Props) => {
// eslint-disable-next-line
const next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next'
const back = firstPage ? 'Cancel' : 'Back'
return (
<Row style={controlStyle} align="end" grow>
<Col xs={12} end="xs">
<Button
style={firstButtonStyle}
type="button"
disabled={firstPage || disabled}
onClick={onPrevious}
size="small"
>
Back
{back}
</Button>
<Button
size="small"
variant="raised"
color="primary"
type="submit"
@ -28,29 +49,9 @@ const ControlButtons = ({
>
{next}
</Button>
</React.Fragment>
)
type Props = {
finishedTx: boolean,
finishedButton: React$Node,
onPrevious: () => void,
firstPage: boolean,
lastPage: boolean,
disabled: boolean,
</Col>
</Row>
)
}
const Controls = ({
finishedTx, finishedButton, onPrevious, firstPage, lastPage, disabled,
}: Props) => (
finishedTx
? <React.Fragment>{finishedButton}</React.Fragment>
: <ControlButtons
disabled={disabled}
next={lastPage ? 'Finish' : 'Next'}
firstPage={firstPage}
onPrevious={onPrevious}
/>
)
export default Controls

View File

@ -0,0 +1,48 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper'
import Block from '~/components/layout/Block'
import { lg } from '~/theme/variables'
const styles = () => ({
root: {
margin: '10px',
maxWidth: '870px',
},
container: {
letterSpacing: '-0.5px',
},
padding: {
padding: lg,
},
})
type Props = {
classes: Object,
children: React$Node,
controls: React$Node,
container?: number,
padding?: boolean,
}
const generateContainerStyleFrom = (container?: number) => ({
maxWidth: container ? `${container}px` : undefined,
})
const OpenPaper = ({
classes, children, controls, container, padding = true,
}: Props) => {
const containerStyle = generateContainerStyleFrom(container)
return (
<Paper className={classes.root} elevation={1}>
<Block style={containerStyle} className={`${classes.container} ${padding ? classes.padding : ''}`}>
{children}
</Block>
{ controls }
</Paper>
)
}
export default withStyles(styles)(OpenPaper)

View File

@ -2,26 +2,25 @@
import Stepper from '@material-ui/core/Stepper'
import FormStep from '@material-ui/core/Step'
import StepLabel from '@material-ui/core/StepLabel'
import StepContent from '@material-ui/core/StepContent'
import { withStyles } from '@material-ui/core/styles'
import * as React from 'react'
import GnoForm from '~/components/forms/GnoForm'
import Hairline from '~/components/layout/Hairline'
import Button from '~/components/layout/Button'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import { history } from '~/store'
import Controls from './Controls'
export { default as Step } from './Step'
type Props = {
disabledWhenValidating?: boolean,
classes: Object,
steps: string[],
finishedTransaction: boolean,
finishedButton: React$Node,
initialValues?: Object,
children: React$Node,
onReset?: () => void,
onSubmit: (values: Object) => Promise<void>,
children: React$Node,
classes: Object,
onReset?: () => void,
initialValues?: Object,
disabledWhenValidating?: boolean,
}
type State = {
@ -34,6 +33,13 @@ type PageProps = {
prepareNextInitialProps: (values: Object) => {},
}
const transitionProps = {
timeout: {
enter: 350,
exit: 0,
},
}
class GnoStepper extends React.PureComponent<Props, State> {
static Page = ({ children }: PageProps) => children
@ -70,7 +76,11 @@ class GnoStepper extends React.PureComponent<Props, State> {
const activePageProps = this.getPageProps(pages)
const { children, ...props } = activePageProps
return children(props)
return children({ ...props, updateInitialProps: this.updateInitialProps })
}
updateInitialProps = (initialValues) => {
this.setState({ values: initialValues })
}
validate = (values: Object) => {
@ -96,10 +106,17 @@ class GnoStepper extends React.PureComponent<Props, State> {
}))
}
previous = () =>
this.setState(state => ({
previous = () => {
const firstPage = this.state.page === 0
if (firstPage) {
return history.goBack()
}
return this.setState(state => ({
page: Math.max(state.page - 1, 0),
}))
}
handleSubmit = async (values: Object) => {
const { children, onSubmit } = this.props
@ -112,47 +129,50 @@ class GnoStepper extends React.PureComponent<Props, State> {
return this.next(values)
}
isLastPage = page => page === this.props.steps.length - 1
render() {
const {
steps, children, finishedTransaction, finishedButton, classes, disabledWhenValidating = false,
steps, children, classes, disabledWhenValidating = false,
} = this.props
const { page, values } = this.state
const activePage = this.getActivePageFrom(children)
const isLastPage = page === steps.length - 1
const finished = React.cloneElement(React.Children.only(finishedButton), { onClick: this.onReset })
const lastPage = this.isLastPage(page)
const penultimate = this.isLastPage(page + 1)
return (
<React.Fragment>
<Stepper classes={{ root: classes.root }} activeStep={page} alternativeLabel>
{steps.map(label => (
<FormStep key={label}>
<StepLabel>{label}</StepLabel>
</FormStep>
))}
</Stepper>
<GnoForm
onSubmit={this.handleSubmit}
initialValues={values}
padding={15}
validation={this.validate}
render={activePage}
>
{(submitting: boolean, validating: boolean) => {
{(submitting: boolean, validating: boolean, ...rest: any) => {
const disabled = disabledWhenValidating ? submitting || validating : submitting
return (
<Row align="end" margin="lg" grow>
<Col xs={12} center="xs">
const controls = (
<React.Fragment>
<Hairline />
<Controls
disabled={disabled}
finishedTx={finishedTransaction}
finishedButton={finished}
onPrevious={this.previous}
firstPage={page === 0}
lastPage={isLastPage}
lastPage={lastPage}
penultimate={penultimate}
/>
</Col>
</Row>
</React.Fragment>
)
return (
<Stepper classes={{ root: classes.root }} activeStep={page} orientation="vertical">
{steps.map(label => (
<FormStep key={label}>
<StepLabel>{label}</StepLabel>
<StepContent TransitionProps={transitionProps}>
{activePage(controls, ...rest)}
</StepContent>
</FormStep>
))}
</Stepper>
)
}}
</GnoForm>

View File

@ -12,21 +12,19 @@ export type OnSubmit = (
type Props = {
onSubmit: OnSubmit,
children: Function,
padding: number,
padding?: number,
validation?: (values: Object) => Object | Promise<Object>,
initialValues?: Object,
render: Function,
}
const stylesBasedOn = (padding: number): $Shape<CSSStyleDeclaration> => ({
padding: `0 ${padding}%`,
display: 'flex',
flexDirection: 'column',
flex: '1 0 auto',
})
const GnoForm = ({
onSubmit, validation, initialValues, children, padding, render,
onSubmit, validation, initialValues, children, padding = 0,
}: Props) => (
<Form
validate={validation}
@ -34,8 +32,7 @@ const GnoForm = ({
initialValues={initialValues}
render={({ handleSubmit, ...rest }) => (
<form onSubmit={handleSubmit} style={stylesBasedOn(padding)}>
{render(rest)}
{children(rest.submitting, rest.validating)}
{children(rest.submitting, rest.validating, rest)}
</form>
)}
/>

View File

@ -0,0 +1,47 @@
// @flow
import React from 'react'
import Select, { type SelectFieldProps } from '@material-ui/core/Select'
import FormControl from '@material-ui/core/FormControl'
import InputLabel from '@material-ui/core/InputLabel'
import FormHelperText from '@material-ui/core/FormHelperText'
const style = {
minWidth: '100%',
}
const SelectInput = ({
input: {
name, value, onChange, ...restInput
},
meta,
label,
formControlProps,
...rest
}: SelectFieldProps) => {
const showError = ((meta.submitError && !meta.dirtySinceLastSubmit) || meta.error) && meta.touched
const inputProps = { ...restInput, name }
return (
<FormControl
{...formControlProps}
error={showError}
style={style}
>
<InputLabel htmlFor={name}>{label}</InputLabel>
<Select
{...rest}
onChange={onChange}
inputProps={inputProps}
value={value}
/>
{ showError &&
<FormHelperText>
{meta.error || meta.submitError}
</FormHelperText>
}
</FormControl>
)
}
export default SelectInput

View File

@ -1,12 +1,23 @@
// @flow
import React from 'react'
import MuiTextField, { TextFieldProps } from '@material-ui/core/TextField'
import { withStyles } from '@material-ui/core/styles'
import { lg } from '~/theme/variables'
// Neded for solving a fix in Windows browsers
const overflowStyle = {
overflow: 'hidden',
width: '100%',
}
const styles = () => ({
root: {
paddingTop: lg,
paddingBottom: '12px',
lineHeight: 0,
},
})
class TextField extends React.PureComponent<TextFieldProps> {
render() {
const {
@ -16,25 +27,33 @@ class TextField extends React.PureComponent<TextFieldProps> {
meta,
render,
text,
inputAdornment,
classes,
...rest
} = this.props
const helperText = value ? text : undefined
const showError = (meta.touched || !meta.pristine) && !meta.valid
const underline = meta.active || (meta.visited && !meta.valid)
const inputRoot = helperText ? classes.root : undefined
const inputProps = { ...restInput, autoComplete: 'off' }
const inputRootProps = { ...inputAdornment, disableUnderline: !underline, className: inputRoot }
return (
<MuiTextField
style={overflowStyle}
{...rest}
name={name}
helperText={showError ? meta.error : helperText}
helperText={showError ? meta.error : helperText || ' '} // blank in order to force to have helper text
error={meta.error && (meta.touched || !meta.pristine)}
inputProps={restInput}
InputProps={inputRootProps}
// eslint-disable-next-line
inputProps={inputProps}
onChange={onChange}
value={value}
fullWidth
/>
)
}
}
export default TextField
export default withStyles(styles)(TextField)

View File

@ -4,9 +4,13 @@ import { withStateHandlers } from 'recompose'
export type Open = {
open: boolean,
toggle: () => void,
clickAway: () => void,
}
export default withStateHandlers(
() => ({ open: false }),
{ toggle: ({ open }) => () => ({ open: !open }) },
{
toggle: ({ open }) => () => ({ open: !open }),
clickAway: () => () => ({ open: false }),
},
)

View File

@ -35,6 +35,7 @@ const Col = ({
xs, sm, md, lg,
start, center, end, top, middle, bottom, around, between,
xsOffset, smOffset, mdOffset, lgOffset,
className,
...props
}: Props) => {
const colClassNames = cx(
@ -58,7 +59,7 @@ const Col = ({
lgOffset ? capitalize(lgOffset, 'lgOffset') : undefined,
{ overflow },
layout,
props.className,
className,
)
return (

View File

@ -3,7 +3,7 @@ import * as React from 'react'
import { type Size, getSize } from '~/theme/size'
import { border } from '~/theme/variables'
const calculateStyleFrom = (margin: Size) => ({
const calculateStyleFrom = (margin?: Size) => ({
width: '100%',
height: '1px',
backgroundColor: border,
@ -14,7 +14,7 @@ type Props = {
margin?: Size,
}
const Hairline = ({ margin = 'md' }: Props) => {
const Hairline = ({ margin }: Props) => {
const style = calculateStyleFrom(margin)
return <div style={style} />

View File

@ -13,18 +13,23 @@
.h2 {
line-height: 28px;
font-weight: $bolderFont;
letter-spacing: -0.5px;
font-family: 'Roboto Mono', monospace;
font-size: $(fontSizeHeadingMd)px;
}
.h3 {
line-height: 21px;
font-weight: bold;
font-weight: $bolderFont;
letter-spacing: -0.5px;
font-family: 'Roboto Mono', monospace;
font-size: $(fontSizeHeadingSm)px;
}
.h4 {
line-height: 21px;
letter-spacing: -0.5px;
font-family: 'Roboto Mono', monospace;
font-size: $(fontSizeHeadingXs)px;
}

View File

@ -2,7 +2,13 @@
display: flex;
flex: 1 0 auto;
flex-direction: column;
padding: $xl;
padding: 80px 200px 0px 200px;
}
@media only screen and (max-width: $(screenLg)px) {
.page {
padding: 80px $lg 0px $lg;
}
}
.center {

View File

@ -2,6 +2,7 @@
import React from 'react'
import Footer from '~/components/Footer'
import Header from '~/components/Header'
import { SharedSnackbarProvider } from '~/components/SharedSnackBar/Context'
import styles from './index.scss'
type Props = {
@ -9,11 +10,13 @@ type Props = {
}
const PageFrame = ({ children }: Props) => (
<SharedSnackbarProvider>
<div className={styles.frame}>
<Header />
{children}
<Footer />
</div>
</SharedSnackbarProvider>
)
export default PageFrame

View File

@ -9,22 +9,23 @@ type Props = {
align?: 'right' | 'center' | 'left',
noMargin?: boolean,
weight?: 'light' | 'regular' | 'bolder' | 'bold',
size?: 'sm' | 'md' | 'lg' | 'xl',
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'warning',
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'secondary' | 'warning' | 'disabled',
transform?: 'capitalize' | 'lowercase' | 'uppercase',
children: React$Node,
dot?: boolean,
className?: string,
}
class Paragraph extends React.PureComponent<Props> {
render() {
const {
weight, children, color, align, size, transform, noMargin, className, ...props
weight, children, color, align, size, transform, noMargin, className, dot, ...props
} = this.props
return (
<p
className={cx(styles.paragraph, className, weight, { noMargin }, size, color, transform, align)}
className={cx(styles.paragraph, className, weight, { noMargin }, { dot }, size, color, transform, align)}
{...props}
>
{ children }

View File

@ -22,10 +22,19 @@
.warning {
color: $warning;
}
.primary {
color: $fontColor;
}
.secondary {
color: $secondary;
}
.disabled {
color: $disabled;
}
.white {
color: white;
}
@ -74,6 +83,10 @@
font-size: $extraLargeFontSize;
}
.xxl {
font-size: $xxlFontSize;
}
.light {
font-weight: $lightFont;
}
@ -89,3 +102,7 @@
.bold {
font-weight: $boldFont;
}
.dot {
display: list-item;
}

View File

@ -1,14 +1,12 @@
// @flow
import {
TX_SERVICE_HOST,
ENABLED_TX_SERVICE_MODULES,
ENABLED_TX_SERVICE_REMOVAL_SENDER,
SIGNATURES_VIA_METAMASK,
} from '~/config/names'
const devConfig = {
[TX_SERVICE_HOST]: 'http://localhost:8000/api/v1/',
[ENABLED_TX_SERVICE_MODULES]: false,
[ENABLED_TX_SERVICE_REMOVAL_SENDER]: false,
[SIGNATURES_VIA_METAMASK]: false,
}

View File

@ -2,7 +2,6 @@
import { ensureOnce } from '~/utils/singleton'
import {
TX_SERVICE_HOST,
ENABLED_TX_SERVICE_MODULES,
ENABLED_TX_SERVICE_REMOVAL_SENDER,
SIGNATURES_VIA_METAMASK,
} from '~/config/names'
@ -32,12 +31,6 @@ export const getTxServiceHost = () => {
export const getTxServiceUriFrom = (safeAddress: string) => `safes/${safeAddress}/transactions/`
export const allowedModulesInTxHistoryService = () => {
const config = getConfig()
return config[ENABLED_TX_SERVICE_MODULES]
}
export const allowedRemoveSenderInTxHistoryService = () => {
const config = getConfig()

View File

@ -1,6 +1,5 @@
// @flow
export const TX_SERVICE_HOST = 'tsh'
export const ENABLED_TX_SERVICE_MODULES = 'tsm'
export const ENABLED_TX_SERVICE_REMOVAL_SENDER = 'trs'
export const SIGNATURES_VIA_METAMASK = 'svm'

View File

@ -1,14 +1,12 @@
// @flow
import {
TX_SERVICE_HOST,
ENABLED_TX_SERVICE_MODULES,
ENABLED_TX_SERVICE_REMOVAL_SENDER,
SIGNATURES_VIA_METAMASK,
} from '~/config/names'
const prodConfig = {
[TX_SERVICE_HOST]: 'https://safe-transaction-history.dev.gnosisdev.com/api/v1/',
[ENABLED_TX_SERVICE_MODULES]: false,
[ENABLED_TX_SERVICE_REMOVAL_SENDER]: false,
[SIGNATURES_VIA_METAMASK]: false,
}

View File

@ -1,14 +1,12 @@
// @flow
import {
TX_SERVICE_HOST,
ENABLED_TX_SERVICE_MODULES,
ENABLED_TX_SERVICE_REMOVAL_SENDER,
SIGNATURES_VIA_METAMASK,
} from '~/config/names'
const testConfig = {
[TX_SERVICE_HOST]: 'http://localhost:8000/api/v1/',
[ENABLED_TX_SERVICE_MODULES]: false,
[ENABLED_TX_SERVICE_REMOVAL_SENDER]: false,
[SIGNATURES_VIA_METAMASK]: false,
}

View File

@ -1,48 +0,0 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { getGnosisSafeContract, getCreateDailyLimitExtensionContract } from '~/logic/contracts/safeContracts'
import { type DailyLimitProps } from '~/routes/safe/store/model/dailyLimit'
export const LIMIT_POSITION = 0
export const SPENT_TODAY_POS = 1
export const getDailyLimitModuleFrom = async (safeAddress: string) => {
const web3 = getWeb3()
const gnosisSafe = getGnosisSafeContract(web3).at(safeAddress)
const modules = await gnosisSafe.getModules()
const dailyAddress = modules[0]
const dailyLimitModule = getCreateDailyLimitExtensionContract(web3).at(dailyAddress)
if (await dailyLimitModule.manager.call() !== gnosisSafe.address) {
throw new Error('Using an extension of different safe')
}
return dailyLimitModule
}
export const getDailyLimitFrom = async (safeAddress: string, tokenAddress: number): Promise<DailyLimitProps> => {
const web3 = getWeb3()
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
const dailyLimitEth = await dailyLimitModule.dailyLimits(tokenAddress)
const limit = web3.fromWei(dailyLimitEth[LIMIT_POSITION].valueOf(), 'ether').toString()
const spentToday = web3.fromWei(dailyLimitEth[SPENT_TODAY_POS].valueOf(), 'ether').toString()
return { value: Number(limit), spentToday: Number(spentToday) }
}
export const getDailyLimitAddress = async (safeAddress: string) => {
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
return dailyLimitModule.address
}
export const getEditDailyLimitData = async (safeAddress: string, token: number, dailyLimit: number) => {
const web3 = getWeb3()
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
const dailyLimitInWei = web3.toWei(dailyLimit, 'ether')
return dailyLimitModule.contract.changeDailyLimit.getData(token, dailyLimitInWei)
}

View File

@ -3,43 +3,14 @@ import contract from 'truffle-contract'
import { ensureOnce } from '~/utils/singleton'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
import GnosisSafeSol from '#/GnosisSafeTeamEdition.json'
import GnosisPersonalSafeSol from '#/GnosisSafePersonalEdition.json'
import GnosisSafeSol from '#/GnosisSafe.json'
import ProxyFactorySol from '#/ProxyFactory.json'
import CreateAndAddModules from '#/CreateAndAddModules.json'
import DailyLimitModule from '#/DailyLimitModule.json'
import { calculateGasOf, calculateGasPrice, EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { signaturesViaMetamask } from '~/config'
import { calculateGasOf, calculateGasPrice } from '~/logic/wallets/ethTransactions'
let proxyFactoryMaster
let createAndAddModuleMaster
let safeMaster
let dailyLimitMaster
const createModuleDataWrapper = () => {
const web3 = getWeb3()
// eslint-disable-next-line
return web3.eth.contract([{"constant":false,"inputs":[{"name":"data","type":"bytes"}],"name":"setup","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}])
}
const getModuleDataWrapper = ensureOnce(createModuleDataWrapper)
function createAndAddModulesData(dataArray) {
const ModuleDataWrapper = getModuleDataWrapper()
const mw = ModuleDataWrapper.at(1)
// Remove method id (10) and position of data in payload (64)
return dataArray.reduce((acc, data) => acc + mw.setup.getData(data).substr(74), EMPTY_DATA)
}
const createGnosisSafeContract = (web3: any) => {
if (signaturesViaMetamask()) {
const gnosisSafe = contract(GnosisPersonalSafeSol)
gnosisSafe.setProvider(web3.currentProvider)
return gnosisSafe
}
const gnosisSafe = contract(GnosisSafeSol)
gnosisSafe.setProvider(web3.currentProvider)
@ -53,24 +24,8 @@ const createProxyFactoryContract = (web3: any) => {
return proxyFactory
}
const createAddExtensionContract = (web3: any) => {
const createAndAddModule = contract(CreateAndAddModules)
createAndAddModule.setProvider(web3.currentProvider)
return createAndAddModule
}
const createDailyLimitExtensionContract = (web3: any) => {
const dailyLimitModule = contract(DailyLimitModule)
dailyLimitModule.setProvider(web3.currentProvider)
return dailyLimitModule
}
export const getGnosisSafeContract = ensureOnce(createGnosisSafeContract)
const getCreateProxyFactoryContract = ensureOnce(createProxyFactoryContract)
const getCreateAddExtensionContract = ensureOnce(createAddExtensionContract)
export const getCreateDailyLimitExtensionContract = ensureOnce(createDailyLimitExtensionContract)
const instanciateMasterCopies = async () => {
const web3 = getWeb3()
@ -79,17 +34,9 @@ const instanciateMasterCopies = async () => {
const ProxyFactory = getCreateProxyFactoryContract(web3)
proxyFactoryMaster = await ProxyFactory.deployed()
// Create AddExtension Master Copy
const CreateAndAddExtension = getCreateAddExtensionContract(web3)
createAndAddModuleMaster = await CreateAndAddExtension.deployed()
// Initialize safe master copy
const GnosisSafe = getGnosisSafeContract(web3)
safeMaster = await GnosisSafe.deployed()
// Initialize extension master copy
const DailyLimitExtension = getCreateDailyLimitExtensionContract(web3)
dailyLimitMaster = await DailyLimitExtension.deployed()
}
// ONLY USED IN TEST ENVIRONMENT
@ -101,43 +48,18 @@ const createMasterCopies = async () => {
const ProxyFactory = getCreateProxyFactoryContract(web3)
proxyFactoryMaster = await ProxyFactory.new({ from: userAccount, gas: '5000000' })
const CreateAndAddExtension = getCreateAddExtensionContract(web3)
createAndAddModuleMaster = await CreateAndAddExtension.new({ from: userAccount, gas: '5000000' })
const GnosisSafe = getGnosisSafeContract(web3)
safeMaster = await GnosisSafe.new([userAccount], 1, 0, 0, { from: userAccount, gas: '5000000' })
const DailyLimitExtension = getCreateDailyLimitExtensionContract(web3)
dailyLimitMaster = await DailyLimitExtension.new([], [], { from: userAccount, gas: '5000000' })
safeMaster = await GnosisSafe.new({ from: userAccount, gas: '6000000' })
}
export const initContracts = ensureOnce(process.env.NODE_ENV === 'test' ? createMasterCopies : instanciateMasterCopies)
const getSafeDataBasedOn = async (accounts, numConfirmations, dailyLimitInEth) => {
const web3 = getWeb3()
const moduleData = await dailyLimitMaster.contract.setup
.getData([0], [web3.toWei(dailyLimitInEth, 'ether')])
const proxyFactoryData = await proxyFactoryMaster.contract.createProxy
.getData(dailyLimitMaster.address, moduleData)
const modulesCreationData = createAndAddModulesData([proxyFactoryData])
const createAndAddModuleData = createAndAddModuleMaster.contract.createAndAddModules
.getData(proxyFactoryMaster.address, modulesCreationData)
return safeMaster.contract.setup
.getData(accounts, numConfirmations, createAndAddModuleMaster.address, createAndAddModuleData)
}
export const deploySafeContract = async (
safeAccounts: string[],
numConfirmations: number,
dailyLimit: number,
userAccount: string,
) => {
const gnosisSafeData = await getSafeDataBasedOn(safeAccounts, numConfirmations, dailyLimit)
const gnosisSafeData = await safeMaster.contract.setup.getData(safeAccounts, numConfirmations, 0, '0x')
const proxyFactoryData = proxyFactoryMaster.contract.createProxy.getData(safeMaster.address, gnosisSafeData)
const gas = await calculateGasOf(proxyFactoryData, userAccount, proxyFactoryMaster.address)
const gasPrice = await calculateGasPrice()

View File

@ -1,9 +1,10 @@
// @flow
import { List } from 'immutable'
import { calculateGasOf, checkReceiptStatus, calculateGasPrice } from '~/logic/wallets/ethTransactions'
import { type Operation, submitOperation } from '~/logic/safe/safeTxHistory'
import { getDailyLimitModuleFrom } from '~/logic/contracts/dailyLimitContracts'
import { getSafeEthereumInstance } from '~/logic/safe/safeFrontendOperations'
import { generateMetamaskSignature, generateTxGasEstimateFrom, estimateDataGas } from '~/logic/safe/safeTxSigner'
import { buildSignaturesFrom } from '~/logic/safe/safeTxSigner'
import { generateMetamaskSignature, generateTxGasEstimateFrom, estimateDataGas } from '~/logic/safe/safeTxSignerEIP712'
import { storeSignature, getSignaturesFrom } from '~/utils/localStorage/signatures'
import { signaturesViaMetamask } from '~/config'
@ -19,18 +20,23 @@ export const approveTransaction = async (
const gasPrice = await calculateGasPrice()
if (signaturesViaMetamask()) {
// return executeTransaction(safeAddress, to, valueInWei, data, operation, nonce, sender)
const safe = await getSafeEthereumInstance(safeAddress)
const txGasEstimate = await generateTxGasEstimateFrom(safe, safeAddress, data, to, valueInWei, operation)
const signature =
await generateMetamaskSignature(safe, safeAddress, sender, to, valueInWei, nonce, data, operation, txGasEstimate)
storeSignature(safeAddress, nonce, signature)
return undefined
}
const gnosisSafe = await getSafeEthereumInstance(safeAddress)
const txData = gnosisSafe.contract.approveTransactionWithParameters.getData(to, valueInWei, data, operation, nonce)
const gas = await calculateGasOf(txData, sender, safeAddress)
const txReceipt = await gnosisSafe
.approveTransactionWithParameters(to, valueInWei, data, operation, nonce, { from: sender, gas, gasPrice })
const contractTxHash = await gnosisSafe.getTransactionHash(to, valueInWei, data, operation, 0, 0, 0, 0, 0, nonce)
const approveData = gnosisSafe.contract.approveHash.getData(contractTxHash)
const gas = await calculateGasOf(approveData, sender, safeAddress)
const txReceipt = await gnosisSafe.approveHash(contractTxHash, { from: sender, gas, gasPrice })
const txHash = txReceipt.tx
await checkReceiptStatus(txHash)
@ -47,6 +53,7 @@ export const executeTransaction = async (
operation: Operation,
nonce: number,
sender: string,
ownersWhoHasSigned: List<string>,
) => {
const gasPrice = await calculateGasPrice()
@ -58,21 +65,22 @@ export const executeTransaction = async (
storeSignature(safeAddress, nonce, signature)
const sigs = getSignaturesFrom(safeAddress, nonce)
const threshold = await safe.getThreshold()
const gas = await estimateDataGas(safe, to, valueInWei, data, operation, txGasEstimate, 0, nonce, Number(threshold))
const gas =
await estimateDataGas(safe, to, valueInWei, data, operation, txGasEstimate, 0, nonce, Number(threshold), 0)
const numOwners = await safe.getOwners()
const gasIncludingRemovingStoreUpfront = gas + txGasEstimate + (numOwners.length * 15000)
const txReceipt = await safe.execTransactionAndPaySubmitter(
const txReceipt = await safe.execTransaction(
to,
valueInWei,
data,
operation,
txGasEstimate,
0,
0,
0,
0, // dataGasEstimate
0, // gasPrice
0, // txGasToken
0, // refundReceiver
sigs,
{ from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice },
)
@ -85,17 +93,23 @@ export const executeTransaction = async (
}
const gnosisSafe = await getSafeEthereumInstance(safeAddress)
const txConfirmationData =
gnosisSafe.contract.execTransactionIfApproved.getData(to, valueInWei, data, operation, nonce)
const signatures = buildSignaturesFrom(ownersWhoHasSigned, sender)
const txExecutionData =
gnosisSafe.contract.execTransaction.getData(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures)
const gas = await calculateGasOf(txExecutionData, sender, safeAddress)
const numOwners = await gnosisSafe.getOwners()
const gas = await calculateGasOf(txConfirmationData, sender, safeAddress)
const gasIncludingRemovingStoreUpfront = gas + (numOwners.length * 15000)
const txReceipt = await gnosisSafe.execTransactionIfApproved(
const txReceipt = await gnosisSafe.execTransaction(
to,
valueInWei,
data,
operation,
nonce,
0,
0,
0,
0,
0,
signatures,
{ from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice },
)
const txHash = txReceipt.tx
@ -105,33 +119,3 @@ export const executeTransaction = async (
return txHash
}
export const executeDailyLimit = async (
safeAddress: string,
to: string,
nonce: number,
valueInWei: number,
sender: string,
) => {
const dailyLimitModule = await getDailyLimitModuleFrom(safeAddress)
const dailyLimitData = dailyLimitModule.contract.executeDailyLimit.getData(0, to, valueInWei)
const gas = await calculateGasOf(dailyLimitData, sender, dailyLimitModule.address)
const gasPrice = await calculateGasPrice()
try {
const txReceipt = await dailyLimitModule.executeDailyLimit(0, to, valueInWei, { from: sender, gas, gasPrice })
await checkReceiptStatus(txReceipt.tx)
return Promise.resolve(txReceipt.tx)
} catch (err) {
return Promise.reject(new Error(err))
}
/*
// Temporarily disabled for daily limit operations
const operation = 0 // CALL for all currencies
const data = '' // empty for ETH
await submitOperation(safeAddress, to, Number(valueInWei), data, operation, nonce, txReceipt.tx, sender, 'execution')
*/
}

View File

@ -1,9 +1,9 @@
// @flow
import { List } from 'immutable'
import { type Transaction } from '~/routes/safe/store/model/transaction'
import { executeDailyLimit, executeTransaction, approveTransaction } from '~/logic/safe/safeBlockchainOperations'
import { executeTransaction, approveTransaction } from '~/logic/safe/safeBlockchainOperations'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { DESTINATION_PARAM, VALUE_PARAM } from '~/routes/safe/component/Withdraw/WithdrawForm'
import { type Safe } from '~/routes/safe/store/model/safe'
import { getGnosisSafeContract } from '~/logic/contracts/safeContracts'
import { storeSubject } from '~/utils/localStorage/transactions'
@ -47,7 +47,7 @@ export const createTransaction = async (
const isExecution = hasOneOwner(safe) || threshold === 1
const txHash = isExecution
? await executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
? await executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender, List([]))
: await approveTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
storeSubject(safeAddress, nonce, name)
@ -61,6 +61,7 @@ export const processTransaction = async (
alreadyConfirmed: number,
sender: string,
threshold: number,
usersConfirmed: List<string>,
) => {
const nonce = tx.get('nonce')
const valueInWei = tx.get('value')
@ -70,21 +71,8 @@ export const processTransaction = async (
const thresholdReached = threshold === alreadyConfirmed + 1
const txHash = thresholdReached
? await executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
? await executeTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender, usersConfirmed)
: await approveTransaction(safeAddress, to, valueInWei, data, CALL, nonce, sender)
return txHash
}
export const withdraw = async (values: Object, safe: Safe, sender: string): Promise<void> => {
const safeAddress = safe.get('address')
const destination = values[DESTINATION_PARAM]
const valueInEth = values[VALUE_PARAM]
const valueInWei = getWeb3().toWei(valueInEth, 'ether')
const nonce = Date.now()
const txHash = await executeDailyLimit(safeAddress, destination, nonce, valueInWei, sender)
storeSubject(safeAddress, nonce, `Withdraw movement of ${valueInEth}`)
return txHash
}

View File

@ -18,7 +18,8 @@ const calculateBodyFrom = async (
type: TxServiceType,
) => {
const gnosisSafe = await getSafeEthereumInstance(safeAddress)
const contractTransactionHash = await gnosisSafe.getTransactionHash(to, valueInWei, data, operation, nonce)
const contractTransactionHash =
await gnosisSafe.getTransactionHash(to, valueInWei, data, operation, 0, 0, 0, 0, 0, nonce)
return JSON.stringify({
to: getWeb3().toChecksumAddress(to),
@ -26,6 +27,11 @@ const calculateBodyFrom = async (
data,
operation,
nonce,
safeTxGas: 0,
dataGas: 0,
gasPrice: 0,
gasToken: null,
refundReceiver: null,
contractTransactionHash,
transactionHash,
sender: getWeb3().toChecksumAddress(sender),

View File

@ -1,161 +1,17 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
import { BigNumber } from 'bignumber.js'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getSignaturesFrom } from '~/utils/localStorage/signatures'
import { List } from 'immutable'
const estimateDataGasCosts = (data) => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0
}
const generateSignatureFrom = (account: string) =>
`000000000000000000000000${account.replace('0x', '')}000000000000000000000000000000000000000000000000000000000000000001`
if (currentValue === '00') {
return accumulator + 4
}
export const buildSignaturesFrom = (ownersWhoHasSigned: List<string>, sender: string) => {
const signatures = ownersWhoHasSigned.push(sender)
const orderedSignatures = signatures.sort() // JS by default sorts in a non case-senstive way
return accumulator + 68
}
let sigs = '0x'
orderedSignatures.forEach((owner: string) => {
sigs += generateSignatureFrom(owner)
})
return data.match(/.{2}/g).reduce(reducer, 0)
}
export const estimateDataGas = (
safe: any,
to: string,
valueInWei: number,
data: string,
operation: number,
txGasEstimate: number,
gasToken: number,
nonce: number,
signatureCount: number,
) => {
// numbers < 256 are 192 -> 31 * 4 + 68
// numbers < 65k are 256 -> 30 * 4 + 2 * 68
// For signature array length and dataGasEstimate we already calculated
// the 0 bytes so we just add 64 for each non-zero byte
const gasPrice = 0 // no need to get refund when we submit txs to metamask
const signatureCost = signatureCount * (68 + 2176 + 2176) // array count (3 -> r, s, v) * signature count
const sigs = getSignaturesFrom(safe.address, nonce)
const payload = safe.contract.execTransactionAndPaySubmitter
.getData(to, valueInWei, data, operation, txGasEstimate, 0, gasPrice, gasToken, sigs)
let dataGasEstimate = estimateDataGasCosts(payload) + signatureCost
if (dataGasEstimate > 65536) {
dataGasEstimate += 64
} else {
dataGasEstimate += 128
}
return dataGasEstimate + 34000 // Add aditional gas costs (e.g. base tx costs, transfer costs)
}
// eslint-disable-next-line
export const generateTxGasEstimateFrom = async (
safe: any,
safeAddress: string,
data: string,
to: string,
valueInWei: number,
operation: number,
) => {
try {
const estimateData = safe.contract.requiredTxGas.getData(to, valueInWei, data, operation)
const estimateResponse = await promisify(cb => getWeb3().eth.call({
to: safeAddress,
from: safeAddress,
data: estimateData,
}, cb))
const txGasEstimate = new BigNumber(estimateResponse.substring(138), 16)
// Add 10k else we will fail in case of nested calls
return Promise.resolve(txGasEstimate.toNumber() + 10000)
} catch (error) {
// eslint-disable-next-line
console.log("Error calculating tx gas estimation " + error)
return Promise.resolve(0)
}
}
const generateTypedDataFrom = async (
safe: any,
safeAddress: string,
to: string,
valueInWei: number,
nonce: number,
data: string,
operation: number,
txGasEstimate: number,
) => {
const txGasToken = 0
// const threshold = await safe.getThreshold()
// estimateDataGas(safe, to, valueInWei, data, operation, txGasEstimate, txGasToken, nonce, threshold)
const dataGasEstimate = 0
const gasPrice = 0
const typedData = {
types: {
EIP712Domain: [
{
type: 'address',
name: 'verifyingContract',
},
],
PersonalSafeTx: [
{ type: 'address', name: 'to' },
{ type: 'uint256', name: 'value' },
{ type: 'bytes', name: 'data' },
{ type: 'uint8', name: 'operation' },
{ type: 'uint256', name: 'safeTxGas' },
{ type: 'uint256', name: 'dataGas' },
{ type: 'uint256', name: 'gasPrice' },
{ type: 'address', name: 'gasToken' },
{ type: 'uint256', name: 'nonce' },
],
},
domain: {
verifyingContract: safeAddress,
},
primaryType: 'PersonalSafeTx',
message: {
to,
value: valueInWei,
data,
operation,
safeTxGas: txGasEstimate,
dataGas: dataGasEstimate,
gasPrice,
gasToken: txGasToken,
nonce,
},
}
return typedData
}
export const generateMetamaskSignature = async (
safe: any,
safeAddress: string,
sender: string,
to: string,
valueInWei: number,
nonce: number,
data: string,
operation: number,
txGasEstimate: number,
) => {
const web3 = getWeb3()
const typedData =
await generateTypedDataFrom(safe, safeAddress, to, valueInWei, nonce, data, operation, txGasEstimate)
const signedTypedData = {
jsonrpc: '2.0',
method: 'eth_signTypedData',
params: [sender, typedData],
id: Date.now(),
}
const txSignedResponse = await promisify(cb => web3.currentProvider.sendAsync(signedTypedData, cb))
return txSignedResponse.result.replace(EMPTY_DATA, '')
return sigs
}

View File

@ -0,0 +1,169 @@
// @flow
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { promisify } from '~/utils/promisify'
import { BigNumber } from 'bignumber.js'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getSignaturesFrom } from '~/utils/localStorage/signatures'
const estimateDataGasCosts = (data) => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0
}
if (currentValue === '00') {
return accumulator + 4
}
return accumulator + 68
}
return data.match(/.{2}/g).reduce(reducer, 0)
}
export const estimateDataGas = (
safe: any,
to: string,
valueInWei: number,
data: string,
operation: number,
txGasEstimate: number,
gasToken: number,
nonce: number,
signatureCount: number,
refundReceiver: number,
) => {
// numbers < 256 are 192 -> 31 * 4 + 68
// numbers < 65k are 256 -> 30 * 4 + 2 * 68
// For signature array length and dataGasEstimate we already calculated
// the 0 bytes so we just add 64 for each non-zero byte
const gasPrice = 0 // no need to get refund when we submit txs to metamask
const signatureCost = signatureCount * (68 + 2176 + 2176) // array count (3 -> r, s, v) * signature count
const sigs = getSignaturesFrom(safe.address, nonce)
const payload = safe.contract.execTransaction
.getData(to, valueInWei, data, operation, txGasEstimate, 0, gasPrice, gasToken, refundReceiver, sigs)
let dataGasEstimate = estimateDataGasCosts(payload) + signatureCost
if (dataGasEstimate > 65536) {
dataGasEstimate += 64
} else {
dataGasEstimate += 128
}
return dataGasEstimate + 34000 // Add aditional gas costs (e.g. base tx costs, transfer costs)
}
// eslint-disable-next-line
export const generateTxGasEstimateFrom = async (
safe: any,
safeAddress: string,
data: string,
to: string,
valueInWei: number,
operation: number,
) => {
try {
const estimateData = safe.contract.requiredTxGas.getData(to, valueInWei, data, operation)
const estimateResponse = await promisify(cb => getWeb3().eth.call({
to: safeAddress,
from: safeAddress,
data: estimateData,
}, cb))
const txGasEstimate = new BigNumber(estimateResponse.substring(138), 16)
// Add 10k else we will fail in case of nested calls
return Promise.resolve(txGasEstimate.toNumber() + 10000)
} catch (error) {
// eslint-disable-next-line
console.log("Error calculating tx gas estimation " + error)
return Promise.resolve(0)
}
}
const generateTypedDataFrom = async (
safe: any,
safeAddress: string,
to: string,
valueInWei: number,
nonce: number,
data: string,
operation: number,
txGasEstimate: number,
) => {
const txGasToken = 0
// const threshold = await safe.getThreshold()
// estimateDataGas(safe, to, valueInWei, data, operation, txGasEstimate, txGasToken, nonce, threshold)
const dataGasEstimate = 0
const gasPrice = 0
const refundReceiver = 0
const typedData = {
types: {
EIP712Domain: [
{
type: 'address',
name: 'verifyingContract',
},
],
SafeTx: [
{ type: 'address', name: 'to' },
{ type: 'uint256', name: 'value' },
{ type: 'bytes', name: 'data' },
{ type: 'uint8', name: 'operation' },
{ type: 'uint256', name: 'safeTxGas' },
{ type: 'uint256', name: 'dataGas' },
{ type: 'uint256', name: 'gasPrice' },
{ type: 'address', name: 'gasToken' },
{ type: 'address', name: 'refundReceiver' },
{ type: 'uint256', name: 'nonce' },
],
},
domain: {
verifyingContract: safeAddress,
},
primaryType: 'SafeTx',
message: {
to,
value: Number(valueInWei),
data,
operation,
safeTxGas: txGasEstimate,
dataGas: dataGasEstimate,
gasPrice,
gasToken: txGasToken,
refundReceiver,
nonce: Number(nonce),
},
}
return typedData
}
export const generateMetamaskSignature = async (
safe: any,
safeAddress: string,
sender: string,
to: string,
valueInWei: number,
nonce: number,
data: string,
operation: number,
txGasEstimate: number,
) => {
const web3 = getWeb3()
const typedData =
await generateTypedDataFrom(safe, safeAddress, to, valueInWei, nonce, data, operation, txGasEstimate)
const jsonTypedData = JSON.stringify(typedData)
const signedTypedData = {
method: 'eth_signTypedData_v3',
// To change once Metamask fixes their status
// https://github.com/MetaMask/metamask-extension/pull/5368
// https://github.com/MetaMask/metamask-extension/issues/5366
params: [jsonTypedData, sender],
from: sender,
}
const txSignedResponse = await promisify(cb => web3.currentProvider.sendAsync(signedTypedData, cb))
return txSignedResponse.result.replace(EMPTY_DATA, '')
}

View File

@ -33,7 +33,9 @@ export const ETHEREUM_NETWORK_IDS = {
42: ETHEREUM_NETWORK.KOVAN,
}
export const openInEtherScan = (address: string, network: string) => () => {
export const openTxInEtherScan = (tx: string, network: string) => `https://${network}.etherscan.io/tx/${tx}`
export const openAddressInEtherScan = (address: string, network: string) => () => {
window.open(`https://${network}.etherscan.io/address/${address}`)
}

View File

@ -1,14 +1,14 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
import { getProviderInfo } from '~/logic/wallets/getWeb3'
import { getProviderInfo, ETHEREUM_NETWORK_IDS, ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
import { makeProvider } from '~/logic/wallets/store/model/provider'
import addProvider from './addProvider'
export const processProviderResponse = (dispatch: ReduxDispatch<*>, response: ProviderProps) => {
export const processProviderResponse = (dispatch: ReduxDispatch<*>, provider: ProviderProps) => {
const {
name, available, loaded, account, network,
} = response
} = provider
const walletRecord = makeProvider({
name, available, loaded, account, network,
@ -17,8 +17,33 @@ export const processProviderResponse = (dispatch: ReduxDispatch<*>, response: Pr
dispatch(addProvider(walletRecord))
}
export default () => async (dispatch: ReduxDispatch<*>) => {
const response: ProviderProps = await getProviderInfo()
const SUCCESS_MSG = 'Wallet connected sucessfully'
const UNLOCK_MSG = 'Unlock your wallet to connect'
const WRONG_NETWORK = 'You are connected to wrong network. Please use RINKEBY'
export const WALLET_ERROR_MSG = 'Error connecting to your wallet'
processProviderResponse(dispatch, response)
const handleProviderNotification = (openSnackbar: Function, provider: ProviderProps) => {
const { loaded, available, network } = provider
if (!loaded) {
openSnackbar(WALLET_ERROR_MSG, 'error')
return
}
if (ETHEREUM_NETWORK_IDS[network] !== ETHEREUM_NETWORK.RINKEBY) {
openSnackbar(WRONG_NETWORK, 'error')
return
}
const msg = available ? SUCCESS_MSG : UNLOCK_MSG
const variant = available ? 'success' : 'warning'
openSnackbar(msg, variant)
}
export default (openSnackbar: Function) => async (dispatch: ReduxDispatch<*>) => {
const provider: ProviderProps = await getProviderInfo()
handleProviderNotification(openSnackbar, provider)
processProviderResponse(dispatch, provider)
}

View File

@ -3,7 +3,7 @@ import type { Dispatch as ReduxDispatch } from 'redux'
import { makeProvider, type ProviderProps, type Provider } from '~/logic/wallets/store/model/provider'
import addProvider from './addProvider'
export default () => async (dispatch: ReduxDispatch<*>) => {
export default (openSnackbar: Function) => async (dispatch: ReduxDispatch<*>) => {
const providerProps: ProviderProps = {
name: '',
available: false,
@ -13,5 +13,7 @@ export default () => async (dispatch: ReduxDispatch<*>) => {
}
const provider: Provider = makeProvider(providerProps)
openSnackbar('Wallet disconnected succesfully', 'info')
dispatch(addProvider(provider))
}

View File

@ -4,7 +4,7 @@ import Loadable from 'react-loadable'
import { Switch, Redirect, Route } from 'react-router-dom'
import Loader from '~/components/Loader'
import Welcome from './welcome/container'
import { SAFELIST_ADDRESS, OPEN_ADDRESS, SAFE_PARAM_ADDRESS, WELCOME_ADDRESS, SETTINS_ADDRESS } from './routes'
import { SAFELIST_ADDRESS, OPEN_ADDRESS, SAFE_PARAM_ADDRESS, WELCOME_ADDRESS, SETTINS_ADDRESS, OPENING_ADDRESS } from './routes'
const Safe = Loadable({
loader: () => import('./safe/container'),
@ -26,6 +26,11 @@ const Open = Loadable({
loading: Loader,
})
const Opening = Loadable({
loader: () => import('./opening/container'),
loading: Loader,
})
const SAFE_ADDRESS = `${SAFELIST_ADDRESS}/:${SAFE_PARAM_ADDRESS}`
const SAFE_SETTINGS = `${SAFE_ADDRESS}${SETTINS_ADDRESS}`
@ -39,6 +44,7 @@ const Routes = () => (
<Route exact path={SAFELIST_ADDRESS} component={SafeList} />
<Route exact path={SAFE_ADDRESS} component={Safe} />
<Route exact path={SAFE_SETTINGS} component={Settings} />
<Route exact path={OPENING_ADDRESS} component={Opening} />
</Switch>
)

View File

@ -1,56 +0,0 @@
// @flow
import * as React from 'react'
import CircularProgress from '@material-ui/core/CircularProgress'
import Block from '~/components/layout/Block'
import Bold from '~/components/layout/Bold'
import Col from '~/components/layout/Col'
import Paragraph from '~/components/layout/Paragraph'
import Pre from '~/components/layout/Pre'
import Row from '~/components/layout/Row'
type FormProps = {
submitting: boolean,
}
type Props = {
address: string,
tx: Object,
}
export const DEPLOYED_COMPONENT_ID = 'deployedSafeComponent'
const Deployment = ({ address, tx }: Props) => (
<Block className={DEPLOYED_COMPONENT_ID}>
<Paragraph><Bold>Deployed safe to: </Bold>{address}</Paragraph>
<Pre>
{JSON.stringify(tx, null, 2) }
</Pre>
</Block>
)
export default ({ address, tx }: Props) => ({ submitting }: FormProps) => {
const txFinished = !!address
return (
<Block>
{ !txFinished &&
<React.Fragment>
<Paragraph align="center" size="lg">
You are about to create a Safe for keeping your funds more secure.
</Paragraph>
<Paragraph align="center" size="lg">
Remember to check you have enough funds in your wallet.
</Paragraph>
</React.Fragment>
}
<Row>
<Col xs={12} center={submitting ? 'xs' : undefined} margin="lg">
{ submitting
? <CircularProgress size={50} />
: txFinished && <Deployment address={address} tx={tx} />
}
</Col>
</Row>
</Block>
)
}

View File

@ -1,56 +1,82 @@
// @flow
import * as React from 'react'
import Stepper from '~/components/Stepper'
import Confirmation from '~/routes/open/components/FormConfirmation'
import Block from '~/components/layout/Block'
import Heading from '~/components/layout/Heading'
import Row from '~/components/layout/Row'
import IconButton from '@material-ui/core/IconButton'
import Review from '~/routes/open/components/ReviewInformation'
import SafeFields, { safeFieldsValidation } from '~/routes/open/components/SafeForm'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import Link from '~/components/layout/Link'
import ChevronLeft from '@material-ui/icons/ChevronLeft'
import SafeNameField from '~/routes/open/components/SafeNameForm'
import SafeThresholdField, { safeFieldsValidation } from '~/routes/open/components/SafeThresholdForm'
import SafeOwnersFields from '~/routes/open/components/SafeOwnersForm'
import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes/open/components/fields'
import { history } from '~/store'
import { secondary } from '~/theme/variables'
const getSteps = () => [
'Fill Safe Form', 'Review Information', 'Deploy it',
'Start', 'Owners', 'Confirmations', 'Review',
]
const initialValuesFrom = (userAccount: string) => ({
owner0Address: userAccount,
[getOwnerNameBy(0)]: 'My Metamask (me)',
[getOwnerAddressBy(0)]: userAccount,
[FIELD_CONFIRMATIONS]: '1',
})
type Props = {
provider: string,
userAccount: string,
safeAddress: string,
safeTx: string,
network: string,
onCallSafeContractSubmit: (values: Object) => Promise<void>,
}
const iconStyle = {
color: secondary,
width: '32px',
height: '32px',
}
const back = () => {
history.goBack()
}
const Layout = ({
provider, userAccount, safeAddress, safeTx, onCallSafeContractSubmit,
provider, userAccount, onCallSafeContractSubmit, network,
}: Props) => {
const steps = getSteps()
const initialValues = initialValuesFrom(userAccount)
const finishedButton = <Stepper.FinishButton title="VISIT SAFES" component={Link} to={SAFELIST_ADDRESS} />
return (
<React.Fragment>
{ provider
? (
<Block>
<Row align="center">
<IconButton onClick={back} style={iconStyle} disableRipple>
<ChevronLeft />
</IconButton>
<Heading tag="h2">Create New Safe</Heading>
</Row>
<Stepper
finishedButton={finishedButton}
finishedTransaction={!!safeAddress}
onSubmit={onCallSafeContractSubmit}
steps={steps}
initialValues={initialValues}
>
<Stepper.Page validate={safeFieldsValidation}>
{ SafeFields }
<Stepper.Page>
{ SafeNameField }
</Stepper.Page>
<Stepper.Page>
{ SafeOwnersFields }
</Stepper.Page>
<Stepper.Page validate={safeFieldsValidation}>
{ SafeThresholdField }
</Stepper.Page>
<Stepper.Page network={network}>
{ Review }
</Stepper.Page>
<Stepper.Page address={safeAddress} tx={safeTx}>
{ Confirmation }
</Stepper.Page>
</Stepper>
</Block>
)
: <div>No metamask detected</div>
}

View File

@ -49,6 +49,7 @@ storiesOf('Routes /open', module)
return (
<State store={store}>
<Component
network="rinkeby"
provider={provider}
userAccount={userAccount}
safeAddress={store.get('safeAddress')}

View File

@ -2,50 +2,158 @@
import * as React from 'react'
import { getNamesFrom, getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import Block from '~/components/layout/Block'
import Bold from '~/components/layout/Bold'
import { withStyles } from '@material-ui/core/styles'
import OpenInNew from '@material-ui/icons/OpenInNew'
import Identicon from '~/components/Identicon'
import OpenPaper from '~/components/Stepper/OpenPaper'
import Col from '~/components/layout/Col'
import Heading from '~/components/layout/Heading'
import Row from '~/components/layout/Row'
import Paragraph from '~/components/layout/Paragraph'
import { FIELD_NAME, FIELD_CONFIRMATIONS, FIELD_DAILY_LIMIT } from '../fields'
import { sm, md, lg, border, secondary, background } from '~/theme/variables'
import Hairline from '~/components/layout/Hairline'
import { openAddressInEtherScan } from '~/logic/wallets/getWeb3'
import { FIELD_NAME, FIELD_CONFIRMATIONS, getNumOwnersFrom } from '../fields'
type FormProps = {
values: Object,
const openIconStyle = {
height: '16px',
color: secondary,
}
const ReviewInformation = () => ({ values }: FormProps) => {
const styles = () => ({
root: {
minHeight: '300px',
},
details: {
padding: lg,
borderRight: `solid 1px ${border}`,
height: '100%',
},
info: {
backgroundColor: background,
padding: lg,
justifyContent: 'center',
textAlign: 'center',
flexDirection: 'column',
},
owners: {
padding: lg,
},
name: {
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
},
owner: {
padding: md,
alignItems: 'center',
},
user: {
justifyContent: 'left',
},
open: {
paddingLeft: sm,
width: 'auto',
'&:hover': {
cursor: 'pointer',
},
},
})
type LayoutProps = {
network: string,
}
type Props = LayoutProps & {
values: Object,
classes: Object,
}
const ReviewComponent = ({ values, classes, network }: Props) => {
const names = getNamesFrom(values)
const addresses = getAccountsFrom(values)
const numOwners = getNumOwnersFrom(values)
return (
<Block>
<Heading tag="h2">Review the Safe information</Heading>
<Paragraph>
<Bold>Safe Name: </Bold> {values[FIELD_NAME]}
<React.Fragment>
<Row className={classes.root}>
<Col xs={4} layout="column">
<Block className={classes.details}>
<Block margin="lg">
<Paragraph size="lg" color="primary" noMargin>
Details
</Paragraph>
<Paragraph>
<Bold>Required confirmations: </Bold> {values[FIELD_CONFIRMATIONS]}
</Block>
<Block margin="lg">
<Paragraph size="sm" color="disabled" noMargin>
Name of new Safe
</Paragraph>
<Paragraph>
<Bold>Daily limit: </Bold> {values[FIELD_DAILY_LIMIT]} ETH
<Paragraph size="lg" color="primary" noMargin weight="bolder" className={classes.name}>
{values[FIELD_NAME]}
</Paragraph>
<Heading tag="h3">Owners</Heading>
{ names.map((name, index) => (
<Row key={`name${(index)}`} margin="md">
<Col xs={11} xsOffset={1}margin="sm">
<Block>
<Paragraph noMargin>{name}</Paragraph>
</Block>
<Block margin="lg">
<Paragraph size="sm" color="disabled" noMargin>
Any transaction requires the confirmation of:
</Paragraph>
<Paragraph size="lg" color="primary" noMargin weight="bolder">
{`${values[FIELD_CONFIRMATIONS]} out of ${numOwners} owners`}
</Paragraph>
</Block>
</Block>
</Col>
<Col xs={11} xsOffset={1} margin="sm">
<Block>
<Paragraph noMargin>{addresses[index]}</Paragraph>
<Col xs={8} layout="column">
<Block className={classes.owners}>
<Paragraph size="lg" color="primary" noMargin>
{`${numOwners} Safe owners`}
</Paragraph>
</Block>
<Hairline />
{ names.map((name, index) => (
<React.Fragment key={`name${(index)}`}>
<Row className={classes.owner}>
<Col xs={1} align="center">
<Identicon address={addresses[index]} diameter={32} />
</Col>
<Col xs={11}>
<Block className={classes.name}>
<Paragraph size="lg" noMargin >{name}</Paragraph>
<Block align="center" className={classes.user}>
<Paragraph size="md" color="disabled" noMargin>{addresses[index]}</Paragraph>
<OpenInNew
className={classes.open}
style={openIconStyle}
onClick={openAddressInEtherScan(addresses[index], network)}
/>
</Block>
</Block>
</Col>
</Row>
<Hairline />
</React.Fragment>
))}
</Block>
</Col>
</Row>
<Row className={classes.info} align="center">
<Paragraph noMargin color="primary" size="md">
{'You\'re about to create a new Safe.'}
</Paragraph>
<Paragraph noMargin color="primary" size="md">
Make sure you have enough ETH in your wallet client to fund this transaction.
</Paragraph>
</Row>
</React.Fragment>
)
}
export default ReviewInformation
const ReviewPage = withStyles(styles)(ReviewComponent)
const Review = ({ network }: LayoutProps) => (controls: React$Node, { values }: Object) => (
<React.Fragment>
<OpenPaper controls={controls} padding={false}>
<ReviewPage network={network} values={values} />
</OpenPaper>
</React.Fragment>
)
export default Review

View File

@ -1,26 +0,0 @@
// @flow
import * as React from 'react'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { composeValidators, minValue, mustBeInteger, required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import { FIELD_CONFIRMATIONS } from '~/routes/open/components/fields'
const Confirmations = () => (
<Block margin="md">
<Field
name={FIELD_CONFIRMATIONS}
component={TextField}
type="text"
validate={composeValidators(
required,
mustBeInteger,
minValue(1),
)}
placeholder="Required confirmations*"
text="Required confirmations"
/>
</Block>
)
export default Confirmations

View File

@ -1,73 +0,0 @@
// @flow
import TextField from '~/components/forms/TextField'
import * as React from 'react'
import * as TestUtils from 'react-dom/test-utils'
import Layout from '~/routes/open/components/Layout'
import { FIELD_CONFIRMATIONS, FIELD_OWNERS } from '~/routes/open/components/fields'
import { getProviderInfo } from '~/logic/wallets/getWeb3'
import Wrapper from '~/test/utils/Wrapper'
import { CONFIRMATIONS_ERROR } from '~/routes/open/components/SafeForm'
const onSubmitMock = async (): Promise<void> => {}
describe('React DOM TESTS > Create Safe form', () => {
let open
let fieldOwners
let fieldConfirmations
beforeEach(async () => {
// init app web3 instance
await getProviderInfo()
open = TestUtils.renderIntoDocument((
<Wrapper>
<Layout
provider="METAMASK"
userAccount="foo"
safeAddress=""
safeTx=""
onCallSafeContractSubmit={onSubmitMock}
/>
</Wrapper>
))
const inputs = TestUtils.scryRenderedDOMComponentsWithTag(open, 'input')
const indexOwners = 1
const indexConfirmations = 2
fieldOwners = inputs[indexOwners]
fieldConfirmations = inputs[indexConfirmations]
expect(fieldOwners.name).toEqual(FIELD_OWNERS)
expect(fieldConfirmations.name).toEqual(FIELD_CONFIRMATIONS)
})
it('should not allow to continue if confirmations are higher than owners', async () => {
// GIVEN
TestUtils.Simulate.change(fieldOwners, { target: { value: '1' } })
// WHEN
TestUtils.Simulate.change(fieldConfirmations, { target: { value: '2' } })
// THEN
const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
expect(6).toEqual(muiFields.length)
const confirmationsField = muiFields[4]
expect(confirmationsField.props.meta.valid).toBe(false)
expect(confirmationsField.props.meta.error).toBe(CONFIRMATIONS_ERROR)
})
it('should raise error when confirmations are 012 and number of owners are 2', async () => {
// GIVEN
TestUtils.Simulate.change(fieldOwners, { target: { value: '2' } })
// WHEN
TestUtils.Simulate.change(fieldConfirmations, { target: { value: '014' } })
// THEN
const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
expect(8).toEqual(muiFields.length)
const confirmationsField = muiFields[6]
expect(confirmationsField.props.meta.valid).toBe(false)
expect(confirmationsField.props.meta.error).toBe(CONFIRMATIONS_ERROR)
})
})

View File

@ -1,22 +0,0 @@
// @flow
import * as React from 'react'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { composeValidators, mustBeFloat, required, minValue } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import { FIELD_DAILY_LIMIT } from '~/routes/open/components/fields'
const DailyLimit = () => (
<Block margin="md">
<Field
name={FIELD_DAILY_LIMIT}
component={TextField}
type="text"
validate={composeValidators(required, mustBeFloat, minValue(0))}
placeholder="Daily Limit*"
text="Daily Limit"
/>
</Block>
)
export default DailyLimit

View File

@ -1,22 +0,0 @@
// @flow
import * as React from 'react'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import { FIELD_NAME } from '~/routes/open/components/fields'
const Name = () => (
<Block margin="md">
<Field
name={FIELD_NAME}
component={TextField}
type="text"
validate={required}
placeholder="Safe name*"
text="Safe name"
/>
</Block>
)
export default Name

View File

@ -1,86 +0,0 @@
// @flow
import * as React from 'react'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import {
composeValidators,
minValue,
maxValue,
mustBeInteger,
mustBeEthereumAddress,
required,
uniqueAddress,
} from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Col from '~/components/layout/Col'
import Heading from '~/components/layout/Heading'
import Row from '~/components/layout/Row'
import Paragraph from '~/components/layout/Paragraph'
import { FIELD_OWNERS, getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
type Props = {
numOwners: number,
otherAccounts: string[],
}
const MAX_NUMBER_OWNERS = 50
const getAddressValidators = (addresses: string[], position: number) => {
const copy = addresses.slice()
copy.splice(position, 1)
return composeValidators(required, mustBeEthereumAddress, uniqueAddress(copy))
}
const Owners = (props: Props) => {
const { numOwners, otherAccounts } = props
const validNumber = numOwners && Number.isInteger(Number(numOwners))
const renderOwners = validNumber && Number(numOwners) <= MAX_NUMBER_OWNERS
return (
<Block margin="md">
<Heading tag="h3">Owners</Heading>
<Block margin="sm">
<Field
name={FIELD_OWNERS}
component={TextField}
type="text"
validate={composeValidators(required, mustBeInteger, maxValue(MAX_NUMBER_OWNERS), minValue(1))}
placeholder="Number of owners*"
text="Number of owners"
/>
</Block>
{ renderOwners && [...Array(Number(numOwners))].map((x, index) => (
<Row key={`owner${(index)}`}>
<Col xs={11} xsOffset={1}>
<Block margin="sm">
<Paragraph weight="bold">Owner {index + 1}</Paragraph>
<Block margin="sm">
<Field
name={getOwnerNameBy(index)}
component={TextField}
type="text"
validate={required}
placeholder="Owner Name*"
text="Owner Name"
/>
</Block>
<Block margin="sm">
<Field
name={getOwnerAddressBy(index)}
component={TextField}
type="text"
validate={getAddressValidators(otherAccounts, index)}
placeholder="Owner Address*"
text="Owner Address"
/>
</Block>
</Block>
</Col>
</Row>
)) }
</Block>
)
}
export default Owners

View File

@ -1,61 +0,0 @@
// @flow
import TextField from '~/components/forms/TextField'
import * as React from 'react'
import * as TestUtils from 'react-dom/test-utils'
import GnoForm from '~/components/forms/GnoForm'
import { FIELD_OWNERS } from '~/routes/open/components/fields'
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import { getProviderInfo } from '~/logic/wallets/getWeb3'
import Wrapper from '~/test/utils/Wrapper'
import { ADDRESS_REPEATED_ERROR } from '~/components/forms/validator'
import Owners from './index'
const onSubmitMock = () => {}
const childrenMock = () => {}
describe('React DOM TESTS > Create Safe form', () => {
beforeEach(async () => {
// init app web3 instance
await getProviderInfo()
})
it('should not allow to continue if owners addresses are duplicated', async () => {
// GIVEN
const open = TestUtils.renderIntoDocument((
<Wrapper>
<GnoForm
onSubmit={onSubmitMock}
padding={15}
render={({ values }) => (
<Owners
numOwners={values.owners}
otherAccounts={getAccountsFrom(values)}
/>
)}
>
{childrenMock}
</GnoForm>
</Wrapper>
))
let inputs = TestUtils.scryRenderedDOMComponentsWithTag(open, 'input')
const fieldOwners = inputs[0]
expect(fieldOwners.name).toEqual(FIELD_OWNERS)
TestUtils.Simulate.change(fieldOwners, { target: { value: '2' } })
// WHEN
inputs = TestUtils.scryRenderedDOMComponentsWithTag(open, 'input')
const firstOwnerAddress = inputs[2]
TestUtils.Simulate.change(firstOwnerAddress, { target: { value: '0xC21aC257Db500a87c65Daa980432F216A719bA30' } })
const secondOwnerAddress = inputs[4]
TestUtils.Simulate.change(secondOwnerAddress, { target: { value: '0xC21aC257Db500a87c65Daa980432F216A719bA30' } })
// THEN
const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
expect(5).toEqual(muiFields.length)
const secondAddressField = muiFields[4]
expect(secondAddressField.props.meta.valid).toBe(false)
expect(secondAddressField.props.meta.error).toBe(ADDRESS_REPEATED_ERROR)
})
})

View File

@ -1,31 +0,0 @@
// @flow
import * as React from 'react'
import Block from '~/components/layout/Block'
import Heading from '~/components/layout/Heading'
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import Name from './Name'
import Owners from './Owners'
import Confirmations from './Confirmations'
import DailyLimit from './DailyLimit'
export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
export const safeFieldsValidation = (values: Object) => {
const errors = {}
if (Number.parseInt(values.owners, 10) < Number.parseInt(values.confirmations, 10)) {
errors.confirmations = CONFIRMATIONS_ERROR
}
return errors
}
export default () => ({ values }: Object) => (
<Block margin="md">
<Heading tag="h2" margin="lg">Deploy a new Safe</Heading>
<Name />
<Owners numOwners={values.owners} otherAccounts={getAccountsFrom(values)} />
<Confirmations />
<DailyLimit />
</Block>
)

View File

@ -0,0 +1,81 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Row from '~/components/layout/Row'
import { FIELD_NAME } from '~/routes/open/components/fields'
import Paragraph from '~/components/layout/Paragraph'
import OpenPaper from '~/components/Stepper/OpenPaper'
import { sm, secondary } from '~/theme/variables'
type Props = {
classes: Object,
}
const styles = () => ({
root: {
display: 'flex',
maxWidth: '440px',
},
text: {
flexWrap: 'nowrap',
},
dot: {
marginRight: sm,
},
links: {
'&>a': {
color: secondary,
},
},
})
const SafeName = ({ classes }: Props) => (
<React.Fragment>
<Block margin="lg">
<Paragraph noMargin size="md" color="primary" weight="light" className={classes.links}>
This setup will create a Safe with one or more owners. Optionally give the Safe a local name.
By continuing you consent with the <a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">terms of use</a> and <a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">privacy policy</a>.
</Paragraph>
</Block>
<Row margin="md" className={classes.text}>
<Paragraph noMargin className={classes.dot} color="secondary">
&#9679;
</Paragraph>
<Paragraph noMargin size="md" color="primary" weight="bolder">
I understand that my funds are held securely in my Safe. They cannot be accessed by Gnosis.
</Paragraph>
</Row>
<Row margin="md">
<Paragraph noMargin className={classes.dot} color="secondary">
&#9679;
</Paragraph>
<Paragraph noMargin size="md" color="primary" weight="bolder">
My Safe is a smart contract on the Ethereum blockchain.
</Paragraph>
</Row>
<Block margin="lg" className={classes.root}>
<Field
name={FIELD_NAME}
component={TextField}
type="text"
validate={required}
placeholder="Name of the new Safe"
text="Safe name"
/>
</Block>
</React.Fragment>
)
const SafeNameForm = withStyles(styles)(SafeName)
const SafeNamePage = () => (controls: React$Node) => (
<OpenPaper controls={controls} container={600}>
<SafeNameForm />
</OpenPaper>
)
export default SafeNamePage

View File

@ -0,0 +1,199 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
import { required, composeValidators, uniqueAddress, mustBeEthereumAddress } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Button from '~/components/layout/Button'
import Row from '~/components/layout/Row'
import Col from '~/components/layout/Col'
import IconButton from '@material-ui/core/IconButton'
import Delete from '@material-ui/icons/Delete'
import InputAdornment from '@material-ui/core/InputAdornment'
import CheckCircle from '@material-ui/icons/CheckCircle'
import { getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
import Paragraph from '~/components/layout/Paragraph'
import OpenPaper from '~/components/Stepper/OpenPaper'
import { getAccountsFrom } from '~/routes/open/utils/safeDataExtractor'
import Hairline from '~/components/layout/Hairline'
import { md, lg, sm } from '~/theme/variables'
type Props = {
classes: Object,
otherAccounts: string[],
errors: Object,
values: Object,
updateInitialProps: (initialValues: Object) => void,
}
type State = {
numOwners: number,
}
const styles = () => ({
root: {
display: 'flex',
},
title: {
padding: `${md} ${lg}`,
},
owner: {
padding: `0 ${lg}`,
},
header: {
padding: `${sm} ${lg}`,
},
name: {
marginRight: `${sm}`,
},
trash: {
top: '5px',
},
add: {
justifyContent: 'center',
},
check: {
color: '#03AE60',
height: '20px',
},
})
const getAddressValidators = (addresses: string[], position: number) => {
const copy = addresses.slice()
copy.splice(position, 1)
return composeValidators(required, mustBeEthereumAddress, uniqueAddress(copy))
}
const noErrorsOn = (name: string, errors: Object) => errors[name] === undefined
export const ADD_OWNER_BUTTON = '+ ADD ANOTHER OWNER'
export const calculateValuesAfterRemoving = (index: number, notRemovedOwners: number, values: Object) => {
const initialValues = { ...values }
const numOwnersAfterRemoving = notRemovedOwners - 1
// muevo indices
for (let i = index; i < numOwnersAfterRemoving; i += 1) {
initialValues[getOwnerNameBy(i)] = values[getOwnerNameBy(i + 1)]
initialValues[getOwnerAddressBy(i)] = values[getOwnerAddressBy(i + 1)]
}
delete initialValues[getOwnerNameBy(numOwnersAfterRemoving)]
delete initialValues[getOwnerAddressBy(numOwnersAfterRemoving)]
return initialValues
}
class SafeOwners extends React.Component<Props, State> {
state = {
numOwners: 1,
}
onRemoveRow = (index: number) => () => {
const { values } = this.props
const { numOwners } = this.state
const initialValues = calculateValuesAfterRemoving(index, numOwners, values)
this.props.updateInitialProps(initialValues)
this.setState(state => ({
numOwners: state.numOwners - 1,
}))
}
onAddOwner = () => {
this.setState(state => ({
numOwners: state.numOwners + 1,
}))
}
render() {
const { classes, errors, otherAccounts } = this.props
const { numOwners } = this.state
return (
<React.Fragment>
<Block className={classes.title}>
<Paragraph noMargin size="md" color="primary" weight="light">
Specify the owners of the Safe.
</Paragraph>
</Block>
<Hairline />
<Row className={classes.header}>
<Col xs={4}>NAME</Col>
<Col xs={8}>ADDRESS</Col>
</Row>
<Hairline />
<Block margin="md">
{ [...Array(Number(numOwners))].map((x, index) => {
const addressName = getOwnerAddressBy(index)
return (
<Row key={`owner${(index)}`} className={classes.owner}>
<Col xs={4}>
<Field
className={classes.name}
name={getOwnerNameBy(index)}
component={TextField}
type="text"
validate={required}
placeholder="Owner Name*"
text="Owner Name"
/>
</Col>
<Col xs={7}>
<Field
name={addressName}
component={TextField}
inputAdornment={noErrorsOn(addressName, errors) && {
endAdornment: (
<InputAdornment position="end">
<CheckCircle className={classes.check} />
</InputAdornment>
),
}}
type="text"
validate={getAddressValidators(otherAccounts, index)}
placeholder="Owner Address*"
text="Owner Address"
/>
</Col>
<Col xs={1} center="xs" middle="xs">
{ index > 0 &&
<IconButton aria-label="Delete" onClick={this.onRemoveRow(index)} className={classes.trash}>
<Delete />
</IconButton>
}
</Col>
</Row>
)
}) }
</Block>
<Row align="center" grow className={classes.add} margin="xl">
<Button color="secondary" onClick={this.onAddOwner}>
{ADD_OWNER_BUTTON}
</Button>
</Row>
</React.Fragment>
)
}
}
const SafeOwnersForm = withStyles(styles)(SafeOwners)
const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React$Node, { values, errors }: Object) => (
<React.Fragment>
<OpenPaper controls={controls} padding={false}>
<SafeOwnersForm
otherAccounts={getAccountsFrom(values)}
errors={errors}
updateInitialProps={updateInitialProps}
values={values}
/>
</OpenPaper>
</React.Fragment>
)
export default SafeOwnersPage

View File

@ -0,0 +1,89 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import MenuItem from '@material-ui/core/MenuItem'
import Field from '~/components/forms/Field'
import SelectField from '~/components/forms/SelectField'
import { composeValidators, minValue, mustBeInteger, required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Row from '~/components/layout/Row'
import Col from '~/components/layout/Col'
import Paragraph from '~/components/layout/Paragraph'
import OpenPaper from '~/components/Stepper/OpenPaper'
import { FIELD_CONFIRMATIONS, getNumOwnersFrom } from '~/routes/open/components/fields'
import { md } from '~/theme/variables'
type Props = {
classes: Object,
values: Object,
}
const styles = () => ({
owners: {
paddingLeft: md,
},
})
export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
export const safeFieldsValidation = (values: Object) => {
const errors = {}
const numOwners = getNumOwnersFrom(values)
if (numOwners < Number.parseInt(values[FIELD_CONFIRMATIONS], 10)) {
errors[FIELD_CONFIRMATIONS] = CONFIRMATIONS_ERROR
}
return errors
}
const SafeThreshold = ({ classes, values }: Props) => {
const numOwners = getNumOwnersFrom(values)
return (
<React.Fragment>
<Block margin="xs">
<Paragraph noMargin size="md" color="primary" weight="bolder">
Any transaction requires the confirmation of:
</Paragraph>
</Block>
<Row margin="xl" align="center">
<Col xs={2}>
<Field
name={FIELD_CONFIRMATIONS}
component={SelectField}
validate={composeValidators(
required,
mustBeInteger,
minValue(1),
)}
>
{
[...Array(Number(numOwners))].map((x, index) => (
<MenuItem key={`selectOwner${index}`} value={`${index + 1}`}>{index + 1}</MenuItem>
))
}
</Field>
</Col>
<Col xs={10}>
<Paragraph size="lg" color="primary" noMargin className={classes.owners}>
out of {numOwners} owner(s)
</Paragraph>
</Col>
</Row>
</React.Fragment>
)
}
const SafeThresholdForm = withStyles(styles)(SafeThreshold)
const SafeOwnersPage = () => (controls: React$Node, { values }: Object) => (
<React.Fragment>
<OpenPaper controls={controls} container={450}>
<SafeThresholdForm values={values} />
</OpenPaper>
</React.Fragment>
)
export default SafeOwnersPage

View File

@ -2,7 +2,12 @@
export const FIELD_NAME: string = 'name'
export const FIELD_CONFIRMATIONS: string = 'confirmations'
export const FIELD_OWNERS: string = 'owners'
export const FIELD_DAILY_LIMIT: string = 'limit'
export const getOwnerNameBy = (index: number) => `owner${index}Name`
export const getOwnerAddressBy = (index: number) => `owner${index}Address`
export const getNumOwnersFrom = (values: Object) => {
const accounts = Object.keys(values).sort().filter(key => /^owner\d+Name$/.test(key))
return accounts.length
}

View File

@ -1,12 +1,13 @@
// @flow
import * as React from 'react'
import { connect } from 'react-redux'
import Page from '~/components/layout/Page'
import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getDailyLimitFrom } from '~/routes/open/utils/safeDataExtractor'
import { getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom } from '~/routes/open/utils/safeDataExtractor'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { getGnosisSafeContract, deploySafeContract, initContracts } from '~/logic/contracts/safeContracts'
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
import { history } from '~/store'
import { OPENING_ADDRESS, stillInOpeningView, SAFELIST_ADDRESS } from '~/routes/routes'
import selector from './selector'
import actions, { type Actions, type AddSafe } from './actions'
import Layout from '../components/Layout'
@ -14,11 +15,11 @@ import Layout from '../components/Layout'
type Props = Actions & {
provider: string,
userAccount: string,
network: string,
}
export type OpenState = {
safeAddress: string,
safeTx: string,
}
export const createSafe = async (values: Object, userAccount: string, addSafe: AddSafe): Promise<OpenState> => {
@ -26,38 +27,40 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A
const numConfirmations = getThresholdFrom(values)
const name = getSafeNameFrom(values)
const owners = getNamesFrom(values)
const dailyLimit = getDailyLimitFrom(values)
const web3 = getWeb3()
const GnosisSafe = getGnosisSafeContract(web3)
await initContracts()
const safe = await deploySafeContract(accounts, numConfirmations, dailyLimit, userAccount)
const safe = await deploySafeContract(accounts, numConfirmations, userAccount)
checkReceiptStatus(safe.tx)
const param = safe.logs[1].args.proxy
const param = safe.logs[0].args.proxy
const safeContract = GnosisSafe.at(param)
addSafe(name, safeContract.address, numConfirmations, dailyLimit, owners, accounts)
addSafe(name, safeContract.address, numConfirmations, owners, accounts)
if (stillInOpeningView()) {
const url = {
pathname: `${SAFELIST_ADDRESS}/${safeContract.address}`,
state: {
name,
tx: safe.tx,
},
}
history.push(url)
}
// returning info for testing purposes, in app is fully async
return { safeAddress: safeContract.address, safeTx: safe }
}
class Open extends React.Component<Props, OpenState> {
constructor() {
super()
this.state = {
safeAddress: '',
safeTx: '',
}
}
class Open extends React.Component<Props> {
onCallSafeContractSubmit = async (values) => {
try {
const { userAccount, addSafe } = this.props
const safeInstance = await createSafe(values, userAccount, addSafe)
this.setState(safeInstance)
createSafe(values, userAccount, addSafe)
history.push(OPENING_ADDRESS)
} catch (error) {
// eslint-disable-next-line
console.log('Error while creating the Safe' + error)
@ -65,16 +68,14 @@ class Open extends React.Component<Props, OpenState> {
}
render() {
const { safeAddress, safeTx } = this.state
const { provider, userAccount } = this.props
const { provider, userAccount, network } = this.props
return (
<Page>
<Layout
network={network}
provider={provider}
userAccount={userAccount}
safeAddress={safeAddress}
safeTx={safeTx}
onCallSafeContractSubmit={this.onCallSafeContractSubmit}
/>
</Page>

View File

@ -1,8 +1,9 @@
// @flow
import { createStructuredSelector } from 'reselect'
import { providerNameSelector, userAccountSelector } from '~/logic/wallets/store/selectors'
import { providerNameSelector, userAccountSelector, networkSelector } from '~/logic/wallets/store/selectors'
export default createStructuredSelector({
provider: providerNameSelector,
network: networkSelector,
userAccount: userAccountSelector,
})

View File

@ -1,6 +1,4 @@
// @flow
export const getDailyLimitFrom = (values: Object): number => Number(values.limit)
export const getAccountsFrom = (values: Object): string[] => {
const accounts = Object.keys(values).sort().filter(key => /^owner\d+Address$/.test(key))

View File

@ -0,0 +1,27 @@
// @flow
import { storiesOf } from '@storybook/react'
import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
import { ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
import Component from './component'
const FrameDecorator = story => (
<div className={styles.frame}>
{ story() }
</div>
)
storiesOf('Routes /opening', module)
.addDecorator(FrameDecorator)
.add('View while safe is being deployed', () => (
<Component
name="Super Vault 2000"
tx="0xed163e50e2e85695f5edafeba51d6be1758549858d12611ed4dcc96feaa19fc9"
network={ETHEREUM_NETWORK.RINKEBY}
/>
))
.add('Load this view without a tx', () => (
<Component
network={ETHEREUM_NETWORK.UNKNOWN}
/>
))

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="111" height="91" viewBox="0 0 111 91">
<g fill="none" fill-rule="evenodd">
<g fill="#A2A8BA">
<path d="M6.535 81.666h9.8V78.4h-9.8v3.266zm64.131-6.535h-67.4V3.266H94.73l.003 47.754c.203-.004.403-.015.608-.015.898 0 1.785.051 2.659.144V0H0v78.4h3.265v6.535H19.6V78.4h51.202c-.097-.888-.15-1.79-.15-2.705 0-.189.01-.376.014-.564z"/>
<path d="M9.8 68.582L9.816 9.8l78.385.015v4.885h-1.635a1.64 1.64 0 0 0-1.635 1.634c0 .9.736 1.635 1.635 1.635H88.2v1.634h-1.635a1.64 1.64 0 0 0-1.635 1.635c0 .9.736 1.635 1.635 1.635H88.2v29.184c1.06-.32 2.15-.572 3.266-.748V22.866c.899 0 1.634-.736 1.634-1.634 0-.9-.735-1.635-1.634-1.635v-1.635a1.64 1.64 0 0 0 1.634-1.635c0-.9-.735-1.635-1.634-1.635V9.816a3.284 3.284 0 0 0-3.281-3.285H9.816a3.283 3.283 0 0 0-3.281 3.285v58.766a3.283 3.283 0 0 0 3.28 3.284H70.95c.173-1.114.423-2.2.74-3.26L9.8 68.582z"/>
<path d="M60.435 42.466A3.276 3.276 0 0 1 57.17 39.2a3.276 3.276 0 0 1 3.265-3.266 3.277 3.277 0 0 1 3.266 3.266 3.276 3.276 0 0 1-3.266 3.265m0-9.8a6.533 6.533 0 0 0-6.535 6.535 6.534 6.534 0 0 0 6.535 6.535 6.535 6.535 0 0 0 0-13.069"/>
<path d="M75.136 40.832h1.55a16.242 16.242 0 0 1-3.61 8.689l-1.095-1.095a1.633 1.633 0 0 0-2.305 0 1.634 1.634 0 0 0 0 2.305l1.095 1.095a16.303 16.303 0 0 1-8.69 3.61l.004-1.535c0-.9-.735-1.635-1.634-1.635-.9 0-1.635.736-1.635 1.635v1.55a16.249 16.249 0 0 1-8.69-3.61l1.095-1.095a1.631 1.631 0 0 0 0-2.304 1.63 1.63 0 0 0-2.305 0l-1.095 1.095a16.303 16.303 0 0 1-3.61-8.69l1.524.004c.9 0 1.634-.735 1.634-1.635s-.734-1.634-1.634-1.634h-1.55a16.25 16.25 0 0 1 3.61-8.69l1.095 1.094c.325.325.734.475 1.16.475.424 0 .834-.165 1.159-.475a1.63 1.63 0 0 0 0-2.305l-1.095-1.095a16.309 16.309 0 0 1 8.69-3.61l-.003 1.524c0 .9.734 1.635 1.634 1.635.9 0 1.635-.734 1.635-1.635v-1.55a16.254 16.254 0 0 1 8.69 3.61l-1.095 1.095a1.63 1.63 0 0 0 0 2.304c.326.326.735.475 1.16.475a1.67 1.67 0 0 0 1.16-.475l1.095-1.094a16.3 16.3 0 0 1 3.61 8.69l-1.554-.004c-.9 0-1.635.734-1.635 1.634a1.65 1.65 0 0 0 1.635 1.647M74.3 25.347c-.015-.016-.035-.016-.05-.035-3.56-3.525-8.426-5.71-13.816-5.71-5.39 0-10.256 2.189-13.8 5.7-.016.014-.035.014-.05.033-.016.015-.016.034-.035.05-3.53 3.557-5.715 8.426-5.715 13.816 0 5.39 2.19 10.256 5.7 13.8.015.016.015.034.034.05.016.015.035.015.05.034 3.557 3.526 8.426 5.716 13.816 5.716 5.39 0 10.256-2.19 13.8-5.7.016-.016.035-.016.051-.035.015-.015.015-.034.034-.049 3.525-3.56 5.716-8.427 5.716-13.816 0-5.39-2.19-10.26-5.701-13.804-.015-.016-.015-.035-.034-.05M17.966 22.862c-.9 0-1.635.735-1.635 1.634v32.666c0 .9.734 1.635 1.635 1.635.899 0 1.634-.735 1.634-1.635v-1.634c.9 0 1.635-.736 1.635-1.635 0-.9-.735-1.635-1.635-1.635V29.4c.9 0 1.635-.734 1.635-1.634 0-.9-.735-1.635-1.635-1.635v-1.635c0-.898-.735-1.634-1.634-1.634M26.135 22.866c-.9 0-1.635.735-1.635 1.634v1.636c-.9 0-1.635.734-1.635 1.634 0 .9.736 1.634 1.635 1.634V52.27c-.9 0-1.635.735-1.635 1.634 0 .9.736 1.636 1.635 1.636v1.634c0 .9.735 1.635 1.635 1.635s1.634-.735 1.634-1.635L27.765 24.5c0-.899-.734-1.634-1.63-1.634"/>
</g>
<path stroke="#467EE5" stroke-width="3" d="M93.756 58.266c-8.466 0-15.361 6.896-15.361 15.362 0 8.466 6.895 15.36 15.361 15.36 8.466 0 15.361-6.894 15.361-15.36s-6.895-15.362-15.361-15.362z"/>
<path fill="#467EE5" fill-rule="nonzero" d="M93.68 68.471h-3.06v10.313h8.39v-3.06h-5.33z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,82 @@
// @flow
import * as React from 'react'
import Block from '~/components/layout/Block'
import OpenInNew from '@material-ui/icons/OpenInNew'
import Paragraph from '~/components/layout/Paragraph'
import LinearProgress from '@material-ui/core/LinearProgress'
import { withStyles } from '@material-ui/core/styles'
import Img from '~/components/layout/Img'
import Page from '~/components/layout/Page'
import { openTxInEtherScan } from '~/logic/wallets/getWeb3'
import { mediumFontSize, secondary, xs } from '~/theme/variables'
import { type SelectorProps } from '../container/selector'
type Props = SelectorProps & {
name: string,
tx: string,
classes: Object,
}
const vault = require('../assets/vault.svg')
const styles = {
page: {
letterSpacing: '-1px',
},
icon: {
height: mediumFontSize,
color: secondary,
},
follow: {
display: 'flex',
justifyContent: 'center',
marginTop: xs,
},
etherscan: {
color: secondary,
textDecoration: 'underline',
display: 'flex',
alignItems: 'center',
marginLeft: xs,
fontWeight: 'bolder',
},
}
const Opening = ({
classes,
name = 'Safe creation process',
tx,
network,
}: Props) => (
<Page align="center">
<Paragraph className={classes.page} color="secondary" size="xxl" weight="bolder" align="center">
{name}
</Paragraph>
<Block margin="lg" align="center">
<Img src={vault} height={90} alt="Vault" />
</Block>
<Block margin="lg">
<LinearProgress color="secondary" />
</Block>
<Block margin="md">
<Paragraph className={classes.page} noMargin size="xl" align="center">
Transaction submitted
</Paragraph>
<Paragraph className={classes.page} noMargin size="xl" align="center" weight="bolder">
Deploying your new Safe...
</Paragraph>
</Block>
<Block margin="md">
<Paragraph size="md" align="center" weight="light" noMargin>
This process should take a couple of minutes. <br />
</Paragraph>
{ tx &&
<Paragraph className={classes.follow} size="md" align="center" weight="light" noMargin>
Follow progress on <a href={openTxInEtherScan(tx, network)} target="_blank" rel="noopener noreferrer" className={classes.etherscan}>Etherscan.io<OpenInNew className={classes.icon} /></a>
</Paragraph>
}
</Block>
</Page>
)
export default withStyles(styles)(Opening)

View File

@ -0,0 +1,6 @@
// @flow
import { connect } from 'react-redux'
import selector from './selector'
import Layout from '../component'
export default connect(selector)(Layout)

View File

@ -0,0 +1,11 @@
// @flow
import { createStructuredSelector } from 'reselect'
import { networkSelector } from '~/logic/wallets/store/selectors'
export type SelectorProps = {
network: string,
}
export default createStructuredSelector({
network: networkSelector,
})

View File

@ -1,6 +1,14 @@
// @flow
import { history } from '~/store'
export const SAFE_PARAM_ADDRESS = 'address'
export const SAFELIST_ADDRESS = '/safes'
export const OPEN_ADDRESS = '/open'
export const WELCOME_ADDRESS = '/welcome'
export const SETTINS_ADDRESS = '/settings'
export const OPENING_ADDRESS = '/opening'
export const stillInOpeningView = () => {
const path = history.location.pathname
return path === OPENING_ADDRESS
}

View File

@ -1,6 +1,7 @@
// @flow
import * as React from 'react'
import Field from '~/components/forms/Field'
import OpenPaper from '~/components/Stepper/OpenPaper'
import TextField from '~/components/forms/TextField'
import Checkbox from '~/components/forms/Checkbox'
import { composeValidators, required, mustBeEthereumAddress, uniqueAddress } from '~/components/forms/validator'
@ -29,8 +30,8 @@ type Props = {
addresses: string[]
}
const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => () => (
<Block margin="md">
const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => (controls: React$Node) => (
<OpenPaper controls={controls}>
<Heading tag="h2" margin="lg">
Add Owner
</Heading>
@ -65,7 +66,7 @@ const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => () => (
/>
<Block>Increase threshold?</Block>
</Block>
</Block>
</OpenPaper>
)
export default AddOwnerForm

Some files were not shown because too many files have changed in this diff Show More