npm package: @starkware-industries/starkgate-sdk
Description: BridgeSDK is a TypeScript library for managing cross-chain token transfers between Ethereum and Starknet networks. It supports multiple token bridges and provides an interface for deposits, withdrawals, and balance checks.
Latest version: 1.1.0

# BridgeSDK

BridgeSDK is a TypeScript library for managing cross-chain token transfers between Ethereum and Starknet networks. It supports multiple token bridges and provides an interface for deposits, withdrawals, and balance checks.

## Features

- Support for multiple tokens and bridges
- Easy configuration for different networks
- Deposit and withdraw tokens between Ethereum and Starknet
- Balance checks for available deposits and withdrawals

## Installation

Install BridgeSDK using npm:

```bash
npm install @starkware-industries/starkgate-sdk
```

## Usage

### Creating an Instance of BridgeSDK

To create an instance of BridgeSDK, use the `create` method:

```typescript
import {BridgeSDK, BridgeSDKConfig} from '@starkware-industries/starkgate-sdk';

const config: BridgeSDKConfig = {
  network: 'main',
  ethereum: {
    provider: yourEthereumProvider,
    signer: yourEthereumSigner
  },
  starknet: {
    provider: yourStarknetProvider,
    account: yourStarknetAccount
  },
  debug: true
};

const bridgeSDK = await BridgeSDK.create(config);
```

## Configuration

### BridgeSDKConfig

- `debug`: A boolean flag to enable debug mode. Default is `false`.
- `network`: The network to use, either `'sepolia'` or `'main'`.
- `ethereum`: An optional object containing the Ethereum provider (`JsonRpcProvider`) and signer(`JsonRpcSigner`).
- `starknet`: An optional object containing the Starknet provider (`RpcProvider`) and account (`Account`).

### Setting Signers and Providers

You can update the Ethereum signer or Starknet provider/account after the SDK has been initialized:

```typescript
bridgeSDK.setEthereumSigner(newSigner);
bridgeSDK.setEthereumProvider(newProvider);
bridgeSDK.setStarknetProvider(newProvider);
bridgeSDK.setStarknetAccount(newAccount);
```

### Getting the supported bridges

```typescript
import {BridgeToken} from '@starkware-industries/starkgate-sdk';

const bridges: BridgeToken = bridgeSDK.getBridgeTokens();
```

### Performing Operations

#### Deposit

```typescript
import {StarknetAddress, TokenIdentifier} from '@starkware-industries/starkgate-sdk';

const tokenId: TokenIdentifier = 'strk';
const amount = '150';
const l2Recipient: StarknetAddress = '0x...';

await bridgeSDK.deposit(tokenId, amount, l2Recipient);
```

#### Withdraw

```typescript
import {EthereumAddress, TokenIdentifier} from '@starkware-industries/starkgate-sdk';

const tokenId: TokenIdentifier = 'strk';
const amount = '10';
const recipient: EthereumAddress = '0x...';

await bridgeSDK.withdraw(tokenId, amount, recipient);
```

#### Initiate Withdraw

```typescript
import {EthereumAddress, TokenIdentifier} from '@starkware-industries/starkgate-sdk';

const tokenId: TokenIdentifier = 'strk';
const l1Recipient: EthereumAddress = '0x...';
const amount = '0.5';

await bridgeSDK.initiateWithdraw(tokenId, l1Recipient, amount);
```

#### Initiate Auto Withdraw

```typescript
import {EthereumAddress, TokenIdentifier} from '@starkware-industries/starkgate-sdk';

const tokenId: TokenIdentifier = 'strk';
const l1Recipient: EthereumAddress = '0x...';
const amount = '0.5';
const autoWithdrawConfig = {
  preferredFeeToken: '0x...' // The L2 address of the preferred token to be used for fees. If the user has a balance in this token, it will be used. Otherwise, the fee will be paid in another available token.
};

await bridgeSDK.initiateWithdraw(tokenId, l1Recipient, amount, autoWithdrawConfig);
```

#### Balance Checks

```typescript
import {
  EthereumAddress,
  StarknetAddress,
  TokenIdentifier
} from '@starkware-industries/starkgate-sdk';

const tokenId: TokenIdentifier = 'strk';
const account: EthereumAddress = '0x...';
const starknetAccount: StarknetAddress = '0x...';

const availableDepositBalance = await bridgeSDK.getAvailableDepositBalance(token, account);
const availableWithdrawBalance = await bridgeSDK.getAvailableWithdrawBalance(
  tokenId,
  starknetAccount
);
```

### Fee Estimation

Run these functions to get a fee estimation on the following flows:

#### Deposit

You must have more than 0 of the selected token in the connected l1 wallet to get an estimate of the deposit.

```typescript
// built into library
type DepositFeeEstimation = {
  l1Fee: L1FeeAmount;
  l2Fee: string;
  l2FeeUnit: SnFeeUnit;
};

const tokenId: TokenIdentifier = 'strk';

const depositEstimate: DepositFeeEstimation = await bridgeSDK.getDepositFeeEstimate(tokenId);
```

#### Initiate Withdraw

You must have more than 0 of the selected token in the connected l2 wallet to get an estimate of the withdrawal.
This function contains two optional fields, `autoWithdrawConfig` and `preferredL2FeeToken`.
Should you want to get the fees to perform an auto withdrawal, you will need to provide `autoWithdrawConfig`, otherwise the parameter defaults to `undefined`.
By default, the l2 fees will be returned as STRK in accordance with V3 starknet transaction standards.
Should you want to receive the Fees in ETH, you will need to pass the string `"ETH"` to the `preferredL2FeeToken` parameter.

Should you try to estimate initiate withdraw using a non-deployed wallet, you will get an error in the `l2FeeError` field and the l2Fee will return as 0.

```typescript
// built into library
type InitiateWithdrawalFeeEstimation = {
  l2Fee: string;
  feeUnit: SnFeeUnit;
  autoWithdrawCostMap?: Record<SnFeeUnit, string>;
  l2FeeError?: string;
};

type AutoWithdrawConfig = {
  preferredFeeToken: StarknetAddress;
};

const tokenId: TokenIdentifier = 'strk';
const autoWithdrawConfig = {
  preferredFeeToken: '0x...'
};

const depositEstimate: InitiateWithdrawalFeeEstimation = await bridgeSDK.getDepositFeeEstimate(
  tokenId,
  autoWithdrawConfig
);
```

#### Withdrawal

Note that this is the only estimation where you need to provide the recipient and the amount being withdrawn.

```typescript
type L1FeeAmount = string; // built in to library

const tokenId: TokenIdentifier = 'strk';
const amount: string = '112';
const l1Recipient: EthereumAddress = '0x...';

const feeEstimation: L1FeeAmount = await bridgeSDK.getWithdrawalFeeEstimate(
  tokenId,
  amount,
  l1Recipient
);
```

### Event Subscription

BridgeSDK provides a robust event subscription API to handle different actions and states during deposit and withdrawal operations. The API allows you to subscribe to specific bridge actions and get notified about various events related to those actions.

#### API

- **`subscribe(action: BridgeAction, cb: BridgeCallback)`**: Subscribes to a specified bridge action.
- **`unsubscribe(action: BridgeAction, cb: BridgeCallback)`**: Unsubscribes from a specified bridge action.

#### Types

- **BridgeCallback**: A callback function that takes an event of type `BridgeEvent`.

  ```typescript
  export type BridgeCallback = (event: BridgeEvent) => void;
  ```

- **BridgeAction**: Enum representing the bridge actions you can subscribe to.

  ```typescript
  export enum BridgeAction {
    DEPOSIT = 'DEPOSIT',
    INITIATE_WITHDRAW = 'INITIATE_WITHDRAW',
    WITHDRAW = 'WITHDRAW'
  }
  ```

- **BridgeEvent**: An object containing the event type and associated data.
  ```typescript
  export class BridgeEvent {
    public type: DepositEventType | WithdrawEventType | InitiateWithdrawEventType;
    public data?: any;
  }
  ```

#### Event Payloads

For each event, the payload contains specific data related to that event. Here are the payloads for each event type:

- **Deposit Events**:

  - **DEPOSIT_STARTED**: `{ amount: bigint; l2Recipient: StarknetAddress }`
  - **CHECKING_ALLOWANCE**: `{ owner: string; spender: string }`
  - **APPROVE_TX_SENT**: `{ spender: string; amount: string }`
  - **APPROVE_TX_SIGNED**: `{ txHash: string }`
  - **APPROVE_TX_COMPLETED**: `{ receipt: ContractTransactionReceipt }`
  - **APPROVAL_OK**: `{ allowance: string }`
  - **DEPOSIT_TX_SENT**: `{ transactionDetails: { args: string[]; transaction: { from: string; value?: bigint } } }`
  - **DEPOSIT_TX_SIGNED**: `{ txHash: string }`
  - **DEPOSIT_COMPLETED**: `{}`

  - **DEPOSIT_ERROR**: `{ error: Error }`

- **Withdraw Events**:

  - **WITHDRAW_STARTED**: `{ amount: bigint; recipient: EthereumAddress }`
  - **WITHDRAW_TX_SENT**: `{ transactionDetails: { method: string; args: string[]; transaction: { from: string; value?: bigint } } }`
  - **WITHDRAW_TX_SIGNED**: `{ txHash: string }`
  - **WITHDRAW_COMPLETED**: `{ txHash: string }`
  - **WITHDRAW_ERROR**: `{ error: Error }`

- **Initiate Withdraw Events**:
  - **INITIATE_WITHDRAW_STARTED**: `{ amount: bigint; l1Recipient: EthereumAddress; auto: boolean }`
  - **INITIATE_WITHDRAW_TX_SENT**: `{ transactionDetails: Call | Call[] }`
  - **INITIATE_WITHDRAW_TX_SIGNED**: `{ txHash: string }`
  - **INITIATE_WITHDRAW_TX_COMPLETED**: `{ receipt: GetTransactionReceiptResponse }`
  - **INITIATE_WITHDRAW_COMPLETED**: `{ txHash: string }`
  - **INITIATE_WITHDRAW_ERROR**: `{ error: Error }`

#### Usage

To subscribe to an event, you need to define a callback function that will handle the event data and then use the `subscribe` method with the appropriate `BridgeAction`. You can unsubscribe from an event using the `unsubscribe` method.

```typescript
import {
  BridgeAction,
  BridgeCallback,
  BridgeEvent,
  BridgeSDK,
  DepositEventType
} from '@starkware-industries/starkgate-sdk';

// Define a callback function to handle events
const handleEvent: BridgeCallback = (event: BridgeEvent) => {
  switch (event.type) {
    case DepositEventType.DEPOSIT_STARTED:
      console.log('Deposit process has started.', event.data);
      break;
    case DepositEventType.APPROVE_TX_SENT:
      console.log('Approval transaction sent.', event.data);
      break;
    case DepositEventType.DEPOSIT_COMPLETED:
      console.log('Deposit completed successfully.', event.data);
      break;
    case DepositEventType.DEPOSIT_ERROR:
      console.error('An error occurred during deposit.', event.data);
      break;
    // Handle other events similarly
    default:
      console.log('Unhandled event:', event);
  }
};

// Subscribe to deposit events
bridgeSDK.subscribe(BridgeAction.DEPOSIT, handleEvent);

// Unsubscribe from deposit events when no longer needed
bridgeSDK.unsubscribe(BridgeAction.DEPOSIT, handleEvent);
```

This approach ensures that you are kept informed about the various stages and statuses of your deposit and withdrawal operations, allowing you to handle each event appropriately within your application.

## Registering an External Bridge

BridgeSDK allows for the registration of external bridge classes that implement the `IBridge` interface. This can be useful for adding support for additional tokens or custom bridge logic.

To register a custom internal bridge class, which doesn't provide a token object, use the `registerInternalBridge` method:

```typescript
class newTokenBridge implements IBridge {
  // Implement required methods...
}

BridgeSDK.registerInternalBridge('myNewToken', newTokenBridge);
```

To register a custom external bridge class, which includes a BridgeToken, use the `registerExternalBridge` method:

```typescript
const myNewToken: BridgeToken = {
  symbol: 'newToken',
  name: 'myNewToken',
  decimals: 18,
  l1Address: '0x...',
  l2Address: '0x...'
  // ...Other properties
};

class newTokenBridge implements IBridge {
  // Implement required methods...
}

BridgeSDK.registerExternalBridge('myNewToken', newTokenBridge, myNewToken);
```