DEV Community

Cover image for iExec DataProtector Core and Web3Mail Tutorial
Petromir Petrov
Petromir Petrov

Posted on

iExec DataProtector Core and Web3Mail Tutorial

Prerequisites

  • Ensure Node.js v18 or later is installed.
  • Install iExec's SDKs:

    yarn add @iexec/dataprotector @iexec/web3mail
    
  • We'll use Wagmi to interact with wallets, though you may use any other dApp library:

    yarn add wagmi
    
  • An Ethereum wallet that will be used to "send" emails.

Step 1: Save an Email Address and Grant Access

In this step, you will:

  • Securely store email addresses using iExec's DataProtector Core.
  • Grant controlled access to a dApp without revealing the email addresses.
  • Allow users to revoke access at any time.

If you have already completed this step, you can proceed to Step 2.

Add Bellecour Network to Your App

Here's an example for Wagmi:

const bellecourNetwork = defineChain({
  id: 134,
  name: 'iExec Sidechain',
  nativeCurrency: { name: 'xRLC', symbol: 'xRLC', decimals: 18 },
  rpcUrls: { default: { http: ['https://bellecour.iex.ec'] } },
  blockExplorers: { default: { name: 'IXEC Explorer', url: 'https://blockscout.bellecour.iex.ec' } },
})

export const config = createConfig(
  getDefaultConfig({
    chains: [
      // Other chains...
      bellecourNetwork,
    ],
    transports: { 134: http('https://bellecour.iex.ec') },
    // Other settings...
  })
)
Enter fullscreen mode Exit fullscreen mode

Switching Networks

Use the useSwitchChain hook to switch to the Bellecour network:

const { switchChain } = useSwitchChain({ config })
Enter fullscreen mode Exit fullscreen mode

Saving Email as Protected Data

const saveEmailAsProtected = async () => {
  if (!isValidEmail(email)) {
    setError('Please enter a valid email address')
    return
  }

  // Switch to Bellecour
  await switchChain(134)
  if (chainId !== 134) return

  setIsInProgress(true)
  try {
    await dataProtectorCore.protectData({
      // Unique identifier for the dataset
      name: 'uniqueDatasetName',
      data: { email },
    })
    setHasProtectedEmail(true)
  } catch (error) {
    // Handle errors
    console.error(error)
    setError('Failed to save email address')
  } finally {
    setIsInProgress(false)
  }
}
Enter fullscreen mode Exit fullscreen mode

💡 Note: All implementations should be adapted to fit your specific requirements.

Retrieving Protected Data

Retrieve the dataset for the following purposes:

  • Check if the user has already saved their email.
  • Fetch the dataset address to grant access to a dApp.
const getProtectedData = async () => {
  if (chainId !== 134) return

  setIsInProgress(true)
  try {
    const result = await dataProtectorCore.getProtectedData({
      owner: address,
      requiredSchema: { email: 'string' },
    })
    // Filter the dataset by name as there may be multiple datasets
    // with the same schema.
    return result.filter(({ name }) => name === 'uniqueDatasetName')
  } catch (error) {
    console.error(error)
    setError('Failed to get email address')
  } finally {
    setIsInProgress(false)
  }
}
Enter fullscreen mode Exit fullscreen mode

Granting Access

Allow dApps to access datasets:

const grantAccess = async () => {
  const protectedData = await getProtectedData()

  if (!protectedData?.length || chainId !== 134) {
    setError('Please switch to iExec\'s sidechain or check your data.')
    return
  }

  setIsInProgress(true)
  try {
    await dataProtectorCore.grantAccess({
      // Get the address of the first dataset
      protectedData: protectedData[0].address,
      // This is iExec's Web3Mail app whitelist address
      // https://tools.docs.iex.ec/tools/web3mail/methods/sendEmail#sendemail
      authorizedApp: '0x781482C39CcE25546583EaC4957Fb7Bf04C277D2',
      // The Ethereum address that will be used to send emails on the backend
      authorizedUser: '0x...',
      numberOfAccess: 100000,
    })
  } catch (error) {
    console.error(error)
    setError('Failed to grant email address access')
  } finally {
    setIsInProgress(false)
  }
}
Enter fullscreen mode Exit fullscreen mode

Revoking Access

Users may want to revoke access to their data. It can be done using revokeAllAccess:

const revokeAccess = async () => {
  const protectedData = await getProtectedData()

  if (!protectedData?.length || chainId !== 134) {
    setError('Please switch to iExec\'s sidechain or check your data.')
    return
  }

  setIsInProgress(true)
  try {
    await dataProtectorCore.revokeAllAccess({
      protectedData: protectedData[0].address,
      authorizedApp: '0x781482C39CcE25546583EaC4957Fb7Bf04C277D2',
      authorizedUser: '0x...',
    })
  } catch (error) {
    console.error(error)
    setError('Failed to revoke access')
  } finally {
    setIsInProgress(false)
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Using Web3Mail SDK

Send emails to recipients who have granted access to your dApp.

Initializing Web3Mail SDK

import { getWeb3Provider, IExecWeb3mail } from '@iexec/web3mail'

// The PRIVATE_KEY of the Ethereum address that users granted access to - 'authorizedUser'
const provider = getWeb3Provider(process.env.PRIVATE_KEY)
const web3mail = new IExecWeb3mail(provider)
Enter fullscreen mode Exit fullscreen mode

Fetching Contacts

Retrieve users who granted access:

// isUserStrict - enables fetching contacts who granted access exclusively to our dApp and no one else.
const contactsList = await web3mail.fetchMyContacts({ isUserStrict: true })
Enter fullscreen mode Exit fullscreen mode

Sending Emails

Loop through contacts to send emails:

for (const { address: protectedDataAddress, owner } of contactsList) {
  const content = `<div><p>Hello ${owner},</p><p>Here’s your update!</p></div>`

  await web3mail.sendEmail({
    protectedData: protectedDataAddress,
    emailSubject: 'Your Update',
    emailContent: content,
    contentType: 'text/html',
    senderName: 'Web3Mail Service',
    workerpoolAddressOrEns: 'prod-v8-learn.main.pools.iexec.eth',
  })
  console.log(`Email sent to ${owner}`)
}
Enter fullscreen mode Exit fullscreen mode

💡 Note: If you are hitting rate limits or get nonce related errors use a setTimeout to add a 1-2sec timeout between emails.

While in Development

For testing purposes, you can use a dev worker pool by setting workerpoolAddressOrEns to prod-v8-learn.main.pools.iexec.eth. This allows you to test email sending without RLC tokens.

Production Considerations

  1. Use a production worker pool for stability.
  2. Follow iExec’s guide for payment.

Validation

Verify protected data on the blockchain using iExec’s Explorer:

  1. Search for the user’s Ethereum address.
  2. View datasets under the DATASETS tab.
  3. Make sure the dataset is stored on the blockchain.

You can find more articles, written by me on my website.

Top comments (0)