test-ic-wallet-middleware-icrc
Version:
Ic middleware wallet ICRC protocol
239 lines (238 loc) • 11.3 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TransactionRepository = void 0;
const ledger_icp_1 = require("@dfinity/ledger-icp");
const common_1 = require("@ic-wallet-middleware/common");
const transactionsRepositoryError_1 = require("../../../errors/transactionsRepositoryError");
const types_1 = require("../../../types");
const enums_1 = require("../../../types/enums");
const indexWrapper_1 = require("../../../wrappers/icrc/indexWrapper/indexWrapper");
const typedi_1 = require("typedi");
const milliPerSecond = 1000000;
let TransactionRepository = class TransactionRepository {
identifierService;
constructor(identifierService) {
this.identifierService = identifierService;
}
async getIcpListTransaction(asset, param) {
const skip = asset.pageInfo.nextPageKey ? Number(asset.pageInfo.nextPageKey) : 0;
if (Number.isNaN(skip)) {
throw new transactionsRepositoryError_1.TransactionsRepositoryError("get.icp.list.transaction.invalid.nextPageKey", "Invalid nextPageKey");
}
let result = [];
for (const subAccountId of asset.subAccountIds) {
let subAccount = ledger_icp_1.SubAccount.fromBytes(subAccountId.toUint8Array());
const accountIdentifier = ledger_icp_1.AccountIdentifier.fromPrincipal({
principal: this.identifierService.getPrincipal(),
subAccount: subAccount,
});
try {
const response = await fetch(`${param.url}/search/transactions`, {
method: "POST",
body: JSON.stringify({
network_identifier: {
blockchain: param.blockchain,
network: param.network,
},
account_identifier: {
address: accountIdentifier.toHex(),
},
offset: skip,
limit: asset.pageInfo.take
}),
headers: {
"Content-Type": "application/json",
Accept: "*/*",
},
}).catch();
if (!response.ok)
throw Error(`${response.statusText}`);
const { transactions } = await response.json();
const trans = transactions.map(({ transaction, block_identifier }) => this.formatIcpTransaction(accountIdentifier.toHex(), transaction, block_identifier.hash, param.canisterId));
result = result.concat(trans);
if (result.length >= asset.pageInfo.take) {
result = result.slice(0, asset.pageInfo.take);
break;
}
}
catch (e) {
throw new transactionsRepositoryError_1.TransactionsRepositoryError("get.icp.list.transaction.error", e.message);
}
}
const hasNext = result.length == asset.pageInfo.take;
let nextPageKey = common_1.PageResultEmptyKey;
if (hasNext) {
nextPageKey = (asset.pageInfo.take + skip).toString();
}
return {
transactions: result,
pageResult: {
hasNext: hasNext,
nextPageKey: nextPageKey
}
};
}
async getIcrcListTransactionByAsset(asset) {
let result = [];
for (const subAccountId of asset.subAccountIds) {
const indexWrapper = indexWrapper_1.IndexWrapper.create(asset.indexAsset);
const transactions = await indexWrapper.getTransactions(this.identifierService.getPrincipal(), subAccountId, asset.pageInfo);
const tran = transactions.map((t) => this.formatCkBTCTransaction(t, asset.indexAsset, asset.symbol, subAccountId));
result = result.concat(tran);
if (result.length >= asset.pageInfo.take) {
result = result.slice(0, asset.pageInfo.take);
break;
}
}
;
const hasNext = result.length == asset.pageInfo.take;
let nextPageKey = common_1.PageResultEmptyKey;
if (hasNext && asset.pageInfo.take > 0) {
nextPageKey = result[result.length - 1].idx;
}
return {
transactions: result,
pageResult: {
hasNext: hasNext,
nextPageKey: nextPageKey
}
};
}
formatIcpTransaction(accountId, rosettaTransaction, blockHash, canisterId) {
const model = {
status: enums_1.OperationStatusEnum.COMPLETED,
hash: rosettaTransaction.transaction_identifier.hash + "-" + blockHash,
timestamp: Math.floor(rosettaTransaction.metadata.timestamp / milliPerSecond)
};
rosettaTransaction.operations.forEach((operation, i) => {
const value = BigInt(operation.amount.value);
const amount = value;
if (operation.type === enums_1.OperationTypeEnum.FEE) {
model.fee = amount;
return;
}
if (value > BigInt(0)) {
model.to = operation.account.address;
}
else if (value < BigInt(0)) {
model.from = operation.account.address;
}
else {
if (i === 0) {
model.from = operation.account.address;
}
if (i === 1) {
model.to = operation.account.address;
}
}
if (model.status === enums_1.OperationStatusEnum.COMPLETED &&
operation.status !== enums_1.OperationStatusEnum.COMPLETED) {
model.status = operation.status;
}
model.type = model.to === accountId ? enums_1.TransactionTypeEnum.RECEIVE : enums_1.TransactionTypeEnum.SEND;
model.amount = amount;
model.canisterId = canisterId;
model.idx = rosettaTransaction.metadata.block_height.toString();
model.symbol = operation.amount.currency.symbol;
});
return model;
}
formatCkBTCTransaction(transactionWithId, canisterId, symbol, subAccountId) {
const transaction = transactionWithId.transaction;
const model = {
timestamp: Math.floor(Number(transaction.timestamp) / milliPerSecond),
status: enums_1.OperationStatusEnum.COMPLETED,
type: enums_1.TransactionTypeEnum.NONE,
kind: transaction.kind
};
switch (transaction.kind) {
case "mint":
transaction.mint.forEach((item) => {
// Get Tx data from Mint record
const amount = item.amount;
this.setTransactionBaseField(model, transactionWithId, canisterId, symbol, amount);
model.to = item.to.owner.toString();
model.toSub = this.getSubAccount(item.to.subaccount);
// Get AccountIdentifier of Receiver
model.identityTo = this.getAccountIdentifier(item.to.subaccount, item.to.owner);
model.type = enums_1.TransactionTypeEnum.RECEIVE;
});
break;
case "burn":
transaction.burn.forEach((item) => {
// Get Tx data from Burn record
const amount = item.amount;
this.setTransactionBaseField(model, transactionWithId, canisterId, symbol, amount);
model.from = item.from.owner.toString();
model.fromSub = this.getSubAccount(item.from.subaccount);
// Get AccountIdentifier of Sender
model.identityFrom = this.getAccountIdentifier(item.from.subaccount, item.from.owner);
model.type = enums_1.TransactionTypeEnum.SEND;
});
break;
default:
transaction.transfer.forEach((item) => {
// Get Tx data from transfer record
const amount = item.amount;
this.setTransactionBaseField(model, transactionWithId, canisterId, symbol, amount);
model.to = item.to.owner.toString();
model.toSub = this.getSubAccount(item.to.subaccount);
model.from = item.from.owner.toString();
model.fromSub = this.getSubAccount(item.from.subaccount);
const subCheck = subAccountId;
if (model.from === this.identifierService.getPrincipalStr()
&& model.fromSub.equals(subCheck)) {
model.type = enums_1.TransactionTypeEnum.SEND;
}
else {
model.type = enums_1.TransactionTypeEnum.RECEIVE;
}
// Get AccountIdentifier of Receiver
model.identityTo = this.getAccountIdentifier(item.to.subaccount, item.to.owner);
// Get AccountIdentifier of Sender
model.identityFrom = this.getAccountIdentifier(item.from.subaccount, item.from.owner);
});
break;
}
return model;
}
getAccountIdentifier(subAccount, owner) {
let subAcc = undefined;
try {
subAcc = ledger_icp_1.SubAccount.fromBytes(subAccount[0]);
}
catch {
subAcc = undefined;
}
const identity = ledger_icp_1.AccountIdentifier.fromPrincipal({
principal: owner,
subAccount: subAcc,
}).toHex();
return identity;
}
getSubAccount(subaccount) {
return subaccount.length > 0
? types_1.SubAccountId.parseFromUint8Array(subaccount[0])
: types_1.SubAccountId.parseFromString("0x0");
}
setTransactionBaseField(model, transactionWithId, canisterId, symbol, amount) {
model.canisterId = canisterId;
model.symbol = symbol;
model.amount = amount;
model.idx = transactionWithId.id.toString();
}
};
exports.TransactionRepository = TransactionRepository;
exports.TransactionRepository = TransactionRepository = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [common_1.IdentifierService])
], TransactionRepository);