Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts-sdk: perform proper serialization of amount to u256 #325

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
15 changes: 5 additions & 10 deletions solana/solana-ibc/tests/solana-ibc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import {
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { solanaIbcProgramId, rpcUrl, depositor } from "./constants";
import { getInt64Bytes, hexToBytes, getGuestChainAccounts } from "./utils";
import { hexToBytes, getGuestChainAccounts, numberTo32ByteBuffer } from "./utils";
import { instructionSchema } from "./schema";

describe("solana-ibc", () => {
it("This is test", async () => {
// Parameters
const sender = depositor.publicKey; // solana account address
const receiver = "centauri1c8jhgqsdzw5su4yeel93nrp9xmhlpapyd9k0ue"; // cosmos address
const amount = 10000000000000000; // amount to send
const amount = 10000000000000000n; // amount to send
const channelIdOfSolana = "channel-0"; // example channel id
const portId = "transfer"; // always the same
const memo = "";
Expand Down Expand Up @@ -69,7 +69,7 @@ describe("solana-ibc", () => {
const sendTransfer = async (
sender: anchor.web3.PublicKey,
receiver: string,
amount: number,
amount: bigint,
channelIdOfSolana: string,
portId: string,
memo: string,
Expand All @@ -80,12 +80,7 @@ const sendTransfer = async (
) => {
const senderPublicKey = new anchor.web3.PublicKey(sender);

const emptyArray = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];

const convertedAmount = getInt64Bytes(amount);
const finalAmount = convertedAmount.concat(emptyArray);
const convertedAmount = numberTo32ByteBuffer(amount);

let tokenMint: anchor.web3.PublicKey;

Expand Down Expand Up @@ -116,7 +111,7 @@ const sendTransfer = async (
trace_path: trace_path,
base_denom: baseDenom,
},
amount: finalAmount,
amount: convertedAmount,
},
sender: sender.toString(),
receiver,
Expand Down
14 changes: 9 additions & 5 deletions solana/solana-ibc/tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ import {
import bs58 from "bs58";
import { solanaIbcProgramId } from "./constants";

export function getInt64Bytes(x: number) {
let y = Math.floor(x / 2 ** 32);
return [y, y << 8, y << 16, y << 24, x, x << 8, x << 16, x << 24].map(
(z) => z >>> 24
);
export function numberTo32ByteBuffer(num: bigint): Uint8Array {
const buffer = Buffer.alloc(32);
let numberHex = num.toString(16);
if (numberHex.length % 2 !== 0) {
numberHex = "0" + numberHex;
}
const numberBytes = Buffer.from(numberHex, "hex");
numberBytes.reverse().copy(buffer, 0);
return new Uint8Array(buffer);
Comment on lines +18 to +25
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps worth checking range? Also perhaps this is more straightforward:

Suggested change
const buffer = Buffer.alloc(32);
let numberHex = num.toString(16);
if (numberHex.length % 2 !== 0) {
numberHex = "0" + numberHex;
}
const numberBytes = Buffer.from(numberHex, "hex");
numberBytes.reverse().copy(buffer, 0);
return new Uint8Array(buffer);
const n = BigInt.asUintN(256, num);
if (num < 0 || n < num) {
throw new RangeError();
}
const numHex = '00'.repeat(32) + n.toString(16);
const numBuf = Buffer.from(numHex.substring(numHex.length - 64), 'hex');
return new Uint8Array(numBuf.reverse());

not tested.

Copy link
Collaborator Author

@dhruvja dhruvja May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya i think the code i came up with is prolly wrong. Since the U256 is [u64; 4] and convert to le, bytes are assigned from the back of the 32 byte array which is prolly not right. It should be converted to LE and then be split into 4 arrays and appended reversely.
Something like this.

export function numberTo32ByteBuffer(num: bigint): Uint8Array {
  // Create a buffer of 32 bytes initialized with zeros
  let buffer = Buffer.alloc(32);

  // Convert the BigInt to a hexadecimal string
  let numberHex = num.toString(16);
  if (numberHex.length % 2 !== 0) {
    numberHex = "0" + numberHex; // Ensure the hex string has an even length
  }

  // Create a buffer from the hexadecimal string
  let numberBytes = Buffer.from(numberHex, "hex");

  // Copy the number bytes to the end of the 32-byte buffer
  numberBytes.copy(buffer, 32 - numberBytes.length);
  let uintBuffer = new Uint8Array(buffer);
  // split above array into 4 chunks of 8 bytes each
  let uintBufferChunks = [];
  for (let i = 0; i < uintBuffer.length; i += 8) {
    uintBufferChunks.push(uintBuffer.slice(i, i + 8));
  }
  let final_uintBuffer: Array<number> = [];
  final_uintBuffer = final_uintBuffer.concat(...uintBufferChunks[3]);
  final_uintBuffer = final_uintBuffer.concat(...uintBufferChunks[2]);
  final_uintBuffer = final_uintBuffer.concat(...uintBufferChunks[1]);
  final_uintBuffer = final_uintBuffer.concat(...uintBufferChunks[0]);
  return new Uint8Array(final_uintBuffer);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still unresolved, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well actually no, the above seems to work. The FE is using that only.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this will break if number is over u64::MAX, no? Because of the weird way U256 is serialised in IBC (each u64 is serialised using little endian but the four u64 are serialised in big endian order IIRC).

}

export function hexToBytes(hex: string) {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
}
},
"compilerOptions": {
"target": "ES2020",
"declaration": true,
"moduleResolution": "node",
"module": "es2015"
Expand Down
Loading