salt-sdk
    Preparing search index...

    Class Salt

    The Salt SDK

    Index

    Constructors

    • Creates an instance of the Salt SDK

      Parameters

      • Optionalparams: { authToken?: string; environment: Environment }

        The constructor parameters

        • OptionalauthToken?: string

          The authentication token for the Salt SDK. See Salt.authenticate for the full authentication flow, or Salt#setAuthToken to set a pre-existing token after calling the constructor.

          null
          
        • environment: Environment

          Environment to use. This will be optional in the future, but right now it is required. Use 'TESTNET'

      Returns Salt

      InvalidParams thrown if the parameters passed in to the constructor are invalid. Params are optional - the default environment is TESTNET.

      InvalidEnvironment Thrown if the provided Environment is invalid.

      InvalidAuthToken Thrown if the provided auth token is invalid. The token must be a string. If you need to authenticate, simply omit ConstructorParams.authToken, then use authenticate.

      import { Salt } from 'salt-sdk';
      import { Wallet } from 'ethers';

      const salt = new Salt({ environment: 'TESTNET' });

      // Log in to an existing account
      const signer = Wallet.createRandom();
      await salt.authenticate(signer);

      // You are ready to use the SDK. For example...
      const orgs = await salt.getOrganisations();
      import { Salt } from 'salt-sdk';

      const salt = new Salt({ environment: 'MAINNET' });
      import { Salt } from 'salt-sdk';

      // Connect to local development instance
      const salt = new Salt({ environment: {
      chainId: 421614,
      websocketUrl: 'https://localhost:8545',
      saltDomain: 'localhost',
      apiUrl: 'https://localhost:8545/api'
      }})
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

    Methods

    • Disconnect the websocket connection. Call this when you are done using a long-lived socket (e.g. after stopping a NudgeListener) to allow the Node.js process to exit cleanly.

      Returns void

      Self-contained methods like createAccount and submitTx disconnect automatically — you need this for NudgeListener and resumeAccountSetup workflows where the socket must stay open until AccountSetup.waitForCompletion finishes.

      const nudgeListener = await salt.listenForNudges(signer);
      // ... handle nudges ...
      nudgeListener.disableNudgeListener();
      Salt.disconnect();

    Accounts

    • Creates a new account within an Organisation. Deploys a vault smart contract, registers the account, and nudges co-signers — but does not block on the MPC huddle.

      Returns an AccountSetup whose accountId is available immediately. Call waitForCompletion() to enter the huddle, complete key generation, and finalize the vault. If you skip waitForCompletion(), the account is persisted and can be resumed later with resumeAccountSetup.

      The SDK automatically determines the required robo signers based on the number of human signers provided.

      Parameters

      Returns Promise<AccountSetup>

      An AccountSetup with the account ID and a waitForCompletion() method

      InvalidAuthToken if the authentication token is invalid

      InvalidSigner if the signer is missing or invalid

      WrongChain if the signer is on a different chain than expected

      InsufficientGas if the signer lacks funds for gas on the orchestration chain

      SocketConnectError if the signer fails to connect to websockets, which are required for setup orchestration

      import { Salt } from 'salt-sdk';
      import { Wallet, providers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const provider = new providers.JsonRpcProvider(process.env.RPC_URL);
      const signer = new Wallet(process.env.PRIVATE_KEY).connect(provider);

      const setup = await salt.createAccount({
      name: 'Treasury',
      organisationId: 'org-id',
      signers: [
      '0x1111111111111111111111111111111111111111',
      '0x2222222222222222222222222222222222222222',
      ],
      signer,
      });

      console.log('Account ID:', setup.accountId);
      const { account } = await setup.waitForCompletion();
      console.log('Account created:', account.publicKey);
      const setup = await salt.createAccount({
      name: 'Treasury',
      organisationId: 'org-id',
      signers: ['0xCreator', '0xCoSigner'],
      signer,
      });

      // Save the account ID — don't call waitForCompletion()
      const accountId = setup.accountId;

      // Later, all signers resume:
      const { account } = await salt.resumeAccountSetup({ accountId, signer });
    • Gets the details of a specific account. The user must have adequate permissions to view the account.

      Parameters

      • accountId: string

        The ID of the account

      Returns Promise<SaltAccount>

      The account details

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const account = await salt.getAccount('account-id');
      console.log(`Account: ${account.name} ID: ${account.id} Public key: ${account.publicKey}`);
    • Gets the list of token balances for an account. This list is not exhaustive. When options.networks is omitted, defaults depend on the SDK environment (testnet: Sepolia + Arbitrum Sepolia; mainnet: Ethereum + Arbitrum One). Unsupported or unknown network IDs are silently ignored by the API — they will not cause an error, but no tokens will be returned for those networks.

      Parameters

      • accountId: string

        The ID of the account

      • Optionaloptions: GetAccountTokensOptions

        Optional override for which networks to query

      Returns Promise<TokenBalance[]>

      The list of tokens & balances

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const tokens = await salt.getAccountTokens('account-id');
      tokens.forEach(t => console.log(`${t.symbol}: ${t.balance}`));
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const tokens = await salt.getAccountTokens('account-id', { networks: ['1', '8453'] });
      tokens.forEach(t => console.log(`${t.symbol}: ${t.balance}`));
    • Gets the transactions of a specific account. The user must have adequate permissions to view the account's transactions.

      Parameters

      • accountId: string

        The ID of the account

      Returns Promise<TransactionObject[]>

      A list of transactions for the account

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const transactions = await salt.getAccountTransactions('account-id');
    • Opens an API connect to receive account nudges. Nudges are ephemeral requests from another Organisation Member asking this user to join an account creation process.

      The nudge listener can be used to accept or reject nudges, and retrieve the details for the account creation process so that this API client can participate in the key material generation process.

      Parameters

      • signer: Signer

        Ethers signer, used during the account creation process

      Returns Promise<NudgeListener>

      NudgeListener for the full NudgeListener description

      InvalidAuthToken if the authentication token is invalid

      InvalidSigner if the signer is missing or invalid

      WrongChain if the signer is on a different chain than expected

      SocketConnectError if the signer fails to connect to websockets, which are required for setup orchestration

      const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
      const walletWithProvider = ethers.Wallet.createRandom().connect(provider);

      const salt = new Salt({
      environment: "TESTNET",
      });

      // from the nudge listener you can observe and manage your signer's reaction to nudges
      const nudgeListener = await salt.listenToAccountNudges(walletWithProvider);

      // read all the nudges in the queue
      const nudgeQueue = nudgeListener.getNudgeQueue();
      // read all the accounts for which the nudge has been processed
      const processedAccounts = nudgeListener.getAccounts();
      // stop listening to nudges
      nudgeListener.disableNudgeListener();
      // start listening again
      nudgeListener.enableNudgeListener();
      // when done, disconnect the websocket to allow the process to exit
      salt.disconnect();
    • Sends a nudge to one or more co-signers, prompting them to join an account creation ceremony. Use this to re-nudge signers if the ceremony times out or a co-signer was not listening when the account was first created.

      Combine with resumeAccountSetup to re-enter the ceremony yourself after nudging offline co-signers.

      When to is provided, only that address is nudged. When omitted, all signers on the account except the caller are nudged.

      Parameters

      • params: { accountId: string; signer: Signer; to?: string }

        Nudge parameters: accountId (the account whose signers to nudge), signer (ethers signer of the caller), and optional to (address of a specific signer to nudge — if omitted, all other signers are nudged)

      Returns Promise<void>

      InvalidAuthToken if the authentication token is invalid

      InvalidSigner if the signer is missing or invalid

      WrongChain if the signer is on a different chain than expected

      SocketConnectError if the signer fails to connect to websockets, which are required for nudge delivery

      import { Salt } from 'salt-sdk';
      import { Wallet, providers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const provider = new providers.JsonRpcProvider(process.env.RPC_URL);
      const signer = new Wallet(process.env.PRIVATE_KEY).connect(provider);

      await salt.nudge({ accountId: 'account-id', signer });
      import { Salt } from 'salt-sdk';
      import { Wallet, providers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const provider = new providers.JsonRpcProvider(process.env.RPC_URL);
      const signer = new Wallet(process.env.PRIVATE_KEY).connect(provider);

      await salt.nudge({
      accountId: 'account-id',
      signer,
      to: '0x2222222222222222222222222222222222222222',
      });
    • Resumes an account setup that did not complete. Returns an AccountSetup configured for the resume path — call AccountSetup.waitForCompletion to re-enter the MPC huddle.

      Both creators and non-creators can call this method — the caller's role is detected automatically from the account's creator address. Non-creators only need this if they are not already listening for nudges via listenToAccountNudges, which handles rejoining automatically.

      Parameters

      Returns Promise<AccountSetup>

      An AccountSetup — call .waitForCompletion() to run the huddle

      When to resume vs. start fresh: Use this method when createAccount failed after the vault was deployed on-chain (e.g. the huddle timed out, a signer went offline, or vault finalization failed). If createAccount failed before vault deployment (validation errors, robos offline, insufficient gas for deploy), simply call createAccount again instead.

      Timeout: The huddle has a built-in timeout (default 5 minutes, max 10 minutes). Override via params.timeoutMs. When the timeout fires, waitForCompletion() rejects with HuddleTimeout.

      Lifecycle events: Listen on the returned AccountSetup for diagnostic events (connected, preRegistered, ready, registering, registered, signerStatusChanged, timedOut).

      InvalidAuthToken if the authentication token is invalid

      InvalidSigner if the signer is missing or invalid

      WrongChain if the signer is on a different chain than expected

      SocketConnectError if the signer fails to connect to websockets

      ApiError if the account cannot be fetched

      import { Salt } from 'salt-sdk';
      import { Wallet, providers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const provider = new providers.JsonRpcProvider(process.env.RPC_URL);
      const signer = new Wallet(process.env.PRIVATE_KEY).connect(provider);

      const setup = await salt.resumeAccountSetup({
      accountId: 'acc-123',
      signer,
      timeoutMs: 120_000, // 2 minutes
      });

      // Listen for diagnostic events
      setup.on('connected', (id) => console.log('Connected to huddle:', id));
      setup.on('signerStatusChanged', (s) => console.log('Signer statuses:', s));
      setup.on('timedOut', (id) => console.log('Huddle timed out:', id));

      const { account } = await setup.waitForCompletion();
      console.log('Account resumed:', account.publicKey);
      import { Salt } from 'salt-sdk';
      import { Wallet, providers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const provider = new providers.JsonRpcProvider(process.env.RPC_URL);
      const signer = new Wallet(process.env.PRIVATE_KEY).connect(provider);

      await salt.nudge({ accountId: 'acc-123', signer });

      const setup = await salt.resumeAccountSetup({
      accountId: 'acc-123',
      signer,
      });
      const { account } = await setup.waitForCompletion();

    Authentication

    • Initiate the authentication flow to get an authentication token from the Salt API. This will require a signature from the Signer, which will be used to authenticate the user. If you already have an authentication token, you can set it using the setAuthToken method, or when you call the "constructor".

      A signer is required to complete the SIWER authentication flow. It is used to sign a message and a nonce, which are then validated by the Salt acceptInvitation and an auth token is returned. If you are using a browser based signer, such as Metamask, you will need to manually approve to the signature request.

      Parameters

      • signer: Signer

        The ethers signer to use for the authentication flow

      Returns Promise<string>

      long lived authentication token. This is also set on the client instance, so you do not normally need to store this manually

      InvalidUrl if the API URL or path is invalid

      Error if the authentication request fails or the user rejects signing

      import { Salt } from 'salt-sdk';
      import { ethers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      });

      const signer = ethers.Wallet.createRandom();
      await salt.authenticate(signer);
      import { Salt } from 'salt-sdk';
      import { ethers } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      });

      const signer = ethers.Wallet.createRandom();
      const authToken = await salt.authenticate(signer);

      // Note: this is not recommended as a secure way to store the auth token
      localStorage.setItem('salt-auth-token', authToken);
    • Sets the authentication token for the Salt SDK. This is useful if you have previously logged in and stored the token. You can also provide the token to the constructor If you do not have a token already, you can use the authenticate method to obtain one.

      Parameters

      • authToken: string

        The authentication token to use for this connection

      Returns void

      This is equivalent to providing the token to the constructor.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      });

      // Retrieve a previously stored auth token (note: this is not recommended as a secure way to store a token)
      const authToken = localStorage.getItem('authToken');

      salt.setAuthToken(authToken);

      // You are ready to use the SDK. For example...
      await salt.getBalance();

    Organisations

    • Accepts an Invitation to an Organisation. The list of transactions for the current user can be retrieved with getOrganisationsInvitations.

      Parameters

      • invitationId: string

        The ID of the invitation to accept

      Returns Promise<{ organisation: Organisation }>

      InvalidAuthToken if the authentication token is invalid

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const invitations = await salt.getOrganisationsInvitations();
      for (const invitation of invitations) {
      console.log(`Accepting invitation to organisation ${invitation.organisation_id}`);
      await salt.acceptOrganisationInvitation(invitation.id);
      }
    • Creates a new Organisation. The authenticated user will be the owner. Collaborators can optionally be invited at creation time — they will receive invitations that can be accepted via acceptOrganisationInvitation.

      This operation is off chain, so it does not require any gas.

      Parameters

      Returns Promise<Organisation>

      The created organisation

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      ApiError if the API returns an error (e.g. duplicate member addresses, invalid name)

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const org = await salt.createOrganisation({
      name: 'My Organisation',
      owner: {
      name: 'Alice',
      address: '0x1234567890123456789012345678901234567890',
      role: 'CEO',
      },
      });
      console.log('Created organisation:', org._id);
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const org = await salt.createOrganisation({
      name: 'My Organisation',
      owner: {
      name: 'Alice',
      address: '0x1234567890123456789012345678901234567890',
      role: 'CEO',
      },
      collaborators: [
      {
      name: 'Bob',
      address: '0x2345678901234567890123456789012345678901',
      role: 'CFO',
      accessLevel: 2,
      },
      ],
      });
    • Gets the list of Accounts that belong to a Organisation.

      Parameters

      Returns Promise<SaltAccount[]>

      The list of accounts

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const accounts = await salt.getAccounts('organisation-id');
      accounts.forEach(account => {
      console.log(`Account: ${account.name} ID: ${account.id} Public key: ${account.publicKey}`);
      });
    • Gets the list of Organisations that the current user is a member of. Requires authentication.

      Returns Promise<Organisation[]>

      The list of organisations

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const organisations = await salt.getOrganisations();
      organisations.forEach(org => {
      console.group('Organisation:', org.name);
      org.members.forEach(member => {
      console.log('Member:', member.name);
      });
      console.groupEnd();
      });
    • Returns pending Invitation to an Organisation for the current user. They can be accepted using acceptOrganisationInvitation.

      Returns Promise<{ invitations: Invitation[] }>

      List of invitations that are pending for this user

      InvalidAuthToken if the authentication token is invalid

      SocketConnectError if the socket connection could not be established

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const invitations = await salt.getOrganisationsInvitations();
      if (invitations.length > 0) {
      console.log('You have pending invitations');
      } else {
      console.log('No pending invitations');
      }

    Policies

    • Creates a new Policy on a Salt account. Policies control what transactions are allowed, denied, or require approval before being signed by the robo guardians.

      Parameters

      Returns Promise<Policy>

      The created policy

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      ApiError if the API returns an error (e.g. invalid policy type or params)

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const policy = await salt.createAccountPolicy({
      accountId: 'account-id',
      type: 'allowed_recipients',
      chain: '11155111', // Sepolia
      params: {
      recipients: [
      { address: '0x1234567890123456789012345678901234567890', nickname: 'Treasury' },
      ],
      },
      });
      console.log('Created policy:', policy.id);
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const policy = await salt.createAccountPolicy({
      accountId: 'account-id',
      type: 'transaction_limit_token_denominated',
      chain: '1', // Ethereum Mainnet
      params: {
      limits: [
      {
      address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
      amount: '1000',
      },
      ],
      },
      });
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const policy = await salt.createAccountPolicy({
      accountId: 'account-id',
      type: 'nominated_approvers',
      chain: '1',
      params: {
      approvers: [
      { address: '0x1234567890123456789012345678901234567890' },
      ],
      },
      });
    • Fetches an existing Policy by its ID.

      Parameters

      • policyId: string

        The ID of the policy to retrieve

      Returns Promise<Policy>

      The policy

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      ApiError if the policy cannot be found or the API returns an error

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const policy = await salt.getAccountPolicy('policy-id');
      console.log(`Policy type: ${policy.type}`);
      console.log(`Policy chain: ${policy.chain}`);
      console.log('Policy params:', policy.params);
    • Updates an existing Policy by its ID. Replaces the policy's params with the new values provided.

      Parameters

      • policyId: string

        The ID of the policy to update

      • params: PolicyParams

        The new policy parameters

      Returns Promise<Policy>

      The updated policy

      InvalidAuthToken if the authentication token is invalid. See authenticate for how to authenticate.

      ApiError if the API returns an error (e.g. policy not found or invalid params)

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      const updated = await salt.updateAccountPolicy('policy-id', {
      recipients: [
      { address: '0x1234567890123456789012345678901234567890', nickname: 'Treasury' },
      { address: '0x2345678901234567890123456789012345678901', nickname: 'Payroll' },
      ],
      });
      console.log('Updated policy:', updated.id);
      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });

      await salt.updateAccountPolicy('policy-id', {
      limits: [
      { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', amount: '5000' },
      ],
      });

    Robos

    • Gets the online status of a robo's guardians for a given account. This indicates whether the robo signers are currently connected and available for signing operations.

      Parameters

      • accountId: string

        The ID of the account to check robo status for

      Returns Promise<RoboStatusResponse>

      The robo status with id and online boolean

      InvalidAuthToken if the authentication token is invalid

      ApiError if the API returns an error (i.e. robos do not exist, insufficient permissions to view status)

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const status = await salt.getRoboStatus('account-id');
      if (status.online) {
      console.log('Robo guardians are online, ready for signing');
      } else {
      console.log('Robo guardians are offline');
      }

    Transactions

    • Gets the nonce for an account on a specific chain. The nonce is an incrementing number stored by Salt that is used to prevent replay attacks. submitTx use the nonce, but if you do not specify one the SDK will automatically use this function to populate it.

      Parameters

      • accountId: string

        The ID of the account

      • chainId: number

        The ID of the chain

      Returns Promise<number>

      The nonce

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const nonce = await salt.getAccountNonce('account-id', 1);
      console.log(`Next nonce: ${nonce}`);
    • Gets the current gas price for a specific chain.

      Parameters

      • chainId: number

        The ID of the chain

      Returns Promise<GasPrice>

      The current gas price

      InvalidChain if the specified chain is unknown or unsupported

      import { Salt } from 'salt-sdk';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });

      const fee = await salt.getGasPrice(1);
      console.log(`Gas for Ethereum Mainnet is between ${fee.lastBaseFeePerGas} and ${fee.maxFeePerGas}`);
    • Initiate, sign and broadcast a generic transaction from a given Salt account. This method provides orchestrated transaction handling with automatic account detail fetching, multi-party signing coordination, and policy enforcement.

      Both the vault (Salt account) and the signer must have sufficient funds to pay gas. For sends, if gas and gasPrice are not provided, they will be estimated automatically. For contract deployment, gas is required (API does not yet support estimate for deploys).

      Important: value is denominated in ETH (not wei). For example, pass '1' for 1 ETH, '0.5' for 0.5 ETH, or '0.000000000000000001' for 1 wei.

      This will require signing multiple transactions and requests:

      • Creating a transaction proposal
      • Proposing the transaction to the robos, so that the policy rules can be checked
      • Signing for broadcast to the destination network
      • Broadcasting the transaction to the destination network

      Parameters

      Returns Promise<Transaction>

      A Transaction object for orchestrated execution

      InvalidAuthToken if the auth token is missing or invalid

      InvalidSigner if the signer is missing or invalid

      WrongChain if the signer is on a different chain than expected

      ApiError if the API returns an error (i.e. account does not exist, insufficient permissions to view account)

      ValidationError if the transaction parameters are invalid

      TransactionError if the underlying SDK returns an unexpected result (e.g. a contract deployment that fails to produce a valid transaction response)

      InsufficientGas if the transaction fails due to insufficient gas

      SocketConnectError if the signer fails to connect to websockets, which are required for signing orchestration

      import { Salt } from 'salt-sdk';
      import { Wallet, utils } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });
      const signer = Wallet.createRandom();

      // Encode the approve function call
      const iface = new utils.Interface(['function approve(address spender, uint256 amount)']);
      const data = iface.encodeFunctionData('approve', [
      '0xE592427A0AEce92De3Edee1F18E0157C05861564', // Uniswap V3 SwapRouter
      '1000000000' // 1000 USDC (6 decimals)
      ]);

      // Gas is estimated automatically when not provided
      await salt.submitTx({
      accountId: '0a1b2c3d4e5f',
      to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC contract
      value: '0',
      chainId: 1,
      data: data,
      signer: signer,
      });
      import { Salt } from 'salt-sdk';
      import { Wallet, utils } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });
      const signer = Wallet.createRandom();

      const iface = new utils.Interface(['function approve(address spender, uint256 amount)']);
      const data = iface.encodeFunctionData('approve', [
      '0xE592427A0AEce92De3Edee1F18E0157C05861564',
      '1000000000'
      ]);

      await salt.submitTx({
      accountId: '0a1b2c3d4e5f',
      to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
      value: '0',
      chainId: 1,
      data: data,
      signer: signer,
      gas: '100000',
      gasPrice: '20000000000', // 20 gwei
      });
      import { Salt } from 'salt-sdk';
      import { Wallet, utils } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token'
      });
      const signer = Wallet.createRandom();

      // Encode the submit function call for Lido staking
      const iface = new utils.Interface(['function submit(address _referral) payable returns (uint256)']);
      const data = iface.encodeFunctionData('submit', [
      '0x0000000000000000000000000000000000000000' // No referral
      ]);

      const tx = await salt.submitTx({
      accountId: '0a1b2c3d4e5f',
      to: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', // Lido stETH contract
      value: '1', // 1 ETH
      chainId: 1,
      data: data,
      signer: signer
      });

      const result = await tx.wait();
      import { Salt } from 'salt-sdk';
      import { Wallet } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });
      const signer = Wallet.createRandom();

      // Omit `to` to submit a contract creation transaction.
      // `data` should contain the compiled contract bytecode; `gas` is required (API does not yet estimate for deploys).
      const tx = await salt.submitTx({
      accountId: '0a1b2c3d4e5f',
      value: '0',
      chainId: 11155111,
      gas: '300000',
      data: '0x608060...', // compiled bytecode
      signer: signer,
      });

      const result = await tx.wait();
      import { Salt, TransactionError, InsufficientGas } from 'salt-sdk';
      import { Wallet } from 'ethers';

      const salt = new Salt({
      environment: 'TESTNET',
      authToken: 'your-auth-token',
      });
      const signer = Wallet.createRandom();

      try {
      const tx = await salt.submitTx({
      accountId: '0a1b2c3d4e5f',
      value: '0',
      chainId: 11155111,
      gas: '300000',
      data: '0xDEAD', // not valid contract bytecode
      signer: signer,
      });
      await tx.wait();
      } catch (error) {
      if (error instanceof TransactionError) {
      console.error('Transaction failed:', error.message);
      console.error('Raw result:', error.data);
      } else if (error instanceof InsufficientGas) {
      console.error('Not enough gas:', error.message);
      } else {
      throw error;
      }
      }