mirror of
https://github.com/Cameri/nostream.git
synced 2025-05-30 17:49:10 +02:00
feat: allow lightning zap receipts on paid relays (#303)
* chore: add event_kinds whitelist for fee schedules * chore: fix identation in default-settings.yml * chore: waive admission fee for specific event kinds * docs: add payment settings to CONFIGURATION.md * docs: improve read replica docs
This commit is contained in:
parent
565f67c5f6
commit
14bc96f516
@ -20,14 +20,31 @@ The following environment variables can be set:
|
||||
| DB_MAX_POOL_SIZE | Max. connections per worker | 32 |
|
||||
| DB_ACQUIRE_CONNECTION_TIMEOUT | New connection timeout (ms) | 60000 |
|
||||
| READ_REPLICA_ENABLED | Read Replica (RR) Toggle | 'false' |
|
||||
| RR_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||
| RR_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||
| RR_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||
| RR_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||
| RR_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||
| RR_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||
| RR_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||
| RR_DB_ACQUIRE_CONNECTION_TIMEOUT | New connection timeout (ms) (RR) | 60000 |
|
||||
| READ_REPLICAS | Number of read replicas (RR0, RR1, ..., RRn) | 2 |
|
||||
| RR0_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||
| RR0_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||
| RR0_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||
| RR0_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||
| RR0_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||
| RR0_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||
| RR0_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||
| RR0_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||
| RR1_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||
| RR1_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||
| RR1_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||
| RR1_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||
| RR1_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||
| RR1_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||
| RR1_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||
| RR1_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||
| RRn_DB_HOST | PostgresSQL Hostname (RR) | |
|
||||
| RRn_DB_PORT | PostgreSQL Port (RR) | 5432 |
|
||||
| RRn_DB_USER | PostgreSQL Username (RR) | nostr_ts_relay |
|
||||
| RRn_DB_PASSWORD | PostgreSQL Password (RR) | nostr_ts_relay |
|
||||
| RRn_DB_NAME | PostgreSQL Database name (RR) | nostr_ts_relay |
|
||||
| RRn_DB_MIN_POOL_SIZE | Min. connections per worker (RR) | 16 |
|
||||
| RRn_DB_MAX_POOL_SIZE | Max. connections per worker (RR) | 32 |
|
||||
| RRn_DB_ACQUIRE_CONNECTION_TIMEOUT| New connection timeout (ms) (RR) | 60000 |
|
||||
| TOR_HOST | Tor Hostname | |
|
||||
| TOR_CONTROL_PORT | Tor control Port | 9051 |
|
||||
| TOR_PASSWORD | Tor control password | nostr_ts_relay |
|
||||
@ -41,6 +58,8 @@ The following environment variables can be set:
|
||||
| DEBUG | Debugging filter | |
|
||||
| ZEBEDEE_API_KEY | Zebedee Project API Key | |
|
||||
|
||||
If you've set READ_REPLICAS to 4, you should configure RR0_ through RR3_.
|
||||
|
||||
# Settings
|
||||
|
||||
Running `nostream` for the first time creates the settings file in `<project_root>/.nostr/settings.yaml`. If the file is not created and an error is thrown ensure that the `<project_root>/.nostr` folder exists. The configuration directory can be changed by setting the `NOSTR_CONFIG_DIR` environment variable.
|
||||
@ -54,6 +73,18 @@ Running `nostream` for the first time creates the settings file in `<project_roo
|
||||
| info.contact | Relay operator's contact. (e.g. mailto:operator@relay-your-domain.com) |
|
||||
| network.maxPayloadSize | Maximum number of bytes accepted per WebSocket frame |
|
||||
| network.remoteIpHeader | HTTP header from proxy containing IP address from client. |
|
||||
| payments.enabled | Enabled payments. Defaults to false. |
|
||||
| payments.processor | Either `zebedee`, `lnbits`, `lnurl`. |
|
||||
| payments.feeSchedules.admission[].enabled | Enables admission fee. Defaults to false. |
|
||||
| payments.feeSchedules.admission[].amount | Admission fee amount in msats. |
|
||||
| payments.feeSchedules.admission[].whitelists.pubkeys | List of pubkeys to waive admission fee. |
|
||||
| payments.feeSchedules.admission[].whitelists.event_kinds | List of event kinds to waive admission fee. Use `[min, max]` for ranges. |
|
||||
| paymentProcessors.zebedee.baseURL | Zebedee's API base URL. |
|
||||
| paymentProcessors.zebedee.callbackBaseURL | Public-facing Nostream's Zebedee Callback URL (e.g. https://relay.your-domain.com/callbacks/zebedee) |
|
||||
| paymentProcessors.zebedee.ipWhitelist | List with Zebedee's API Production IPs. See [ZBD API Documentation](https://api-reference.zebedee.io/#c7e18276-6935-4cca-89ae-ad949efe9a6a) for more info. |
|
||||
| paymentProcessors.lnbits.baseURL | Base URL of your Lnbits instance. |
|
||||
| paymentProcessors.lnbits.callbackBaseURL | Public-facing Nostream's Lnbits Callback URL. (e.g. https://relay.your-domain.com/callbacks/lnbits) |
|
||||
| paymentProcessors.lnurl.invoiceURL | [LUD-06 Pay Request](https://github.com/lnurl/luds/blob/luds/06.md) provider URL. (e.g. https://getalby.com/lnurlp/your-username) |
|
||||
| mirroring.static[].address | Address of mirrored relay. (e.g. ws://100.100.100.100:8008) |
|
||||
| mirroring.static[].filters | Subscription filters used to mirror. |
|
||||
| mirroring.static[].secret | Secret to pass to relays. Nostream relays only. Optional. |
|
||||
|
@ -16,7 +16,7 @@ services:
|
||||
DB_MAX_POOL_SIZE: 64
|
||||
DB_ACQUIRE_CONNECTION_TIMEOUT: 60000
|
||||
# Read Replica
|
||||
READ_REPLICAS: 1
|
||||
READ_REPLICAS: 2
|
||||
READ_REPLICA_ENABLED: 'false'
|
||||
# Read Replica No. 1
|
||||
RR0_DB_HOST: db
|
||||
@ -36,6 +36,7 @@ services:
|
||||
RR1_DB_MIN_POOL_SIZE: 16
|
||||
RR1_DB_MAX_POOL_SIZE: 64
|
||||
RR1_DB_ACQUIRE_CONNECTION_TIMEOUT: 10000
|
||||
# Add RR2, RR3, etc. to configure more read replicas
|
||||
# Redis
|
||||
REDIS_HOST: nostream-cache
|
||||
REDIS_PORT: 6379
|
||||
|
@ -9,15 +9,14 @@ payments:
|
||||
processor: zebedee
|
||||
feeSchedules:
|
||||
admission:
|
||||
- enabled: false
|
||||
description: Admission fee charged per public key in msats (1000 msats = 1 satoshi)
|
||||
amount: 1000000
|
||||
whitelists:
|
||||
pubkeys:
|
||||
- replace-with-your-pubkey-in-hex
|
||||
# Allow the following Zap providers:
|
||||
# LightningTipBot by Calle
|
||||
- "fcd720c38d9ee337188f47aac845dcd8f590ccdb4a928b76dde18187b4c9d37d"
|
||||
- enabled: false
|
||||
description: Admission fee charged per public key in msats (1000 msats = 1 satoshi)
|
||||
amount: 1000000
|
||||
whitelists:
|
||||
pubkeys:
|
||||
- replace-with-your-pubkey-in-hex
|
||||
event_kinds:
|
||||
- 9735 # Nip-57 Lightning Zap Receipts
|
||||
paymentsProcessors:
|
||||
zebedee:
|
||||
baseURL: https://api.zebedee.io/
|
||||
@ -43,24 +42,24 @@ mirroring:
|
||||
limits:
|
||||
invoice:
|
||||
rateLimits:
|
||||
- period: 60000
|
||||
rate: 12
|
||||
- period: 3600000
|
||||
rate: 30
|
||||
- period: 60000
|
||||
rate: 12
|
||||
- period: 3600000
|
||||
rate: 30
|
||||
ipWhitelist:
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
connection:
|
||||
rateLimits:
|
||||
- period: 1000
|
||||
rate: 12
|
||||
- period: 60000
|
||||
rate: 48
|
||||
- period: 1000
|
||||
rate: 12
|
||||
- period: 60000
|
||||
rate: 48
|
||||
ipWhitelist:
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
event:
|
||||
eventId:
|
||||
minLeadingZeroBits: 0
|
||||
@ -76,69 +75,69 @@ limits:
|
||||
maxPositiveDelta: 900
|
||||
maxNegativeDelta: 0
|
||||
content:
|
||||
- description: 64 KB for event kind ranges 0-10 and 40-49
|
||||
kinds:
|
||||
- - 0
|
||||
- 10
|
||||
- - 40
|
||||
- 49
|
||||
maxLength: 102400
|
||||
- description: 96 KB for event kind ranges 11-39 and 50-max
|
||||
kinds:
|
||||
- - 11
|
||||
- 39
|
||||
- - 50
|
||||
- 9007199254740991
|
||||
maxLength: 102400
|
||||
- description: 64 KB for event kind ranges 0-10 and 40-49
|
||||
maxLength: 102400
|
||||
kinds:
|
||||
- - 0
|
||||
- 10
|
||||
- - 40
|
||||
- 49
|
||||
- description: 96 KB for event kind ranges 11-39 and 50-max
|
||||
maxLength: 102400
|
||||
kinds:
|
||||
- - 11
|
||||
- 39
|
||||
- - 50
|
||||
- 9007199254740991
|
||||
rateLimits:
|
||||
- description: 6 events/min for event kinds 0, 3, 40 and 41
|
||||
kinds:
|
||||
- 0
|
||||
- 3
|
||||
- 40
|
||||
- 41
|
||||
period: 60000
|
||||
rate: 6
|
||||
- description: 12 events/min for event kinds 1, 2, 4 and 42
|
||||
kinds:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
- 42
|
||||
period: 60000
|
||||
rate: 12
|
||||
- description: 30 events/min for event kind ranges 5-7 and 43-49
|
||||
kinds:
|
||||
- - 5
|
||||
- 7
|
||||
- - 43
|
||||
- 49
|
||||
period: 60000
|
||||
rate: 30
|
||||
- description: 24 events/min for replaceable events and parameterized replaceable
|
||||
events
|
||||
kinds:
|
||||
- - 10000
|
||||
- 19999
|
||||
- - 30000
|
||||
- 39999
|
||||
period: 60000
|
||||
rate: 24
|
||||
- description: 60 events/min for ephemeral events
|
||||
kinds:
|
||||
- - 20000
|
||||
- 29999
|
||||
period: 60000
|
||||
rate: 60
|
||||
- description: 720 events/hour for all events
|
||||
period: 3600000
|
||||
rate: 720
|
||||
- description: 6 events/min for event kinds 0, 3, 40 and 41
|
||||
kinds:
|
||||
- 0
|
||||
- 3
|
||||
- 40
|
||||
- 41
|
||||
period: 60000
|
||||
rate: 6
|
||||
- description: 12 events/min for event kinds 1, 2, 4 and 42
|
||||
kinds:
|
||||
- 1
|
||||
- 2
|
||||
- 4
|
||||
- 42
|
||||
period: 60000
|
||||
rate: 12
|
||||
- description: 30 events/min for event kind ranges 5-7 and 43-49
|
||||
kinds:
|
||||
- - 5
|
||||
- 7
|
||||
- - 43
|
||||
- 49
|
||||
period: 60000
|
||||
rate: 30
|
||||
- description: 24 events/min for replaceable events and parameterized replaceable
|
||||
events
|
||||
kinds:
|
||||
- - 10000
|
||||
- 19999
|
||||
- - 30000
|
||||
- 39999
|
||||
period: 60000
|
||||
rate: 24
|
||||
- description: 60 events/min for ephemeral events
|
||||
kinds:
|
||||
- - 20000
|
||||
- 29999
|
||||
period: 60000
|
||||
rate: 60
|
||||
- description: 720 events/hour for all events
|
||||
period: 3600000
|
||||
rate: 720
|
||||
whitelists:
|
||||
pubkeys: []
|
||||
ipAddresses:
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
client:
|
||||
subscription:
|
||||
maxSubscriptions: 10
|
||||
@ -149,10 +148,10 @@ limits:
|
||||
minPrefixLength: 4
|
||||
message:
|
||||
rateLimits:
|
||||
- description: 240 raw messages/min
|
||||
period: 60000
|
||||
rate: 240
|
||||
- description: 240 raw messages/min
|
||||
period: 60000
|
||||
rate: 240
|
||||
ipWhitelist:
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
- "::1"
|
||||
- "10.10.10.1"
|
||||
- "::ffff:10.10.10.1"
|
||||
|
@ -126,6 +126,7 @@ export interface Worker {
|
||||
|
||||
export interface FeeScheduleWhitelists {
|
||||
pubkeys?: Pubkey[]
|
||||
event_kinds?: (EventKinds | [EventKinds, EventKinds])[]
|
||||
}
|
||||
|
||||
export interface FeeSchedule {
|
||||
|
@ -5,6 +5,7 @@ export enum EventKinds {
|
||||
CONTACT_LIST = 3,
|
||||
ENCRYPTED_DIRECT_MESSAGE = 4,
|
||||
DELETE = 5,
|
||||
REPOST = 6,
|
||||
REACTION = 7,
|
||||
// Channels
|
||||
CHANNEL_CREATION = 40,
|
||||
@ -17,6 +18,9 @@ export enum EventKinds {
|
||||
// Relay-only
|
||||
RELAY_INVITE = 50,
|
||||
INVOICE_UPDATE = 402,
|
||||
// Lightning zaps
|
||||
ZAP_REQUEST = 9734,
|
||||
ZAP_RECEIPT = 9735,
|
||||
// Replaceable events
|
||||
REPLACEABLE_FIRST = 10000,
|
||||
REPLACEABLE_LAST = 19999,
|
||||
|
@ -268,6 +268,7 @@ export class EventMessageHandler implements IMessageHandler {
|
||||
const isApplicableFee = (feeSchedule: FeeSchedule) =>
|
||||
feeSchedule.enabled
|
||||
&& !feeSchedule.whitelists?.pubkeys?.some((prefix) => event.pubkey.startsWith(prefix))
|
||||
&& !feeSchedule.whitelists?.event_kinds?.some(isEventKindOrRangeMatch(event))
|
||||
|
||||
const feeSchedules = currentSettings.payments?.feeSchedules?.admission?.filter(isApplicableFee)
|
||||
if (!Array.isArray(feeSchedules) || !feeSchedules.length) {
|
||||
|
@ -585,7 +585,7 @@ describe('EventMessageHandler', () => {
|
||||
|
||||
it('returns undefined if kind is not blacklisted in range', () => {
|
||||
eventLimits.kind.blacklist = [[1, 5]]
|
||||
event.kind = 6
|
||||
event.kind = EventKinds.REACTION
|
||||
expect(
|
||||
(handler as any).canAcceptEvent(event)
|
||||
).to.be.undefined
|
||||
@ -652,10 +652,10 @@ describe('EventMessageHandler', () => {
|
||||
|
||||
it('returns reason if kind is not whitelisted in range', () => {
|
||||
eventLimits.kind.whitelist = [[1, 5]]
|
||||
event.kind = 6
|
||||
event.kind = EventKinds.REACTION
|
||||
expect(
|
||||
(handler as any).canAcceptEvent(event)
|
||||
).to.equal('blocked: event kind 6 not allowed')
|
||||
).to.equal('blocked: event kind 7 not allowed')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -867,11 +867,6 @@ describe('EventMessageHandler', () => {
|
||||
period: 60000,
|
||||
rate: 2,
|
||||
},
|
||||
{
|
||||
kinds: [[10, 20]],
|
||||
period: 86400000,
|
||||
rate: 3,
|
||||
},
|
||||
]
|
||||
|
||||
rateLimiterHitStub.resolves(false)
|
||||
@ -931,4 +926,167 @@ describe('EventMessageHandler', () => {
|
||||
expect(actualResult).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('isUserAdmitted', () => {
|
||||
let settings: Settings
|
||||
let userRepository: IUserRepository
|
||||
let getClientAddressStub: SinonStub
|
||||
let webSocket: IWebSocketAdapter
|
||||
let getRelayPublicKeyStub: SinonStub
|
||||
let userRepositoryFindByPubkeyStub: SinonStub
|
||||
|
||||
beforeEach(() => {
|
||||
settings = {
|
||||
info: {
|
||||
relay_url: 'relay_url',
|
||||
},
|
||||
payments: {
|
||||
enabled: true,
|
||||
feeSchedules: {
|
||||
admission: [
|
||||
{
|
||||
enabled: true,
|
||||
amount: 1000n,
|
||||
whitelists: {
|
||||
pubkeys: [],
|
||||
event_kinds: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
limits: {
|
||||
event: {
|
||||
pubkey: {
|
||||
minBalance: 0n,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as any
|
||||
event = {
|
||||
content: 'hello',
|
||||
created_at: 1665546189,
|
||||
id: 'f'.repeat(64),
|
||||
kind: 1,
|
||||
pubkey: 'f'.repeat(64),
|
||||
sig: 'f'.repeat(128),
|
||||
tags: [],
|
||||
}
|
||||
getRelayPublicKeyStub = sandbox.stub(EventMessageHandler.prototype, 'getRelayPublicKey' as any)
|
||||
getClientAddressStub = sandbox.stub()
|
||||
userRepositoryFindByPubkeyStub = sandbox.stub()
|
||||
webSocket = {
|
||||
getClientAddress: getClientAddressStub,
|
||||
} as any
|
||||
userRepository = {
|
||||
findByPubkey: userRepositoryFindByPubkeyStub,
|
||||
} as any
|
||||
handler = new EventMessageHandler(
|
||||
webSocket,
|
||||
() => null,
|
||||
userRepository,
|
||||
() => settings,
|
||||
() => ({ hit: async () => false })
|
||||
)
|
||||
})
|
||||
|
||||
it ('fulfills with undefined if payments are disabled', async () => {
|
||||
settings.payments.enabled = false
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if event pubkey equals relay\'s own public key', async () => {
|
||||
getRelayPublicKeyStub.returns(event.pubkey)
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if fee schedules are not set', async () => {
|
||||
settings.payments.feeSchedules = undefined
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if admission fee schedules are not set', async () => {
|
||||
settings.payments.feeSchedules.admission = undefined
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if there are no admission fee schedules', async () => {
|
||||
settings.payments.feeSchedules.admission = []
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if there are no enabled admission fee schedules', async () => {
|
||||
settings.payments.feeSchedules.admission[0].enabled = false
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if admission fee schedule is waived for pubkey', async () => {
|
||||
settings.payments.feeSchedules.admission[0].whitelists.pubkeys.push(event.pubkey)
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if admission fee schedule is waived for event kind', async () => {
|
||||
event.kind = EventKinds.ZAP_RECEIPT
|
||||
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push(EventKinds.ZAP_RECEIPT)
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with undefined if admission fee schedule is waived for event kind range', async () => {
|
||||
event.kind = EventKinds.TEXT_NOTE
|
||||
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push([
|
||||
EventKinds.SET_METADATA,
|
||||
EventKinds.RECOMMEND_SERVER,
|
||||
])
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
|
||||
it('fulfills with reason if admission fee schedule is not waived for event kind range', async () => {
|
||||
event.kind = EventKinds.CONTACT_LIST
|
||||
settings.payments.feeSchedules.admission[0].whitelists.event_kinds.push([
|
||||
EventKinds.SET_METADATA,
|
||||
EventKinds.RECOMMEND_SERVER,
|
||||
])
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||
})
|
||||
|
||||
it('fulfills with reason if user is not found', async () => {
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||
})
|
||||
|
||||
it('fulfills with reason if user is not admitted', async () => {
|
||||
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: false })
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||
})
|
||||
|
||||
it('fulfills with reason if user is not admitted', async () => {
|
||||
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: false })
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: pubkey not admitted')
|
||||
})
|
||||
|
||||
it('fulfills with reason if user does not meet minimum balance', async () => {
|
||||
settings.limits.event.pubkey.minBalance = 1000n
|
||||
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: true, balance: 999n })
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.equal('blocked: insufficient balance')
|
||||
})
|
||||
|
||||
it('fulfills with undefined if user is admitted', async () => {
|
||||
settings.limits.event.pubkey.minBalance = 0n
|
||||
userRepositoryFindByPubkeyStub.resolves({ isAdmitted: true })
|
||||
|
||||
return expect((handler as any).isUserAdmitted(event)).to.eventually.be.undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user