Skip to content

Commit

Permalink
Merge pull request #62 from connext/hotfixes
Browse files Browse the repository at this point in the history
hotfixes
  • Loading branch information
Rahul Sethuram authored Jul 22, 2021
2 parents 3cf9fec + 5338fdf commit d824107
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 141 deletions.
54 changes: 40 additions & 14 deletions packages/router/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,25 @@ export class Handler {
messagingError: jsonifyError(err as Error),
}),
);
})
.orElse((err) => {
this.logger.info({ method, methodId, transactionHash: "" }, "Error relaying transaction");
const _err = new HandlerError(HandlerError.reasons.TxServiceError, {
method,
methodId,
calling: "txManager.fulfill",
txServiceError: jsonifyError(err),
});
return ResultAsync.fromPromise(
this.messagingService.publishMetaTxResponse(inbox, { chainId, transactionHash: "" }, jsonifyError(_err)),
(err) =>
new HandlerError(HandlerError.reasons.MessagingError, {
method,
methodId,
calling: "messagingService.publishMetaTxResponse",
messagingError: jsonifyError(err as Error),
}),
);
});

if (res.isOk()) {
Expand Down Expand Up @@ -428,21 +447,28 @@ export class Handler {
transactionId: txData.transactionId,
prepareError: jsonifyError(res.error),
},
"Could not prepare tx, cancelling",
"Could not prepare tx",
);
const cancelRes = await this.txManager.cancel(txData.sendingChainId, {
txData,
signature: "0x",
relayerFee: "0",
});
if (cancelRes.isOk()) {
this.logger.warn(
{ method, methodId, transactionHash: cancelRes.value.transactionHash },
"Cancelled transaction",
);
} else {
this.logger.error({ method, methodId }, "Could not cancel transaction after error!");
}
this.logger.error(
{
method,
methodId,
},
"Do not cancel ATM, figure out why we are in this case first",
);
// const cancelRes = await this.txManager.cancel(txData.sendingChainId, {
// txData,
// signature: "0x",
// relayerFee: "0",
// });
// if (cancelRes.isOk()) {
// this.logger.warn(
// { method, methodId, transactionHash: cancelRes.value.transactionHash },
// "Cancelled transaction",
// );
// } else {
// this.logger.error({ method, methodId }, "Could not cancel transaction after error!");
// }
}
}
}
Expand Down
220 changes: 96 additions & 124 deletions packages/sdk/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ export class NxtpSdk {
);

if (sendingAssetId !== constants.AddressZero) {
await this.transactionManager
const approveRes = await this.transactionManager
.approveTokensIfNeeded(sendingChainId, sendingAssetId, amount, infiniteApprove)
.andThen((approveTx) => {
// handle optional approval
Expand Down Expand Up @@ -460,20 +460,13 @@ export class NxtpSdk {
});
}
return okAsync(approveReceipt);
})
.match(
() => {
this.logger.info({ method, methodId }, "Approval complete");
},
(err) => {
throw new NxtpSdkError(NxtpSdkError.reasons.ApprovalError, {
txError: jsonifyError(err as TransactionManagerError),
transactionId,
methodId,
method,
});
},
);
});

if (approveRes.isOk()) {
this.logger.info({ method, methodId, approveRes: approveRes.value }, "Approval complete");
} else {
throw approveRes.error;
}
}

// Prepare sender side tx
Expand All @@ -499,28 +492,17 @@ export class NxtpSdk {
amount,
expiry,
};
return await this.transactionManager
.prepare(sendingChainId, params)
.andThen((prepareResponse) => {
this.evts.SenderTransactionPrepareSubmitted.post({
prepareParams: params,
transactionResponse: prepareResponse,
});
return okAsync(prepareResponse);
})
.match(
(prepareResponse) => {
return { prepareResponse, transactionId };
},
(err) => {
throw new NxtpSdkError(NxtpSdkError.reasons.ApprovalError, {
txError: jsonifyError(err as TransactionManagerError),
transactionId,
methodId,
method,
});
},
);
const prepareRes = await this.transactionManager.prepare(sendingChainId, params);

if (prepareRes.isOk()) {
this.evts.SenderTransactionPrepareSubmitted.post({
prepareParams: params,
transactionResponse: prepareRes.value,
});
return { prepareResponse: prepareRes.value, transactionId };
} else {
throw prepareRes.error;
}
}

public async finishTransfer(
Expand All @@ -537,6 +519,7 @@ export class NxtpSdk {
const signerAddress = await this.signer.getAddress();

this.logger.info({ method, methodId, transactionId: params.txData.transactionId }, "Generating fulfill signature");
let signature: string;
const prepareRes = ResultAsync.fromPromise(
// Generate signature
signFulfillTransactionPayload(txData.transactionId, relayerFee, this.signer),
Expand All @@ -548,8 +531,9 @@ export class NxtpSdk {
signerError: jsonifyError(err as Error),
}),
)
.andThen((signature) => {
this.logger.info({ method, methodId }, "Generated signature");
.andThen((_signature) => {
this.logger.info({ method, methodId, signature }, "Generated signature");
signature = _signature;
this.evts.ReceiverPrepareSigned.post({ signature, transactionId: txData.transactionId, signer: signerAddress });
if (!this.messaging.isConnected()) {
return ResultAsync.fromPromise(
Expand All @@ -563,9 +547,9 @@ export class NxtpSdk {
}),
);
}
return okAsync(signature);
return okAsync(undefined);
})
.andThen((signature) => {
.andThen(() => {
// Submit fulfill to receiver chain
this.logger.info({ method, methodId, transactionId: txData.transactionId, relayerFee }, "Preparing fulfill tx");
let callData = "0x";
Expand All @@ -592,97 +576,85 @@ export class NxtpSdk {

if (useRelayers) {
// send through messaging to metatx relayers
return await prepareRes
.andThen(({ callData, signature }) => {
const responseInbox = generateMessagingInbox();
const metaTxRes = await prepareRes.andThen(({ callData, signature }) => {
const responseInbox = generateMessagingInbox();

return ResultAsync.fromPromise(
new Promise<{ metaTxResponse?: MetaTxResponse; fulfillResponse?: providers.TransactionResponse }>(
async (resolve, reject) => {
if (!this.messaging.isConnected()) {
await this.messaging.connect();
}

await this.messaging.subscribeToMetaTxResponse(responseInbox, (data, err) => {
this.logger.info({ method, methodId, data, err }, "MetaTx response received");
if (err || !data) {
return reject(err);
}
this.logger.info({ method, methodId, responseInbox, data }, "Fulfill metaTx response received");
return resolve({ metaTxResponse: data, fulfillResponse: undefined });
});

await this.messaging.publishMetaTxRequest(
{
type: "Fulfill",
relayerFee,
to: this.transactionManager.getTransactionManagerAddress(txData.receivingChainId),
chainId: txData.receivingChainId,
data: {
relayerFee,
signature,
txData,
callData,
},
},
responseInbox,
);
return ResultAsync.fromPromise(
new Promise<MetaTxResponse>(async (resolve, reject) => {
if (!this.messaging.isConnected()) {
await this.messaging.connect();
}

await this.messaging.subscribeToMetaTxResponse(responseInbox, (data, err) => {
this.logger.info({ method, methodId, data, err }, "MetaTx response received");
if (err || !data) {
return reject(err);
}
this.logger.info({ method, methodId, responseInbox, data }, "Fulfill metaTx response received");
return resolve(data);
});

await this.messaging.publishMetaTxRequest(
{
type: "Fulfill",
relayerFee,
to: this.transactionManager.getTransactionManagerAddress(txData.receivingChainId),
chainId: txData.receivingChainId,
data: {
relayerFee,
signature,
txData,
callData,
},
},
),
(err) =>
new NxtpSdkError(NxtpSdkError.reasons.MessagingError, {
method,
methodId,
transactionId: txData.transactionId,
messagingError: jsonifyError(err as Error),
}),
);
})
.match(
(res) => res,
(err) => {
throw err;
},
);
} else {
return await prepareRes
.andThen(({ callData, signature }) => {
return this.transactionManager
.fulfill(txData.receivingChainId, {
callData,
relayerFee,
signature,
txData,
})
.map((t) => {
return { fulfillResponse: t, metaTxResponse: undefined };
})
.mapErr(
(err) =>
new NxtpSdkError(NxtpSdkError.reasons.TxError, {
method,
methodId,
txError: jsonifyError(err),
transactionId: txData.transactionId,
}),
responseInbox,
);
})
.match(
(res) => res,
(err) => {
throw err;
},
}),
(err) =>
new NxtpSdkError(NxtpSdkError.reasons.MessagingError, {
method,
methodId,
transactionId: txData.transactionId,
messagingError: jsonifyError(err as Error),
}),
);
});

if (metaTxRes.isOk()) {
this.logger.info({ method, methodId }, "Method complete");
return { metaTxResponse: metaTxRes.value };
} else {
throw metaTxRes.error;
}
} else {
const fulfillRes = await prepareRes.andThen(({ callData, signature }) => {
return this.transactionManager.fulfill(txData.receivingChainId, {
callData,
relayerFee,
signature,
txData,
});
});
if (fulfillRes.isOk()) {
this.logger.info({ method, methodId }, "Method complete");
return { fulfillResponse: fulfillRes.value };
} else {
throw fulfillRes.error;
}
}
}

public async cancelExpired(cancelParams: CancelParams, chainId: number): Promise<providers.TransactionResponse> {
return await this.transactionManager.cancel(chainId, cancelParams).match(
(res) => res,
(err) => {
throw err;
},
);
const method = this.cancelExpired.name;
const methodId = getRandomBytes32();
this.logger.info({ method, methodId, cancelParams, chainId }, "Method started");
const cancelRes = await this.transactionManager.cancel(chainId, cancelParams);
if (cancelRes.isOk()) {
this.logger.info({ method, methodId }, "Method complete");
return cancelRes.value;
} else {
throw cancelRes.error;
}
}

public changeInjectedSigner(signer: Signer) {
Expand Down
8 changes: 5 additions & 3 deletions packages/txservice/src/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { jsonifyError } from "@connext/nxtp-utils";
import { BigNumber, providers } from "ethers";
import { BigNumber, providers, errors } from "ethers";
import { BaseLogger } from "pino";
import hyperid from "hyperid";
import { Logger } from "ethers/lib/utils";
Expand Down Expand Up @@ -85,11 +85,13 @@ export class Transaction {
if (
this.responses.length >= 1 &&
(error.message.includes("nonce has already been used") ||
(error as any).reason.includes("nonce has already been used") ||
(error as any).code === errors.NONCE_EXPIRED ||
// If we get a 'nonce is too low' message, a previous tx has been mined, and ethers thought
// we were making another tx attempt with the same nonce.
error.message.includes("Transaction nonce is too low.") ||
error.message.includes("Transaction nonce is too low") ||
// Another ethers message that we could potentially be getting back.
error.message.includes("There is another transaction with same nonce in the queue."))
error.message.includes("There is another transaction with same nonce in the queue"))
) {
this.nonceExpired = true;
await this.logInfo("Tx reverted: nonce already used.", method, { error: error.message });
Expand Down

0 comments on commit d824107

Please sign in to comment.