XYOracleNetwork/sdk-diviner-nodejs

View on GitHub
src/payment/eth/xyo-eth-payment.ts

Summary

Maintainability
A
1 hr
Test Coverage
/* eslint-disable @typescript-eslint/no-explicit-any */
import Web3 from 'web3'
import { IXyoPaymentStore } from '..'
import ethSigUtil from 'eth-sig-util'

const erc2Contract = '0x55296f69f40ea6d20e478533c15a6b08b654e758'

export class XyoEthPaymentValidator {
  private paymentStore: IXyoPaymentStore
  private web3: Web3

  constructor(endpoint: string, paymentStore: IXyoPaymentStore) {
    this.web3 = new Web3(new Web3.providers.HttpProvider(endpoint))
    this.paymentStore = paymentStore
  }

  public async redeem(
    txHash: string,
    from: string,
    to: string,
    signature: string,
    privateApiKey: string,
    erc20ToCreditRatio: number
  ): Promise<boolean> {
    const expectedAddress = (ethSigUtil as any).recoverTypedSignature({
      data: [
        {
          type: 'string', // Any valid solidity type
          name: 'Message', // Any string label you want
          value: privateApiKey
        }
      ],
      sig: signature
    })

    if (expectedAddress.toLowerCase() === from.toLowerCase()) {
      const numberOfErc20 = await this.getAmountInTransaction(txHash, from, to)

      if (numberOfErc20 && !(await this.paymentStore.didSpend(txHash))) {
        await this.paymentStore.spent(txHash)
        const numberOfCredits =
          (await this.paymentStore.getCreditsForKey(privateApiKey)) || 0
        await this.paymentStore.setCreditsForKey(
          privateApiKey,
          numberOfCredits + erc20ToCreditRatio * numberOfErc20
        )
        return true
      }
    }

    return false
  }

  public async getAmountInTransaction(
    txHash: string,
    fromEth: string,
    toEth: string
  ): Promise<number | undefined> {
    return new Promise((resolve, reject) => {
      this.web3.eth.getTransactionReceipt(txHash, (err, transaction) => {
        if (!transaction) {
          reject('transaction is null')
          return
        }

        if (transaction.from !== fromEth) {
          reject('Invalid from ')
          return
        }

        if (transaction.to !== erc2Contract) {
          reject('Invalid contract')
          return
        }

        if (transaction.logs.length > 0) {
          const sendingTokensToWhom = transaction.logs[0].topics[2] as string

          if (
            `0x${sendingTokensToWhom.slice(26, 68)}`.toLowerCase() !==
            toEth.toLowerCase()
          ) {
            reject('Did not send to the right person')
            return
          }

          const xyoSent = this.web3.utils.fromWei(
            transaction.logs[0].data as string,
            'ether'
          )
          resolve(parseFloat(xyoSent))
          return
        }

        reject('no logs')
      })
    })
  }
}

// async function main() {
//   const end = new Eth('https://mainnet.infura.io/v3/79ea25bb01d34467a8179dbe940d5b68')
//   const b = await end.checkRedeemTransaction(
//       '',
//       '0xc0ffee314cdb6e324bdf673d10c4ad08f685b202',
//       '',
//       '0xf498e7300c03e749601e7859d8cdf283bbb488c2341a4432bb05103a1bcd97a06963f7bac1ebf55f7797af2cf6dbca879228f5f7454806a63457c07957651c041b',
//       'xyo'
// )
//   console.log(b)
//   const a = await end.getAmountInTransaction(
//       '0xd5380299a51226663dbf6711e801427c4a835a2b593a3cf24a2fe40219710d45',
//       '0x1943fca00ccad9f0c00ad73ade04bc683c9adc06',
//       '0x69696969e0cc7aed2b683214d8796c7b8796bd08')
//   console.log(a)
// }

// main()