Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Show confirmations for Wallet #3282
Browse files Browse the repository at this point in the history
  • Loading branch information
ngotchac committed Nov 30, 2016
1 parent 4a9623b commit 152b31d
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 94 deletions.
4 changes: 0 additions & 4 deletions js/src/abi/util/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,5 @@ export function sliceData (_data) {
data = padAddress('');
}

if (data.length % 64) {
throw new Error(`Invalid data length (not mod 64) passed to sliceData, ${data}, % 64 == ${data.length % 64}`);
}

return data.match(/.{1,64}/g);
}
27 changes: 26 additions & 1 deletion js/src/api/contract/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,29 @@ export default class Contract {
return this.unsubscribe(subscriptionId);
};

event.getAll = (options = {}) => {
return this.getAll(event);
};

return event;
}

getAll (event, _options) {
// Options as first parameter
if (!_options && event && event.topics) {
return this.getAll(null, event);
}

const options = this._getFilterOptions(event, _options);
return this._api.eth
.getLogs({
fromBlock: 0,
toBlock: 'latest',
...options
})
.then((logs) => this.parseEventLogs(logs));
}

_findEvent (eventName = null) {
const event = eventName
? this._events.find((evt) => evt.name === eventName)
Expand All @@ -256,7 +276,7 @@ export default class Contract {
return event;
}

_createEthFilter (event = null, _options) {
_getFilterOptions (event = null, _options = {}) {
const optionTopics = _options.topics || [];
const signature = event && event.signature || null;

Expand All @@ -271,6 +291,11 @@ export default class Contract {
topics
});

return options;
}

_createEthFilter (event = null, _options) {
const options = this._getFilterOptions(event, _options);
return this._api.eth.newFilter(options);
}

Expand Down
3 changes: 2 additions & 1 deletion js/src/api/rpc/eth/eth.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ export default class Eth {

getLogs (options) {
return this._transport
.execute('eth_getLogs', inFilter(options));
.execute('eth_getLogs', inFilter(options))
.then((logs) => logs.map(outLog));
}

getLogsEx (options) {
Expand Down
4 changes: 4 additions & 0 deletions js/src/api/util/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export function hex2Ascii (_hex) {
return str;
}

export function bytesToAscii (bytes) {
return bytes.map((b) => String.fromCharCode(b % 512)).join('');
}

export function asciiToHex (string) {
return '0x' + string.split('').map((s) => s.charCodeAt(0).toString(16)).join('');
}
Expand Down
132 changes: 109 additions & 23 deletions js/src/redux/providers/walletActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ import { isEqual, uniq, range } from 'lodash';

import Contract from '../../api/contract';
import { wallet as WALLET_ABI } from '../../contracts/abi';
import { bytesToHex } from '../../api/util/format';

const UPDATE_OWNERS = 'owners';
const UPDATE_REQUIRE = 'require';
const UPDATE_DAILYLIMIT = 'dailylimit';
const UPDATE_CONFIRMATIONS = 'confirmations';

export function attachWallets (_wallets) {
return (dispatch, getState) => {
Expand Down Expand Up @@ -109,6 +111,7 @@ function fetchWalletsInfo (updates) {
[ UPDATE_OWNERS ]: true,
[ UPDATE_REQUIRE ]: true,
[ UPDATE_DAILYLIMIT ]: true,
[ UPDATE_CONFIRMATIONS ]: true,
transactions: true,
address
};
Expand All @@ -119,11 +122,14 @@ function fetchWalletsInfo (updates) {
return fetchWalletsInfo(_updates)(dispatch, getState);
}

const { contract } = getState().wallet;
const { api } = getState();
const _updates = Object.values(updates);

Promise
.all(_updates.map((update) => fetchWalletInfo(contract, update)))
.all(_updates.map((update) => {
const contract = new Contract(api, WALLET_ABI).at(update.address);
return fetchWalletInfo(contract, update);
}))
.then((updates) => {
dispatch(updateWalletsDetails(updates));
})
Expand All @@ -141,19 +147,31 @@ function fetchWalletInfo (contract, update) {
const promises = [];

if (update[UPDATE_OWNERS]) {
promises.push(fetchWalletOwners(contract, update.address));
promises.push(fetchWalletOwners(contract));
}

if (update[UPDATE_REQUIRE]) {
promises.push(fetchWalletRequire(contract, update.address));
promises.push(fetchWalletRequire(contract));
}

if (update[UPDATE_DAILYLIMIT]) {
promises.push(fetchWalletDailylimit(contract, update.address));
promises.push(fetchWalletDailylimit(contract));
}

return Promise
.all(promises)
.then((updates) => {
if (update[UPDATE_CONFIRMATIONS]) {
const owners = updates.find((u) => u.key === UPDATE_OWNERS);
return fetchWalletConfirmations(contract, owners && owners.value || null)
.then((update) => {
updates.push(update);
return updates;
});
}

return updates;
})
.then((updates) => {
const wallet = { address: update.address };

Expand All @@ -165,8 +183,8 @@ function fetchWalletInfo (contract, update) {
});
}

function fetchWalletOwners (contract, address) {
const walletInstance = contract.at(address).instance;
function fetchWalletOwners (contract) {
const walletInstance = contract.instance;

return walletInstance
.m_numOwners.call()
Expand All @@ -181,8 +199,8 @@ function fetchWalletOwners (contract, address) {
});
}

function fetchWalletRequire (contract, address) {
const walletInstance = contract.at(address).instance;
function fetchWalletRequire (contract) {
const walletInstance = contract.instance;

return walletInstance
.m_required.call()
Expand All @@ -194,8 +212,8 @@ function fetchWalletRequire (contract, address) {
});
}

function fetchWalletDailylimit (contract, address) {
const walletInstance = contract.at(address).instance;
function fetchWalletDailylimit (contract) {
const walletInstance = contract.instance;

return Promise
.all([
Expand All @@ -215,6 +233,74 @@ function fetchWalletDailylimit (contract, address) {
});
}

/**
* @todo Filter out transactions from confirmations
* before fetching the Confirmation/Revoke events
*/
function fetchWalletConfirmations (contract, owners = null) {
const walletInstance = contract.instance;

return walletInstance
.ConfirmationNeeded
.getAll()
.then((logs) => {
return logs.map((log) => ({
initiator: log.params.initiator.value,
to: log.params.to.value,
data: log.params.data.value,
value: log.params.value.value,
operation: bytesToHex(log.params.operation.value),
transactionHash: log.transactionHash,
blockNumber: log.blockNumber,
confirmedBy: []
}));
})
.then((confirmations) => {
if (confirmations.length === 0) {
return confirmations;
}

const operations = confirmations.map((conf) => conf.operation);
return Promise
.all(operations.map((op) => fetchOperationConfirmations(contract, op, owners)))
.then((confirmedBys) => {
confirmations.forEach((_, index) => {
confirmations[index].confirmedBy = confirmedBys[index];
});

return confirmations;
});
})
.then((confirmations) => {
return {
key: UPDATE_CONFIRMATIONS,
value: confirmations
};
});
}

function fetchOperationConfirmations (contract, operation, owners = null) {
if (!owners) {
console.warn('[fetchOperationConfirmations] try to provide the owners for the Wallet', contract.address);
}

const walletInstance = contract.instance;

const promise = owners
? Promise.resolve({ value: owners })
: fetchWalletOwners(contract);

return promise
.then((result) => {
const owners = result.value;
return Promise
.all(owners.map((owner) => walletInstance.hasConfirmed.call({}, [ operation, owner ])))
.then((data) => {
return owners.filter((owner, index) => data[index]);
});
});
}

function parseLogs (logs) {
return (dispatch, getState) => {
if (!logs || logs.length === 0) {
Expand All @@ -232,49 +318,49 @@ function parseLogs (logs) {
const prev = updates[address] || { address };

switch (eventSignature) {
case [ contract.OwnerChanged.signature ]:
case [ contract.OwnerAdded.signature ]:
case [ contract.OwnerRemoved.signature ]:
case [ contract.instance.OwnerChanged.signature ]:
case [ contract.instance.OwnerAdded.signature ]:
case [ contract.instance.OwnerRemoved.signature ]:
updates[address] = {
...prev,
[ UPDATE_OWNERS ]: true
};
return;

case [ contract.RequirementChanged.signature ]:
case [ contract.instance.RequirementChanged.signature ]:
updates[address] = {
...prev,
[ UPDATE_REQUIRE ]: true
};
return;

case [ contract.Confirmation.signature ]:
case [ contract.Revoke.signature ]:
case [ contract.instance.Confirmation.signature ]:
case [ contract.instance.Revoke.signature ]:
const operation = log.params.operation.value;

updates[address] = {
...prev,
operations: uniq(
[ UPDATE_CONFIRMATIONS ]: uniq(
(prev.operations || []).concat(operation)
)
};
return;

case [ contract.Deposit.signature ]:
case [ contract.SingleTransact.signature ]:
case [ contract.MultiTransact.signature ]:
case [ contract.instance.Deposit.signature ]:
case [ contract.instance.SingleTransact.signature ]:
case [ contract.instance.MultiTransact.signature ]:
updates[address] = {
...prev,
transactions: true
};
return;

case [ contract.ConfirmationNeeded.signature ]:
case [ contract.instance.ConfirmationNeeded.signature ]:
const op = log.params.operation.value;

updates[address] = {
...prev,
operations: uniq(
[ UPDATE_CONFIRMATIONS ]: uniq(
(prev.operations || []).concat(op)
)
};
Expand Down
Loading

0 comments on commit 152b31d

Please sign in to comment.