Make Wallet first-class citizens (#3990)
* Fixed hint in Address Select + Wallet as first-class-citizen * Separate Owned and not Owned Wallets * Fix balance not updating * Fix MethodDecoding for Contract Deployment * Fix TypedInput params * Fix Token Transfer for Wallet * Small change to contracts * Fix wallets shown twice * Fix separation of accounts and wallets in Accounts * Fix linting * Execute contract methods from Wallet ✓ * Fixing linting * Wallet as first-class citizen: Part 1 (Manual) #3784 * Lower level wallet transaction convertion * Fix linting * Proper autoFocus on right Signer input * PR Grumble: don't show Wallets in dApps Permissions * Add postTransaction and gasEstimate wrapper methods * Extract Wallet postTx and gasEstimate to utils + PATCH api * Remove invalid test It's totally valid for input's length not to be a multiple of 32 bytes. EG. for Wallet Contracts * Merge master * Fix linting * Fix merge issue * Rename Portal * Rename Protal => Portal (typo)
This commit is contained in:
committed by
Gav Wood
parent
88c0329a31
commit
fd41a10319
@@ -14,10 +14,93 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import WalletsUtils from '~/util/wallets';
|
||||
|
||||
const isValidReceipt = (receipt) => {
|
||||
return receipt && receipt.blockNumber && receipt.blockNumber.gt(0);
|
||||
};
|
||||
|
||||
function getTxArgs (func, options, values = []) {
|
||||
const { contract } = func;
|
||||
const { api } = contract;
|
||||
const address = options.from;
|
||||
|
||||
if (!address) {
|
||||
return Promise.resolve({ func, options, values });
|
||||
}
|
||||
|
||||
return WalletsUtils
|
||||
.isWallet(api, address)
|
||||
.then((isWallet) => {
|
||||
if (!isWallet) {
|
||||
return { func, options, values };
|
||||
}
|
||||
|
||||
options.data = contract.getCallData(func, options, values);
|
||||
options.to = options.to || contract.address;
|
||||
|
||||
if (!options.to) {
|
||||
return { func, options, values };
|
||||
}
|
||||
|
||||
return WalletsUtils
|
||||
.getCallArgs(api, options, values)
|
||||
.then((callArgs) => {
|
||||
if (!callArgs) {
|
||||
return { func, options, values };
|
||||
}
|
||||
|
||||
return callArgs;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function estimateGas (_func, _options, _values = []) {
|
||||
return getTxArgs(_func, _options, _values)
|
||||
.then((callArgs) => {
|
||||
const { func, options, values } = callArgs;
|
||||
return func._estimateGas(options, values);
|
||||
})
|
||||
.then((gas) => {
|
||||
return WalletsUtils
|
||||
.isWallet(_func.contract.api, _options.from)
|
||||
.then((isWallet) => {
|
||||
if (isWallet) {
|
||||
return gas.mul(1.5);
|
||||
}
|
||||
|
||||
return gas;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function postTransaction (_func, _options, _values = []) {
|
||||
return getTxArgs(_func, _options, _values)
|
||||
.then((callArgs) => {
|
||||
const { func, options, values } = callArgs;
|
||||
return func._postTransaction(options, values);
|
||||
});
|
||||
}
|
||||
|
||||
export function patchApi (api) {
|
||||
api.patch = {
|
||||
...api.patch,
|
||||
contract: patchContract
|
||||
};
|
||||
}
|
||||
|
||||
export function patchContract (contract) {
|
||||
contract._functions.forEach((func) => {
|
||||
if (!func.constant) {
|
||||
func._postTransaction = func.postTransaction;
|
||||
func._estimateGas = func.estimateGas;
|
||||
|
||||
func.postTransaction = postTransaction.bind(contract, func);
|
||||
func.estimateGas = estimateGas.bind(contract, func);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function checkIfTxFailed (api, tx, gasSent) {
|
||||
return api.pollMethod('eth_getTransactionReceipt', tx)
|
||||
.then((receipt) => {
|
||||
|
||||
@@ -14,13 +14,92 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { range, uniq } from 'lodash';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { intersection, range, uniq } from 'lodash';
|
||||
|
||||
import Contract from '~/api/contract';
|
||||
import { bytesToHex, toHex } from '~/api/util/format';
|
||||
import { validateAddress } from '~/util/validation';
|
||||
import WalletAbi from '~/contracts/abi/wallet.json';
|
||||
|
||||
const _cachedWalletLookup = {};
|
||||
|
||||
export default class WalletsUtils {
|
||||
|
||||
static getCallArgs (api, options, values = []) {
|
||||
const walletContract = new Contract(api, WalletAbi);
|
||||
|
||||
const promises = [
|
||||
api.parity.accountsInfo(),
|
||||
WalletsUtils.fetchOwners(walletContract.at(options.from))
|
||||
];
|
||||
|
||||
return Promise
|
||||
.all(promises)
|
||||
.then(([ accounts, owners ]) => {
|
||||
const addresses = Object.keys(accounts);
|
||||
const owner = intersection(addresses, owners).pop();
|
||||
|
||||
if (!owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return owner;
|
||||
})
|
||||
.then((owner) => {
|
||||
if (!owner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const _options = Object.assign({}, options);
|
||||
const { from, to, value = new BigNumber(0), data } = options;
|
||||
|
||||
delete _options.data;
|
||||
|
||||
const nextValues = [ to, value, data ];
|
||||
const nextOptions = {
|
||||
..._options,
|
||||
from: owner,
|
||||
to: from,
|
||||
value: new BigNumber(0)
|
||||
};
|
||||
|
||||
const execFunc = walletContract.instance.execute;
|
||||
|
||||
return { func: execFunc, options: nextOptions, values: nextValues };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given address could be
|
||||
* a Wallet. The result is cached in order not
|
||||
* to make unnecessary calls on non-wallet accounts
|
||||
*/
|
||||
static isWallet (api, address) {
|
||||
if (!_cachedWalletLookup[address]) {
|
||||
const walletContract = new Contract(api, WalletAbi);
|
||||
|
||||
_cachedWalletLookup[address] = walletContract
|
||||
.at(address)
|
||||
.instance
|
||||
.m_numOwners
|
||||
.call()
|
||||
.then((result) => {
|
||||
if (!result || result.equals(0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.then((bool) => {
|
||||
_cachedWalletLookup[address] = Promise.resolve(bool);
|
||||
return bool;
|
||||
});
|
||||
}
|
||||
|
||||
return _cachedWalletLookup[address];
|
||||
}
|
||||
|
||||
static fetchRequire (walletContract) {
|
||||
return walletContract.instance.m_required.call();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user