Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
6.7 kB
1
Indexable
Never
async txBuild(ticker: string, params: SuiTransactionParams): Promise<SuiTransactionParams> {
    SuiServiceUtils.validateBuildParams(params);
    const {
      from,
      to,
    } = params;

    const { address: fromAddress } = Array.isArray(from) ? from[0] : from;

    const {
      address: toAddress,
      value,
    } = Array.isArray(to) ? to[0] : to;

    const valueMiniMIST = mistToSui(value);
    const gasPrice = params.gasPrice
      ?? params.fee?.properties?.gasPrice
      ?? DEFAULT_GAS_AMOUNT;
    const gasBudget = params.gasLimit
      ?? params.gasAmount
      ?? params.fee?.properties?.gasLimit
      ?? params.fee?.properties?.gasAmount
      ?? DEFAULT_GAS_LIMIT;

    if (!Array.isArray(to)) {
      const params: ToParams = {
        address: to.address,
        value: to.value,
      };

      const bytesTx = await this.build(fromAddress, gasPrice, gasBudget, params);
      if (!bytesTx) {
        throw new Error('BytesTx not serialized');
      }

      return {
        ...params,
        from: [
          {
            address: fromAddress,
            value: valueMiniMIST,
          },
        ],
        to: [
          {
            address: toAddress,
            value: valueMiniMIST,
          },
        ],
        gasPrice,
        gasLimit: gasBudget,
        data: Buffer.from(bytesTx).toString('hex'),
      };
    } else {
      throw new Error('toParams must be array');
    }
  }

  async build(fromAddress: string, gasPrice: string, gasBudget: string, toParams: ToParams): Promise<Uint8Array> {
    const tx = new Transaction();
    tx.setSender(fromAddress);
    tx.setGasOwner(fromAddress);
    tx.setGasBudget(BigInt(gasBudget));
    tx.setGasPrice(BigInt(gasPrice));

    const coins = await this.getBuildParams(NETWORK, {
      fromAddress,
      method: RPC_METHODS.GET_COINS,
    });

    const gasCoin: CoinData | CoinData[] = SuiServiceUtils.selectGasCoin(+gasBudget, coins);
    const gasCoinBalance = SuiServiceUtils.gasCoinTotalBalance(gasCoin);

    const gasPaymentObjects = Array.isArray(gasCoin)
      ? gasCoin.map((coin) => ({
        objectId: coin.coinObjectId,
        digest: coin.digest,
        version: coin.version,
      }))
      : [
        {
          objectId: gasCoin.coinObjectId,
          digest: gasCoin.digest,
          version: gasCoin.version,
        },
      ];

    tx.setGasPayment(gasPaymentObjects);

    if (coins.data.length > 1) {
      let mergeStartIndex = 0;
      if (!Array.isArray(gasCoin)) {
        if (coins.data.length > 1 && coins.data[0].coinObjectId === gasCoin.coinObjectId) {
          mergeStartIndex = 1;
        }
      } else {
        for (let i = 0; i < gasCoin.length; i++) {
          if (coins.data[i].coinObjectId === gasCoin[i].coinObjectId) {
            mergeStartIndex++;
          } else {
            break;
          }
        }
      }

      const mainCoin = coins.data[mergeStartIndex];
      for (let i = mergeStartIndex + 1; i < coins.data.length; i++) {
        const coinToMerge = coins.data[i];
        let shouldMerge = true;

        if (Array.isArray(gasCoin)) {
          for (const coin of gasCoin) {
            if (coinToMerge.coinObjectId === coin.coinObjectId) {
              shouldMerge = false;
              break;
            }
          }
        } else if (coinToMerge.coinObjectId === gasCoin.coinObjectId) {
          shouldMerge = false;
        }

        if (shouldMerge) {
          tx.mergeCoins(
            tx.object(Inputs.ObjectRef({
              objectId: mainCoin.coinObjectId,
              digest: mainCoin.digest,
              version: mainCoin.version,
            })),
            [
              tx.object(Inputs.ObjectRef({
                objectId: coinToMerge.coinObjectId,
                digest: coinToMerge.digest,
                version: coinToMerge.version,
              })),
            ],
          );
        }
      }

      if (!Array.isArray(toParams)) {
        if (SuiServiceUtils.validateBalance(mainCoin.balance, toParams.value, gasBudget)) {
          if (Big(gasCoinBalance).gt(gasBudget)) {
            // const sum = Big(gasCoinBalance).minus(gasBudget); // Под вопросом, нужна ли такая жесткая валидация
            // const sumNumber = sum.toNumber();

            // if (Big(toParams.value).gt(sum)) { // Под вопросом, нужна ли такая жесткая валидация
            //   throw new Error(`sum: ${sumNumber} less than the value to send: ${mistToSui(toParams.value)}`);
            // }

            if (Big(mainCoin.balance).lt(Big(toParams.value))) {
              throw new Error(`coinBalance: ${mainCoin.balance} less than the value to send: ${Number(Big(toParams.value))}`);
            }
            if (Big(mainCoin.balance).gte(Big(toParams.value))) {
              const coinToSend = tx.splitCoins(
                tx.object(Inputs.ObjectRef({
                  objectId: mainCoin.coinObjectId,
                  digest: mainCoin.digest,
                  version: mainCoin.version,
                })),
                [toParams.value],
              );

              tx.transferObjects(
                [coinToSend],
                tx.pure.address(toParams.address),
              );
              return await tx.build();
            } else {
              throw new Error('mainCoin balance must be greater than the value to send');
            }
          }
        } else if (SuiServiceUtils.validateGasBalance(gasCoinBalance.toString(), toParams.value, gasBudget)) {
          tx.splitCoins({ GasCoin: true }, [toParams.value]);
          tx.transferObjects([{ Result: 0 }], tx.pure.address(toParams.address));
          return await tx.build();
        } else {
          const sum = SuiServiceUtils.getTxSumError(toParams.value, gasBudget);
          throw new Error(`gasCoin balance less than the ${mistToSui(gasCoinBalance.toString())} of gasBudget: ${(gasBudget)} + value: ${
            toParams.value} = ${sum}`);
        }
      }
    } else {
      if (!Array.isArray(toParams) && !Array.isArray(gasCoin)) {
        if (SuiServiceUtils.validateGasBalance(gasCoinBalance.toString(), toParams.value, gasBudget)) {
          tx.splitCoins({ GasCoin: true }, [toParams.value]);
          tx.transferObjects([{ Result: 0 }], tx.pure.address(toParams.address));
          return await tx.build();
        }
      } else {
        const sum = mistToSui(SuiServiceUtils.getTxSumError(toParams.value, gasBudget));
        throw new Error(`gasCoin balance less than the ${mistToSui(gasCoinBalance.toString())} of gasBudget: ${mistToSui(
          gasBudget)} + value: ${mistToSui(
          toParams.value)} = ${sum}`);
      }
    }
  }
Leave a Comment