@renproject/ren
Version:
Official Ren JavaScript SDK for bridging crypto assets cross-chain.
209 lines • 9.18 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { crossChainParamsType, } from "@renproject/provider";
import { renExplorerUrls } from "@renproject/provider/rpcUrls";
import { ChainTransactionStatus, ErrorWithCode, eventEmitter, generateTransactionHash, RenJSError, TxStatus, utils, } from "@renproject/utils";
export class RenVMTxSubmitter {
constructor(provider, tx, signatureCallback, config = {}, providerNetwork) {
this.chain = "RenVM";
this.updateProgress = (progress) => {
const currentProgress = this.progress;
this.progress = Object.assign(Object.assign({}, currentProgress), progress);
this.eventEmitter.emit("progress", this.progress);
return this.progress;
};
this.export = () => {
return this.tx;
};
this.query = () => __awaiter(this, void 0, void 0, function* () {
const tx = yield this.provider.queryTx(this.tx.hash, 1);
if (tx.txStatus === TxStatus.TxStatusDone ||
tx.txStatus === TxStatus.TxStatusReverted) {
return this._handleDoneTransaction(tx);
}
else {
return this.updateProgress({
response: tx,
status: ChainTransactionStatus.Confirming,
});
}
});
this.submit = () => {
const promiEvent = utils.newPromiEvent(this.eventEmitter);
(() => __awaiter(this, void 0, void 0, function* () {
// Alternate trying to submit and trying to query.
const retries = 4;
let errorInner;
for (let i = 0; i < retries; i++) {
try {
yield this.provider.submitTx(this.tx, 1);
break;
}
catch (error) {
errorInner = error;
}
try {
yield this.provider.queryTx(this.tx.hash, 1);
break;
}
catch (error) {
// Ignore error.
}
if (i === retries - 1) {
throw errorInner;
}
}
if (this.progress.status === ChainTransactionStatus.Ready) {
return this.updateProgress({
status: ChainTransactionStatus.Confirming,
confirmations: 0,
});
}
else {
return this.progress;
}
// const response = {
// version: parseInt(tx.version),
// hash: tx.hash,
// selector: tx.selector,
// in: unmarshalTypedPackValue(tx.in),
// };
}))()
.then(promiEvent.resolve)
.catch(promiEvent.reject);
return promiEvent;
};
this.setTransaction = () => {
return this.progress;
};
this.wait = () => {
const promiEvent = utils.newPromiEvent(this.eventEmitter);
(() => __awaiter(this, void 0, void 0, function* () {
let tx;
let existingStatus = undefined;
while (true) {
try {
tx = yield this.provider.queryTx(this.tx.hash, 1);
if (tx.txStatus === TxStatus.TxStatusDone ||
tx.txStatus === TxStatus.TxStatusReverted) {
break;
}
if (tx.txStatus !== existingStatus ||
!this.progress.response) {
try {
existingStatus = tx.txStatus;
this.updateProgress({
response: tx,
status: ChainTransactionStatus.Confirming,
confirmations: 0,
});
}
catch (error) {
// Ignore non-critical error.
}
}
}
catch (error) {
if (error instanceof Error &&
/(not found)|(not available)/.exec(String((error || {}).message))) {
// ignore
}
else {
console.error(error);
// TODO: throw unexpected errors
}
}
yield utils.sleep(this.config && this.config.networkDelay
? this.config.networkDelay
: 15 * utils.sleep.SECONDS);
}
return yield this._handleDoneTransaction(tx);
}))()
.then(promiEvent.resolve)
.catch(promiEvent.reject);
return promiEvent;
};
/**
* Process a complete RenVM transaction, handling checking for a revert
* reason and calling the signatureCallback.
*/
this._handleDoneTransaction = (tx) => __awaiter(this, void 0, void 0, function* () {
if (tx.tx.out && tx.tx.out.revert && tx.tx.out.revert.length > 0) {
const revertMessage = tx.tx.out.revert;
this.updateProgress({
status: ChainTransactionStatus.Reverted,
revertReason: revertMessage,
confirmations: 1,
});
throw new ErrorWithCode(`RenVM transaction reverted: ${revertMessage}`, RenJSError.RENVM_TRANSACTION_REVERTED);
}
if (this.signatureCallback) {
yield this.signatureCallback(tx);
}
return this.updateProgress({
response: tx,
status: ChainTransactionStatus.Done,
confirmations: 1,
});
});
this.provider = provider;
this.eventEmitter = eventEmitter();
this.signatureCallback = signatureCallback;
this.config = config;
this.providerNetwork = providerNetwork;
const version = tx.version || "1";
const expectedHash = utils.toURLBase64(generateTransactionHash(version, tx.selector, tx.in));
if (tx.hash && tx.hash !== expectedHash) {
throw new Error(`Invalid hash (expected '${expectedHash}', got '${tx.hash}').`);
}
const hash = tx.hash || expectedHash;
this.tx = Object.assign(Object.assign({}, tx), { version,
hash });
const explorerLinkBase = this.providerNetwork && renExplorerUrls[this.providerNetwork];
const explorerLink = explorerLinkBase
? `${explorerLinkBase}/#/tx/${this.tx.hash}`
: ``;
this.progress = {
chain: this.chain,
status: ChainTransactionStatus.Ready,
target: 1,
transaction: {
chain: this.chain,
txid: this.tx.hash,
txHash: this.tx.hash,
txindex: "0",
explorerLink,
},
};
}
}
export class RenVMCrossChainTxSubmitter extends RenVMTxSubmitter {
constructor(provider, selector, params, signatureCallback, config = {}, providerNetwork) {
super(provider, {
selector,
in: {
t: crossChainParamsType,
v: {
txid: utils.toURLBase64(params.txid),
txindex: params.txindex.toFixed(),
amount: params.amount.toFixed(),
payload: utils.toURLBase64(params.payload),
phash: utils.toURLBase64(params.phash),
to: params.to,
nonce: utils.toURLBase64(params.nonce),
nhash: utils.toURLBase64(params.nhash),
gpubkey: utils.toURLBase64(params.gpubkey),
ghash: utils.toURLBase64(params.ghash),
},
},
}, signatureCallback, config, providerNetwork);
}
}
//# sourceMappingURL=renVMTxSubmitter.js.map