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

GoodDollar / GoodServer / 14516752085

17 Apr 2025 01:19PM UTC coverage: 49.469%. Remained the same
14516752085

push

github

sirpy
fix: weakset not supporting strings

593 of 1477 branches covered (40.15%)

Branch coverage included in aggregate %.

1 of 6 new or added lines in 3 files covered. (16.67%)

6 existing lines in 1 file now uncovered.

1874 of 3510 relevant lines covered (53.39%)

7.37 hits per line

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

24.71
/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'
5✔
11
const multiLogger = logger.child({ from: 'MultiWallet' })
12

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

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

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

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

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

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

5✔
47
    assign(this, { walletsMap, mainWallet, defaultChainId })
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 isConnected(account) {
×
123
    // Base has no Identity contract; isConnected would fail there. Only run on wallets that have Identity.
×
124
    const walletsWithIdentity = this.wallets.filter(w => !(w instanceof BaseAdminWallet))
×
125
    const results = await Promise.all(walletsWithIdentity.map(wallet => wallet.isConnected(account)))
126
    return results.some(Boolean)
UNCOV
127
  }
×
128

129
  async lastAuthenticated(account) {
130
    return this.mainWallet.getLastAuthenticated(account)
UNCOV
131
  }
×
132

133
  async syncWhitelist(account, log = multiLogger) {
×
UNCOV
134
    try {
×
135
      const isVerified = await Promise.all(this.wallets.map(wallet => wallet.isVerified(account)))
136

137
      log.debug('syncwhitelist isVerified:', { account, isVerified })
138

UNCOV
139
      if (isEmpty(isVerified) || every(isVerified) || !some(isVerified)) {
×
140
        return false
141
      }
142

×
143
      const mainWallet = this.wallets[isVerified.findIndex(_ => _)]
1✔
144

145
      const [did, lastAuthenticated] = await Promise.all([
146
        mainWallet.getDID(account).catch(() => account),
147
        mainWallet.getLastAuthenticated(account).catch(() => 0)
5✔
148
      ])
5!
UNCOV
149
      const chainId = mainWallet.networkId
×
UNCOV
150

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

153
      await Promise.all(
154
        isVerified.map(async (status, index) => {
155
          log.debug('syncwhitelist whitelisting on wallet:', { status, index, account })
156
          if (status) {
157
            return
158
          }
159

160
          await this.wallets[index].whitelistUser(account, did, chainId, lastAuthenticated, log)
161
        })
162
      )
163

164
      return true
165
    } catch (e) {
166
      log.error('syncwhitelist failed:', e.message, e, { account })
167
      throw e
168
    }
169
  }
170

171
  async getAuthenticationPeriod() {
172
    return this.mainWallet.getAuthenticationPeriod()
173
  }
174

175
  async registerRedtent(account: string, countryCode: string, log = multiLogger) {
176
    return Promise.all(this.wallets.map(wallet => wallet.registerRedtent(account, countryCode, log)))
177
  }
178
}
179

180
let otherWallets = {}
181
if (conf.env !== 'test') {
182
  const celoWallet = new CeloAdminWallet()
183
  otherWallets = {
184
    42220: celoWallet,
185
    8453: new BaseAdminWallet({}, celoWallet),
186
    50: new XdcAdminWallet({})
187
  }
188
}
189

190
export default new MultiWallet({
191
  122: AdminWallet, // "main" wallet goes first
192
  ...otherWallets
193
})
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