Block calling contract methods until it deployed, if it is pending deployment.

This commit is contained in:
Richard Moore 2018-08-27 13:38:48 +02:00
parent 280dc56a74
commit afae5cd2f9
No known key found for this signature in database
GPG Key ID: 525F70A6FCABC295
3 changed files with 51 additions and 22 deletions

@ -8,7 +8,6 @@ import { BigNumber, bigNumberify } from '../utils/bignumber';
import { hexDataLength, hexDataSlice, isHexString } from '../utils/bytes';
import { Zero } from '../utils/constants';
import { defineReadOnly, deepCopy, shallowCopy } from '../utils/properties';
import { poll } from '../utils/web';
import * as errors from '../utils/errors';
@ -131,8 +130,10 @@ function runMethod(contract: Contract, functionName: string, estimateOnly: boole
}
});
// Send to the contract address
tx.to = contract.addressPromise;
// Send to the contract address (after checking the contract is deployed)
tx.to = contract.deployed().then(() => {
return contract.addressPromise;
});
return resolveAddresses(contract.provider, params, method.inputs).then((params) => {
tx.data = method.encode(params);
@ -271,6 +272,8 @@ export class Contract {
// This is only set if the contract was created with a call to deploy
readonly deployTransaction: TransactionResponse;
private _deployed: Promise<Contract>;
// https://github.com/Microsoft/TypeScript/issues/5453
// Once this issue is resolved (there are open PR) we can do this nicer
// by making addressOrName default to null for 2 operand calls. :)
@ -339,7 +342,7 @@ export class Contract {
}
Object.keys(this.interface.functions).forEach((name) => {
var run = runMethod(this, name, false);
let run = runMethod(this, name, false);
if ((<any>this)[name] == null) {
defineReadOnly(this, name, run);
@ -356,21 +359,32 @@ export class Contract {
// @TODO: Allow timeout?
deployed(): Promise<Contract> {
if (!this._deployed) {
// If we were just deployed, we know the transaction we should occur in
if (this.deployTransaction) {
return this.deployTransaction.wait().then(() => {
return this;
});
// If we were just deployed, we know the transaction we should occur in
if (this.deployTransaction) {
this._deployed = this.deployTransaction.wait().then(() => {
return this;
});
} else {
// @TODO: Once we allow a timeout to be passed in, we will wait
// up to that many blocks for getCode
// Otherwise, poll for our code to be deployed
this._deployed = this.provider.getCode(this.address).then((code) => {
if (code === '0x') {
errors.throwError('contract not deployed', errors.UNSUPPORTED_OPERATION, {
contractAddress: this.address,
operation: 'getDeployed'
});
}
return this;
});
}
}
// Otherwise, poll for our code to be deployed
return poll(() => {
return this.provider.getCode(this.address).then((code) => {
if (code === '0x') { return undefined; }
return this;
});
}, { onceBlock: this.provider });
return this._deployed;
}
// @TODO:
@ -392,12 +406,18 @@ export class Contract {
});
tx.to = this.addressPromise;
return this.signer.sendTransaction(tx);
return this.deployed().then(() => {
return this.signer.sendTransaction(tx);
});
}
// Reconnect to a different signer or provider
connect(signerOrProvider: Signer | Provider): Contract {
return new Contract(this.address, this.interface, signerOrProvider);
let contract = new Contract(this.address, this.interface, signerOrProvider);
if (this.deployTransaction) {
defineReadOnly(contract, 'deployTransaction', this.deployTransaction);
}
return contract;
}
// Re-attach to a different on=chain instance of this contract

@ -14,7 +14,7 @@ import { randomBytes } from './random-bytes';
import { getNetwork } from './networks';
import { deepCopy, defineReadOnly, resolveProperties, shallowCopy } from './properties';
import * as RLP from './rlp';
import { computePublicKey, verifyMessage } from './secp256k1';
import { computePublicKey, computeSharedSecret, verifyMessage } from './secp256k1';
import { parse as parseTransaction, serialize as serializeTransaction } from './transaction';
import { formatBytes32String, parseBytes32String, toUtf8Bytes, toUtf8String } from './utf8';
import { formatEther, parseEther, formatUnits, parseUnits } from './units';
@ -91,6 +91,7 @@ export {
getJsonWalletAddress,
computePublicKey,
computeSharedSecret,
verifyMessage
}

@ -101,10 +101,14 @@ export function computeAddress(key: string): string {
}
export function verifyMessage(message: Arrayish | string, signature: Signature | string): string {
let sig = splitSignature(signature);
let digest = hashMessage(message);
export function computeSharedSecret(privateKey: Arrayish, publicKey: Arrayish): string {
let privateKeyPair = getCurve().keyFromPrivate(arrayify(privateKey));
let publicKeyPair = getCurve().keyFromPublic(arrayify(publicKey));
return hexZeroPad('0x' + privateKeyPair.derive(publicKeyPair.getPublic()).toString(16), 32);
}
export function verifyDigest(digest: Arrayish | string, signature: Signature | string): string {
let sig = splitSignature(signature);
return recoverAddress(
digest,
{
@ -114,3 +118,7 @@ export function verifyMessage(message: Arrayish | string, signature: Signature |
}
);
}
export function verifyMessage(message: Arrayish | string, signature: Signature | string): string {
return verifyDigest(hashMessage(message), signature);
}