@arcana/ca-sdk
Version:
Arcana Network's chain abstraction SDK for unified balance in Web3 apps
99 lines (98 loc) • 3.4 kB
JavaScript
import Decimal from "decimal.js";
import { Account, bn, CHAIN_IDS, hexlify, OutputType, } from "fuels";
import { FUEL_BASE_ASSET_ID } from "../../constants";
import { getLogger } from "../../logger";
import { divDecimals } from "../../utils";
const logger = getLogger();
const simulate = async (tx, address, provider, chainList) => {
const outputs = tx.outputs?.filter((o) => o.type === OutputType.Coin) ?? [];
const tokens = outputs
.map((o) => {
const token = chainList.getTokenByAddress(CHAIN_IDS.fuel.mainnet, o.assetId);
if (!token)
return null;
return {
from: hexlify(address).toLowerCase(),
to: hexlify(o.to).toLowerCase(),
token: {
address: hexlify(o.assetId),
amount: divDecimals(o.amount.toString(), token.decimals),
decimals: token.decimals,
logo: token.logo,
name: token.name,
symbol: token.symbol,
},
};
})
.filter((o) => !!o)
.reduce((acc, o) => {
const existingCoin = acc.find((a) => o.from === a.from && o.token.address === a.token.contractAddress);
if (existingCoin) {
existingCoin.token.amount = new Decimal(existingCoin.token.amount).plus(o.token.amount);
return acc;
}
acc.push({
from: o.from,
to: o.to,
token: {
amount: new Decimal(o.token.amount),
contractAddress: o.token.address,
decimals: o.token.decimals,
logo: o.token.logo,
name: o.token.name,
symbol: o.token.symbol,
},
});
return acc;
}, [])
.sort((a, b) => new Decimal(a.token.amount).lessThan(b.token.amount) ? 1 : -1);
const { assembledRequest } = await provider.assembleTx({
feePayerAccount: new Account(address),
request: tx,
});
logger.debug("Fuel Simulate: mappedOutputsToInputs", {
assembledRequest,
});
const coin = tokens?.length ? tokens[0] : null;
if (!coin) {
return null;
}
logger.debug("FuelSimulate", {
amount: coin.token.amount.toFixed(),
coin: coin,
});
const { amount, ...token } = coin.token;
return {
amount: amount,
gas: BigInt(0),
gasFee: divDecimals(BigInt(assembledRequest.maxFee.toString()) * 2n, 9),
token: { ...token, type: "src20" },
};
};
const fixTx = async (address, tx, provider) => {
delete tx.inputs;
const outputQuantities = tx.outputs
?.filter((o) => o.type === OutputType.Coin)
.map(({ amount, assetId }) => ({
amount: bn(amount),
assetId: String(assetId),
}));
const aResponse = await provider.assembleTx({
accountCoinQuantities: outputQuantities,
estimatePredicates: true,
feePayerAccount: new Account(address),
// @ts-ignore
request: tx,
});
logger.debug("fixTx:sendTransaction:3", {
assembleTxResponse: aResponse,
request: tx,
});
return aResponse.assembledRequest;
};
const isFuelNativeTransfer = (tx) => {
return tx.outputs?.every((o) => {
return "assetId" in o && o.assetId === FUEL_BASE_ASSET_ID;
});
};
export { fixTx, isFuelNativeTransfer, simulate };