Skip to content
This repository was archived by the owner on Jan 8, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/ProviderExample.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react'
import {ChainMetadata, Connector} from "@soroban-react/types";
import {SorobanReactProvider} from '@soroban-react/core';
import {SorobanEventsProvider} from '@soroban-react/events';
import {futurenet, sandbox, standalone} from '@soroban-react/chains';
import {freighter} from '@soroban-react/freighter';
import {ChainMetadata, Connector} from "@soroban-react/types";

const chains: ChainMetadata[] = [sandbox, standalone, futurenet];
const connectors: Connector[] = [freighter()];
Expand Down
2 changes: 1 addition & 1 deletion components/molecules/deposits/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as SorobanClient from 'soroban-client'
import styles from './style.module.css'
import { Utils } from '../../../shared/utils'
import { Spacer } from '../../atoms/spacer'
import * as convert from '../../../convert'
import * as convert from '../../../helpers/convert'
import { Constants } from '../../../shared/constants'
import {
ContractValueType,
Expand Down
2 changes: 1 addition & 1 deletion components/molecules/form-pledge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useSendTransaction, useContractValue, contractTransaction } from '@soro
import { useSorobanReact } from '@soroban-react/core'
import * as SorobanClient from 'soroban-client'
import BigNumber from 'bignumber.js'
import * as convert from '../../../convert'
import * as convert from '../../../helpers/convert'
import { Constants } from '../../../shared/constants'
import { Spacer } from '../../atoms/spacer'
let xdr = SorobanClient.xdr
Expand Down
2 changes: 1 addition & 1 deletion components/organisms/pledge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { useContractValue } from '@soroban-react/contracts'
import * as SorobanClient from 'soroban-client'
import { Deposits, FormPledge } from '../../molecules'
import * as convert from '../../../convert'
import * as convert from '../../../helpers/convert'
import { Constants } from '../../../shared/constants'
import { useSorobanReact } from '@soroban-react/core'
import { useSorobanEvents, EventSubscription } from '@soroban-react/events'
Expand Down
34 changes: 27 additions & 7 deletions convert.ts → helpers/convert.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import BigNumber from 'bignumber.js';
import * as SorobanClient from 'soroban-client';
import { I128 } from "./xdr";

let xdr = SorobanClient.xdr;

export function scvalToBigNumber(scval: SorobanClient.xdr.ScVal | undefined): BigNumber {
console.log("🚀 ~ file: convert.ts:6 ~ scvalToBigNumber ~ scval:", scval)
if (scval){
console.log("If we decode: ", decodei128ScVal(scval))
}

switch (scval?.switch()) {
case undefined: {
return BigNumber(0);
Expand All @@ -23,15 +30,13 @@ export function scvalToBigNumber(scval: SorobanClient.xdr.ScVal | undefined): Bi
}
case xdr.ScValType.scvU128(): {
const parts = scval.u128();
const a = parts.hi();
const b = parts.lo();
return bigNumberFromBytes(false, a.high, a.low, b.high, b.low);
console.log("🚀 ~ file: convert.ts:28 ~ casexdr.ScValType.scvU128 ~ parts:", parts)
const hi = parts.hi();
const lo = parts.lo();
return bigNumberFromBytes(false, lo.low, lo.high, hi.low, hi.high);
}
case xdr.ScValType.scvI128(): {
const parts = scval.i128();
const a = parts.hi();
const b = parts.lo();
return bigNumberFromBytes(true, a.high, a.low, b.high, b.low);
return BigNumber(decodei128ScVal(scval));
}
case xdr.ScValType.scvU256(): {
const parts = scval.u256();
Expand Down Expand Up @@ -139,3 +144,18 @@ export function scvalToString(value: SorobanClient.xdr.ScVal): string | undefine
return value.bytes().toString();
}


// XDR -> String
export const decodei128ScVal = (value: SorobanClient.xdr.ScVal) => {
try {
return new I128([
BigInt(value.i128().lo().low),
BigInt(value.i128().lo().high),
BigInt(value.i128().hi().low),
BigInt(value.i128().hi().high),
]).toString();
} catch (error) {
console.log(error);
return 0;
}
};
85 changes: 85 additions & 0 deletions helpers/xdr/bigint-encoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Ported from https://github.com/stellar/js-xdr/pull/96
// Can remove this and use them through stellar base once it is merged

/* eslint-disable */
export function encodeBigIntFromBits(
parts: any[],
size: number,
unsigned: boolean,
) {
let result = BigInt(0);
// check arguments length
if (parts.length && parts[0] instanceof Array) {
parts = parts[0];
}
const total = parts.length;
if (total === 1) {
try {
result = BigInt(parts[0]);
if (!unsigned) {
result = BigInt.asIntN(size, result);
}
} catch (e) {
throw new TypeError(`Invalid integer value: ${parts[0]}`);
}
} else {
const sliceSize = size / total;
if (sliceSize !== 32 && sliceSize !== 64 && sliceSize !== 128)
throw new TypeError("Invalid number of arguments");
// combine parts
for (let i = 0; i < total; i++) {
let part = BigInt.asUintN(sliceSize, BigInt(parts[i].valueOf()));
if (i > 0) {
// shift if needed
part <<= BigInt(i * sliceSize);
}
result |= part;
}
if (!unsigned) {
// clamp value to the requested size
result = BigInt.asIntN(size, result);
}
}
// check type
if (typeof result === "bigint") {
// check boundaries
const [min, max] = calculateBigIntBoundaries(size, unsigned);
if (result >= min && result <= max) return result;
}
// failed to encode
throw new TypeError(`Invalid ${formatIntName(size, unsigned)} value`);
}

export function sliceBigInt(value: BigInt, size: number, sliceSize: number) {
if (typeof value !== "bigint") throw new TypeError("Invalid BigInt value");
const total = size / sliceSize;
if (total === 1) return [value];
if (
sliceSize < 32 ||
sliceSize > 128 ||
(total !== 2 && total !== 4 && total !== 8)
)
throw new TypeError("Invalid slice size");
// prepare shift and mask
const shift = BigInt(sliceSize);
const mask = (BigInt(1) << shift) - BigInt(1);
// iterate shift and mask application
const result = new Array(total);
for (let i = 0; i < total; i++) {
if (i > 0) {
value >>= shift;
}
result[i] = BigInt.asIntN(sliceSize, value & mask); // clamp value
}
return result;
}

export function formatIntName(precision: number, unsigned: boolean) {
return `${unsigned ? "u" : "i"}${precision}`;
}

export function calculateBigIntBoundaries(size: number, unsigned: boolean) {
if (unsigned) return [BigInt(0), (BigInt(1) << BigInt(size)) - BigInt(1)];
const boundary = BigInt(1) << BigInt(size - 1);
return [BigInt(0) - boundary, boundary - BigInt(1)];
}
25 changes: 25 additions & 0 deletions helpers/xdr/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export class XdrWriterError extends TypeError {
constructor(message: string) {
super(`XDR Write Error: ${message}`);
}
}

export class XdrReaderError extends TypeError {
constructor(message: string) {
super(`XDR Read Error: ${message}`);
}
}

export class XdrDefinitionError extends TypeError {
constructor(message: string) {
super(`XDR Type Definition Error: ${message}`);
}
}

export class XdrNotImplementedDefinitionError extends XdrDefinitionError {
constructor() {
super(
`method not implemented, it should be overloaded in the descendant class.`,
);
}
}
17 changes: 17 additions & 0 deletions helpers/xdr/i128.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { LargeInt } from "./large-int";

export class I128 extends LargeInt {
constructor(...args: any) {
super(args);
}

get unsigned(): any {
return false;
}

get size(): any {
return 128;
}
}

I128.defineIntBoundaries();
1 change: 1 addition & 0 deletions helpers/xdr/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./i128";
131 changes: 131 additions & 0 deletions helpers/xdr/large-int.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// @ts-nocheck

import { XdrPrimitiveType } from "./xdr-type";
import {
calculateBigIntBoundaries,
encodeBigIntFromBits,
sliceBigInt,
} from "./bigint-encoder";
import { XdrNotImplementedDefinitionError, XdrWriterError } from "./errors";

/* eslint-disable */

/* tslint:disable */
export class LargeInt extends XdrPrimitiveType {
constructor(args) {
super();
this._value = encodeBigIntFromBits(args, this.size, this.unsigned);
}

/**
* Signed/unsigned representation
* @type {Boolean}
* @abstract
*/
get unsigned() {
throw new XdrNotImplementedDefinitionError();
}

/**
* Size of the integer in bits
* @type {Number}
* @abstract
*/
get size() {
throw new XdrNotImplementedDefinitionError();
}

/**
* Slice integer to parts with smaller bit size
* @param {32|64|128} sliceSize - Size of each part in bits
* @return {BigInt[]}
*/
slice(sliceSize) {
return sliceBigInt(this._value, this.size, sliceSize);
}

toString() {
return this._value.toString();
}

toJSON() {
return { _value: this._value.toString() };
}

/**
* @inheritDoc
*/
static read(reader) {
const { size } = this.prototype;
if (size === 64) return new this(reader.readBigUInt64BE());
return new this(
...Array.from({ length: size / 64 }, () =>
reader.readBigUInt64BE(),
).reverse(),
);
}

/**
* @inheritDoc
*/
static write(value, writer) {
if (value instanceof this) {
value = value._value;
} else if (
typeof value !== "bigint" ||
value > this.MAX_VALUE ||
value < this.MIN_VALUE
)
throw new XdrWriterError(`${value} is not a ${this.name}`);

const { unsigned, size } = this.prototype;
if (size === 64) {
if (unsigned) {
writer.writeBigUInt64BE(value);
} else {
writer.writeBigInt64BE(value);
}
} else {
for (const part of sliceBigInt(value, size, 64).reverse()) {
if (unsigned) {
writer.writeBigUInt64BE(part);
} else {
writer.writeBigInt64BE(part);
}
}
}
}

/**
* @inheritDoc
*/
static isValid(value) {
return typeof value === "bigint" || value instanceof this;
}

/**
* Create instance from string
* @param {String} string - Numeric representation
* @return {LargeInt}
*/
static fromString(string) {
return new this(string);
}

static MAX_VALUE = 0n;

static MIN_VALUE = 0n;

/**
* @internal
* @return {void}
*/
static defineIntBoundaries() {
const [min, max] = calculateBigIntBoundaries(
this.prototype.size,
this.prototype.unsigned,
);
this.MIN_VALUE = min;
this.MAX_VALUE = max;
}
}
Loading