diff --git a/README.md b/README.md index 9eaaceb..40f4306 100644 --- a/README.md +++ b/README.md @@ -3,28 +3,34 @@ Welcome to the tip.cc API Client npm package! # Installation + Simply create an npm project if you don't have an already, and install the package. + ``` npm init npm i tipcc.js ``` # Getting Started + > Tip: Want to get started without an introduction? Check out our [documentation](https://tipccjs.org/). You can create a simple TipccClient like this: + ```js import { TipccClient } from 'tipcc.js'; const client = TipccClient(myToken); client.on('ready', () => { - console.log('TipccClient is ready!') + console.log('TipccClient is ready!'); }); ``` + `myToken` is your tip.cc API key. ## A note on API values + The tip.cc API uses the smallest denomination of currencies, giving values in atomic units. For an explanation of how this works, use [Ethereum's wei](https://www.investopedia.com/terms/w/wei.asp) as an example. @@ -33,6 +39,7 @@ tipcc.js uses the bignumber.js package to handle these numbers, and our API will For a in-depth explanation of BigNumbers and available features, check their own [documentation](https://mikemcl.github.io/bignumber.js/). ## Wallets + To get your balance on tip.cc, use the [WalletManager](https://tipccjs.org/classes/WalletManager): ```js @@ -42,13 +49,16 @@ client.on('ready', async () => { return console.log('No BNB wallet found. Have you received any BNB?'); } - console.log(`We've got ${wallet.balance.value} ${wallet.code} on our BNB wallet`); + console.log( + `We've got ${wallet.balance.value} ${wallet.code} on our BNB wallet`, + ); console.log(`This is approximately ${wallet.balance.usdValue} USD`); }); ``` ## Transactions + To receive transactions as events, use [TransactionManager](https://tipccjs.org/classes/TransactionManager)'s events: ```js @@ -62,14 +72,19 @@ client.transactions.on('tip', (transaction) => { ``` You can also get a single or many transactions by id: + ```js client.on('ready', async () => { const oneTransaction = await client.transactions.fetch('one-id'); - const manyTransactions = await client.transactions.fetchMany(['this-id', 'another-id']); + const manyTransactions = await client.transactions.fetchMany([ + 'this-id', + 'another-id', + ]); }); ``` Getting transactions based on a filter is also possible: + ```js client.on('ready', async () => { const transactionsByFilter = await client.transactions.fetchAll({ @@ -83,6 +98,7 @@ Using no filter will get all transactions for the bot/user. This is not recommended, unless you know what you're doing. ## Exchange rates + Use the [ExchangeRateCache](https://tipccjs.org/classes/ExchangeRateCache) to get exchange rates: ```js @@ -97,6 +113,7 @@ client.on('ready', async () => { ``` This is also accessible on other structures, such as wallets: + ```js client.on('ready', async () => { const wallet = await client.wallets.fetch('BTC'); @@ -109,11 +126,13 @@ client.on('ready', async () => { ``` ## Currencies + The client provides caches for cryptocurrencies ([CryptocurrencyCache](https://tipccjs.org/classes/CryptocurrencyCache)) and fiats ([FiatCache](https://tipccjs.org/classes/FiatCache)). This may be useful when you need some basic information about a currency. Getting a cryptocurrency: + ```js client.on('ready', async () => { const btc = client.cryptos.get('BTC'); @@ -127,6 +146,7 @@ client.on('ready', async () => { ``` Getting a fiat: + ```js client.on('ready', async () => { const usd = client.fiats.get('USD'); @@ -140,14 +160,17 @@ client.on('ready', async () => { ``` ## Exploring + Feel free to check out our [documentation](https://tipccjs.org/) to learn about our API and how you can use it. Notice that the examples above are bits of code separated from each other. You can often use provided properties to get your task done with fewer lines of code by combining the structures explained. # License + This project is licensed under the [MIT License](https://github.com/tipccjs/tipcc.js/blob/main/LICENSE). # Disclaimer + The authors of this package are not the authors of [tip.cc](https://tip.cc). We are not responsible for any loss of funds caused by incorrect usage, bugs, exploits, or other causes when using this package. diff --git a/src/structures/managers/TransactionManager.ts b/src/structures/managers/TransactionManager.ts index dc49743..976ff47 100644 --- a/src/structures/managers/TransactionManager.ts +++ b/src/structures/managers/TransactionManager.ts @@ -11,6 +11,7 @@ import { import { Transaction } from '../Transaction'; import { Cache } from '../Cache'; import { EventEmitter } from 'stream'; +import { CacheSet } from '../../utils/CacheSet'; interface ValueTransaction { recipient_s: string | string[]; @@ -51,6 +52,10 @@ export class TransactionManager extends EventEmitter { private _pollingRetries = 0; + private _processedTransactions: CacheSet = new CacheSet( + 24 * 60 * 60 * 1000, + ); + public constructor(payload: { client: TipccClient; cacheTtl?: number; @@ -165,12 +170,20 @@ export class TransactionManager extends EventEmitter { await this.client.cryptos.refresh(); refreshedCurrencies = true; } - if (this.client.cryptos.get(transaction.amount.currencyCode)) + if (this.client.cryptos.get(transaction.amount.currencyCode)) { + if (this._processedTransactions.has(transaction.id)) { + console.warn( + `Event emittion cancelled: Transaction ${transaction.id} has already been emitted`, + ); + continue; + } + this._processedTransactions.add(transaction.id); this.emit(transaction.type, transaction); - else + } else { console.warn( `Event emittion cancelled: Unknown currency code ${transaction.amount.currencyCode} for transaction ${transaction.id}`, ); + } } this._lastPoll = now; diff --git a/src/utils/CacheSet.ts b/src/utils/CacheSet.ts new file mode 100644 index 0000000..47d5768 --- /dev/null +++ b/src/utils/CacheSet.ts @@ -0,0 +1,30 @@ +export class CacheSet extends Set { + private _cacheTtl: number; + + private _timeouts: Map = new Map(); + + constructor(cacheTtl: number) { + super(); + this._cacheTtl = cacheTtl; + } + + public add(value: T): this { + super.add(value); + if (this._timeouts.has(value)) clearTimeout(this._timeouts.get(value)!); + this._timeouts.set( + value, + setTimeout(() => this.delete(value), this._cacheTtl), + ); + return this; + } + + public delete(value: T): boolean { + if (this._timeouts.has(value)) clearTimeout(this._timeouts.get(value)!); + return super.delete(value); + } + + public clear(): void { + for (const timeout of this._timeouts.values()) clearTimeout(timeout); + super.clear(); + } +}