@scallop-io/sui-kit 1.4.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +32 -0
- package/dist/index.d.cts +747 -0
- package/dist/index.d.ts +745 -6
- package/dist/index.js +13 -29
- package/package.json +14 -13
- package/src/index.ts +10 -6
- package/src/libs/multiSig/client.ts +1 -1
- package/src/libs/multiSig/index.ts +1 -1
- package/src/libs/suiAccountManager/index.ts +7 -4
- package/src/libs/suiAccountManager/keypair.ts +1 -1
- package/src/libs/suiInteractor/index.ts +7 -1
- package/src/libs/suiInteractor/suiInteractor.ts +150 -71
- package/src/libs/suiModel/index.ts +2 -2
- package/src/libs/suiModel/suiOwnedObject.ts +17 -8
- package/src/libs/suiTxBuilder/index.ts +24 -13
- package/src/libs/suiTxBuilder/util.ts +40 -5
- package/src/suiKit.ts +62 -32
- package/src/types/index.ts +17 -3
- package/dist/index.mjs +0 -15
- package/dist/libs/multiSig/client.d.ts +0 -15
- package/dist/libs/multiSig/index.d.ts +0 -1
- package/dist/libs/multiSig/publickey.d.ts +0 -2
- package/dist/libs/suiAccountManager/crypto.d.ts +0 -1
- package/dist/libs/suiAccountManager/index.d.ts +0 -39
- package/dist/libs/suiAccountManager/keypair.d.ts +0 -21
- package/dist/libs/suiAccountManager/util.d.ts +0 -29
- package/dist/libs/suiInteractor/index.d.ts +0 -1
- package/dist/libs/suiInteractor/suiInteractor.d.ts +0 -39
- package/dist/libs/suiInteractor/util.d.ts +0 -2
- package/dist/libs/suiModel/index.d.ts +0 -2
- package/dist/libs/suiModel/suiOwnedObject.d.ts +0 -24
- package/dist/libs/suiModel/suiSharedObject.d.ts +0 -11
- package/dist/libs/suiTxBuilder/index.d.ts +0 -637
- package/dist/libs/suiTxBuilder/util.d.ts +0 -43
- package/dist/suiKit.d.ts +0 -128
- package/dist/types/index.d.ts +0 -76
package/dist/index.js
CHANGED
|
@@ -1,31 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { SUI_SYSTEM_STATE_OBJECT_ID, normalizeStructTag, SUI_TYPE_ARG, isValidSuiAddress, normalizeSuiAddress, isValidSuiObjectId, normalizeSuiObjectId } from '@mysten/sui/utils';
|
|
2
|
+
export * from '@mysten/sui/utils';
|
|
3
|
+
import { Transaction, Inputs, getPureBcsSchema } from '@mysten/sui/transactions';
|
|
4
|
+
export * from '@mysten/sui/transactions';
|
|
5
|
+
import { Ed25519Keypair, Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';
|
|
6
|
+
import { fromHex, fromBase64, SerializedBcs, isSerializedBcs, bcs } from '@mysten/bcs';
|
|
7
|
+
import { generateMnemonic } from '@scure/bip39';
|
|
8
|
+
import { wordlist } from '@scure/bip39/wordlists/english';
|
|
9
|
+
import { SUI_PRIVATE_KEY_PREFIX, decodeSuiPrivateKey } from '@mysten/sui/cryptography';
|
|
10
|
+
import { SuiGrpcClient } from '@mysten/sui/grpc';
|
|
11
|
+
import { MultiSigPublicKey } from '@mysten/sui/multisig';
|
|
2
12
|
|
|
3
|
-
var utils = require('@mysten/sui/utils');
|
|
4
|
-
var transactions = require('@mysten/sui/transactions');
|
|
5
|
-
var client = require('@mysten/sui/client');
|
|
6
|
-
var ed25519 = require('@mysten/sui/keypairs/ed25519');
|
|
7
|
-
var bcs = require('@mysten/bcs');
|
|
8
|
-
var bip39 = require('@scure/bip39');
|
|
9
|
-
var english = require('@scure/bip39/wordlists/english');
|
|
10
|
-
var cryptography = require('@mysten/sui/cryptography');
|
|
11
|
-
var multisig = require('@mysten/sui/multisig');
|
|
13
|
+
var Y=(r={})=>{let{accountIndex:t=0,isExternal:e=!1,addressIndex:i=0}=r;return `m/44'/784'/${t}'/${e?1:0}'/${i}'`},b=(r,t={})=>{let e=Y(t);return Ed25519Keypair.deriveKeypair(r,e)};var X=r=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(r),H=r=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(r),B=r=>{if(X(r))return fromHex(r);if(H(r))return fromBase64(r);throw new Error("The string is not a valid hex or base64 string.")},O=32,L=64,w=r=>{if(r.length===L)return r.slice(0,O);if(r.length===O+1&&r[0]===0)return r.slice(1);if(r.length===O)return r;throw new Error("invalid secret key")};var I=(r=24)=>generateMnemonic(wordlist,r===12?128:256);var S=class{mnemonics;secretKey;currentKeyPair;currentAddress;constructor({mnemonics:t,secretKey:e}={}){this.mnemonics=t||"",this.secretKey=e||"",!this.mnemonics&&!this.secretKey&&(this.mnemonics=I(24)),this.currentKeyPair=this.secretKey?this.parseSecretKey(this.secretKey):b(this.mnemonics),this.currentAddress=this.currentKeyPair.getPublicKey().toSuiAddress();}parseSecretKey(t){if(t.startsWith(SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=decodeSuiPrivateKey(t);return Ed25519Keypair.fromSecretKey(w(e))}return Ed25519Keypair.fromSecretKey(w(B(t)))}getKeyPair(t){return !t||!this.mnemonics?this.currentKeyPair:b(this.mnemonics,t)}getAddress(t){return !t||!this.mnemonics?this.currentAddress:b(this.mnemonics,t).getPublicKey().toSuiAddress()}switchAccount(t){this.mnemonics&&(this.currentKeyPair=b(this.mnemonics,t),this.currentAddress=this.currentKeyPair.getPublicKey().toSuiAddress());}};var ct=["u8","u16","u32","u64","u128","u256","bool","address"];function ut(r){if(!ct.includes(r))throw new Error(`Invalid SimpleBcsType: ${r}`);return {$kind:r}}var lt=r=>{if(typeof r=="string"&&isValidSuiObjectId(r))return "object";if(typeof r=="number"||typeof r=="bigint")return "u64";if(typeof r=="boolean")return "bool"};function U(r){return typeof r=="number"||typeof r=="bigint"||typeof r=="string"&&!isValidSuiAddress(r)&&!isNaN(Number(r))}function ht(r){return typeof r=="object"&&"vecType"in r&&"value"in r?!0:!!Array.isArray(r)}function dt(r){return typeof r=="object"&&"digest"in r&&"version"in r&&"objectId"in r}function mt(r){return typeof r=="object"&&"objectId"in r&&"initialSharedVersion"in r&&"mutable"in r}function E(r,t,e){if(t.length===0)throw new Error("Transaction builder error: Empty array is not allowed");let i=lt(t[0]),n=/^vector<(.+)>$/,s=/^([^:]+)::([^:]+)::([^<]+)(<(.+)>)?/;if(e=e||i,e==="object"){let o=t.map(a=>typeof a=="string"&&isValidSuiObjectId(a)?r.object(normalizeSuiObjectId(a)):d(r,a));return r.makeMoveVec({elements:o})}else if(typeof e=="string"&&!n.test(e)&&!s.test(e)){let o=ut(e),a=getPureBcsSchema(o);if(!a)throw new Error(`Unknown type: ${e}`);return r.pure(bcs.vector(a).serialize(t))}else {let o=t.map(a=>d(r,a));return r.makeMoveVec({elements:o,type:e})}}function y(r,t){return t.map(e=>e instanceof SerializedBcs||isSerializedBcs(e)?r.pure(e):ht(e)?"vecType"in e?E(r,e.value,e.vecType):E(r,e):U(e)?p(r,[e])[0]:d(r,e))}function g(r,t){return typeof t=="string"&&isValidSuiAddress(t)?r.pure.address(normalizeSuiAddress(t)):y(r,[t])[0]}function d(r,t){if(typeof t=="string")return r.object(t);if(dt(t))return r.objectRef(t);if(mt(t))return r.sharedObjectRef(t);if("Object"in t){if("ImmOrOwnedObject"in t.Object)return r.object(Inputs.ObjectRef(t.Object.ImmOrOwnedObject));if("SharedObject"in t.Object)return r.object(Inputs.SharedObjectRef(t.Object.SharedObject));throw new Error("Invalid argument type")}if(typeof t=="function"||"GasCoin"in t||"Input"in t||"Result"in t||"NestedResult"in t)return t;throw new Error("Invalid argument type")}function p(r,t){return t.map(e=>U(e)?r.pure.u64(e):y(r,[e])[0])}var V=(r,t)=>{let e=[];for(let i=0;i<r.length;i+=t)e.push(r.slice(i,i+t));return e};var u=class{txBlock;constructor(t){this.txBlock=t?Transaction.from(t):new Transaction;}get gas(){return this.txBlock.gas}getData(){return this.txBlock.getData()}address(t){return this.txBlock.pure.address(t)}get pure(){return this.txBlock.pure}object(t){return this.txBlock.object(t)}objectRef(t){return this.txBlock.objectRef(t)}sharedObjectRef(t){return this.txBlock.sharedObjectRef(t)}setSender(t){return this.txBlock.setSender(t)}setSenderIfNotSet(t){return this.txBlock.setSenderIfNotSet(t)}setExpiration(t){return this.txBlock.setExpiration(t)}setGasPrice(t){return this.txBlock.setGasPrice(t)}setGasBudget(t){return this.txBlock.setGasBudget(t)}setGasOwner(t){return this.txBlock.setGasOwner(t)}setGasPayment(t){return this.txBlock.setGasPayment(t)}serialize(){return this.txBlock.serialize()}toJSON(){return this.txBlock.toJSON()}sign(t){return this.txBlock.sign(t)}build(t={}){return this.txBlock.build(t)}getDigest(t={}){return this.txBlock.getDigest(t)}add(...t){return this.txBlock.add(...t)}publish({modules:t,dependencies:e}){return this.txBlock.publish({modules:t,dependencies:e})}upgrade(...t){return this.txBlock.upgrade(...t)}makeMoveVec(...t){return this.txBlock.makeMoveVec(...t)}transferObjects(t,e){return this.txBlock.transferObjects(t.map(i=>d(this.txBlock,i)),g(this.txBlock,e))}splitCoins(t,e){let i=this.txBlock.splitCoins(d(this.txBlock,t),p(this.txBlock,e));return e.map((n,s)=>i[s])}mergeCoins(t,e){let i=d(this.txBlock,t),n=e.map(s=>d(this.txBlock,s));return this.txBlock.mergeCoins(i,n)}moveCall(t,e=[],i=[]){let n=/(?<package>[a-zA-Z0-9]+)::(?<module>[a-zA-Z0-9_]+)::(?<function>[a-zA-Z0-9_]+)/;if(t.match(n)===null)throw new Error("Invalid target format. Expected `${string}::${string}::${string}`");let o=y(this.txBlock,e);return this.txBlock.moveCall({target:t,arguments:o,typeArguments:i})}transferSuiToMany(t,e){if(t.length!==e.length)throw new Error("transferSuiToMany: recipients.length !== amounts.length");let i=this.txBlock.splitCoins(this.txBlock.gas,p(this.txBlock,e));return t.map(s=>g(this.txBlock,s)).forEach((s,o)=>{this.txBlock.transferObjects([i[o]],s);}),this}transferSui(t,e){return this.transferSuiToMany([t],[e])}takeAmountFromCoins(t,e){let{splitedCoins:i,mergedCoin:n}=this.splitMultiCoins(t,p(this.txBlock,[e]));return [i,n]}splitSUIFromGas(t){return this.txBlock.splitCoins(this.txBlock.gas,p(this.txBlock,t))}splitMultiCoins(t,e){if(t.length===0)throw new Error("takeAmountFromCoins: coins array is empty");let i=V(t.slice(1),511),n=d(this.txBlock,t[0]);for(let o of i){let a=o.map(m=>d(this.txBlock,m));this.txBlock.mergeCoins(n,a);}return {splitedCoins:this.txBlock.splitCoins(n,p(this.txBlock,e)),mergedCoin:n}}transferCoinToMany(t,e,i,n){if(i.length!==n.length)throw new Error("transferCoinToMany: recipients.length !== amounts.length");let s=t.map(c=>d(this.txBlock,c)),{splitedCoins:o,mergedCoin:a}=this.splitMultiCoins(s,p(this.txBlock,n));return i.map(c=>g(this.txBlock,c)).forEach((c,h)=>{this.txBlock.transferObjects([o[h]],c);}),this.txBlock.transferObjects([a],g(this.txBlock,e)),this}transferCoin(t,e,i,n){return this.transferCoinToMany(t,e,[i],[n])}stakeSui(t,e){let[i]=this.txBlock.splitCoins(this.txBlock.gas,p(this.txBlock,[t]));return this.txBlock.moveCall({target:"0x3::sui_system::request_add_stake",arguments:y(this.txBlock,[this.txBlock.object(SUI_SYSTEM_STATE_OBJECT_ID),i,g(this.txBlock,e)])})}};var A=class{objectId;version;digest;constructor(t){this.objectId=t.objectId,this.version=t.version,this.digest=t.digest;}isFullObject(){return !!this.version&&!!this.digest}asCallArg(){return !this.version||!this.digest?this.objectId:{$kind:"Object",Object:{$kind:"ImmOrOwnedObject",ImmOrOwnedObject:{objectId:this.objectId,version:this.version,digest:this.digest}}}}updateFromTxResponse(t){let e=t.Transaction??t.FailedTransaction;if(!e)throw new Error("Bad transaction response!");let i=e.effects;if(!i)throw new Error("Transaction response has no effects!");for(let n of i.changedObjects)if(n.objectId===this.objectId&&n.outputDigest){this.digest=n.outputDigest,this.version=n.outputVersion??void 0;return}throw new Error("Could not find object in transaction response!")}};var x=class{objectId;initialSharedVersion;constructor(t){this.objectId=t.objectId,this.initialSharedVersion=t.initialSharedVersion;}asCallArg(t=!1){return this.initialSharedVersion?{$kind:"Object",Object:{$kind:"SharedObject",SharedObject:{objectId:this.objectId,initialSharedVersion:this.initialSharedVersion,mutable:t}}}:this.objectId}};var P=r=>new Promise(t=>setTimeout(t,r)),$=(r,t)=>{let e=[];for(let i=0;i<r.length;i+=t)e.push(r.slice(i,i+t));return e};var _=50;function k(r,t){return {baseUrl:r,network:t}}function T(r){switch(r){case"mainnet":return "https://fullnode.mainnet.sui.io:443";case"testnet":return "https://fullnode.testnet.sui.io:443";case"devnet":return "https://fullnode.devnet.sui.io:443";case"localnet":return "http://127.0.0.1:9000";default:throw new Error(`Unknown network: ${r}`)}}var f=class{clients=[];currentClient;fullNodes=[];network;constructor(t){this.network="mainnet","fullnodeUrls"in t&&t.fullnodeUrls?(this.network=t.network??"mainnet",this.fullNodes=t.fullnodeUrls,this.clients=this.fullNodes.map(e=>new SuiGrpcClient(k(e,this.network)))):"suiClients"in t&&t.suiClients?this.clients=t.suiClients:(this.fullNodes=[T(this.network)],this.clients=[new SuiGrpcClient(k(this.fullNodes[0],this.network))]),this.currentClient=this.clients[0];}switchToNextClient(){let t=this.clients.indexOf(this.currentClient);this.currentClient=this.clients[(t+1)%this.clients.length];}switchFullNodes(t,e){if(t.length===0)throw new Error("fullNodes cannot be empty");this.fullNodes=t,e&&(this.network=e),this.clients=t.map(i=>new SuiGrpcClient(k(i,this.network))),this.currentClient=this.clients[0];}get currentFullNode(){if(this.fullNodes.length===0)throw new Error("No full nodes available");let t=this.clients.indexOf(this.currentClient);if(t===-1)throw new Error("Current client not found");return this.fullNodes[t]}async sendTx(t,e){let i=typeof t=="string"?Uint8Array.from(Buffer.from(t,"base64")):t,n=Array.isArray(e)?e:[e];for(let s in this.clients)try{return await this.clients[s].core.executeTransaction({transaction:i,signatures:n,include:{balanceChanges:!0,effects:!0,events:!0,objectTypes:!0}})}catch(o){console.warn(`Failed to send transaction with fullnode ${this.fullNodes[s]}: ${o}`),await P(2e3);}throw new Error("Failed to send transaction with all fullnodes")}async dryRunTx(t){for(let e in this.clients)try{return await this.clients[e].core.simulateTransaction({transaction:t,include:{effects:!0,events:!0,balanceChanges:!0,commandResults:!0}})}catch(i){console.warn(`Failed to dry run transaction with fullnode ${this.fullNodes[e]}: ${i}`),await P(2e3);}throw new Error("Failed to dry run transaction with all fullnodes")}async getObjects(t,e){let i=e?.include??{content:!0,json:!0},n=$(t,Math.max(e?.batchSize??_,_)),s=[],o=null;for(let a of n){for(let m in this.clients)try{let h=(await this.clients[m].core.getObjects({objectIds:a,include:i})).objects.map(l=>l instanceof Error?null:l).filter(l=>l!==null);s.push(...h),o=null;break}catch(c){o=c instanceof Error?c:new Error(String(c)),await P(e?.switchClientDelay??2e3),console.warn(`Failed to get objects with fullnode ${this.fullNodes[m]}: ${c}`);}if(o)throw new Error(`Failed to get objects with all fullnodes: ${o}`)}return s}async getObject(t,e){return (await this.getObjects([t],e))[0]}async updateObjects(t){let e=t.map(n=>n.objectId),i=await this.getObjects(e);for(let n of i){let s=t.find(o=>o.objectId===n?.objectId);if(s instanceof x){let o=n.owner;o&&typeof o=="object"&&"Shared"in o?s.initialSharedVersion=o.Shared.initialSharedVersion:s.initialSharedVersion=void 0;}else s instanceof A&&(s.version=n?.version,s.digest=n?.digest);}}async selectCoins(t,e,i="0x2::SUI::SUI"){let n=[],s=0,o=!0,a=null;for(;o&&s<e;){let{objects:m,hasNextPage:c,cursor:h}=await this.currentClient.core.listCoins({owner:t,coinType:i,cursor:a});m.sort((l,W)=>parseInt(W.balance)-parseInt(l.balance));for(let l of m)if(n.push({objectId:l.objectId,digest:l.digest,version:l.version,balance:l.balance}),s=s+parseInt(l.balance),s>=e)break;a=h,o=c;}if(!n.length)throw new Error("No valid coins found for the transaction.");return n}};var v=class{accountManager;suiInteractor;constructor(t){let{mnemonics:e,secretKey:i,networkType:n}=t;this.accountManager=new S({mnemonics:e,secretKey:i});let s=n??"mainnet",o;"fullnodeUrls"in t?o={fullnodeUrls:t.fullnodeUrls,network:s}:"suiClients"in t?o={suiClients:t.suiClients}:o={fullnodeUrls:[T(s)],network:s},this.suiInteractor=new f(o);}createTxBlock(){let t=new u;return t.setSender(this.accountManager.currentAddress),t}getKeypair(t){return this.accountManager.getKeyPair(t)}switchAccount(t){this.accountManager.switchAccount(t);}getAddress(t){return this.accountManager.getAddress(t)}get currentAddress(){return this.accountManager.currentAddress}async getBalance(t,e){let i=this.accountManager.getAddress(e),{balance:n}=await this.suiInteractor.currentClient.core.getBalance({owner:i,coinType:t});return n}get client(){return this.suiInteractor.currentClient}async getObjects(t,e){return this.suiInteractor.getObjects(t,e)}async updateObjects(t){return this.suiInteractor.updateObjects(t)}async signTxn(t,e){t instanceof u&&t.setSender(this.getAddress(e));let i=t instanceof u?t.txBlock:t,n=i instanceof Uint8Array?i:await i.build({client:this.client});return await this.getKeypair(e).signTransaction(n)}async signAndSendTxn(t,e){let{bytes:i,signature:n}=await this.signTxn(t,e);return this.suiInteractor.sendTx(i,n)}async dryRunTxn(t,e){t instanceof u&&t.setSender(this.getAddress(e));let i=t instanceof u?t.txBlock:t,n=i instanceof Uint8Array?i:await i.build({client:this.client});return this.suiInteractor.dryRunTx(n)}async transferSui(t,e,i=!0,n){let s=new u;return s.transferSui(t,e),i?await this.signAndSendTxn(s,n):s}async transferSuiToMany(t,e,i=!0,n){let s=new u;return s.transferSuiToMany(t,e),i?await this.signAndSendTxn(s,n):s}async transferCoinToMany(t,e,i,n=!0,s){let o=new u,a=this.accountManager.getAddress(s),m=e.reduce((c,h)=>c+h,0);if(normalizeStructTag(i)===normalizeStructTag(SUI_TYPE_ARG))o.transferSuiToMany(t,e);else {let c=await this.suiInteractor.selectCoins(a,m,i);o.transferCoinToMany(c.map(h=>"objectId"in h?o.objectRef(h):h),a,t,e);}return n?await this.signAndSendTxn(o,s):o}async transferCoin(t,e,i,n=!0,s){return this.transferCoinToMany([t],[e],i,n,s)}async transferObjects(t,e,i=!0,n){let s=new u;return s.transferObjects(t,e),i?await this.signAndSendTxn(s,n):s}async moveCall(t){let{target:e,arguments:i=[],typeArguments:n=[],derivePathParams:s}=t,o=new u;return o.moveCall(e,i,n),this.signAndSendTxn(o,s)}async selectCoinsWithAmount(t,e,i){return i=i||this.accountManager.currentAddress,await this.suiInteractor.selectCoins(i,t,e)}async stakeSui(t,e,i=!0,n){let s=new u;return s.stakeSui(t,e),i?await this.signAndSendTxn(s,n):s}async inspectTxn(t,e){t instanceof u&&t.setSender(this.getAddress(e));let i=t instanceof u?t.txBlock:t,n=i instanceof Uint8Array?i:await i.build({client:this.client});return this.suiInteractor.currentClient.core.simulateTransaction({transaction:n,include:{effects:!0,events:!0,balanceChanges:!0,commandResults:!0}})}};function G(r){let t=fromBase64(r);if(t.length!==32&&t.length!==33)throw "invalid pubkey length";return t=t.length===33?t.slice(1):t,new Ed25519PublicKey(t)}var j=class r{pksWeightPairs;threshold;multiSigPublicKey;constructor(t,e){this.pksWeightPairs=t,this.threshold=e,this.multiSigPublicKey=MultiSigPublicKey.fromPublicKeys({threshold:this.threshold,publicKeys:this.pksWeightPairs});}static fromRawEd25519PublicKeys(t,e,i){let n=t.map((s,o)=>({publicKey:G(s),weight:e[o]}));return new r(n,i)}multiSigAddress(){return this.multiSigPublicKey.toSuiAddress()}combinePartialSigs(t){return this.multiSigPublicKey.combinePartialSignatures(t)}};
|
|
12
14
|
|
|
13
|
-
var _=(r={})=>{let{accountIndex:t=0,isExternal:e=!1,addressIndex:i=0}=r;return `m/44'/784'/${t}'/${e?1:0}'/${i}'`},S=(r,t={})=>{let e=_(t);return ed25519.Ed25519Keypair.deriveKeypair(r,e)};var W=r=>/^0x[0-9a-fA-F]+$|^[0-9a-fA-F]+$/.test(r),Z=r=>/^[a-zA-Z0-9+/]+={0,2}$/g.test(r),B=r=>{if(W(r))return bcs.fromHex(r);if(Z(r))return bcs.fromBase64(r);throw new Error("The string is not a valid hex or base64 string.")},T=32,Y=64,O=r=>{if(r.length===Y)return r.slice(0,T);if(r.length===T+1&&r[0]===0)return r.slice(1);if(r.length===T)return r;throw new Error("invalid secret key")};var v=(r=24)=>bip39.generateMnemonic(english.wordlist,r===12?128:256);var f=class{constructor({mnemonics:t,secretKey:e}={}){this.mnemonics=t||"",this.secretKey=e||"",!this.mnemonics&&!this.secretKey&&(this.mnemonics=v(24)),this.currentKeyPair=this.secretKey?this.parseSecretKey(this.secretKey):S(this.mnemonics),this.currentAddress=this.currentKeyPair.getPublicKey().toSuiAddress();}parseSecretKey(t){if(t.startsWith(cryptography.SUI_PRIVATE_KEY_PREFIX)){let{secretKey:e}=cryptography.decodeSuiPrivateKey(t);return ed25519.Ed25519Keypair.fromSecretKey(O(e))}return ed25519.Ed25519Keypair.fromSecretKey(O(B(t)))}getKeyPair(t){return !t||!this.mnemonics?this.currentKeyPair:S(this.mnemonics,t)}getAddress(t){return !t||!this.mnemonics?this.currentAddress:S(this.mnemonics,t).getPublicKey().toSuiAddress()}switchAccount(t){this.mnemonics&&(this.currentKeyPair=S(this.mnemonics,t),this.currentAddress=this.currentKeyPair.getPublicKey().toSuiAddress());}};var nt=r=>{if(typeof r=="string"&&utils.isValidSuiObjectId(r))return "object";if(typeof r=="number"||typeof r=="bigint")return "u64";if(typeof r=="boolean")return "bool"};function E(r){return typeof r=="number"||typeof r=="bigint"||typeof r=="string"&&!utils.isValidSuiAddress(r)&&!isNaN(Number(r))}function st(r){return typeof r=="object"&&"vecType"in r&&"value"in r?!0:!!Array.isArray(r)}function ot(r){return typeof r=="object"&&"digest"in r&&"version"in r&&"objectId"in r}function at(r){return typeof r=="object"&&"objectId"in r&&"initialSharedVersion"in r&&"mutable"in r}function K(r,t,e){if(t.length===0)throw new Error("Transaction builder error: Empty array is not allowed");let i=nt(t[0]),n=/^vector<(.+)>$/,s=/^([^:]+)::([^:]+)::([^<]+)(<(.+)>)?/;if(e=e||i,e==="object"){let o=t.map(c=>typeof c=="string"&&utils.isValidSuiObjectId(c)?r.object(utils.normalizeSuiObjectId(c)):h(r,c));return r.makeMoveVec({elements:o})}else if(typeof e=="string"&&!n.test(e)&&!s.test(e)){let o=transactions.getPureBcsSchema(e);return r.pure(bcs.bcs.vector(o).serialize(t))}else {let o=t.map(c=>h(r,c));return r.makeMoveVec({elements:o,type:e})}}function y(r,t){return t.map(e=>e instanceof bcs.SerializedBcs||bcs.isSerializedBcs(e)?r.pure(e):st(e)?"vecType"in e?K(r,e.value,e.vecType):K(r,e):E(e)?d(r,[e])[0]:h(r,e))}function g(r,t){return typeof t=="string"&&utils.isValidSuiAddress(t)?r.pure.address(utils.normalizeSuiAddress(t)):y(r,[t])[0]}function h(r,t){if(typeof t=="string")return r.object(t);if(ot(t))return r.objectRef(t);if(at(t))return r.sharedObjectRef(t);if("Object"in t){if("ImmOrOwnedObject"in t.Object)return r.object(transactions.Inputs.ObjectRef(t.Object.ImmOrOwnedObject));if("SharedObject"in t.Object)return r.object(transactions.Inputs.SharedObjectRef(t.Object.SharedObject));throw new Error("Invalid argument type")}if(typeof t=="function"||"GasCoin"in t||"Input"in t||"Result"in t||"NestedResult"in t)return t;throw new Error("Invalid argument type")}function d(r,t){return t.map(e=>E(e)?r.pure.u64(e):y(r,[e])[0])}var M=(r,t)=>{let e=[];for(let i=0;i<r.length;i+=t)e.push(r.slice(i,i+t));return e};var u=class{constructor(t){this.txBlock=t?transactions.Transaction.from(t):new transactions.Transaction;}get gas(){return this.txBlock.gas}get blockData(){return this.txBlock.blockData}get getData(){return this.txBlock.getData()}address(t){return this.txBlock.pure.address(t)}get pure(){return this.txBlock.pure}object(t){return this.txBlock.object(t)}objectRef(t){return this.txBlock.objectRef(t)}sharedObjectRef(t){return this.txBlock.sharedObjectRef(t)}setSender(t){return this.txBlock.setSender(t)}setSenderIfNotSet(t){return this.txBlock.setSenderIfNotSet(t)}setExpiration(t){return this.txBlock.setExpiration(t)}setGasPrice(t){return this.txBlock.setGasPrice(t)}setGasBudget(t){return this.txBlock.setGasBudget(t)}setGasOwner(t){return this.txBlock.setGasOwner(t)}setGasPayment(t){return this.txBlock.setGasPayment(t)}serialize(){return this.txBlock.serialize()}toJSON(){return this.txBlock.toJSON()}sign(t){return this.txBlock.sign(t)}build(t={}){return this.txBlock.build(t)}getDigest(t={}){return this.txBlock.getDigest(t)}add(...t){return this.txBlock.add(...t)}publish({modules:t,dependencies:e}){return this.txBlock.publish({modules:t,dependencies:e})}upgrade(...t){return this.txBlock.upgrade(...t)}makeMoveVec(...t){return this.txBlock.makeMoveVec(...t)}transferObjects(t,e){return this.txBlock.transferObjects(t.map(i=>h(this.txBlock,i)),g(this.txBlock,e))}splitCoins(t,e){let i=this.txBlock.splitCoins(h(this.txBlock,t),d(this.txBlock,e));return e.map((n,s)=>i[s])}mergeCoins(t,e){let i=h(this.txBlock,t),n=e.map(s=>h(this.txBlock,s));return this.txBlock.mergeCoins(i,n)}moveCall(t,e=[],i=[]){let n=/(?<package>[a-zA-Z0-9]+)::(?<module>[a-zA-Z0-9_]+)::(?<function>[a-zA-Z0-9_]+)/;if(t.match(n)===null)throw new Error("Invalid target format. Expected `${string}::${string}::${string}`");let o=y(this.txBlock,e);return this.txBlock.moveCall({target:t,arguments:o,typeArguments:i})}transferSuiToMany(t,e){if(t.length!==e.length)throw new Error("transferSuiToMany: recipients.length !== amounts.length");let i=this.txBlock.splitCoins(this.txBlock.gas,d(this.txBlock,e));return t.map(s=>g(this.txBlock,s)).forEach((s,o)=>{this.txBlock.transferObjects([i[o]],s);}),this}transferSui(t,e){return this.transferSuiToMany([t],[e])}takeAmountFromCoins(t,e){let{splitedCoins:i,mergedCoin:n}=this.splitMultiCoins(t,d(this.txBlock,[e]));return [i,n]}splitSUIFromGas(t){return this.txBlock.splitCoins(this.txBlock.gas,d(this.txBlock,t))}splitMultiCoins(t,e){if(t.length===0)throw new Error("takeAmountFromCoins: coins array is empty");let i=M(t.slice(1),511),n=h(this.txBlock,t[0]);for(let o of i){let c=o.map(l=>h(this.txBlock,l));this.txBlock.mergeCoins(n,c);}return {splitedCoins:this.txBlock.splitCoins(n,d(this.txBlock,e)),mergedCoin:n}}transferCoinToMany(t,e,i,n){if(i.length!==n.length)throw new Error("transferSuiToMany: recipients.length !== amounts.length");let s=t.map(a=>h(this.txBlock,a)),{splitedCoins:o,mergedCoin:c}=this.splitMultiCoins(s,d(this.txBlock,n));return i.map(a=>g(this.txBlock,a)).forEach((a,m)=>{this.txBlock.transferObjects([o[m]],a);}),this.txBlock.transferObjects([c],g(this.txBlock,e)),this}transferCoin(t,e,i,n){return this.transferCoinToMany(t,e,[i],[n])}stakeSui(t,e){let[i]=this.txBlock.splitCoins(this.txBlock.gas,d(this.txBlock,[t]));return this.txBlock.moveCall({target:"0x3::sui_system::request_add_stake",arguments:y(this.txBlock,[this.txBlock.object(utils.SUI_SYSTEM_STATE_OBJECT_ID),i,g(this.txBlock,e)])})}};var A=class{constructor(t){this.objectId=t.objectId,this.version=t.version,this.digest=t.digest;}isFullObject(){return !!this.version&&!!this.digest}asCallArg(){return !this.version||!this.digest?this.objectId:{$kind:"Object",Object:{$kind:"ImmOrOwnedObject",ImmOrOwnedObject:{objectId:this.objectId,version:this.version,digest:this.digest}}}}updateFromTxResponse(t){let e=t.objectChanges;if(!e)throw new Error("Bad transaction response!");for(let i of e)if(i.type==="mutated"&&i.objectId===this.objectId){this.digest=i.digest,this.version=i.version;return}throw new Error("Could not find object in transaction response!")}};var x=class{constructor(t){this.objectId=t.objectId,this.initialSharedVersion=t.initialSharedVersion;}asCallArg(t=!1){return this.initialSharedVersion?{$kind:"Object",Object:{$kind:"SharedObject",SharedObject:{objectId:this.objectId,initialSharedVersion:this.initialSharedVersion,mutable:t}}}:this.objectId}};var P=r=>new Promise(t=>setTimeout(t,r)),U=(r,t)=>{let e=[];for(let i=0;i<r.length;i+=t)e.push(r.slice(i,i+t));return e};var b=class{constructor(t){this.clients=[];this.fullNodes=[];"fullnodeUrls"in t?(this.fullNodes=t.fullnodeUrls??[client.getFullnodeUrl("mainnet")],this.clients=this.fullNodes.map(e=>new client.SuiClient({url:e}))):"suiClients"in t&&t.suiClients?this.clients=t.suiClients:this.clients=[new client.SuiClient({url:client.getFullnodeUrl("mainnet")})],this.currentClient=this.clients[0];}switchToNextClient(){let t=this.clients.indexOf(this.currentClient);this.currentClient=this.clients[(t+1)%this.clients.length];}switchFullNodes(t){if(t.length===0)throw new Error("fullNodes cannot be empty");this.fullNodes=t,this.clients=t.map(e=>new client.SuiClient({url:e})),this.currentClient=this.clients[0];}get currentFullNode(){if(this.fullNodes.length===0)throw new Error("No full nodes available");let t=this.clients.indexOf(this.currentClient);if(t===-1)throw new Error("Current client not found");return this.fullNodes[t]}async sendTx(t,e){let i={showEvents:!0,showEffects:!0,showRawEffects:!0,showObjectChanges:!0,showBalanceChanges:!0};for(let n in this.clients)try{return await this.clients[n].executeTransactionBlock({transactionBlock:t,signature:e,options:i})}catch(s){console.warn(`Failed to send transaction with fullnode ${this.fullNodes[n]}: ${s}`),await P(2e3);}throw new Error("Failed to send transaction with all fullnodes")}async dryRunTx(t){for(let e in this.clients)try{return await this.clients[e].dryRunTransactionBlock({transactionBlock:t})}catch(i){console.warn(`Failed to dry run transaction with fullnode ${this.fullNodes[e]}: ${i}`),await P(2e3);}throw new Error("Failed to dry run transaction with all fullnodes")}async getObjects(t,e){let i=e??{showContent:!0,showDisplay:!0,showType:!0,showOwner:!0},n=U(t,Math.max(e?.batchSize??50,50)),s=[],o=null;for(let c of n){for(let l in this.clients)try{let m=(await this.clients[l].multiGetObjects({ids:c,options:i})).map(p=>p.data).filter(p=>p!=null);s.push(...m),o=null;break}catch(a){o=a instanceof Error?a:new Error(String(a)),await P(e?.switchClientDelay??2e3),console.warn(`Failed to get objects with fullnode ${this.fullNodes[l]}: ${a}`);}if(o)throw new Error(`Failed to get objects with all fullnodes: ${o}`)}return s}async getObject(t,e){return (await this.getObjects([t],e))[0]}async updateObjects(t){let e=t.map(n=>n.objectId),i=await this.getObjects(e);for(let n of i){let s=t.find(o=>o.objectId===n?.objectId);s instanceof x?n.owner&&typeof n.owner=="object"&&"Shared"in n.owner?s.initialSharedVersion=n.owner.Shared.initial_shared_version:s.initialSharedVersion=void 0:s instanceof A&&(s.version=n?.version,s.digest=n?.digest);}}async selectCoins(t,e,i="0x2::SUI::SUI"){let n=[],s=0,o=!0,c=null;for(;o&&s<e;){let l=await this.currentClient.getCoins({owner:t,coinType:i,cursor:c});l.data.sort((a,m)=>parseInt(m.balance)-parseInt(a.balance));for(let a of l.data)if(n.push({objectId:a.coinObjectId,digest:a.digest,version:a.version,balance:a.balance}),s=s+parseInt(a.balance),s>=e)break;c=l.nextCursor,o=l.hasNextPage;}if(!n.length)throw new Error("No valid coins found for the transaction.");return n}};var k=class{constructor(t){let{mnemonics:e,secretKey:i,networkType:n}=t;this.accountManager=new f({mnemonics:e,secretKey:i});let s;"fullnodeUrls"in t?s={fullnodeUrls:t.fullnodeUrls}:"suiClients"in t?s={suiClients:t.suiClients}:s={fullnodeUrls:[client.getFullnodeUrl(n??"mainnet")]},this.suiInteractor=new b(s);}createTxBlock(){let t=new u;return t.setSender(this.accountManager.currentAddress),t}getKeypair(t){return this.accountManager.getKeyPair(t)}switchAccount(t){this.accountManager.switchAccount(t);}getAddress(t){return this.accountManager.getAddress(t)}get currentAddress(){return this.accountManager.currentAddress}async getBalance(t,e){let i=this.accountManager.getAddress(e);return this.suiInteractor.currentClient.getBalance({owner:i,coinType:t})}get client(){return this.suiInteractor.currentClient}async getObjects(t,e){return this.suiInteractor.getObjects(t,e)}async updateObjects(t){return this.suiInteractor.updateObjects(t)}async signTxn(t,e){t instanceof u&&t.setSender(this.getAddress(e));let i=t instanceof u?t.txBlock:t,n=i instanceof Uint8Array?i:await i.build({client:this.client});return await this.getKeypair(e).signTransaction(n)}async signAndSendTxn(t,e){let{bytes:i,signature:n}=await this.signTxn(t,e);return this.suiInteractor.sendTx(i,n)}async dryRunTxn(t,e){t instanceof u&&t.setSender(this.getAddress(e));let i=t instanceof u?t.txBlock:t,n=i instanceof Uint8Array?i:await i.build({client:this.client});return this.suiInteractor.dryRunTx(n)}async transferSui(t,e,i=!0,n){let s=new u;return s.transferSui(t,e),i?await this.signAndSendTxn(s,n):s}async transferSuiToMany(t,e,i=!0,n){let s=new u;return s.transferSuiToMany(t,e),i?await this.signAndSendTxn(s,n):s}async transferCoinToMany(t,e,i,n=!0,s){let o=new u,c=this.accountManager.getAddress(s),l=e.reduce((m,p)=>m+p,0),a=await this.suiInteractor.selectCoins(c,l,i);return o.transferCoinToMany(a.map(m=>m.objectId),c,t,e),n?await this.signAndSendTxn(o,s):o}async transferCoin(t,e,i,n=!0,s){return this.transferCoinToMany([t],[e],i,n,s)}async transferObjects(t,e,i=!0,n){let s=new u;return s.transferObjects(t,e),i?await this.signAndSendTxn(s,n):s}async moveCall(t){let{target:e,arguments:i=[],typeArguments:n=[],derivePathParams:s}=t,o=new u;return o.moveCall(e,i,n),this.signAndSendTxn(o,s)}async selectCoinsWithAmount(t,e,i){return i=i||this.accountManager.currentAddress,await this.suiInteractor.selectCoins(i,t,e)}async stakeSui(t,e,i=!0,n){let s=new u;return s.stakeSui(t,e),i?await this.signAndSendTxn(s,n):s}async inspectTxn(t,e){let i=t instanceof u?t.txBlock:t;return this.suiInteractor.currentClient.devInspectTransactionBlock({transactionBlock:i,sender:this.getAddress(e)})}};function N(r){let t=bcs.fromBase64(r);if(t.length!==32&&t.length!==33)throw "invalid pubkey length";return t=t.length===33?t.slice(1):t,new ed25519.Ed25519PublicKey(t)}var j=class r{constructor(t,e){this.pksWeightPairs=t,this.threshold=e,this.multiSigPublicKey=multisig.MultiSigPublicKey.fromPublicKeys({threshold:this.threshold,publicKeys:this.pksWeightPairs});}static fromRawEd25519PublicKeys(t,e,i){let n=t.map((s,o)=>({publicKey:N(s),weight:e[o]}));return new r(n,i)}multiSigAddress(){return this.multiSigPublicKey.toSuiAddress()}combinePartialSigs(t){return this.multiSigPublicKey.combinePartialSignatures(t)}};
|
|
14
|
-
|
|
15
|
-
exports.MultiSigClient = j;
|
|
16
|
-
exports.SuiAccountManager = f;
|
|
17
|
-
exports.SuiInteractor = b;
|
|
18
|
-
exports.SuiKit = k;
|
|
19
|
-
exports.SuiTxBlock = u;
|
|
20
|
-
Object.keys(utils).forEach(function (k) {
|
|
21
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
get: function () { return utils[k]; }
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
Object.keys(transactions).forEach(function (k) {
|
|
27
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
28
|
-
enumerable: true,
|
|
29
|
-
get: function () { return transactions[k]; }
|
|
30
|
-
});
|
|
31
|
-
});
|
|
15
|
+
export { j as MultiSigClient, S as SuiAccountManager, f as SuiInteractor, v as SuiKit, u as SuiTxBlock, T as getFullnodeUrl };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scallop-io/sui-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Toolkit for interacting with SUI network",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sui",
|
|
@@ -21,16 +21,15 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"node": ">=
|
|
24
|
+
"node": ">=22"
|
|
25
25
|
},
|
|
26
|
+
"type": "module",
|
|
26
27
|
"main": "./dist/index.js",
|
|
27
|
-
"module": "./dist/index.mjs",
|
|
28
28
|
"types": "./dist/index.d.ts",
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
|
-
"
|
|
32
|
-
"import": "./dist/index.
|
|
33
|
-
"require": "./dist/index.js"
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js"
|
|
34
33
|
}
|
|
35
34
|
},
|
|
36
35
|
"files": [
|
|
@@ -38,8 +37,8 @@
|
|
|
38
37
|
"src"
|
|
39
38
|
],
|
|
40
39
|
"dependencies": {
|
|
41
|
-
"@mysten/bcs": "^
|
|
42
|
-
"@mysten/sui": "^
|
|
40
|
+
"@mysten/bcs": "^2.0.0",
|
|
41
|
+
"@mysten/sui": "^2.0.0",
|
|
43
42
|
"@scure/bip39": "^1.5.4",
|
|
44
43
|
"assert": "^2.1.0",
|
|
45
44
|
"bech32": "^2.0.0"
|
|
@@ -48,6 +47,8 @@
|
|
|
48
47
|
"@commitlint/cli": "^18.0.0",
|
|
49
48
|
"@commitlint/config-conventional": "^18.0.0",
|
|
50
49
|
"@commitlint/prompt-cli": "^18.0.0",
|
|
50
|
+
"@protobuf-ts/grpcweb-transport": "^2.11.1",
|
|
51
|
+
"@protobuf-ts/runtime-rpc": "^2.11.1",
|
|
51
52
|
"@types/node": "^20.8.7",
|
|
52
53
|
"@types/tmp": "^0.2.5",
|
|
53
54
|
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
|
@@ -135,12 +136,12 @@
|
|
|
135
136
|
},
|
|
136
137
|
"scripts": {
|
|
137
138
|
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
|
138
|
-
"build": "npm run build:types && npm run build:
|
|
139
|
-
"build:
|
|
139
|
+
"build": "npm run build:types && npm run build:prod",
|
|
140
|
+
"build:prod": "tsup --env.NODE_ENV production",
|
|
141
|
+
"build:dev": "tsup",
|
|
140
142
|
"build:types": "tsc --build",
|
|
141
|
-
"watch:tsup": "tsup
|
|
142
|
-
"watch
|
|
143
|
-
"watch": "pnpm run clean & pnpm run watch:types & pnpm run watch:tsup",
|
|
143
|
+
"watch:tsup": "tsup --watch",
|
|
144
|
+
"watch": "pnpm run clean && pnpm run watch:tsup",
|
|
144
145
|
"test": "pnpm test:typecheck && pnpm test:unit && pnpm test:integration",
|
|
145
146
|
"test:typecheck": "tsc -p ./test",
|
|
146
147
|
"test:unit": "vitest run test/unit --test-timeout=60000",
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
export * from '@mysten/sui/utils';
|
|
2
2
|
export * from '@mysten/sui/transactions';
|
|
3
|
-
export { SuiKit } from './suiKit';
|
|
4
|
-
export { SuiAccountManager } from './libs/suiAccountManager';
|
|
5
|
-
export { SuiTxBlock } from './libs/suiTxBuilder';
|
|
6
|
-
export { MultiSigClient } from './libs/multiSig';
|
|
7
|
-
export {
|
|
8
|
-
|
|
3
|
+
export { SuiKit } from './suiKit.js';
|
|
4
|
+
export { SuiAccountManager } from './libs/suiAccountManager/index.js';
|
|
5
|
+
export { SuiTxBlock } from './libs/suiTxBuilder/index.js';
|
|
6
|
+
export { MultiSigClient } from './libs/multiSig/index.js';
|
|
7
|
+
export {
|
|
8
|
+
SuiInteractor,
|
|
9
|
+
getFullnodeUrl,
|
|
10
|
+
type SimulateTransactionResponse,
|
|
11
|
+
} from './libs/suiInteractor/index.js';
|
|
12
|
+
export type * from './types/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MultiSigPublicKey } from '@mysten/sui/multisig';
|
|
2
2
|
import type { PublicKey } from '@mysten/sui/cryptography';
|
|
3
|
-
import { ed25519PublicKeyFromBase64 } from './publickey';
|
|
3
|
+
import { ed25519PublicKeyFromBase64 } from './publickey.js';
|
|
4
4
|
|
|
5
5
|
export type PublicKeyWeightPair = {
|
|
6
6
|
publicKey: PublicKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { MultiSigClient } from './client';
|
|
1
|
+
export { MultiSigClient } from './client.js';
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
2
|
-
import { getKeyPair } from './keypair';
|
|
3
|
-
import { hexOrBase64ToUint8Array, normalizePrivateKey } from './util';
|
|
4
|
-
import { generateMnemonic } from './crypto';
|
|
5
|
-
import type {
|
|
2
|
+
import { getKeyPair } from './keypair.js';
|
|
3
|
+
import { hexOrBase64ToUint8Array, normalizePrivateKey } from './util.js';
|
|
4
|
+
import { generateMnemonic } from './crypto.js';
|
|
5
|
+
import type {
|
|
6
|
+
AccountManagerParams,
|
|
7
|
+
DerivePathParams,
|
|
8
|
+
} from '../../types/index.js';
|
|
6
9
|
import {
|
|
7
10
|
SUI_PRIVATE_KEY_PREFIX,
|
|
8
11
|
decodeSuiPrivateKey,
|
|
@@ -1,32 +1,81 @@
|
|
|
1
|
-
import { SuiInteractorParams } from '
|
|
2
|
-
import { SuiOwnedObject, SuiSharedObject } from '../suiModel';
|
|
3
|
-
import { batch, delay } from './util';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { SuiInteractorParams, NetworkType } from '../../types/index.js';
|
|
2
|
+
import { SuiOwnedObject, SuiSharedObject } from '../suiModel/index.js';
|
|
3
|
+
import { batch, delay } from './util.js';
|
|
4
|
+
import { SuiGrpcClient, type SuiGrpcClientOptions } from '@mysten/sui/grpc';
|
|
5
|
+
import type { ClientWithCoreApi, SuiClientTypes } from '@mysten/sui/client';
|
|
6
|
+
|
|
7
|
+
const MAX_OBJECTS_PER_REQUEST = 50;
|
|
8
|
+
|
|
9
|
+
// Helper to create gRPC client options with baseUrl
|
|
10
|
+
function createGrpcClientOptions(
|
|
11
|
+
url: string,
|
|
12
|
+
network: NetworkType
|
|
13
|
+
): SuiGrpcClientOptions {
|
|
14
|
+
return { baseUrl: url, network } satisfies SuiGrpcClientOptions;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Helper to get fullnode URLs for each network
|
|
18
|
+
function getFullnodeUrl(network: NetworkType): string {
|
|
19
|
+
switch (network) {
|
|
20
|
+
case 'mainnet':
|
|
21
|
+
return 'https://fullnode.mainnet.sui.io:443';
|
|
22
|
+
case 'testnet':
|
|
23
|
+
return 'https://fullnode.testnet.sui.io:443';
|
|
24
|
+
case 'devnet':
|
|
25
|
+
return 'https://fullnode.devnet.sui.io:443';
|
|
26
|
+
case 'localnet':
|
|
27
|
+
return 'http://127.0.0.1:9000';
|
|
28
|
+
default:
|
|
29
|
+
throw new Error(`Unknown network: ${network}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Object data type from SDK v2
|
|
34
|
+
export type SuiObjectData = SuiClientTypes.Object<{
|
|
35
|
+
content: true;
|
|
36
|
+
json: true;
|
|
37
|
+
}>;
|
|
38
|
+
|
|
39
|
+
// Options for getObjects (SDK v2 naming)
|
|
40
|
+
export type SuiObjectDataOptions = SuiClientTypes.ObjectInclude;
|
|
41
|
+
|
|
42
|
+
// Simulate transaction response type
|
|
43
|
+
export type SimulateTransactionResponse =
|
|
44
|
+
SuiClientTypes.SimulateTransactionResult<{
|
|
45
|
+
effects: true;
|
|
46
|
+
events: true;
|
|
47
|
+
balanceChanges: true;
|
|
48
|
+
commandResults: true;
|
|
49
|
+
}>;
|
|
13
50
|
|
|
14
51
|
/**
|
|
15
52
|
* Encapsulates all functions that interact with the sui sdk
|
|
16
53
|
*/
|
|
17
54
|
export class SuiInteractor {
|
|
18
|
-
private clients:
|
|
19
|
-
public currentClient:
|
|
55
|
+
private clients: ClientWithCoreApi[] = [];
|
|
56
|
+
public currentClient: ClientWithCoreApi;
|
|
20
57
|
private fullNodes: string[] = [];
|
|
58
|
+
private network: NetworkType;
|
|
21
59
|
|
|
22
60
|
constructor(params: Partial<SuiInteractorParams>) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
61
|
+
// Default network
|
|
62
|
+
this.network = 'mainnet';
|
|
63
|
+
|
|
64
|
+
if ('fullnodeUrls' in params && params.fullnodeUrls) {
|
|
65
|
+
this.network = params.network ?? 'mainnet';
|
|
66
|
+
this.fullNodes = params.fullnodeUrls;
|
|
67
|
+
this.clients = this.fullNodes.map(
|
|
68
|
+
(url) => new SuiGrpcClient(createGrpcClientOptions(url, this.network))
|
|
69
|
+
);
|
|
26
70
|
} else if ('suiClients' in params && params.suiClients) {
|
|
27
71
|
this.clients = params.suiClients;
|
|
28
72
|
} else {
|
|
29
|
-
this.
|
|
73
|
+
this.fullNodes = [getFullnodeUrl(this.network)];
|
|
74
|
+
this.clients = [
|
|
75
|
+
new SuiGrpcClient(
|
|
76
|
+
createGrpcClientOptions(this.fullNodes[0], this.network)
|
|
77
|
+
),
|
|
78
|
+
];
|
|
30
79
|
}
|
|
31
80
|
this.currentClient = this.clients[0];
|
|
32
81
|
}
|
|
@@ -37,12 +86,17 @@ export class SuiInteractor {
|
|
|
37
86
|
this.clients[(currentClientIdx + 1) % this.clients.length];
|
|
38
87
|
}
|
|
39
88
|
|
|
40
|
-
switchFullNodes(fullNodes: string[]) {
|
|
89
|
+
switchFullNodes(fullNodes: string[], network?: NetworkType) {
|
|
41
90
|
if (fullNodes.length === 0) {
|
|
42
91
|
throw new Error('fullNodes cannot be empty');
|
|
43
92
|
}
|
|
44
93
|
this.fullNodes = fullNodes;
|
|
45
|
-
|
|
94
|
+
if (network) {
|
|
95
|
+
this.network = network;
|
|
96
|
+
}
|
|
97
|
+
this.clients = fullNodes.map(
|
|
98
|
+
(url) => new SuiGrpcClient(createGrpcClientOptions(url, this.network))
|
|
99
|
+
);
|
|
46
100
|
this.currentClient = this.clients[0];
|
|
47
101
|
}
|
|
48
102
|
|
|
@@ -62,21 +116,32 @@ export class SuiInteractor {
|
|
|
62
116
|
async sendTx(
|
|
63
117
|
transactionBlock: Uint8Array | string,
|
|
64
118
|
signature: string | string[]
|
|
65
|
-
): Promise<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
119
|
+
): Promise<
|
|
120
|
+
SuiClientTypes.TransactionResult<{
|
|
121
|
+
balanceChanges: true;
|
|
122
|
+
effects: true;
|
|
123
|
+
events: true;
|
|
124
|
+
objectTypes: true;
|
|
125
|
+
}>
|
|
126
|
+
> {
|
|
127
|
+
const txBytes =
|
|
128
|
+
typeof transactionBlock === 'string'
|
|
129
|
+
? Uint8Array.from(Buffer.from(transactionBlock, 'base64'))
|
|
130
|
+
: transactionBlock;
|
|
131
|
+
|
|
132
|
+
const signatures = Array.isArray(signature) ? signature : [signature];
|
|
73
133
|
|
|
74
134
|
for (const clientIdx in this.clients) {
|
|
75
135
|
try {
|
|
76
|
-
return await this.clients[clientIdx].
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
136
|
+
return await this.clients[clientIdx].core.executeTransaction({
|
|
137
|
+
transaction: txBytes,
|
|
138
|
+
signatures,
|
|
139
|
+
include: {
|
|
140
|
+
balanceChanges: true,
|
|
141
|
+
effects: true,
|
|
142
|
+
events: true,
|
|
143
|
+
objectTypes: true,
|
|
144
|
+
},
|
|
80
145
|
});
|
|
81
146
|
} catch (err) {
|
|
82
147
|
console.warn(
|
|
@@ -90,11 +155,17 @@ export class SuiInteractor {
|
|
|
90
155
|
|
|
91
156
|
async dryRunTx(
|
|
92
157
|
transactionBlock: Uint8Array
|
|
93
|
-
): Promise<
|
|
158
|
+
): Promise<SimulateTransactionResponse> {
|
|
94
159
|
for (const clientIdx in this.clients) {
|
|
95
160
|
try {
|
|
96
|
-
return await this.clients[clientIdx].
|
|
97
|
-
transactionBlock,
|
|
161
|
+
return await this.clients[clientIdx].core.simulateTransaction({
|
|
162
|
+
transaction: transactionBlock,
|
|
163
|
+
include: {
|
|
164
|
+
effects: true,
|
|
165
|
+
events: true,
|
|
166
|
+
balanceChanges: true,
|
|
167
|
+
commandResults: true,
|
|
168
|
+
},
|
|
98
169
|
});
|
|
99
170
|
} catch (err) {
|
|
100
171
|
console.warn(
|
|
@@ -108,35 +179,42 @@ export class SuiInteractor {
|
|
|
108
179
|
|
|
109
180
|
async getObjects(
|
|
110
181
|
ids: string[],
|
|
111
|
-
options?:
|
|
182
|
+
options?: {
|
|
183
|
+
include?: SuiObjectDataOptions;
|
|
112
184
|
batchSize?: number;
|
|
113
185
|
switchClientDelay?: number;
|
|
114
186
|
}
|
|
115
187
|
): Promise<SuiObjectData[]> {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
188
|
+
const include = options?.include ?? { content: true, json: true };
|
|
189
|
+
|
|
190
|
+
const batchIds = batch(
|
|
191
|
+
ids,
|
|
192
|
+
Math.max(
|
|
193
|
+
options?.batchSize ?? MAX_OBJECTS_PER_REQUEST,
|
|
194
|
+
MAX_OBJECTS_PER_REQUEST
|
|
195
|
+
)
|
|
196
|
+
);
|
|
124
197
|
const results: SuiObjectData[] = [];
|
|
125
198
|
let lastError = null;
|
|
126
199
|
|
|
127
|
-
for (const
|
|
200
|
+
for (const batchChunk of batchIds) {
|
|
128
201
|
for (const clientIdx in this.clients) {
|
|
129
202
|
try {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
203
|
+
const response = await this.clients[clientIdx].core.getObjects({
|
|
204
|
+
objectIds: batchChunk,
|
|
205
|
+
include,
|
|
133
206
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
207
|
+
|
|
208
|
+
const parsedObjects = response.objects
|
|
209
|
+
.map((obj) => {
|
|
210
|
+
if (obj instanceof Error) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return obj as SuiObjectData;
|
|
137
214
|
})
|
|
138
|
-
.filter((object)
|
|
139
|
-
|
|
215
|
+
.filter((object): object is SuiObjectData => object !== null);
|
|
216
|
+
|
|
217
|
+
results.push(...parsedObjects);
|
|
140
218
|
lastError = null;
|
|
141
219
|
break; // Exit the client loop if successful
|
|
142
220
|
} catch (err) {
|
|
@@ -157,7 +235,7 @@ export class SuiInteractor {
|
|
|
157
235
|
return results;
|
|
158
236
|
}
|
|
159
237
|
|
|
160
|
-
async getObject(id: string, options?: SuiObjectDataOptions) {
|
|
238
|
+
async getObject(id: string, options?: { include?: SuiObjectDataOptions }) {
|
|
161
239
|
const objects = await this.getObjects([id], options);
|
|
162
240
|
return objects[0];
|
|
163
241
|
}
|
|
@@ -174,13 +252,11 @@ export class SuiInteractor {
|
|
|
174
252
|
(obj) => obj.objectId === object?.objectId
|
|
175
253
|
);
|
|
176
254
|
if (suiObject instanceof SuiSharedObject) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
suiObject.initialSharedVersion =
|
|
183
|
-
object.owner.Shared.initial_shared_version;
|
|
255
|
+
const owner = object.owner;
|
|
256
|
+
if (owner && typeof owner === 'object' && 'Shared' in owner) {
|
|
257
|
+
suiObject.initialSharedVersion = (
|
|
258
|
+
owner as { Shared: { initialSharedVersion: string } }
|
|
259
|
+
).Shared.initialSharedVersion;
|
|
184
260
|
} else {
|
|
185
261
|
suiObject.initialSharedVersion = undefined;
|
|
186
262
|
}
|
|
@@ -212,16 +288,17 @@ export class SuiInteractor {
|
|
|
212
288
|
let hasNext = true,
|
|
213
289
|
nextCursor: string | null | undefined = null;
|
|
214
290
|
while (hasNext && totalAmount < amount) {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
291
|
+
const { objects, hasNextPage, cursor } =
|
|
292
|
+
await this.currentClient.core.listCoins({
|
|
293
|
+
owner: addr,
|
|
294
|
+
coinType: coinType,
|
|
295
|
+
cursor: nextCursor,
|
|
296
|
+
});
|
|
220
297
|
// Sort the coins by balance in descending order
|
|
221
|
-
|
|
222
|
-
for (const coinData of
|
|
298
|
+
objects.sort((a, b) => parseInt(b.balance) - parseInt(a.balance));
|
|
299
|
+
for (const coinData of objects) {
|
|
223
300
|
selectedCoins.push({
|
|
224
|
-
objectId: coinData.
|
|
301
|
+
objectId: coinData.objectId,
|
|
225
302
|
digest: coinData.digest,
|
|
226
303
|
version: coinData.version,
|
|
227
304
|
balance: coinData.balance,
|
|
@@ -232,8 +309,8 @@ export class SuiInteractor {
|
|
|
232
309
|
}
|
|
233
310
|
}
|
|
234
311
|
|
|
235
|
-
nextCursor =
|
|
236
|
-
hasNext =
|
|
312
|
+
nextCursor = cursor;
|
|
313
|
+
hasNext = hasNextPage;
|
|
237
314
|
}
|
|
238
315
|
|
|
239
316
|
if (!selectedCoins.length) {
|
|
@@ -242,3 +319,5 @@ export class SuiInteractor {
|
|
|
242
319
|
return selectedCoins;
|
|
243
320
|
}
|
|
244
321
|
}
|
|
322
|
+
|
|
323
|
+
export { getFullnodeUrl };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { SuiOwnedObject } from './suiOwnedObject';
|
|
2
|
-
export { SuiSharedObject } from './suiSharedObject';
|
|
1
|
+
export { SuiOwnedObject } from './suiOwnedObject.js';
|
|
2
|
+
export { SuiSharedObject } from './suiSharedObject.js';
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// TODO: I think we can remove this file or update to NormalizedCallArg
|
|
2
|
-
import type {
|
|
2
|
+
import type { SuiClientTypes } from '@mysten/sui/client';
|
|
3
3
|
import type { CallArg } from '@mysten/sui/transactions';
|
|
4
4
|
|
|
5
|
+
// Transaction result type with effects
|
|
6
|
+
type TransactionResultWithEffects = SuiClientTypes.TransactionResult<{
|
|
7
|
+
effects: true;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
5
10
|
export class SuiOwnedObject {
|
|
6
11
|
public readonly objectId: string;
|
|
7
12
|
public version?: string;
|
|
@@ -43,15 +48,19 @@ export class SuiOwnedObject {
|
|
|
43
48
|
* Update object version & digest based on the transaction response.
|
|
44
49
|
* @param txResponse
|
|
45
50
|
*/
|
|
46
|
-
updateFromTxResponse(txResponse:
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
51
|
+
updateFromTxResponse(txResponse: TransactionResultWithEffects) {
|
|
52
|
+
const tx = txResponse.Transaction ?? txResponse.FailedTransaction;
|
|
53
|
+
if (!tx) {
|
|
49
54
|
throw new Error('Bad transaction response!');
|
|
50
55
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
const effects = tx.effects;
|
|
57
|
+
if (!effects) {
|
|
58
|
+
throw new Error('Transaction response has no effects!');
|
|
59
|
+
}
|
|
60
|
+
for (const change of effects.changedObjects) {
|
|
61
|
+
if (change.objectId === this.objectId && change.outputDigest) {
|
|
62
|
+
this.digest = change.outputDigest;
|
|
63
|
+
this.version = change.outputVersion ?? undefined;
|
|
55
64
|
return;
|
|
56
65
|
}
|
|
57
66
|
}
|