UNPKG

@nitin-spheron/desub-js

Version:

Typescript library for working with the decentralised subscription contracts in Spheron

835 lines (728 loc) 30 kB
import 'mocha' import Vendor from '../vendors/ethers' import { JsonRpcProvider, TransactionReceipt } from '@ethersproject/providers' import { Wallet } from '@ethersproject/wallet' import { Contract, SubscriptionParameters, TokenData, TxResponse } from '../interfaces' import * as dotenv from 'dotenv' import { Subscription } from '..' import { cloneWithWriteAccess } from '../helpers' import { assert } from 'chai' import { stub } from 'sinon' import { BigNumber } from 'ethers' import cloneDeep from 'lodash.clonedeep' describe('subscriptions methods', () => { let subscription: Subscription let vendor: Vendor let biconomyKey: any beforeEach(async () => { dotenv.config() biconomyKey = process.env.BICONOMY_KEY const url = process.env.RPC_ENDPOINT const httpProvider = new JsonRpcProvider(url) const mnemonic: any = process.env.MNEMONIC_TEST const signer = Wallet.fromMnemonic(mnemonic).connect(httpProvider) vendor = new Vendor(httpProvider, signer, biconomyKey) subscription = new Subscription(vendor) await subscription.subscriptionAt( '0x07A07C4a107B8Bd2fCeC6B595AAA0F20296a8fD1', '0x069ca3a23bc4B75E9700E34657370A6A1178E1F3', '0x6794a9E5411f8f9B3E5Dc7457162728544A443E0', 18, ) }) it('it should charege user', async () => { // allow stubbing contract properties subscription.subscriptionPaymentContract = cloneWithWriteAccess(subscription.subscriptionPaymentContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionPaymentContract ? subscription.subscriptionPaymentContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'chargeUser') fake.resolves({ hash: '0xhash' }) const address = '0x123' const params: Array<SubscriptionParameters> = [{ param: 'ABC', value: 10 }] const result: TxResponse = await subscription.chargeUser(address, params, address) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const paramArray: Array<string> = [] const paramValue: Array<number> = [] for (let i = 0; i < params.length; i++) { paramArray.push(params[i].param) paramValue.push(vendor.convertToBN(params[i].value.toString())) } const { args } = fake.getCall(0) assert.deepEqual(args[0], address) assert.deepEqual(args[1], paramArray) assert.deepEqual(args[2], paramValue) assert.deepEqual(args[3], address) }) it('it should update params', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'updateParams') fake.resolves({ hash: '0xhash' }) const params: Array<SubscriptionParameters> = [{ param: 'ABC', value: 10 }] const result: TxResponse = await subscription.upadteParams(params) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const paramArray: Array<string> = [] const paramValue: Array<number> = [] for (let i = 0; i < params.length; i++) { paramArray.push(params[i].param) paramValue.push(vendor.convertToBN(params[i].value.toString())) } const { args } = fake.getCall(0) assert.deepEqual(args[0], paramArray) assert.deepEqual(args[1], paramValue) }) it('it should delete params', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'deleteParams') fake.resolves({ hash: '0xhash' }) const params: Array<string> = ['ABC'] const result: TxResponse = await subscription.deleteParams(params) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.deepEqual(args[0], params) }) it('it should pass correct escrow address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'updateEscrow') fake.resolves({ hash: '0xhash' }) const addr = '0x1abc' const result: TxResponse = await subscription.updateEscrow(addr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], addr) }) it('it should pass correct escrow address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'changeUsdPrecision') fake.resolves({ hash: '0xhash' }) const decimals = BigNumber.from(18) const result: TxResponse = await subscription.changeUsdPrecision(18) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.deepEqual(args[0], decimals) }) it('it should pass correct address for removing token', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'removeTokens') fake.resolves({ hash: '0xhash' }) const tokens = ['0x123', '0xabc'] const result: TxResponse = await subscription.removeTokens(tokens) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.deepEqual(args[0], tokens) }) it('it should pass correct data for adding tokens', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'addNewTokens') fake.resolves({ hash: '0xhash' }) const data: Array<TokenData> = [ { address: '0x123', decimals: 18, priceFeedPrecision: 18, priceFeedAddress: '0xabc', symobl: 'ARGO', isChainLinkFeed: false, }, ] const result: TxResponse = await subscription.addTokens(data) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const symbols: Array<string> = ['ARGO'] const tokenAddresses: Array<string> = ['0x123'] const tokenDecimals: Array<any> = [vendor.convertToBN('18')] const chainLinkBools: Array<boolean> = [false] const priceFeedAddresses: Array<string> = ['0xabc'] const priceFeedPrecisions: Array<any> = [vendor.convertToBN('18')] const { args } = fake.getCall(0) assert.deepEqual(args[0], symbols) assert.deepEqual(args[1], tokenAddresses) assert.deepEqual(args[2], tokenDecimals) assert.deepEqual(args[3], chainLinkBools) assert.deepEqual(args[4], priceFeedAddresses) assert.deepEqual(args[5], priceFeedPrecisions) }) it('it should pass data contract address', async () => { // allow stubbing contract properties subscription.subscriptionPaymentContract = cloneWithWriteAccess(subscription.subscriptionPaymentContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionPaymentContract ? subscription.subscriptionPaymentContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'updateDataContract') fake.resolves({ hash: '0xhash' }) const addr = '0x1abc' const result: TxResponse = await subscription.setDataContract(addr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], addr) }) it('it should pass correct staked token address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'updateStakedToken') fake.resolves({ hash: '0xhash' }) const addr = '0x1abc' const result: TxResponse = await subscription.updateStakedToken(addr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], addr) }) it('it should pass correct slabs array', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'updateDiscountSlabs') fake.resolves({ hash: '0xhash' }) const discountSlabs = ['1200', '1300', '1400'] const percents = ['12', '13', '14'] const result: TxResponse = await subscription.updateDiscountSlabs(discountSlabs, percents) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.deepEqual(args[0], vendor.convertStringArrayToBigNumberArray(discountSlabs)) assert.deepEqual(args[1], vendor.convertStringArrayToBigNumberArray(percents)) }) it('it should pass correct staking address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'enableDiscounts') fake.resolves({ hash: '0xhash' }) const stakingAddr = '0xabc' const result: TxResponse = await subscription.enableDiscounts(stakingAddr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], stakingAddr) }) it('it should return hash', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'disableDiscounts') fake.resolves({ hash: '0xhash' }) const result: TxResponse = await subscription.disableDiscounts() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') }) it('it should pass correct address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'setGovernanceAddress') fake.resolves({ hash: '0xhash' }) const addr = '0xabc' const result: TxResponse = await subscription.setGovernanceAddress(addr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], addr) }) it('it should pass correct array of address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'setManagers') fake.resolves({ hash: '0xhash' }) const arr = ['0x1bw', '0xasb'] const result: TxResponse = await subscription.setManagers(arr) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.deepEqual(args[0], arr) }) it('it should pass correct array of address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'approve') fake.resolves({ hash: '0xhash' }) const amount = '12' const result: TxResponse = await subscription.setNewApprovals(amount) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0xhash') const { args } = fake.getCall(0) assert.equal(args[0], subscription.subscriptionPaymentContract?.address) assert.deepEqual(args[1], vendor.convertToWei(amount, 18)) }) it('it should get correct approval amount', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'allowance') fake.resolves(vendor.convertToBN('1000000000000000000000000')) const arg1 = '0x123' const result: any = await subscription.getApprovalAmount(arg1) assert(fake.calledOnce) assert.isNotNull(result) assert.deepEqual(result, vendor.convertWeiToEth(vendor.convertToBN('1000000000000000000000000'), 18)) const { args } = fake.getCall(0) assert.equal(args[0], arg1) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion assert.equal(args[1], subscription.subscriptionPaymentContract!.address) }) it('it should get correct balance of user', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'balanceOf') fake.resolves(vendor.convertToBN('1000000000000000000000000')) const arg1 = '0x123' const result: any = await subscription.getUserBalance(arg1) assert(fake.calledOnce) assert.isNotNull(result) assert.deepEqual(result, vendor.convertWeiToEth(vendor.convertToBN('1000000000000000000000000'), 18)) const { args } = fake.getCall(0) assert.equal(args[0], arg1) }) it('it should give correct address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'getManagers') fake.resolves('0x123') const result = await subscription.getManagers() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, ['0x123']) }) it('it should give correct governance address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'governanceAddress') fake.resolves('0x123') const result = await subscription.getGovernanceAddress() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, '0x123') }) it('it should give correct escrow address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'escrow') fake.resolves('0x123') const result = await subscription.getEscrow() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, '0x123') }) it('it should give correct discount status', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'discountsEnabled') fake.resolves(true) const result = await subscription.checkIfDiscountsEnabled() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, true) }) it('it should give correct staking manager address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'stakingManager') fake.resolves('0x123') const result = await subscription.getStakingManagerAddress() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, '0x123') }) it('it should give correct staked token address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'stakedToken') fake.resolves('0x123') const result = await subscription.getStakedTokenAddress() assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result, '0x123') }) it('it should give correct staked token address', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'usdPricePrecision') fake.resolves(BigNumber.from(18)) const result = await subscription.getUsdPricePrecision() assert(fake.calledOnce) assert.isNotNull(result) assert.deepEqual(result, BigNumber.from(18)) }) it('it should give correct staking manager address', async () => { // allow stubbing contract properties subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const user = '0x123' const fake = stub(contract.functions, 'getNonce') fake.resolves([BigNumber.from(0)]) const result = await subscription.getNonceForGaslessERC20(user) assert(fake.calledOnce) assert.isNotNull(result) const { args } = fake.getCall(0) assert.equal(args[0], user) assert.equal(result, [BigNumber.from(0)][0].toNumber()) }) it('it should give correct discount slabs', async () => { // allow stubbing contract properties subscription.subscriptionDataContract = cloneWithWriteAccess(subscription.subscriptionDataContract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.subscriptionDataContract ? subscription.subscriptionDataContract : invalidContract assert.isNotNull(contract) assert.notDeepEqual(contract, invalidContract) const fake = stub(contract.functions, 'discountSlabs') fake.resolves([ { amount: vendor.convertToBN('10'), percent: vendor.convertToBN('10') }, { amount: vendor.convertToBN('11'), percent: vendor.convertToBN('11') }, ]) const result = await subscription.getDiscountSlabs() assert(fake.calledOnce) assert.isNotNull(result) assert.deepEqual( result, vendor.parseDiscountSlabs([ { amount: vendor.convertToBN('10'), percent: vendor.convertToBN('10') }, { amount: vendor.convertToBN('11'), percent: vendor.convertToBN('11') }, ]), ) }) it('it should pass correct values for gassless transaction', async () => { subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const contract: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract const fakeNonce = stub(contract.functions, 'getNonce') fakeNonce.resolves([BigNumber.from(0)]) const fake = stub(subscription, 'sendRawBiconomyERC20Transaction') fake.resolves({ hash: '0x123', confirmations: 0, from: '0x123', to: '0x123', gasLimit: BigNumber.from(0), gasPrice: BigNumber.from(0), nonce: 0, data: 'Ad', value: BigNumber.from(0), chainId: 0, // eslint-disable-next-line @typescript-eslint/no-empty-function wait: () => new Promise<TransactionReceipt>(() => {}), }) const chainID = 80001 const wei = vendor.convertToWei('10', 18) const abiEncodedApprove = vendor.abiEncodeErc20Functions('approve', [ subscription.subscriptionPaymentContract?.address, wei, ]) const userAddress = await vendor.signer.getAddress() const nonce = await subscription.getNonceForGaslessERC20(userAddress) const signedMessage = await vendor.signedMessageForTx( userAddress, nonce, abiEncodedApprove, subscription.erc20Contract?.address || '0x', chainID, ) const rsv = vendor.getSignatureParameters(signedMessage) const result: TxResponse = await subscription.gasslessApproval('10', chainID) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0x123') const { args } = fake.getCall(0) assert.deepEqual(args[0], userAddress) assert.deepEqual(args[1], abiEncodedApprove) assert.deepEqual(args[2], rsv) }) it('it should pass correct values for meta transaction', async () => { subscription.erc20Contract = cloneWithWriteAccess(subscription.erc20Contract) subscription.biconomyERC20Contract = cloneDeep(subscription.biconomyERC20Contract) const invalidContract = { address: '0xinvalid', functions: {}, } const erc20: Contract = subscription.erc20Contract ? subscription.erc20Contract : invalidContract const contract: Contract = subscription.biconomyERC20Contract ? subscription.biconomyERC20Contract : invalidContract const fakeNonce = stub(erc20.functions, 'getNonce') fakeNonce.resolves([BigNumber.from(0)]) const fake = stub(contract.functions, 'executeMetaTransaction') fake.resolves({ hash: '0x123', confirmations: 0, from: '0x123', to: '0x123', gasLimit: BigNumber.from(0), gasPrice: BigNumber.from(0), nonce: 0, data: 'Ad', value: BigNumber.from(0), chainId: 0, wait: () => new Promise<TransactionReceipt>(() => { return undefined }), }) const chainID = 80001 const wei = vendor.convertToWei('10', 18) const abiEncodedApprove = vendor.abiEncodeErc20Functions('approve', [ subscription.subscriptionPaymentContract?.address, wei, ]) const userAddress = await vendor.signer.getAddress() const nonce = await subscription.getNonceForGaslessERC20(userAddress) const signedMessage = await vendor.signedMessageForTx( userAddress, nonce, abiEncodedApprove, subscription.biconomyERC20Contract?.address || '0x', chainID, ) const rsv = vendor.getSignatureParameters(signedMessage) const result: TxResponse = await subscription.gasslessApproval('10', chainID) assert(fake.calledOnce) assert.isNotNull(result) assert.equal(result.hash, '0x123') const { args } = fake.getCall(0) assert.deepEqual(args[0], userAddress) assert.deepEqual(args[1], abiEncodedApprove) assert.deepEqual(args[2], rsv.r) assert.deepEqual(args[3], rsv.s) assert.deepEqual(args[4], rsv.v) }).timeout(50000) })