0.2.2 • Published 1 month ago

@relicprotocol/client v0.2.2

Weekly downloads
-
License
MIT
Repository
github
Last release
1 month ago

Relic Client SDK

The client SDK is designed to simplify fetching proofs from the Relic Prover and generating transaction data to be submitted on-chain for verification.

Relic Architecture Overview

Usage

Initializing RelicClient requires passing an ethers Provider. Providers can be created with an RPC url or by connecting to Metamask or another wallet extension.

import { AccountNotFound, RelicClient, utils, InfoType } from '@relicprotocol/client'
import { ethers } from 'ethers'

async function main() {
  // Note: you could also get the provider from a browser wallet extension
  const provider = new ethers.providers.JsonRpcProvider('[RPC URL here]')
  const signer = await provider.getSigner()

  const relic = await RelicClient.fromProvider(provider)

  // prove an account's birth certificate
  const account = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' // vitalik.eth
  const bcTx = await relic.birthCertificateProver.prove({ account })
  console.log(await provider.estimateGas(bcTx))

  // use the transaction data...
  // to send the proof transaction as is:
  // let tx = await signer.sendTransaction(bcTx)
  // await tx.wait()

  // prove an account's code hash
  // note: other account data fields can be proven by changing the |info| param
  const aiTx = await relic.accountInfoProver.prove(
      { block, account, info: InfoType.CodeHash }
  )
  // use the transaction data...
  console.log(await provider.estimateGas(aiTx)

  // prove a storage slot's value, in this case WETH.balanceOf(account)
  const blockNum = 15000000
  const wethAddr = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' // WETH
  const slot = utils.mapElemSlot(3, account) // calculate balanceOf(account) slot

  // you can optionally specify the expected slot value, to ensure the slot is correct
  // we'll compute this by calling balanceOf(account) at the target block
  const contract = new ethers.Contract(
    wethAddr,
    ['function balanceOf(address) external view returns (uint256)'],
    provider
  )
  const expected = await contract.balanceOf(account, { blockTag: blockNum })

  // expected is optional parameter
  const ssTx = await relic.storageSlotProver.prove({
    block: blockNum,
    account: wethAddr,
    slot,
    expected,
  })

  // use the transaction data...
  console.log(await provider.estimateGas(ssTx))

  // You can also prove multiple storage slots in one call to save gas
  const ZERO_ADDR = '0x' + '0'.repeat(40)
  const slot2 = utils.mapElemSlot(3, ZERO_ADDR) // calculate balanceOf(0x000..00) slot
  const expected2 = await contract.balanceOf(ZERO_ADDR, { blockTag: blockNum })

  // prove two storage slots from the same account simultaneously
  const mssTx = await relic.multiStorageSlotProver.prove({
    block: blockNum,
    account: wethAddr,
    slots: [slot, slot2],
    expected: [expected, expected2],
  })

  // use the transaction data...
  console.log(await provider.estimateGas(mssTx))

  // prove the storage root an account in a particular block,
  // potentially making slot proofs in that block much cheaper
  const asTx = await relic.accountStorageProver.prove({
    block: 15000000,
    account: wethAddr,
  })
  console.log(await provider.estimateGas(asTx))

  // once the above transaction is confirmed, you can use cheap cached storage
  // slot proofs for that (account, block)
  const cssTx = await relic.cachedStorageSlotProver.prove({
    block: blockNum,
    account: wethAddr,
    slot,
    expected,
  })
  // use the transaction data...
  console.log(await provider.estimateGas(cssTx))

  // Now let's prove some ephemeral facts; a block header proof and a log proof
  // NOTE: you probably don't want to prove these facts without using proveEphemeral,
  // because storing these large facts on-chain costs a lot of gas

  // Your contract which implements IRelicReceiver
  // Consider using the RelicReceiver base contract in the solidity SDK
  const receiver = '0x...'

  // prove a historical block header is valid
  const bhTx = await relic.blockHeaderProver.proveEphemeral(
    {
      initiator: await signer.getAddress(),
      receiver,
      gasLimit: 50000, // 50000 gas is enough for our receiver callback, be sure to check yours!
    },
    { block: 15000000 }
  )
  console.log(await signer.estimateGas(bhTx))

  // get BAYC mint events
  // NOTE: this may be very slow if your RPC provider doesn't index logs well
  const logs = await provider.getLogs({
    address: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D', // BAYC contract
    topics: [
      '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // Transfer event
      '0x0000000000000000000000000000000000000000000000000000000000000000', // from == address(0)
    ],
    fromBlock: 0,
  })

  // prove the first BAYC mint log
  const logTx = await relic.logProver.proveEphemeral(
    {
      initiator: await signer.getAddress(),
      receiver,
      gasLimit: 50000,
    },
    logs[0]
  )

  // use the transaction data...
  console.log(await signer.estimateGas(logTx))

  // prove the first withdrawal
  const withdrawalTx = await relic.withdrawalProver.prove({
    block: 17034871,
    idx: 0,
  })
  // use the transaction data...
  console.log(await signer.estimateGas(withdrawalTx))

  // prove a transaction was included
  const receipt = await provider.getTransactionReceipt(logs[0].transactionHash)
  const txTx = await relic.transactionProver.prove(receipt)

  // use the transaction data...
  console.log(await signer.estimateGas(txTx))

  // prove a beacon chain withdrawal occured
  const withdrawalTx = await relic.withdrawalProver.prove(
      { block: 17034871, idx: 0 } // first withdrawal in the first shapella block
  )
  // use the transaction data...
  console.log(await signer.estimateGas(withdrawalTx))


  // demonstrate error handling
  try {
    const randomAddr = ethers.utils.hexlify(ethers.utils.randomBytes(20))
    await relic.birthCertificateProver.prove({ account: randomAddr })
  } catch (error: any) {
    if (!(error instanceof AccountNotFound)) throw error
    // handle account not found
  }
}

main()
0.2.2

1 month ago

0.2.1

2 months ago

0.2.0

2 months ago

0.1.2

4 months ago

0.1.1

4 months ago

0.1.0

10 months ago

0.0.10

1 year ago

0.0.9

1 year ago

0.0.8

1 year ago

0.0.5

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.4

1 year ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago