• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

GoodDollar / GoodServer / 18878690898

28 Oct 2025 02:46PM UTC coverage: 49.137% (-0.4%) from 49.515%
18878690898

push

github

gooddollar-techadmin
chore: release qa version 1.63.1-0 [skip build]

616 of 1530 branches covered (40.26%)

Branch coverage included in aggregate %.

1888 of 3566 relevant lines covered (52.94%)

7.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.0
/src/server/blockchain/MultiWallet.js
1
// @flow
2
import { assign, every, forOwn, isEmpty, isError, map, some } from 'lodash'
3
import AdminWallet from './AdminWallet'
4
import { CeloAdminWallet } from './CeloAdminWallet'
5
import { BaseAdminWallet } from './BaseAdminWallet'
6
import { XdcAdminWallet } from './XdcAdminWallet'
7

8
import conf from '../server.config'
9
import logger from '../../imports/logger'
10
import { DefenderRelayer } from './DefenderRelayer'
11
const multiLogger = logger.child({ from: 'MultiWallet' })
5✔
12

13
class MultiWallet {
14
  mainWallet = null
5✔
15
  otherWallets = []
5✔
16
  wallets = []
5✔
17
  walletsMap = {}
5✔
18
  defaultChainId = null
5✔
19
  signer: DefenderRelayer = null
5✔
20

21
  get ready() {
22
    return Promise.all(map(this.wallets, 'ready')).then(() => this.mainWallet.addresses)
3✔
23
  }
24

25
  constructor(walletsMap) {
26
    let mainWallet
27
    let defaultChainId
28
    this.signer = DefenderRelayer.getInstance()
5✔
29

30
    forOwn(walletsMap, (wallet, chainId) => {
5✔
31
      this.wallets.push(wallet)
5✔
32

33
      if (mainWallet) {
5!
34
        this.otherWallets.push(wallet)
×
35
      } else {
36
        mainWallet = wallet
5✔
37
        defaultChainId = chainId
5✔
38
      }
39
    })
40

41
    multiLogger.debug('MultiWallet constructor:', {
5✔
42
      wallets: Object.keys(walletsMap),
43
      mainWallet: mainWallet.networkId,
44
      otherWallets: this.otherWallets.map(_ => _.networkId)
×
45
    })
46

47
    assign(this, { walletsMap, mainWallet, defaultChainId })
5✔
48
  }
49

50
  signMessage(message: string) {
51
    return this.signer.signMessage(message)
×
52
  }
53

54
  async banInFaucet(account, chainId = 'all', log = multiLogger) {
×
55
    const runTx = wallet => wallet.banInFaucet(account, log)
×
56

57
    log.debug('MultiWallet: banInFaucet request:', { account, chainId })
×
58
    if (chainId === 'all') {
×
59
      // ban on chains that have ubi
60
      const results = await Promise.all(
×
61
        this.wallets.filter(_ => Number(_.UBIContract?._address) > 0).map(wallet => runTx(wallet).catch(e => e))
×
62
      )
63
      const error = results.find(isError)
×
64

65
      if (error) {
×
66
        throw error
×
67
      }
68

69
      return results
×
70
    }
71

72
    const { walletsMap } = this
×
73

74
    if (chainId in walletsMap) return runTx(walletsMap[chainId])
×
75

76
    throw new Error(`unsupported chain ${chainId}`)
×
77
  }
78

79
  async topWallet(account, chainId = null, log = multiLogger) {
×
80
    const runTx = wallet => wallet.topWallet(account, log)
×
81

82
    log.debug('MultiWallet: topWallet request:', { account, chainId })
×
83
    if (chainId === 'all') {
×
84
      // topwallet on chains that have ubi
85
      const results = await Promise.all(
×
86
        this.wallets.filter(_ => Number(_.UBIContract?._address) > 0).map(wallet => runTx(wallet).catch(e => e))
×
87
      )
88
      const error = results.find(isError)
×
89

90
      if (error) {
×
91
        throw error
×
92
      }
93

94
      return results
×
95
    }
96

97
    const { walletsMap } = this
×
98

99
    if (chainId in walletsMap) return runTx(walletsMap[chainId])
×
100

101
    throw new Error(`unsupported chain ${chainId}`)
×
102
  }
103

104
  async whitelistUser(account, did, chainId = null, log = multiLogger) {
×
105
    return Promise.all(this.wallets.map(wallet => wallet.whitelistUser(account, did, chainId, 0, log)))
×
106
  }
107

108
  async removeWhitelisted(account) {
109
    return Promise.all(this.wallets.map(wallet => wallet.removeWhitelisted(account)))
×
110
  }
111

112
  async verifiedStatus(account) {
113
    return Promise.all(
×
114
      this.wallets.map(wallet => wallet.isVerified(account).then(status => ({ chainId: wallet.networkId, status })))
×
115
    )
116
  }
117

118
  async isVerified(account) {
119
    return this.mainWallet.isVerified(account)
×
120
  }
121

122
  async lastAuthenticated(account) {
123
    return this.mainWallet.getLastAuthenticated(account)
×
124
  }
125

126
  async syncWhitelist(account, log = multiLogger) {
×
127
    try {
×
128
      const isVerified = await Promise.all(this.wallets.map(wallet => wallet.isVerified(account)))
×
129

130
      log.debug('syncwhitelist isVerified:', { account, isVerified })
×
131

132
      if (isEmpty(isVerified) || every(isVerified) || !some(isVerified)) {
×
133
        return false
×
134
      }
135

136
      const mainWallet = this.wallets[isVerified.findIndex(_ => _)]
×
137

138
      const [did, lastAuthenticated] = await Promise.all([
×
139
        mainWallet.getDID(account).catch(() => account),
×
140
        mainWallet.getLastAuthenticated(account).catch(() => 0)
×
141
      ])
142
      const chainId = mainWallet.networkId
×
143

144
      log.debug('syncwhitelist did:', { account, did, lastAuthenticated, chainId })
×
145

146
      await Promise.all(
×
147
        isVerified.map(async (status, index) => {
148
          log.debug('syncwhitelist whitelisting on wallet:', { status, index, account })
×
149
          if (status) {
×
150
            return
×
151
          }
152

153
          await this.wallets[index].whitelistUser(account, did, chainId, lastAuthenticated, log)
×
154
        })
155
      )
156

157
      return true
×
158
    } catch (e) {
159
      log.error('syncwhitelist failed:', e.message, e, { account })
×
160
      throw e
×
161
    }
162
  }
163

164
  async getAuthenticationPeriod() {
165
    return this.mainWallet.getAuthenticationPeriod()
×
166
  }
167

168
  async registerRedtent(account: string, countryCode: string, log = multiLogger) {
×
169
    return Promise.all(this.wallets.map(wallet => wallet.registerRedtent(account, countryCode, log)))
1✔
170
  }
171
}
172

173
let otherWallets = {}
5✔
174
if (conf.env !== 'test') {
5!
175
  const celoWallet = new CeloAdminWallet()
×
176
  otherWallets = {
×
177
    42220: celoWallet,
178
    8453: new BaseAdminWallet({}, celoWallet),
179
    50: new XdcAdminWallet({})
180
  }
181
}
182

183
export default new MultiWallet({
184
  122: AdminWallet, // "main" wallet goes first
185
  ...otherWallets
186
})
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc