import Knex from 'knex' ; import { JSONSchema , Model , Pojo , ModelOptions } from 'objection' ; import { ethers } from 'ethers' ; import { Address } from '@statechannels/wallet-core' ; import { Uint48 } from '../type-aliases' ; import { EngineError , Values } from '../errors/engine-error' ; export class Nonce extends Model { readonly id ! : number ; readonly addresses ! : Address [ ] ; readonly value ! : Uint48 ; static tableName = 'nonces' ; static get jsonSchema ( ) : JSONSchema { return { type : 'object' , required : [ 'addresses' ] , } ; } $beforeValidate ( jsonSchema , json , _opt ) { super . $beforeValidate ( jsonSchema , json , _opt ) ; const { addresses } = json ; if ( ! Array . isArray ( addresses ) ) { throw new NonceError ( NonceError . reasons . addressNotInArray , { addresses } ) ; } const notAddr = addresses . find ( addr => ! isAddress ( addr ) ) ; if ( notAddr ) throw new NonceError ( NonceError . reasons . notAnAddress , { notAddr } ) ; return json ; } static async next ( knex , addresses ) { const insertQuery = knex ( 'nonces' ) . insert ( { addresses } ) ; return knex . raw ( `
      ${ insertQuery } ON CONFLICT (addresses)
      DO UPDATE SET value = nonces.value + 1
      RETURNING value ` ) . then ( res => res . rows [ 0 ] . value ) ; } static async ensureLatest ( value , addresses , knex ) { await Nonce . fromJson ( { value , addresses } ) . use ( knex ) ; } async use ( knex ) { return await knex . raw ( `
        ${ knex ( 'nonces' ) . insert ( this ) }
        ON CONFLICT (addresses) DO UPDATE
        SET value = GREATEST(EXCLUDED.value, nonces.value)
        RETURNING value
      ` ) . then ( res => res . rows [ 0 ] . value ) ; } } class NonceError extends EngineError { readonly type = EngineError . errors . NonceError ; static readonly reasons = { addressNotInArray : 'Addresses are not an array' , notAnAddress : 'Not an address' , nonceTooLow : 'Nonce too low -- ask for a new nonce' , } as const ; constructor ( reason , public readonly data = undefined ) { super ( reason ) ; } } const isAddress = ethers . utils . isAddress ;