Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 19x 19x 19x 19x 1x 1x 1x 19x 1x 1x 1x 1x 1x 1x 1x | import { BlockfrostClient, BlockfrostProvider } from '../blockfrost';
import { Logger } from 'ts-log';
import {
ProviderError,
SubmitTxArgs,
TxSubmissionError,
TxSubmissionErrorCode,
TxSubmitProvider,
ValueNotConservedData
} from '@cardano-sdk/core';
type BlockfrostTxSubmissionErrorMessage = {
contents: {
contents: {
contents: {
error: [string];
};
};
};
};
const tryParseBlockfrostTxSubmissionErrorMessage = (
errorMessage: string
): BlockfrostTxSubmissionErrorMessage | null => {
try {
const error = JSON.parse(errorMessage);
Iif (typeof error === 'object' && Array.isArray(error?.contents?.contents?.contents?.error)) {
return error;
}
} catch {
return null;
}
return null;
};
/**
* @returns TxSubmissionError if sucessfully mapped, otherwise `null`
*/
const tryMapTxBlockfrostSubmissionError = (error: ProviderError): TxSubmissionError | null => {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const detail = JSON.parse(error.detail as any);
Iif (typeof detail?.message === 'string') {
const blockfrostTxSubmissionErrorMessage = tryParseBlockfrostTxSubmissionErrorMessage(detail.message);
Iif (!blockfrostTxSubmissionErrorMessage) {
return null;
}
const message = blockfrostTxSubmissionErrorMessage.contents.contents.contents.error[0];
Iif (message.includes('OutsideValidityIntervalUTxO')) {
// error also contains information about validity interval and actual slots,
// but we're currently not using this info
return new TxSubmissionError(TxSubmissionErrorCode.OutsideOfValidityInterval, null, message);
}
// eslint-disable-next-line wrap-regex
const valueNotConservedMatch = /ValueNotConservedUTxO.+Coin (\d+).+Coin (\d+)/.exec(message);
Iif (valueNotConservedMatch) {
const consumed = BigInt(valueNotConservedMatch[1]);
const produced = BigInt(valueNotConservedMatch[2]);
const valueNotConservedData: ValueNotConservedData = {
// error also contains information about consumed and produced native assets
// but we're currently not using this info
consumed: { coins: consumed },
produced: { coins: produced }
};
return new TxSubmissionError(TxSubmissionErrorCode.ValueNotConserved, valueNotConservedData, message);
}
}
} catch {
return null;
}
return null;
};
export class BlockfrostTxSubmitProvider extends BlockfrostProvider implements TxSubmitProvider {
constructor(client: BlockfrostClient, logger: Logger) {
super(client, logger);
}
async submitTx({ signedTransaction }: SubmitTxArgs): Promise<void> {
// @ todo handle context and resolutions
try {
await this.request<string>('tx/submit', {
body: Buffer.from(signedTransaction, 'hex'),
headers: { 'Content-Type': 'application/cbor' },
method: 'POST'
});
} catch (error) {
if (error instanceof ProviderError) {
const submissionError = tryMapTxBlockfrostSubmissionError(error);
Iif (submissionError) {
throw new ProviderError(error.reason, submissionError, error.detail);
}
}
throw error;
}
}
}
|