sign pinless

This commit is contained in:
Andrea Franz 2019-04-11 00:04:01 +02:00
parent a359f3bc9d
commit bdeb6d2bbe
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
18 changed files with 510 additions and 56 deletions

View File

@ -11,6 +11,9 @@
</head>
<body>
<div id="root"></div>
<script>
window.statusWeb3 = window.web3;
</script>
<script src="/js/app.js"></script>
</body>
</html>

View File

@ -1,6 +1,7 @@
import EmbarkJS from 'Embark/EmbarkJS';
import TapWalletFactory from 'Embark/contracts/TapWalletFactory';
import TapWallet from 'Embark/contracts/TapWallet';
import { emptyAddress } from '../utils';
export const NEW_WALLET = 'NEW_WALLET';
export const newWallet = () => ({
@ -64,14 +65,16 @@ export const loadingWallet = (index) => ({
});
export const WALLET_LOADED = 'WALLET_LOADED';
export const walletLoaded = (index, address, name, keycard, value, icon) => ({
export const walletLoaded = (index, address, nonce, name, keycard, balance, icon, maxTxValue) => ({
type: WALLET_LOADED,
index,
address,
nonce,
name,
keycard,
value,
icon
balance,
icon,
maxTxValue,
});
export const NETWORK_ID_LOADED = "NETWORK_ID_LOADED";
@ -93,6 +96,15 @@ export const loadNetworkID = () => {
export const enableEthereum = () => {
if (window.ethereum) {
window.web3 = new Web3(ethereum);
//FIXME: hack
try {
// alert(statusWeb3)
web3.eth.personal.signMessagePinless = statusWeb3.personal.signMessagePinless;
// alert(web3.eth.personal.signMessagePinless)
} catch(err){
alert(err)
}
return (dispatch) => {
ethereum.enable()
.then(() => {
@ -125,6 +137,7 @@ export const loadOwner = () => {
return web3.eth.getAccounts()
.then((accounts) => {
const owner = accounts[0];
// web3.eth.personal.signMessagePinless("hello", owner)
dispatch(ownerLoaded(owner))
dispatch(loadWallets(owner))
dispatch(loadOwnerBalance(owner))
@ -186,15 +199,17 @@ export const loadWallet = (owner, index) => {
walletContract.address = address;
const name = await walletContract.methods.name().call();
const value = await web3.eth.getBalance(address);
const balance = await web3.eth.getBalance(address);
const keycard = await walletContract.methods.keycard().call();
const nonce = await walletContract.methods.nonce().call();
const maxTxValue = await walletContract.methods.settings().call();
let icon = "";
try {
icon = String.fromCodePoint(name);
} catch(e){}
dispatch(walletLoaded(index, address, name, keycard, value, icon))
dispatch(walletLoaded(index, address, nonce, name, keycard, balance, icon, maxTxValue))
};
}
@ -207,7 +222,7 @@ export const newWalletSelectIcon = (icon) => {
}
export const NEW_WALLET_CANCEL = "NEW_WALLET_CANCEL";
export const newWalletCancel = (icon) => {
export const newWalletCancel = () => {
return {
type: NEW_WALLET_CANCEL
}
@ -231,21 +246,36 @@ export const walletCreationError = (error) => ({
error
});
export const NEW_WALLET_FORM_KEYCARD_ADDRESS_CHANGED = "NEW_WALLET_FORM_KEYCARD_ADDRESS_CHANGED";
export const newWalletFormKeycardAddressChanged = (address) => ({
type: NEW_WALLET_FORM_KEYCARD_ADDRESS_CHANGED,
address
});
export const NEW_WALLET_FORM_MAX_TX_VALUE_CHANGED = "NEW_WALLET_FORM_MAX_TX_VALUE_CHANGED";
export const newWalletFormMaxTxValueChanged = (value) => ({
type: NEW_WALLET_FORM_MAX_TX_VALUE_CHANGED,
value
});
export const createWallet = () => {
return async (dispatch, getState) => {
const state = getState();
const icon = state.newWalletForm.icon;
const maxTxValue = web3.utils.toWei(state.newWalletForm.maxTxValue);
const keycardAddress = state.newWalletForm.keycardAddress || emptyAddress;
const codePoint = icon.codePointAt(0);
const name = "0x" + codePoint.toString(16);
const create = TapWalletFactory.methods.create(name);
const create = TapWalletFactory.methods.create(name, keycardAddress, maxTxValue);
const walletIndex = state.wallets.length;
try {
const estimatedGas = await create.estimateGas()
create.send({ from: state.owner, gas: estimatedGas,})
create.send({ from: state.owner, gas: estimatedGas })
.then((receipt) => {
console.log(receipt)
dispatch(walletCreated(receipt))
dispatch(newWalletCancel())
dispatch(loadWallets(state.owner))
})
.catch((err) => {
@ -259,3 +289,85 @@ export const createWallet = () => {
}
}
}
export const SELECT_WALLET = 'SELECT_WALLET';
export const selectWallet = (index) => ({
type: SELECT_WALLET,
index
});
export const CLOSE_SELECTED_WALLET = 'CLOSE_SELECTED_WALLET';
export const closeSelectedWallet = (index) => ({
type: CLOSE_SELECTED_WALLET,
});
export const TOPPING_UP_WALLET = 'TOPPING_UP_WALLET';
export const toppingUpWallet = (index) => ({
type: TOPPING_UP_WALLET,
index
});
export const ERROR_TOPPING_UP_WALLET = 'ERROR_TOPPING_UP_WALLET';
export const errorToppingUpWallet = (index) => ({
type: ERROR_TOPPING_UP_WALLET,
index
});
export const WALLET_TOPPED_UP = 'WALLET_TOPPED_UP';
export const walletToppedUp = (index) => ({
type: WALLET_TOPPED_UP,
index
});
export const topUpWallet = (index, address, value) => {
return async (dispatch, getState) => {
const owner = getState().owner;
const tx = {
from: owner,
to: address,
value: web3.utils.toWei("0.001"),
}
const gas = await web3.eth.estimateGas(tx);
tx.gas = gas;
dispatch(toppingUpWallet(index));
web3.eth.sendTransaction(tx)
.then(() => {
dispatch(loadWallet(owner, index))
dispatch(walletToppedUp(index))
})
.catch((err) => {
dispatch(errorToppingUpWallet(index))
})
}
};
export const KEYCARD_DISCOVERED = "KEYCARD_DISCOVERED";
export const keycardDiscovered = (sig) => {
//FIXME: put a random message
const address = web3.eth.accounts.recover("0x112233", sig)
return {
type: KEYCARD_DISCOVERED,
address,
}
}
export const signMessagePinless = (message) => {
return (dispatch, getState) => {
const owner = getState().owner;
// web3 0.2 style using status injected web3
try {
//FIXME: put a random message
web3.eth.personal.signMessagePinless("112233", "0x0000000000000000000000000000000000000000", "", function(err, sig) {
if (err) {
dispatch(web3Error(err))
} else {
dispatch(keycardDiscovered(sig));
}
})
} catch(err) {
dispatch(web3Error(err))
}
};
}

View File

@ -4,6 +4,7 @@ import EmbarkJS from 'Embark/EmbarkJS';
import WalletsList from '../containers/WalletsList';
import NewWalletDialog from '../containers/NewWalletDialog';
import SelectedWalletDialog from '../containers/SelectedWalletDialog';
import TapWalletFactory from 'Embark/contracts/TapWalletFactory';
import { withStyles } from '@material-ui/core/styles';
@ -58,6 +59,7 @@ const App = (props) => {
<div>
<NewWalletDialog />
<SelectedWalletDialog />
{body}
</div>

View File

@ -9,6 +9,9 @@ import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import Slide from '@material-ui/core/Slide';
import TextField from '@material-ui/core/TextField';
import CircularProgress from '@material-ui/core/CircularProgress';
import Divider from '@material-ui/core/Divider';
import InputAdornment from '@material-ui/core/InputAdornment';
const icons = ["💳", "👛", "💸", "😺"]
@ -32,7 +35,7 @@ function Transition(props) {
return <Slide direction="up" {...props} />;
}
const NewWalletDialog = ({open, creating, selected, onIconClick, onCancelClick, onCreateClick, error}) => (
const NewWalletDialog = ({open, creating, selected, keycard, onIconClick, onCancelClick, onCreateClick, onKeycardChange, error, onTapButtonClick, onMaxTxValueChange, maxTxValue}) => (
<Dialog
fullScreen
TransitionComponent={Transition}
@ -40,21 +43,57 @@ const NewWalletDialog = ({open, creating, selected, onIconClick, onCancelClick,
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Choose an icon to identify your new Wallet</DialogTitle>
<DialogTitle id="alert-dialog-title">New Wallet</DialogTitle>
<DialogContent>
<div>
<Typography variant="body2" gutterBottom>
Choose an icon to identify your wallet
</Typography>
<div style={{marginBottom: 16}}>
{icons.map((icon) =>
<a key={icon} onClick={() => onIconClick(icon) }
style={selected == icon ? selectedIconStyles : iconStyles}>{icon}</a>
)}
</div>
<TextField
margin="dense"
label="Maximum transaction value"
type="text"
value={maxTxValue}
style={{marginBottom: 16}}
fullWidth
onChange={(event) => onMaxTxValueChange(event.currentTarget.value)}
InputProps={{
startAdornment: <InputAdornment position="start" style={{paddingBottom: 7}}>Ξ</InputAdornment>,
}}
/>
<TextField
margin="dense"
label="Keycard address"
type="text"
value={keycard}
style={{marginBottom: 16}}
fullWidth
onChange={(event) => onKeycardChange(event.currentTarget.value)}
/>
<div style={{margin: 16, textAlign: "center"}}>
<Typography variant="body2" gutterBottom>
or
</Typography>
</div>
<Button onClick={() => onTapButtonClick("hello world")} size="large" color="primary" variant="contained" fullWidth>
CONNECT TAPPING YOUR KEYCARD
</Button>
{creating && <div style={{marginTop: 50, textAlign: "center"}}>
<CircularProgress />
</div>}
</DialogContent>
<DialogActions>
{!creating &&
<Button onClick={onCancelClick} color="primary">

View File

@ -0,0 +1,118 @@
import React from 'react';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Paper from '@material-ui/core/Paper';
import CloseIcon from '@material-ui/icons/Close';
import Slide from '@material-ui/core/Slide';
import Zoom from '@material-ui/core/Zoom';
import Divider from '@material-ui/core/Divider';
import CircularProgress from '@material-ui/core/CircularProgress';
const formattedBalance = (balance) => {
if (balance) {
return web3.utils.fromWei(balance);
}
return "";
}
const styles = {
appBar: {
position: 'relative',
marginBottom: 32,
}
};
function Transition(props) {
// return <Slide direction="up" {...props} />;
return <Zoom {...props} />;
}
const SelectedWalletDialog = ({open, onCloseClick, icon, address, nonce, keycardAddress, balance, index, onTopUp, toppingUp, maxTxValue}) => (
<Dialog
fullScreen
TransitionComponent={Transition}
open={open}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<AppBar style={styles.appBar}>
<Toolbar>
<IconButton color="inherit" onClick={onCloseClick} aria-label="Close">
<CloseIcon />
</IconButton>
<Typography variant="h6" color="inherit">
Wallet {icon}
</Typography>
</Toolbar>
</AppBar>
<DialogContent>
<Typography variant="h6" gutterBottom>
🔖 Wallet Address
</Typography>
<Typography variant="body1" gutterBottom>
{address}
</Typography>
<Divider style={{margin: "16px 0"}} />
<Typography variant="h6" gutterBottom>
💳 Keycard Address
</Typography>
<Typography variant="body1" gutterBottom>
{keycardAddress || "0x"}
</Typography>
<Divider style={{margin: "16px 0"}} />
<Typography variant="h6" gutterBottom>
Balance
</Typography>
<Typography variant="body1" gutterBottom>
{formattedBalance(balance)}
</Typography>
<Divider style={{margin: "16px 0"}} />
<Typography variant="h6" gutterBottom>
Number of transactions
</Typography>
<Typography variant="body1" gutterBottom>
{nonce}
</Typography>
<Divider style={{margin: "16px 0"}} />
<Typography variant="h6" gutterBottom>
Maximum transaction value
</Typography>
<Typography variant="body1" gutterBottom>
{formattedBalance(maxTxValue)}
</Typography>
<Divider style={{margin: "16px 0"}} />
{!toppingUp && <Button onClick={() => onTopUp(index, address)} size="large" color="primary" variant="contained" fullWidth>
TOP UP 0.001 ETH
</Button>}
{toppingUp && <div style={{marginTop: 50, textAlign: "center"}}>
<CircularProgress />
</div>}
</DialogContent>
</Dialog>
);
export default SelectedWalletDialog;

View File

@ -16,26 +16,17 @@ const styles = {
}
};
const TopPanel = ({ wallets }) => {
const totalWei = wallets.filter((wallet) => wallet).reduce((acc, w) => {
return acc.add(new web3.utils.BN(w.value))
}, new web3.utils.BN(0));
let unit = "wei",
label = "wei",
total = totalWei;
const totalEth = web3.utils.fromWei(total);
return (
<div style={styles.container}>
<div>
<Typography variant="h2" color="inherit">
{totalEth} Ξ
</Typography>
</div>
const TopPanel = ({ total, fullTotal }) => (
<div style={styles.container}>
<div>
<Typography variant="h2" color="inherit">
{total} Ξ
</Typography>
<Typography variant="body1" color="inherit" style={{textAlign: "center"}}>
{fullTotal}
</Typography>
</div>
);
}
</div>
);
export default TopPanel;

View File

@ -4,7 +4,7 @@ import { newWallet } from '../actions';
import WalletsListItem from '../containers/WalletsListItem';
import TopPanel from './TopPanel';
import TopPanel from '../containers/TopPanel';
import List from '@material-ui/core/List';
import Fab from '@material-ui/core/Fab';
import AddIcon from '@material-ui/icons/Add';

View File

@ -21,27 +21,55 @@ const StyledListItemText = withStyles({
},
})(ListItemText);
const secondaryLineStyles = {
display: "block"
const formattedBalance = (balance) => {
if (balance) {
return web3.utils.fromWei(balance);
}
return "";
}
const styles = {
secondaryLine: {
display: "block"
},
avatar: {
color: "#1a1a1a",
backgroundColor: '#fff',
backgroundImage: 'linear-gradient(120deg, rgba(250, 112, 154, 0.5) 0%, rgba(254, 225, 64, 0.5) 100%)',
boxShadow: "rgba(180, 180, 180, 0.6) 0 0 5px 1px",
position: "relative",
},
avatarLoading: {
position: "absolute",
top: 0,
left: 0,
}
};
const WalletsListItem = ({ wallet, onItemClick }) => {
const secondary = <span>
<span style={secondaryLineStyles}>🔖 {compressedAddress(wallet.address)}</span>
<span style={secondaryLineStyles}>💳 {isEmptyAddress(wallet.keycard) ? "" : compressedAddress(wallet.keycard)}</span>
<span style={styles.secondaryLine}>🔖 {compressedAddress(wallet.address, 8)}</span>
<span style={styles.secondaryLine}>💳 {isEmptyAddress(wallet.keycard) ? "" : compressedAddress(wallet.keycard, 8)}</span>
</span>;
const secondaryLoading = "loading..."
return (
<React.Fragment>
<ListItem button onClick={() => onItemClick()}>
<ListItem button onClick={() => onItemClick(wallet.index)}>
{!wallet.creating &&
<React.Fragment>
<Avatar>{wallet.icon}</Avatar>
<StyledListItemText primary={wallet.value + " Ξ"} secondary={wallet.creating ? secondaryLoading : secondary} />
<Avatar style={styles.avatar}>
{wallet.toppingUp &&
<CircularProgress color="secondary" style={styles.avatarLoading}/>}
{wallet.icon}
</Avatar>
<StyledListItemText primary={formattedBalance(wallet.balance) + " Ξ"} secondary={wallet.creating ? secondaryLoading : secondary} />
</React.Fragment>
}
{wallet.creating && <CircularProgress color="secondary" />}
</ListItem>
<Divider />

View File

@ -4,6 +4,9 @@ import {
newWalletSelectIcon,
newWalletCancel,
createWallet,
newWalletFormKeycardAddressChanged,
newWalletFormMaxTxValueChanged,
signMessagePinless,
} from '../actions';
const mapStateToProps = state => ({
@ -11,12 +14,17 @@ const mapStateToProps = state => ({
selected: state.newWalletForm.icon,
creating: state.newWalletForm.creating,
error: (state.newWalletForm.error || "").toString(),
keycard: state.newWalletForm.keycardAddress || "",
maxTxValue: state.newWalletForm.maxTxValue,
});
const mapDispatchToProps = dispatch => ({
onIconClick: (icon) => dispatch(newWalletSelectIcon(icon)),
onCancelClick: () => dispatch(newWalletCancel()),
onCreateClick: () => dispatch(createWallet()),
onKeycardChange: (address) => dispatch(newWalletFormKeycardAddressChanged(address)),
onMaxTxValueChange: (value) => dispatch(newWalletFormMaxTxValueChanged(value)),
onTapButtonClick: (message) => dispatch(signMessagePinless(message)),
});
export default connect(

View File

@ -0,0 +1,42 @@
import { connect } from 'react-redux';
import SelectedWalletDialog from '../components/SelectedWalletDialog';
import {
closeSelectedWallet,
topUpWallet,
} from '../actions';
const mapStateToProps = state => {
const props = {
open: state.selectedWallet.open,
}
const index = state.selectedWallet.index;
if (index == null || index == undefined) {
return props;
}
const wallet = state.wallets[index];
return {
...props,
icon: wallet.icon,
address: wallet.address,
nonce: wallet.nonce,
keycardAddress: wallet.keycardAddress,
balance: wallet.balance,
index: wallet.index,
toppingUp: wallet.toppingUp,
maxTxValue: wallet.maxTxValue,
}
}
const mapDispatchToProps = dispatch => ({
onCloseClick: () => dispatch(closeSelectedWallet()),
onTopUp: (index, address) => dispatch(topUpWallet(index, address)),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(SelectedWalletDialog);

View File

@ -0,0 +1,28 @@
import { connect } from 'react-redux';
import TopPanel from '../components/TopPanel';
const mapStateToProps = state => {
const totalWei = state.wallets.filter((wallet) => wallet).reduce((acc, w) => {
return acc.add(new web3.utils.BN(w.balance))
}, new web3.utils.BN(0));
const fullTotal = web3.utils.fromWei(totalWei);
const parts = fullTotal.split(".");
let total = parts[0];
let decimals = (parts[1] || "").slice(0, 4)
if (decimals.length > 0) {
total = `${total}.${decimals}`;
}
return {
total: total,
fullTotal: fullTotal,
}
}
const mapDispatchToProps = dispatch => ({});
export default connect(
mapStateToProps,
mapDispatchToProps
)(TopPanel);

View File

@ -1,14 +1,14 @@
import { connect } from 'react-redux';
import WalletsListItem from '../components/WalletsListItem';
import { newWallet } from '../actions';
const VALID_NETWORK_ID = 3;
import { selectWallet } from '../actions';
const mapStateToProps = state => ({
//FIXME: hack
wallets: state.wallets,
});
const mapDispatchToProps = dispatch => ({
onItemClick: () => dispatch(newWallet())
onItemClick: (index) => dispatch(selectWallet(index))
});
export default connect(

View File

@ -15,16 +15,34 @@ import {
NEW_WALLET,
NEW_WALLET_SELECT_ICON,
NEW_WALLET_CANCEL,
NEW_WALLET_FORM_KEYCARD_ADDRESS_CHANGED,
NEW_WALLET_FORM_MAX_TX_VALUE_CHANGED,
CREATING_WALLET,
WALLET_CREATED,
WALLET_CREATION_ERROR,
SELECT_WALLET,
CLOSE_SELECTED_WALLET,
TOPPING_UP_WALLET,
ERROR_TOPPING_UP_WALLET,
WALLET_TOPPED_UP,
KEYCARD_DISCOVERED,
} from "../actions";
const newWalletFormInitialState = {
open: false,
icon: null,
creating: false,
error: null
error: null,
keycardAddress: null,
index: null,
balance: null,
toppingUp: false,
maxTxValue: "0.1",
}
const selectedWalletInitialState = {
open: false,
index: null,
}
const initialState = {
@ -39,11 +57,12 @@ const initialState = {
loadedWalletsCount: 0,
wallets: [],
newWalletForm: newWalletFormInitialState,
selectedWallet: selectedWalletInitialState,
};
export default function(state, action) {
console.log("state", state)
console.log("action", action)
console.log("state", state)
if (typeof state === 'undefined') {
return initialState;
@ -105,10 +124,13 @@ export default function(state, action) {
case WALLET_LOADED:
const wallet = {
address: action.address,
nonce: action.nonce,
keycard: action.keycard,
name: action.name,
value: action.value,
icon: action.icon
balance: action.balance,
icon: action.icon,
index: action.index,
maxTxValue: action.maxTxValue,
}
return Object.assign({}, state, {
@ -140,13 +162,27 @@ export default function(state, action) {
open: false
}
});
case NEW_WALLET_FORM_KEYCARD_ADDRESS_CHANGED:
return Object.assign({}, state, {
newWalletForm: {
...state.newWalletForm,
keycardAddress: action.address
}
});
case NEW_WALLET_FORM_MAX_TX_VALUE_CHANGED:
return Object.assign({}, state, {
newWalletForm: {
...state.newWalletForm,
maxTxValue: action.value
}
});
case CREATING_WALLET:
const tmpWallet = {
creating: true,
address: "",
keycard: "",
name: "",
value: 0,
balance: 0,
icon: action.icon
}
@ -173,6 +209,48 @@ export default function(state, action) {
error: action.error
}
});
case SELECT_WALLET:
return Object.assign({}, state, {
selectedWallet: {
...state.selectedWallet,
open: true,
index: action.index,
}
});
case CLOSE_SELECTED_WALLET:
return Object.assign({}, state, {
selectedWallet: selectedWalletInitialState,
});
case TOPPING_UP_WALLET:
const toppingUpWallet = state.wallets[action.index];
toppingUpWallet.toppingUp = true;
return Object.assign({}, state, {
wallets: [
...state.wallets.slice(0, action.index),
toppingUpWallet,
...state.wallets.slice(action.index + 1)
],
});
case ERROR_TOPPING_UP_WALLET:
case WALLET_TOPPED_UP:
const toppedUpWallet = state.wallets[action.index];
toppedUpWallet.toppingUp = false;
return Object.assign({}, state, {
wallets: [
...state.wallets.slice(0, action.index),
toppedUpWallet,
...state.wallets.slice(action.index + 1)
],
});
case KEYCARD_DISCOVERED:
return Object.assign({}, state, {
newWalletForm: {
...state.newWalletForm,
keycardAddress: action.address,
}
});
}
return state;

View File

@ -1,7 +1,10 @@
export const compressedAddress = (a) =>
`${a.slice(0, 6)}...${a.slice(a.length - 4)}`
export const emptyAddress = "0x0000000000000000000000000000000000000000"
export const compressedAddress = (a, padding) => {
padding = padding || 4;
return `${a.slice(0, padding + 2)}...${a.slice(a.length - padding)}`
}
const emptyAddress = "0x0000000000000000000000000000000000000000"
export const isEmptyAddress = (a) =>
a == emptyAddress

View File

@ -23,9 +23,11 @@ contract TapWallet {
// anyone can add funds to the wallet
function () external payable {}
constructor(bytes3 _name) public {
constructor(bytes3 _name, address _keycard, uint256 _maxTxValue) public {
owner = msg.sender;
name = _name;
keycard = _keycard;
settings.maxTxValue = _maxTxValue;
nonce = 0;
}

View File

@ -10,8 +10,8 @@ contract TapWalletFactory {
bytes3 name
);
function create(bytes3 name) public {
TapWallet wallet = new TapWallet(name);
function create(bytes3 name, address keycard, uint256 maxTxValue) public {
TapWallet wallet = new TapWallet(name, keycard, maxTxValue);
ownersWallets[msg.sender].push(address(wallet));
emit NewWallet(wallet, name);
}

View File

@ -28,7 +28,7 @@ contract('TapWalletFactory', () => {
const ownerWalletsCountBefore = await TapWalletFactory.methods.ownerWalletsCount(owner).call();
assert.equal(ownerWalletsCountBefore, 0);
const create = TapWalletFactory.methods.create("0x010203");
const create = TapWalletFactory.methods.create("0x010203", zeroAddress, 0);
const receipt = await create.send({
from: owner
});

View File

@ -6,7 +6,7 @@ let owner,
config({
contracts: {
TapWallet: {
args: ["0x000000"]
args: ["0x000000", "0x0000000000000000000000000000000000000000", 0]
}
}
}, (err, _accounts) => {