# `Portal`

The `@portal-hq/core` package includes a class constructor for the `Portal` class, a React Context Provider for the `PortalContext`, the `usePortal` hook for use within child components, and some helpful types and enums for working with Portal in your app. These pieces allow you to initialize `Portal` in your app, expose the instance to your component tree, and consume the instance in your child components.

## The Portal Class

The `Portal` class that houses three main sub-classes

- `api` makes requests to the Portal api
- `mpc` facilitates the generation, backup, and recovery of MPC wallets
- `provider` the core Portal provider ([EIP-1139](https://eips.ethereum.org/EIPS/eip-1193) compliant)

## Instantiation

When instantiating the `Portal` class, you must provide a `PortalOptions` object. This object is used to initialize all of the sub-classes (and their sub-classes).

### Example instantiation

```typescript
import { BackupMethods, Portal } from '@portal-hq/core'

const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),
  keychain: keychain, // See: @portal-hq/keychain
})
```

### PortalOptions

The `PortalOptions` object is where you configure your instance of `Portal`. It contains a set of required properties and a set of optional properties.

#### Required properties

- `apiKey` **string** a valid Portal Client API Key created via the [Portal REST API](https://api.portalhq.io/api/clients)
- `backupConfig` **object**
  - `gdrive` **Storage** (optional) expects an instance of `@portal-hq/gdrive-storage`
  - `icloud` **Storage** (optional) expects an instance of `@portal-hq/icloud-storage`
- `chainId` **number** the ID of the current Ethereum chain you'd like to perform actions on
  - You can update this property on your `Portal` instance later – if your app requires this – by setting `portal.chainId` property
- `gatewayConfig` **string** or **GatewayConfig** the base url (including your API key) you'd like us to use for Gateway requests (reading from and writing to chain) _**Note: this will be required in the future**_
  - `GatewayConfig` – if you don't want to use the same url for all requests, you can instead provide a chain-level config for all Gateway RPC calls this can be passed in as an object with key/value pairs where the `key` is the `chainId` as a number and the value is the base url you'd like to use when performing actions on this `chainId`
- `isSimulator` **boolean** whether or not you're currently running the app in a simulator (this is required to ensure that keychain storage is configured appropriately for the current device)
- `keychain` **Keychain** expects an instance of either `@portal-hq/keychain` or `@portal-hq/mobile-key-values`

#### Optional properties

- `autoApprove` **boolean** (default: `false`) whether you'd like the provider to auto-approve transactions
- `mpcEnabled` **boolean** (default: `true`) whether or not to use MPC

## `api`

The `api` property contains an instance of the `PortalApi` class, which has a number of helper methods to facilitate the retrieval of relevant application data from the Portal REST API.

### Methods

#### `getEnabledDapps`

Fetches a list of allowed dApps based on your dApp settings in the Portal web app.

##### Example usage

```typescript
const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),,
  keychain: keychain // See: @portal-hq/keychain
})

const dapps = await portal.api.getEnabledDapps()
```

#### `getNetworks`

Fetches a list of supported networks based on your dApp settings in the Portal web app.

##### Example usage

```typescript
const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),,
  keychain: keychain // See: @portal-hq/keychain
})

const networks = await portal.api.getNetworks()
```

## `mpc`

The `mpc` property contains an instance of the `PortalMpc` class, which has a number of helper methods to facilitate the management of Portal MPC wallets.

### Methods

#### `generate`

Performs the MPC generate process to create an MPC wallet and its signing shares

##### Example usage

```typescript
const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),,
  keychain: keychain // See: @portal-hq/keychain
})

const createWallet = async () => {
  await portal.createWallet()
}
```

#### `backup`

Performs the MPC backup process to create the backup shares for the generated MPC wallet.

##### Example usage

```typescript
const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),,
  keychain: keychain, // See: @portal-hq/keychain
})

const backupWallet = async () => {
  await portal.backupWallet(BackupMethods.GDrive)
}
```

#### `recover`

Performs the MPC recovery process to generate new signing shares for the MPC wallet.

##### Example usage

```typescript
const portal = new Portal({
  apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
  backup: {
    gdrive: gDriveStorage, // See: @portal-hq/gdrive-storage
    icloud: iCloudStorage, // See: @portal-hq/icloud-storage
  },
  chainId: 1,
  gatewayConfig: 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
  isSimulator: DeviceInfo.isEmulator(),
  keychain: keychain, // See: @portal-hq/keychain
})

const recoverWallet = async () => {
  await portal.mpc.recoverWallet(cipherText, BackupMethods.GDrive)
}
```

## `provider`

The `provider` property contains an [EIP-1139](https://eips.ethereum.org/EIPS/eip-1193) compliant provider.

### Making requests through the provider

In order to perform basic web3 operations, such as `eth_accounts` and `eth_sendTransaction`, you can use the provider's `request` method.

This method conforms to [EIP-1139](https://eips.ethereum.org/EIPS/eip-1193).

#### Example usage

```typescript
const transaction = {
  data: '',
  to: toAddress,
  value: BigNumber.from('1').toHexString(),
  gas: '0x6000',
  from: portal.address, // The address of the current connected wallet
}

const txHash = await portal.provider.request({
  method: 'eth_sendTransaction',
  params: transaction,
})
```

_For more information on how to use this provider natively within your React Native app, see the [Provider Docs](LINK_TO_PROVIDER_DOCS)._

## The Portal context

`PortalContext` is used to persist an instance of `Portal` within your application. This allows you to initialize `Portal` once, and easily share this instance between all of the components within a given scope in your app.

The exported members allow for 2 ways to set the `PortalContext` and one way to get the `PortalContext`.

### Setters

You only need to choose one of these when implementing the `PortalContext` in your app.

- `PortalContextProvider` a React Context Provider to provide your `Portal` instance to the components in your app

### Getters

- `usePortal` a React hook to use the `Portal` instance in any component within the `PortalContextProvider` scope (any component being rendered as either a shallow or deep child of the `PortalContextProvider`)

_For more info on working with React Context, [check out the docs](https://reactjs.org/docs/context.html)._

### `PortalContextProvider`

The `PortalContextProvider` allows you to share your instance of the Portal class with all components in your component tree. Providing a `value` prop with your Portal instance and wrapping your components in the `PortalContextProvider` enables this behavior. All children of the `PortalContextProvider` can access the Portal instance using the `usePortal` hook (see below).

_**Note**: The easiest way to ensure you're exposing Portal to all components in your component tree is to use it in your App component_

```tsx
// MyRootComponent.tsx
import { Portal, PortalContextProvider } from '@portal-hq/react-native'
import { useEffect, useState } from 'react'

const MyRootComponent = () => {
  const [portal, setPortal] = useState<Portal>(null)

  useEffect(() => {
    if (!portal) {
      setPortal(
        new Portal({
          // TODO: Add all of the appropriate config options
        }),
      )
    }
  }, [portal])

  return (
    <PortalContextProvider value={portal}>
      {/* Now all children rendered in this scope will have access to the `Portal` instance via the `usePortal` hook */}
    </PortalContextProvider>
  )
}
```

### `usePortal`

The `usePortal` hook allows any child in the component tree below a `PortalContextProvider` to access the Portal instance.

```tsx
// MyChildComponent.tsx

import { usePortal } from '@portal-hq/react-native'

const MyChildComponent = () => {
  const portal = usePortal()

  // You can now do things with the `Portal` instance directly, such as:
  // - `await portal.api.getEnabledDapps()`
  // - `await portal.mpc.generate()`
  //
  // For more information on this, please see the `Portal` docs in `src/lib/portal`

  ...
}

```

## Additional exports

In addition to the `Portal` class and context exports, the `@portal-hq/core` package exports some helpful types and enums for use when building your app.

The additional exports are as follows:

- `BackupMethods` – an enum of supported storage methods for backup MPC key shares
- `Address` - a type representing Portal Address records
- `Dapp` - a type representing Portal Dapp records (`portal.api.getEnabledDapps()` returns `Dapp[]`)
- `PortalOptions` - a type representing the object used to configure the `Portal` class on initialization

## Native Bridge Files

The iOS implementation includes native bridge files (`MpcBridge.h` and `MpcBridge.m`) that provide C-compatible function declarations and implementations to interface with the underlying Go MPC library via gomobile.

> **Important Note**: When the Go build/library is updated, these bridge files (`packages/core/ios/MpcBridge.h` and `packages/core/ios/MpcBridge.m`) should be reviewed and updated accordingly to ensure compatibility with any new function signatures or API changes from the Go layer.

## iOS (CocoaPods + React Native)

### `use_frameworks! :linkage => :static`

Firebase and other Swift pods commonly require static frameworks. The `PortalMpc` pod vendors `Mpc.xcframework` (Go-mobile output is a **static archive** inside `Mpc.framework`). With React Native’s static-framework path, the pod target is assembled with **libtool**, which does **not** apply `OTHER_LDFLAGS`, so the Go symbols stay unresolved until the **app** link step. The podspec therefore sets `user_target_xcconfig` with SDK-conditional **`-Wl,-force_load,<path-to-Mpc.framework/Mpc>`** so the final Clang/ld link pulls in `Mobile*`.

### Default install layout

`user_target_xcconfig` expands the vendored archive path as:

`$(PODS_ROOT)/../../node_modules/@portal-hq/core/ios/Frameworks/Mpc.xcframework/...`

That matches the usual React Native layout (`ios/Podfile` next to `node_modules`). If you integrate the pod from a **custom `:path`** without this `node_modules` layout, add your own `post_install` / target `OTHER_LDFLAGS` with a correct `-force_load` to the same `Mpc.framework/Mpc` binary inside the matching xcframework slice.

### Case-sensitive filesystems

The vendored bundle is named **`Mpc.xcframework`** so the linker flag name matches the inner **`Mpc.framework`** (avoids `mpc` vs `Mpc` issues on case-sensitive CI).

### Xcode 26 + React Native 0.80.x (`fmt`)

Apple Clang 21 rejects `consteval` in the `fmt` version pinned by RN 0.80.x. Until you upgrade to **RN ≥ 0.83** (fmt 12.1.0+), apply the small `Pods/fmt/include/fmt/base.h` patch in your app’s `Podfile` `post_install` (disable `FMT_USE_CONSTEVAL`). See `examples/react-native-example/ios/Podfile` for a labeled, idempotent snippet.
