-
Notifications
You must be signed in to change notification settings - Fork 393
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #138 from tallycash/pop-up-video
Pop Up Video: Add browser notifications for balance changes
- Loading branch information
Showing
6 changed files
with
157 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import BlocknativeSdk from "bnc-sdk" | ||
|
||
import { EthereumTransactionData } from "./types" | ||
|
||
export const BlocknativeNetworkIds = { | ||
ethereum: { | ||
mainnet: 1, | ||
}, | ||
} | ||
|
||
// TODO Improve code to clearly discriminate between Bitcoin and | ||
// TODO Ethereum---either top-level or inside the instance. | ||
|
||
/** | ||
* The Blocknative class wraps access to the Blocknative API for the Tally | ||
* extension backend. It exposes Tally-specific functionality, and manages | ||
* connection and disconnection from Blocknative based on registered needs and | ||
* feedback from the Blocknative system to minimize usage when possible. | ||
*/ | ||
export default class Blocknative { | ||
private blocknative: BlocknativeSdk | ||
|
||
static connect(apiKey: string, networkId: number): Blocknative { | ||
const connection = new this(apiKey, networkId) | ||
|
||
return connection | ||
} | ||
|
||
private constructor(apiKey: string, networkId: number) { | ||
// TODO Handle lazy connection, disconnects, resubscribing, rate limits, | ||
// TODO etc. | ||
this.blocknative = new BlocknativeSdk({ | ||
dappId: apiKey, | ||
networkId, | ||
}) | ||
} | ||
|
||
watchBalanceUpdatesFor( | ||
accountAddress: string, | ||
handler: ( | ||
transactionData: EthereumTransactionData, | ||
balanceDelta: bigint | ||
) => void | ||
): void { | ||
// TODO Centralize handling of txConfirmed. | ||
this.blocknative | ||
.account(accountAddress) | ||
.emitter.on("txConfirmed", (transactionData) => { | ||
if ( | ||
"system" in transactionData && | ||
transactionData.system === "ethereum" // not Bitcoin or a log | ||
) { | ||
const transaction = transactionData as EthereumTransactionData | ||
|
||
const balanceDelta = transaction.netBalanceChanges | ||
?.filter(({ address }) => address.toLowerCase() === accountAddress) | ||
.flatMap(({ balanceChanges }) => balanceChanges) | ||
.filter(({ asset: { type: assetType } }) => assetType === "ether") | ||
.reduce( | ||
(ethBalanceChangeDelta, { delta }) => | ||
ethBalanceChangeDelta + BigInt(delta), | ||
0n | ||
) | ||
|
||
if (balanceDelta) { | ||
// Only if there is a balance delta to report. | ||
handler(transaction, balanceDelta) | ||
} | ||
} | ||
}) | ||
} | ||
|
||
unwatchBalanceUpdatesFor(accountAddress: string): void { | ||
// TODO After centralizing handling, handle overall unsubscribing through | ||
// that mechanism. | ||
this.blocknative.account(accountAddress).emitter.off("txConfirmed") | ||
this.blocknative.unsubscribe(accountAddress) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { EthereumTransactionData as BlocknativeEthereumTransactionData } from "bnc-sdk/dist/types/src/interfaces" | ||
|
||
// Some remedial typing for BlockNative; see blocknative/sdk#138 . | ||
type EthereumNetBalanceChanges = { | ||
address: string | ||
balanceChanges: EthereumAssetBalanceChanges[] | ||
} | ||
|
||
type EthereumAssetBalanceChanges = { | ||
delta: string | ||
asset: AssetDetails | ||
breakdown: TransferDetails[] | ||
} | ||
|
||
type AssetDetails = { | ||
type: AssetType | ||
symbol: string | ||
} | ||
|
||
type AssetType = "ether" | "ERC20" | ||
|
||
type TransferDetails = { | ||
counterparty: string | ||
amount: string | ||
} | ||
|
||
export type EthereumTransactionData = BlocknativeEthereumTransactionData & { | ||
netBalanceChanges?: EthereumNetBalanceChanges[] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { browser, startApi } from "@tallyho/tally-api" | ||
|
||
startApi().then(async ({ main }) => { | ||
const accountsApi = main.getApi()["/accounts/"] | ||
let latestActivityHashes = ( | ||
await accountsApi.GET({ address: null }) | ||
).activity.map(({ hash }) => hash) | ||
main | ||
.getApi() | ||
["/accounts/"].subscribe( | ||
({ | ||
total_balance: { amount: totalBalance }, | ||
activity: updatedActivity, | ||
}) => { | ||
const newActivity = updatedActivity.filter(({ hash }) => | ||
latestActivityHashes.includes(hash) | ||
) | ||
|
||
browser.notifications.create("balance-udpate", { | ||
type: "basic", | ||
title: "Balance Update", | ||
message: `<address> has balance ${totalBalance}`, | ||
contextMessage: `${newActivity.length} transactions have updated the balance for <address> to ${totalBalance}`, | ||
}) | ||
|
||
latestActivityHashes = updatedActivity.map(({ hash }) => hash) | ||
} | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters