# Credenza3 Passport

## Installation

with npm

```
npm install @credenza3/passport-evm
```

with yarn

```
yarn add @credenza3/passport-evm
```

with pnpm

```
pnpm install @credenza3/passport-evm
```

or include a script tag

```
<script src="https://cdn.jsdelivr.net/npm/@credenza3/passport-evm/dist/passport.umd.js"></script>
<script>
  const Passport = window.CredenzaPassport
</script>
```

or with esm

```
<script type="module">
  import {Passport} from 'https://cdn.jsdelivr.net/npm/@credenza3/passport-evm/+esm'
</script>
```

## Usage

Create the Passport instance

```
const passport = new Passport({
  chainId: Passport.chains.POLYGON_AMOY,
  clientId: "СREDENZA OAUTH CLIENT ID",
  config: {
    erc20Contract?: { // can be used for alternative erc20 tokens (instead of CRED)
        address: "",
         decimals: 6,
    },
    buyTokens?: true,
    transferTokens?: {
      nativeCurrency?: boolean // set false if you want to allow only CRED transfer on SendTokens page
    },
    auth?: {
      extendedRegistration: false,
    },
    nav?: {
      theme?: Passport.themes.BLACK,
      direction?: Passport.navDirections.BOTTOM,
    },
    email?: {
      templateId?: string // For custom email template usage
    },
    content?: {
      cloak?: boolean
      // depends on `cloak: true`
      payPerArticle?: [
        {
          nfts: [{address: 'contract-address-1', tokens:['token-id-1', 'token-id-2'], type: 'ERC1155' | 'ERC721'}],
          memberships: [{address: 'contract-address-1', owner: 'owner-address-1'}],
          uriMasks: ['part-of-the-article-uri'] // [''] for all uris,
          primaryAction: { text: 'buy nft', contractAddress: '', tokenId?: 'tokenid', membershipTokenId?: '' },
          secondaryAction: { text: 'get sub', link: '', openInNewTab: true }
        }
      ],
      imageUrl?: 'https://yoursite.com/image.png', // Replaces default `Standford Socker` image
      signin: {
        title: "Your title!", // Replaces default ``
        description: "Your description.", // Replaces default ``
      },
      signup: {
        title: "Your title!", // Replaces default ``
        description: "Your description.", // Replaces default ``
      },
      logout: {
        title: "Your title!", // Replaces default ``
        description: "Your description!", // Replaces default ``
      },
      paymentResult?: {
        title?: "Your title!", // Replaces default `Success!`
        subtitle?: "Your subtitle!", // Replaces default `Your payment was successful!`
        description?: "Your description!", // Replaces default `Usually it takes us as many as a few minutes to deliver tokens to your account.`
      }
      progressVideos?: [{
        embedded: true,
        src: 'https://www.youtube.com/embed/tgbNymZ7vqY',
      }, {
        src: 'https://media.w3.org/2010/05/sintel/trailer.mp4'
      }]
    },
  },
})

await passport.init()
```

### Passport instance Properties

`isLoggedIn`: boolean

`chainId`: string

`ethers`: Ethers.js https://docs.ethers.io/v5/

`user`: User instance

### Passport static properties

`Passport.version` (string) Current package version

`Passport.chains` (enum) Supported chains

`Passport.pages` = (enum) Available pages for logged in User

`Passport.paymentTypes` = (enum) Available payment types

`Passport.themes` = (enum) Available color schemas

`Passport.navDirections` = (enum) Available directions where passport nav bar will expand when opened

`Passport.navMinimizationTogglerPositions` = (enum) Available minimization toggler positions

`Passport.events` = (enum) Available events for `passport.on()` listener

### Modes

Passport can be used in 3 modes:
`Code` `UI` `Navigation`

### Apple Pay

You must verify your domain.
https://support.stripe.com/questions/enable-apple-pay-on-your-stripe-account
Enabled by default on all supported devices and registered domains.

### Google Pay

Is enabled on all supported devices by default

### Code mode

Login with credentials

```
await passport.login(
  provider: "OAUTH" | "EVM",
  opts: {
    oauthType?: "credentials" | "google" | "passwordless" | "ticketmaster",
    forceEmail?: string,
    forcePhone?: string,
    passwordlessType?: "EMAIL" | "PHONE",
  }
)
// Do not provide is 'signUp' param if you want passport to try detect automatically.
```

Logout

```
await passport.logout()
```

Switch chain

```
await passport.switchChain({chainId: string}):Promise<void> // any of Passport.chains
```

Get ethers provider

```
await passport.getWeb3Provider():Promise<EthersRPCProvider> // returns Ethers provider
```

Get current session address

```
await passport.getAddress():Promise<string | null>
```

Check membership

```
await passport.checkMembership(ownerAddress:string, membershipAddress?: string):Promise<{isMember:boolean, meta: unknown}>
```

Get current user roles

```
await passport.getRoles():Promise<(Admin | Superadmin | User)[]>
```

Get CRED Contract

```
await passport.getCREDContract():Promise<({
  address: string
  decimals: number
  contract: ethers.Contract
})>
```

Send CRED Stored Value

`Do not pass contract if you transfer the native network tokens.`

```

await passport.sendTokens(opts: {
  address: string,
  amount: string | bigint,
  contract?: ethers.Contract
}): Promise<{ hash?: string; wait?: () => Promise<void> }>;
```

Send Credenza NFT

```
await passport.sendNft({ contract, recipient, tokenId, amount }: {
  contract: ethers.Contract,
  recipient: string,
  tokenId: string,
  amount: number
}):Promise<any>
```

Request AirDrop

```
await passport.requestAirDrop({ contractAddress, tokenId, amount, targetAddress }: {
  targetAddress: string
  contractAddress: string
  tokenId?: string | number // tokenId can be skipped if we need to airdrop erc721
  amount?: number // if amount is skipped - default is 1
}):Promise<void>
```

Request Loyalty Points

```
await passport.requestLoyaltyPoints(eventId: number, contractAddress: string):Promise<void>
```

Confirm email / phone number

```
await passport.confirmAccount({phoneCode?:number, emailCode?:number}):Promise<boolean>

```

Delete account

```
await passport.deleteAccount():Promise<void>
// Opens account deletion flow in a new tab
```

### Navigation mode

Show navigation panel

```
await passport.showNavigation({
  bottom?: "5px",
  right?: "5px",
  left?: "inherit",
  top?: "inherit",
}, {
  minimization?: {
    enabled?: boolean, // false
    toggler?: {
      enabled?: boolean, // false
      position?: Passport.navMinimizationTogglerPositions.(LEFT | RIGHT), // left
    }
  }
}); // Bottom right corner
```

Hide navigation panel

```
passport.hideNavigation();
```

Get assets of current chain

```
passport.getAssets(opts: {
  assetsConfig: Array<{ address: string; tokenIds?: string[] }>,
  opts?: { fetchMetadataUri?: boolean, fetchMetadata?: boolean }
}): Promise<{
  contractAddress: string
  tokenId: string
  balance: string
  uri?: string
  metadata?: Record<string, unknown> | null
}[]>;
```

### Passport UI mode

Open UI (Use one of `Credenza.pages.PROFILE`, `Credenza.pages.PASSPORT_ID`)

```
await passport.openUI() // defaults to Credenza.pages.PROFILE
```

Close UI

```
passport.close()
```

Open Passport alert

```
passport.toastAlert(
  message,
  type?: 'success' | 'warning' | 'failure' | 'info', // defaults to info
  opts?:{
    duration?: number // if -1 - then there is no timer and it stays untill dismissed,
    centered?: {
      enabled?: boolean,
      position?: 'top' | 'bottom' // can be used only for centered block
    }
  }
)
```

Open Passport rich alert

```

passport.openUI(Passport.pages.RICH_ALERT, {
  richAlertData: {
    title?: string,
    description?: string,
    action?: {
      text: string;
      link?: string;
      onClick?: (...args: unknown[]) => unknown;
    },
    closeButtonText?: string;
  },
})
```

Open Menu UI

```
await passport.openUI('navMenu')
```

Perform NFT or Membership payment

```
await passport.openUI(Passport.pages.PAYMENT, {
  title: string,
  subtitle: string,
  payments?: {
    credenzaStoredValue?: {
        disabled?: boolean //default - false
    },
    card?: {
      disabled?: boolean // default - false
    }
  },
  tokens: [{
    contractAddress: string, // contract address
    tokenId: string,
    amount?: number  // amount of tokens
  }],
  memberships: [
    {
      contractAddress: string, // contract address
      membershipTokenId?: string
    }
  ]
  email?: {
    templateId?: string // For custom email template usage
  }
})
```

Perform License purchase

```
await passport.openUI(Passport.pages.PAYMENT, {
  title: string,
  subtitle: string,
  payments?: {
    credenzaStoredValue?: {
        disabled?: boolean //default - false
    },
  },
  licenses: [
    {
      contractAddress: string;
      amount: number;
      // these fields are needed in case of license purchase
      // contractAddress in this case is content contract address (needed for price calculation), so we need licenseContractAddress to purchase a license
      licenseContractAddress?: string;
      contentTokenId?: string;
      licenseType?: string;
    },
  ]

})
```

Destroy passport

```
passport.destroy()
```

### Events (Most likely for Navigation and UI modes)

Listen for event

```
const unsubscribe = passport.on(Passport.events[eventName], (data) => {
  console.log(data)
})
```

Listen for event(Triggers once)

```
const unsubscribe = passport.once(Passport.events[eventName], (data) => {
  console.log(data)
})
```

### Supported query params

Prepopulates email address on login / signup form.

```
?credenza_user_email=test%40test.com
// ?credenza_user_email=encodeURIComponent(test@test.com)
```

### SSR

Passport is not build for the Server Side Rendering, but you still can make it work with the SSR app. Make sure you disable SSR for passport specific component or you can dynamically import passport after it's mounted e.g.

```
// svelte
onMount(() => {
  const {Passport} = (await import('@credenza3/passport-evm'))
})

```
