Skip to content

Commit

Permalink
feat(ts)!: added support for bcs building for arbitrary types (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
Foivos authored Jan 22, 2025
1 parent 38200de commit 7a9eda4
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 15 deletions.
74 changes: 73 additions & 1 deletion src/common/bcs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { bcs } from '@mysten/sui/bcs';
import { bcs, BcsType } from '@mysten/sui/bcs';
import { SuiClient, SuiMoveNormalizedType } from '@mysten/sui/dist/cjs/client';
import { UID } from './types';
import { isString } from './utils';

function getCommonStructs() {
const Bytes32 = bcs.Address;
Expand Down Expand Up @@ -329,6 +331,76 @@ function getGasServiceStructs() {
};
}

export async function getBcsForStruct(
client: SuiClient,
type: SuiMoveNormalizedType,
typeArguments: SuiMoveNormalizedType[] = [],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<BcsType<any, any>> {
switch (type) {
case 'Address':
return bcs.Address;
case 'Bool':
return bcs.Bool;
case 'U8':
return bcs.U8;
case 'U16':
return bcs.U16;
case 'U32':
return bcs.U32;
case 'U64':
return bcs.U64;
case 'U128':
return bcs.U128;
case 'U256':
return bcs.U256;

default: {
}
}

if (isString(type)) {
return bcs.String;
}

if ('Vector' in (type as object)) {
return bcs.vector(await getBcsForStruct(client, (type as { Vector: SuiMoveNormalizedType }).Vector, typeArguments));
}

if ('Struct' in (type as object)) {
const structType = (
type as {
Struct: {
address: string;
module: string;
name: string;
typeArguments: SuiMoveNormalizedType[];
};
}
).Struct;
const struct = await client.getNormalizedMoveStruct({
package: structType.address,
module: structType.module,
struct: structType.name,
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const fields: Record<any, any> = {};

for (const field of struct.fields) {
fields[field.name] = await getBcsForStruct(client, field.type, structType.typeArguments);
}

return bcs.struct(structType.name, fields);
}

if ('TypeParameter' in (type as object)) {
const index = (type as { TypeParameter: number }).TypeParameter;
return await getBcsForStruct(client, typeArguments[index], typeArguments);
}

throw new Error(`Unsupported type ${type}`);
}

export const bcsStructs = {
common: getCommonStructs(),
gateway: getGatewayStructs(),
Expand Down
15 changes: 2 additions & 13 deletions src/common/tx-builder-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
import { Keypair } from '@mysten/sui/cryptography';
import { Transaction, TransactionObjectInput, TransactionResult } from '@mysten/sui/transactions';
import { utils as ethersUtils } from 'ethers';
import { STD_PACKAGE_ID, SUI_PACKAGE_ID } from '../common/types';
import { SUI_PACKAGE_ID } from '../common/types';
import { isString } from './utils';

const { arrayify, hexlify } = ethersUtils;

Expand Down Expand Up @@ -178,18 +179,6 @@ function isTxContext(parameter: SuiMoveNormalizedType): boolean {
return inside.address === SUI_PACKAGE_ID && inside.module === 'tx_context' && inside.name === 'TxContext';
}

function isString(parameter: SuiMoveNormalizedType): boolean {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let asAny = parameter as any;
if (asAny.MutableReference) parameter = asAny.MutableReference;
if (asAny.Reference) asAny = asAny.Reference;
asAny = asAny.Struct;
if (!asAny) return false;
const isAsciiString = asAny.address === STD_PACKAGE_ID && asAny.module === 'ascii' && asAny.name === 'String';
const isStringString = asAny.address === STD_PACKAGE_ID && asAny.module === 'string' && asAny.name === 'String';
return isAsciiString || isStringString;
}

export class TxBuilderBase {
client: SuiClient;
tx: Transaction;
Expand Down
26 changes: 25 additions & 1 deletion src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getFullnodeUrl } from '@mysten/sui/client';
import { getFullnodeUrl, SuiMoveNormalizedType } from '@mysten/sui/client';
import { getFaucetHost, requestSuiFromFaucetV0 } from '@mysten/sui/faucet';
import { arrayify, keccak256 } from 'ethers/lib/utils';
import secp256k1 from 'secp256k1';
import { STD_PACKAGE_ID } from './types';

export const fundAccountsFromFaucet = async (addresses: string[]) => {
const promises = addresses.map(async (address) => {
Expand Down Expand Up @@ -46,3 +47,26 @@ export function signMessage(privKeys: string[], messageToSign: Uint8Array) {

return signatures;
}

export function isString(parameter: SuiMoveNormalizedType): boolean {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let asAny = parameter as any;

if (asAny.MutableReference) {
parameter = asAny.MutableReference;
}

if (asAny.Reference) {
asAny = asAny.Reference;
}

asAny = asAny.Struct;

if (!asAny) {
return false;
}

const isAsciiString = asAny.address === STD_PACKAGE_ID && asAny.module === 'ascii' && asAny.name === 'String';
const isStringString = asAny.address === STD_PACKAGE_ID && asAny.module === 'string' && asAny.name === 'String';
return isAsciiString || isStringString;
}

0 comments on commit 7a9eda4

Please sign in to comment.