├── .DS_Store
├── .gitignore
├── README.md
├── channel-creation
├── README.md
├── channel.txt
├── logo.png
├── logo.psd
├── logodry.png
└── logodry.psd
├── frontend-integration
├── your-dapp-modified
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ └── packages
│ │ ├── contracts
│ │ ├── README.md
│ │ ├── package.json
│ │ └── src
│ │ │ ├── abis.js
│ │ │ ├── abis
│ │ │ ├── erc20.json
│ │ │ └── ownable.json
│ │ │ ├── addresses.js
│ │ │ └── index.js
│ │ ├── react-app
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── logo192.png
│ │ │ ├── logo512.png
│ │ │ ├── manifest.json
│ │ │ └── robots.txt
│ │ └── src
│ │ │ ├── App.js
│ │ │ ├── App.test.js
│ │ │ ├── components
│ │ │ └── index.js
│ │ │ ├── ethereumLogo.png
│ │ │ ├── graphql
│ │ │ └── subgraph.js
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ └── setupTests.js
│ │ └── subgraph
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── schema.graphql
│ │ ├── src
│ │ └── mappings
│ │ │ ├── tokens.ts
│ │ │ └── transfers.ts
│ │ └── subgraph.yaml
└── your-dapp-og
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ └── packages
│ ├── contracts
│ ├── README.md
│ ├── package.json
│ └── src
│ │ ├── abis.js
│ │ ├── abis
│ │ ├── erc20.json
│ │ └── ownable.json
│ │ ├── addresses.js
│ │ └── index.js
│ ├── react-app
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ └── src
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ └── index.js
│ │ ├── ethereumLogo.png
│ │ ├── graphql
│ │ └── subgraph.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── setupTests.js
│ └── subgraph
│ ├── README.md
│ ├── package.json
│ ├── schema.graphql
│ ├── src
│ └── mappings
│ │ ├── tokens.ts
│ │ └── transfers.ts
│ └── subgraph.yaml
├── receiving-notifications
├── epns-sns-boilerplate-modded
│ ├── .gitignore
│ ├── README.md
│ ├── index.js
│ └── package.json
├── epns-sns-boilerplate-og
│ ├── .gitignore
│ ├── README.md
│ ├── index.js
│ └── package.json
└── epns-subgraph-notif-boilerplate
│ ├── README.md
│ ├── abis
│ └── PushToken.json
│ ├── contracts
│ └── PushToken.sol
│ ├── networks.json
│ ├── package.json
│ ├── schema.graphql
│ ├── src
│ ├── EPNSNotification.ts
│ └── mapping.ts
│ ├── subgraph.yaml
│ └── tsconfig.json
├── sdk-functionality
├── .env.sample
├── .gitignore
├── README.md
├── index.ts
├── package.json
└── tsconfig.json
└── sending-notifications
├── via-epns-sdk-gasless
└── README.md
├── via-epns-subgraph
├── README.md
├── epns-subgraph-modified
│ ├── .gitignore
│ ├── README.md
│ ├── abis
│ │ └── PushToken.json
│ ├── contracts
│ │ └── PushToken.sol
│ ├── networks.json
│ ├── package.json
│ ├── schema.graphql
│ ├── src
│ │ ├── EPNSNotification.ts
│ │ └── mapping.ts
│ ├── subgraph.yaml
│ └── tsconfig.json
└── epns-subgraph-og
│ ├── .gitignore
│ ├── README.md
│ ├── abis
│ ├── Burnable.json
│ ├── ERC20.json
│ ├── Mintable.json
│ ├── Pausable.json
│ └── TokenRegistry.json
│ ├── data
│ ├── tokens-finance.json
│ └── tokens-uniswap.json
│ ├── package.json
│ ├── schema.graphql
│ ├── scripts
│ └── tokens-uniswap.sh
│ ├── src
│ ├── config.ts
│ ├── helpers
│ │ ├── number.ts
│ │ └── token.ts
│ └── mappings
│ │ ├── account.ts
│ │ ├── registry.ts
│ │ └── token.ts
│ └── subgraph.yaml
├── via-manual-dapp-gasless
└── README.md
├── via-showrunners-gasless
├── README.md
├── epns-showrunners-framework-modified
│ ├── .circleci
│ │ └── config.yml
│ ├── .editorconfig
│ ├── .env.sample
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .gitattributes
│ ├── .gitignore
│ ├── .prettierrc.js
│ ├── LICENSE
│ ├── Procfile
│ ├── README.md
│ ├── deploy.sh
│ ├── docker-compose.yml
│ ├── ecosystem.config.js
│ ├── jest.config.js
│ ├── logs
│ │ └── .keepfolderalive
│ ├── nodemon.json
│ ├── package.json
│ ├── public
│ │ ├── assets
│ │ │ └── .keepfolderalive
│ │ └── cache
│ │ │ └── .keepfolderalive
│ ├── run.sh
│ ├── src
│ │ ├── api
│ │ │ ├── index.ts
│ │ │ ├── middlewares
│ │ │ │ ├── index.ts
│ │ │ │ ├── onlyLocalhost.ts
│ │ │ │ └── onlyTrustedSource.ts
│ │ │ └── routes
│ │ │ │ ├── mailing.ts
│ │ │ │ └── walletMonitoringRoutes.ts
│ │ ├── app.ts
│ │ ├── config
│ │ │ ├── channelsConfig.ts
│ │ │ ├── epns_contract.json
│ │ │ ├── epns_contract_communicator.json
│ │ │ ├── index.ts
│ │ │ └── staticConfig.json
│ │ ├── decorators
│ │ │ └── eventDispatcher.ts
│ │ ├── helpers
│ │ │ ├── cryptoHelper.ts
│ │ │ ├── dbHelper.ts
│ │ │ ├── epnschannel.ts
│ │ │ ├── showrunnersHelper.ts
│ │ │ ├── utilsHelper.ts
│ │ │ └── webhookHelper.ts
│ │ ├── interfaces
│ │ │ └── IGas.ts
│ │ ├── loaders
│ │ │ ├── cache.ts
│ │ │ ├── db.ts
│ │ │ ├── dbListener.ts
│ │ │ ├── dependencyInjector.ts
│ │ │ ├── envVerifier.ts
│ │ │ ├── express.ts
│ │ │ ├── index.ts
│ │ │ ├── jobs.ts
│ │ │ ├── logger.ts
│ │ │ ├── mongoose.ts
│ │ │ ├── redis.ts
│ │ │ └── webhooks.ts
│ │ ├── postman
│ │ │ └── EPNS Showrunners Staging SDK.postman_collection.json
│ │ ├── sample_showrunners
│ │ │ ├── README.md
│ │ │ ├── aave
│ │ │ │ ├── aaveChannel.ts
│ │ │ │ ├── aaveJobs.ts
│ │ │ │ ├── aaveKeys.example
│ │ │ │ ├── aaveKeys.json
│ │ │ │ ├── aaveRoutes.ts
│ │ │ │ ├── aaveSettings.json
│ │ │ │ └── aave_LendingPool.json
│ │ │ ├── digible
│ │ │ │ ├── ERC20.json
│ │ │ │ ├── digiTrackabi.json
│ │ │ │ ├── digiTradeAbi.json
│ │ │ │ ├── digibleChannel.ts
│ │ │ │ ├── digibleJobs.ts
│ │ │ │ ├── digibleKeys.example
│ │ │ │ ├── digibleKeys.json
│ │ │ │ ├── digibleModel.ts
│ │ │ │ ├── digibleRoutes.ts
│ │ │ │ └── digibleSettings.json
│ │ │ ├── ens
│ │ │ │ ├── ensChannel.ts
│ │ │ │ ├── ensJobs.ts
│ │ │ │ ├── ensKeys.example
│ │ │ │ ├── ensKeys.json
│ │ │ │ ├── ensRoutes.ts
│ │ │ │ └── ensSettings.json
│ │ │ ├── helloWorld
│ │ │ │ ├── helloWorldAWSSNS.ts
│ │ │ │ ├── helloWorldChannel.ts
│ │ │ │ ├── helloWorldJobs.ts
│ │ │ │ ├── helloWorldKeys.example
│ │ │ │ ├── helloWorldKeys.json
│ │ │ │ ├── helloWorldRoutes.ts
│ │ │ │ └── messages.ts
│ │ │ └── proofOfHumanity
│ │ │ │ ├── pohCacheModel.ts
│ │ │ │ ├── proofOfHumanity.json
│ │ │ │ ├── proofOfHumanityChannel.ts
│ │ │ │ ├── proofOfHumanityJobs.ts
│ │ │ │ ├── proofOfHumanityKeys.json
│ │ │ │ ├── proofOfHumanityModel.ts
│ │ │ │ ├── proofOfHumanityRoutes.ts
│ │ │ │ └── proofOfHumanitySettings.json
│ │ ├── services
│ │ │ ├── emailService.ts
│ │ │ └── walletMonitoring.ts
│ │ ├── showrunners
│ │ │ ├── .keepfolderalive
│ │ │ └── helloWorld
│ │ │ │ ├── helloWorldAWSSNS.ts
│ │ │ │ ├── helloWorldChannel.ts
│ │ │ │ ├── helloWorldJobs.ts
│ │ │ │ ├── helloWorldKeys.example
│ │ │ │ ├── helloWorldRoutes.ts
│ │ │ │ └── messages.ts
│ │ └── subscribers
│ │ │ └── events.ts
│ ├── tests
│ │ ├── .gitkeep
│ │ ├── sample.test.ts
│ │ └── services
│ │ │ └── .gitkeep
│ └── tsconfig.json
└── epns-showrunners-framework-og
│ ├── .circleci
│ └── config.yml
│ ├── .editorconfig
│ ├── .env.sample
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .gitattributes
│ ├── .gitignore
│ ├── .prettierrc.js
│ ├── LICENSE
│ ├── Procfile
│ ├── README.md
│ ├── deploy.sh
│ ├── docker-compose.yml
│ ├── ecosystem.config.js
│ ├── jest.config.js
│ ├── logs
│ └── .keepfolderalive
│ ├── nodemon.json
│ ├── package.json
│ ├── public
│ ├── assets
│ │ └── .keepfolderalive
│ └── cache
│ │ └── .keepfolderalive
│ ├── run.sh
│ ├── src
│ ├── api
│ │ ├── index.ts
│ │ ├── middlewares
│ │ │ ├── index.ts
│ │ │ ├── onlyLocalhost.ts
│ │ │ └── onlyTrustedSource.ts
│ │ └── routes
│ │ │ ├── mailing.ts
│ │ │ └── walletMonitoringRoutes.ts
│ ├── app.ts
│ ├── config
│ │ ├── channelsConfig.ts
│ │ ├── epns_contract.json
│ │ ├── epns_contract_communicator.json
│ │ ├── index.ts
│ │ └── staticConfig.json
│ ├── decorators
│ │ └── eventDispatcher.ts
│ ├── helpers
│ │ ├── cryptoHelper.ts
│ │ ├── dbHelper.ts
│ │ ├── epnschannel.ts
│ │ ├── showrunnersHelper.ts
│ │ ├── utilsHelper.ts
│ │ └── webhookHelper.ts
│ ├── interfaces
│ │ └── IGas.ts
│ ├── loaders
│ │ ├── cache.ts
│ │ ├── db.ts
│ │ ├── dbListener.ts
│ │ ├── dependencyInjector.ts
│ │ ├── envVerifier.ts
│ │ ├── express.ts
│ │ ├── index.ts
│ │ ├── jobs.ts
│ │ ├── logger.ts
│ │ ├── mongoose.ts
│ │ ├── redis.ts
│ │ └── webhooks.ts
│ ├── postman
│ │ └── EPNS Showrunners Staging SDK.postman_collection.json
│ ├── sample_showrunners
│ │ ├── README.md
│ │ ├── aave
│ │ │ ├── aaveChannel.ts
│ │ │ ├── aaveJobs.ts
│ │ │ ├── aaveKeys.example
│ │ │ ├── aaveKeys.json
│ │ │ ├── aaveRoutes.ts
│ │ │ ├── aaveSettings.json
│ │ │ └── aave_LendingPool.json
│ │ ├── digible
│ │ │ ├── ERC20.json
│ │ │ ├── digiTrackabi.json
│ │ │ ├── digiTradeAbi.json
│ │ │ ├── digibleChannel.ts
│ │ │ ├── digibleJobs.ts
│ │ │ ├── digibleKeys.example
│ │ │ ├── digibleKeys.json
│ │ │ ├── digibleModel.ts
│ │ │ ├── digibleRoutes.ts
│ │ │ └── digibleSettings.json
│ │ ├── ens
│ │ │ ├── ensChannel.ts
│ │ │ ├── ensJobs.ts
│ │ │ ├── ensKeys.example
│ │ │ ├── ensKeys.json
│ │ │ ├── ensRoutes.ts
│ │ │ └── ensSettings.json
│ │ ├── helloWorld
│ │ │ ├── helloWorldAWSSNS.ts
│ │ │ ├── helloWorldChannel.ts
│ │ │ ├── helloWorldJobs.ts
│ │ │ ├── helloWorldKeys.example
│ │ │ ├── helloWorldKeys.json
│ │ │ ├── helloWorldRoutes.ts
│ │ │ └── messages.ts
│ │ └── proofOfHumanity
│ │ │ ├── pohCacheModel.ts
│ │ │ ├── proofOfHumanity.json
│ │ │ ├── proofOfHumanityChannel.ts
│ │ │ ├── proofOfHumanityJobs.ts
│ │ │ ├── proofOfHumanityKeys.json
│ │ │ ├── proofOfHumanityModel.ts
│ │ │ ├── proofOfHumanityRoutes.ts
│ │ │ └── proofOfHumanitySettings.json
│ ├── services
│ │ ├── emailService.ts
│ │ └── walletMonitoring.ts
│ ├── showrunners
│ │ └── .keepfolderalive
│ └── subscribers
│ │ └── events.ts
│ ├── tests
│ ├── .gitkeep
│ ├── sample.test.ts
│ └── services
│ │ └── .gitkeep
│ └── tsconfig.json
└── via-smart-contract
├── README.md
├── token-modified.sol
└── token-og.sol
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Example Repo for Hackers
2 |
3 | This repo is meant for hackathon buidlers and contains examples for the workshop presented. Feel free to fork and poke around.
4 |
5 | ## Repo has been moved!
6 |
7 | > :warning: **This repos has moved to our [push-sdk repos](https://github.com/ethereum-push-notification-service/push-sdk/tree/main/packages/examples).**
8 |
9 |
10 |
11 | # Docs
12 | - [Developer Docs](https://docs.push.org/developers)
13 | - [Documentation Hub](https://docs.push.org/)
14 |
15 | Let's Push
16 |
--------------------------------------------------------------------------------
/channel-creation/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Creating your first channel](https://docs.epns.io/developers/developer-guides/examples/deploying-your-first-channel)
--------------------------------------------------------------------------------
/channel-creation/channel.txt:
--------------------------------------------------------------------------------
1 | ------
2 | Channel - Multichain
3 |
4 | EthOnline 2022 Dry Run
5 | Let's Hack Together - Dry Run
6 |
7 | https://online.ethglobal.com/
--------------------------------------------------------------------------------
/channel-creation/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/channel-creation/logo.png
--------------------------------------------------------------------------------
/channel-creation/logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/channel-creation/logo.psd
--------------------------------------------------------------------------------
/channel-creation/logodry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/channel-creation/logodry.png
--------------------------------------------------------------------------------
/channel-creation/logodry.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/channel-creation/logodry.psd
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # production
12 | build
13 |
14 | # misc
15 | .DS_Store
16 | .env*
17 |
18 | # debug
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | # subgraph
24 | packages/subgraph/build/
25 | packages/subgraph/src/types/
26 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/monorepo",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "ethereum",
6 | "react",
7 | "workspaces",
8 | "yarn"
9 | ],
10 | "private": true,
11 | "scripts": {
12 | "subgraph:auth": "yarn workspace @my-app/subgraph auth",
13 | "subgraph:codegen": "yarn workspace @my-app/subgraph codegen",
14 | "subgraph:build": "yarn workspace @my-app/subgraph build",
15 | "subgraph:deploy": "yarn workspace @my-app/subgraph deploy",
16 | "react-app:build": "yarn workspace @my-app/react-app build",
17 | "react-app:eject": "yarn workspace @my-app/react-app eject",
18 | "react-app:ipfs": "yarn workspace @my-app/react-app ipfs",
19 | "react-app:start": "yarn workspace @my-app/react-app start",
20 | "react-app:test": "yarn workspace @my-app/react-app test"
21 | },
22 | "workspaces": {
23 | "packages": [
24 | "packages/*"
25 | ]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/README.md:
--------------------------------------------------------------------------------
1 | ## @my-app/contracts
2 |
3 | A minimalist, opinionated structure for managing smart contract ABIs and addresses.
4 |
5 | [Read more about Application Binary Interfaces (ABIs) here](https://ethereum.stackexchange.com/questions/234/what-is-an-abi-and-why-is-it-needed-to-interact-with-contracts).
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/contracts",
3 | "version": "1.0.0",
4 | "main": "./src/index.js"
5 | }
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/src/abis.js:
--------------------------------------------------------------------------------
1 | import erc20Abi from "./abis/erc20.json";
2 | import ownableAbi from "./abis/ownable.json";
3 |
4 | const abis = {
5 | erc20: erc20Abi,
6 | ownable: ownableAbi,
7 | };
8 |
9 | export default abis;
10 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/src/abis/ownable.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [],
4 | "payable": false,
5 | "stateMutability": "nonpayable",
6 | "type": "constructor"
7 | },
8 | {
9 | "anonymous": false,
10 | "inputs": [
11 | {
12 | "indexed": true,
13 | "internalType": "address",
14 | "name": "previousOwner",
15 | "type": "address"
16 | },
17 | {
18 | "indexed": true,
19 | "internalType": "address",
20 | "name": "newOwner",
21 | "type": "address"
22 | }
23 | ],
24 | "name": "OwnershipTransferred",
25 | "type": "event"
26 | },
27 | {
28 | "constant": true,
29 | "inputs": [],
30 | "name": "owner",
31 | "outputs": [
32 | {
33 | "internalType": "address",
34 | "name": "",
35 | "type": "address"
36 | }
37 | ],
38 | "payable": false,
39 | "stateMutability": "view",
40 | "type": "function"
41 | },
42 | {
43 | "constant": true,
44 | "inputs": [],
45 | "name": "isOwner",
46 | "outputs": [
47 | {
48 | "internalType": "bool",
49 | "name": "",
50 | "type": "bool"
51 | }
52 | ],
53 | "payable": false,
54 | "stateMutability": "view",
55 | "type": "function"
56 | },
57 | {
58 | "constant": false,
59 | "inputs": [],
60 | "name": "renounceOwnership",
61 | "outputs": [],
62 | "payable": false,
63 | "stateMutability": "nonpayable",
64 | "type": "function"
65 | },
66 | {
67 | "constant": false,
68 | "inputs": [
69 | {
70 | "internalType": "address",
71 | "name": "newOwner",
72 | "type": "address"
73 | }
74 | ],
75 | "name": "transferOwnership",
76 | "outputs": [],
77 | "payable": false,
78 | "stateMutability": "nonpayable",
79 | "type": "function"
80 | }
81 | ]
82 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/src/addresses.js:
--------------------------------------------------------------------------------
1 | // This address points to a dummy ERC-20 contract. Replace it with your own smart contracts.
2 | const addresses = {
3 | ceaErc20: "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7",
4 | };
5 | export default addresses;
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/contracts/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as abis } from "./abis";
2 | export { default as addresses } from "./addresses";
3 |
4 | export * from "./addresses";
5 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/react-app",
3 | "version": "1.0.0",
4 | "homepage": "./",
5 | "browserslist": {
6 | "production": [
7 | ">0.2%",
8 | "not dead",
9 | "not op_mini all"
10 | ],
11 | "development": [
12 | "last 1 chrome version",
13 | "last 1 firefox version",
14 | "last 1 safari version"
15 | ]
16 | },
17 | "dependencies": {
18 | "@apollo/client": "^3.5.10",
19 | "@pushprotocol/restapi": "^0.1.1",
20 | "@ethersproject/contracts": "^5.6.0",
21 | "@ethersproject/providers": "^5.6.0",
22 | "@my-app/contracts": "^1.0.0",
23 | "@testing-library/dom": "^8.11.3",
24 | "@testing-library/jest-dom": "^5.16.2",
25 | "@testing-library/react": "^12.1.4",
26 | "@testing-library/user-event": "^13.5.0",
27 | "@types/react": "^17.0.40",
28 | "@usedapp/core": "^0.12.1",
29 | "ethers": "5.7.0",
30 | "graphql": "^16.3.0",
31 | "ipfs-deploy": "^11.2.0",
32 | "react": "17.0.2",
33 | "react-dom": "17.0.2",
34 | "react-scripts": "4.0.3",
35 | "styled-components": "^5.3.3"
36 | },
37 | "eslintConfig": {
38 | "extends": [
39 | "react-app",
40 | "react-app/jest"
41 | ]
42 | },
43 | "scripts": {
44 | "build": "react-scripts build",
45 | "eject": "react-scripts eject",
46 | "ipfs": "yarn build && ipfs-deploy build/",
47 | "start-legacy": "react-scripts --openssl-legacy-provider start",
48 | "start": "react-scripts start",
49 | "test": "react-scripts test"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-modified/packages/react-app/public/favicon.ico
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Ethereum App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-modified/packages/react-app/public/logo192.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-modified/packages/react-app/public/logo512.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Eth App",
3 | "name": "Create Eth App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render } from "@testing-library/react";
2 | import React from "react";
3 |
4 | import App from "./App";
5 |
6 | test("renders learn react link", () => {
7 | const { getByText } = render();
8 | const linkElement = getByText(/learn react/i);
9 | expect(linkElement).toBeInTheDocument();
10 | });
11 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/components/index.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Body = styled.div`
4 | align-items: center;
5 | color: white;
6 | display: flex;
7 | flex-direction: column;
8 | font-size: calc(10px + 2vmin);
9 | justify-content: center;
10 | margin-top: 40px;
11 | `;
12 |
13 | export const Button = styled.button`
14 | background-color: white;
15 | border: none;
16 | border-radius: 8px;
17 | color: #282c34;
18 | cursor: pointer;
19 | font-size: 16px;
20 | margin: 0px 20px;
21 | padding: 12px 24px;
22 | text-align: center;
23 | text-decoration: none;
24 | `;
25 |
26 | export const Container = styled.div`
27 | background-color: #282c34;
28 | display: flex;
29 | flex-direction: column;
30 | height: calc(100vh);
31 | `;
32 |
33 | export const Header = styled.header`
34 | align-items: center;
35 | background-color: #282c34;
36 | color: white;
37 | display: flex;
38 | flex-direction: row;
39 | justify-content: flex-end;
40 | min-height: 70px;
41 | `;
42 |
43 | export const Image = styled.img`
44 | height: 40vmin;
45 | margin-bottom: 16px;
46 | pointer-events: none;
47 | `;
48 |
49 | export const Link = styled.a.attrs({
50 | target: "_blank",
51 | rel: "noopener noreferrer",
52 | })`
53 | color: #61dafb;
54 | margin-top: 8px;
55 | `;
56 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/ethereumLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-modified/packages/react-app/src/ethereumLogo.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/graphql/subgraph.js:
--------------------------------------------------------------------------------
1 | import { gql } from "@apollo/client";
2 |
3 | // See more example queries on https://thegraph.com/explorer/subgraph/paulrberg/create-eth-app
4 | const GET_TRANSFERS = gql`
5 | {
6 | transfers(first: 10) {
7 | id
8 | from
9 | to
10 | value
11 | }
12 | }
13 | `;
14 |
15 | export default GET_TRANSFERS;
16 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
4 | "Droid Sans", "Helvetica Neue", sans-serif;
5 | -webkit-font-smoothing: antialiased;
6 | -moz-osx-font-smoothing: grayscale;
7 | }
8 |
9 | code {
10 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
11 | }
12 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/index.js:
--------------------------------------------------------------------------------
1 | import "./index.css";
2 |
3 | import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
4 | import { DAppProvider, Mainnet } from "@usedapp/core";
5 | import React from "react";
6 | import ReactDOM from "react-dom";
7 |
8 | import App from "./App";
9 |
10 | // Change this to your own Infura project id: https://infura.io/register
11 | const INFURA_PROJECT_ID = "47c9a3746a614d32b5f0f85646792273";
12 | const config = {
13 | readOnlyChainId: Mainnet.chainId,
14 | readOnlyUrls: {
15 | [Mainnet.chainId]: "https://mainnet.infura.io/v3/" + INFURA_PROJECT_ID,
16 | },
17 | }
18 |
19 | // You should replace this url with your own and put it into a .env file
20 | // See all subgraphs: https://thegraph.com/explorer/
21 | const client = new ApolloClient({
22 | cache: new InMemoryCache(),
23 | uri: "https://api.thegraph.com/subgraphs/name/paulrberg/create-eth-app",
24 | });
25 |
26 | ReactDOM.render(
27 |
28 |
29 |
30 |
31 |
32 |
33 | ,
34 | document.getElementById("root"),
35 | );
36 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/react-app/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import "@testing-library/jest-dom/extend-expect";
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/subgraph/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/subgraph",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "@graphprotocol/graph-cli": "0.28.0",
6 | "@graphprotocol/graph-ts": "0.26.0"
7 | },
8 | "license": "MIT",
9 | "scripts": {
10 | "auth": "graph auth https://api.thegraph.com/ $GRAPH_ACCESS_TOKEN",
11 | "build": "graph build",
12 | "codegen": "graph codegen --output-dir src/types/",
13 | "deploy": "graph deploy paulrberg/create-eth-app --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/subgraph/schema.graphql:
--------------------------------------------------------------------------------
1 | type Token @entity {
2 | id: ID!
3 | decimals: Int
4 | name: String
5 | symbol: String
6 | }
7 |
8 | type Transfer @entity {
9 | id: ID!
10 | from: String!
11 | to: String!
12 | value: BigInt!
13 | }
14 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/subgraph/src/mappings/tokens.ts:
--------------------------------------------------------------------------------
1 | import { Token } from "../types/schema";
2 |
3 | export function addToken(address: string): void {
4 | let token: Token | null = Token.load(address);
5 | if (token != null) {
6 | return;
7 | }
8 |
9 | token = new Token(address);
10 | if (address == "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7") {
11 | token.decimals = 18;
12 | token.name = "CeaErc20";
13 | token.symbol = "CEAERC20";
14 | } else {
15 | token.decimals = 0;
16 | token.name = null;
17 | token.symbol = null;
18 | }
19 |
20 | token.save();
21 | }
22 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/subgraph/src/mappings/transfers.ts:
--------------------------------------------------------------------------------
1 | import { Address } from "@graphprotocol/graph-ts";
2 |
3 | import { Transfer as TransferEvent } from "../types/CeaErc20/erc20";
4 | import { Transfer } from "../types/schema";
5 | import { addToken } from "./tokens";
6 |
7 | export function handleTransfer(event: TransferEvent): void {
8 | let transactionHash: string = event.transaction.hash.toHex();
9 | let transfer = new Transfer(transactionHash);
10 | transfer.from = event.params.from.toHex();
11 | transfer.to = event.params.to.toHex();
12 | transfer.value = event.params.value;
13 | transfer.save();
14 |
15 | let to: Address | null = event.transaction.to;
16 | if (to) {
17 | addToken(to.toHex());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-modified/packages/subgraph/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.4
2 | description: Subgraph that indexes the blockchain data
3 | repository: https://github.com/sablierhq/sablier-subgraph
4 | schema:
5 | file: ./schema.graphql
6 | dataSources:
7 | - kind: ethereum/contract
8 | name: CeaErc20
9 | network: mainnet
10 | source:
11 | abi: erc20
12 | address: "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7"
13 | mapping:
14 | kind: ethereum/events
15 | apiVersion: 0.0.6
16 | abis:
17 | - name: erc20
18 | file: ../contracts/src/abis/erc20.json
19 | entities:
20 | - Token
21 | - Transfer
22 | eventHandlers:
23 | - event: Transfer(indexed address,indexed address,uint256)
24 | handler: handleTransfer
25 | file: ./src/mappings/transfers.ts
26 | language: wasm/assemblyscript
27 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 |
8 | # testing
9 | coverage
10 |
11 | # production
12 | build
13 |
14 | # misc
15 | .DS_Store
16 | .env*
17 |
18 | # debug
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | # subgraph
24 | packages/subgraph/build/
25 | packages/subgraph/src/types/
26 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/monorepo",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "ethereum",
6 | "react",
7 | "workspaces",
8 | "yarn"
9 | ],
10 | "private": true,
11 | "scripts": {
12 | "subgraph:auth": "yarn workspace @my-app/subgraph auth",
13 | "subgraph:codegen": "yarn workspace @my-app/subgraph codegen",
14 | "subgraph:build": "yarn workspace @my-app/subgraph build",
15 | "subgraph:deploy": "yarn workspace @my-app/subgraph deploy",
16 | "react-app:build": "yarn workspace @my-app/react-app build",
17 | "react-app:eject": "yarn workspace @my-app/react-app eject",
18 | "react-app:ipfs": "yarn workspace @my-app/react-app ipfs",
19 | "react-app:start": "yarn workspace @my-app/react-app start",
20 | "react-app:test": "yarn workspace @my-app/react-app test"
21 | },
22 | "workspaces": {
23 | "packages": [
24 | "packages/*"
25 | ]
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/README.md:
--------------------------------------------------------------------------------
1 | ## @my-app/contracts
2 |
3 | A minimalist, opinionated structure for managing smart contract ABIs and addresses.
4 |
5 | [Read more about Application Binary Interfaces (ABIs) here](https://ethereum.stackexchange.com/questions/234/what-is-an-abi-and-why-is-it-needed-to-interact-with-contracts).
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/contracts",
3 | "version": "1.0.0",
4 | "main": "./src/index.js"
5 | }
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/src/abis.js:
--------------------------------------------------------------------------------
1 | import erc20Abi from "./abis/erc20.json";
2 | import ownableAbi from "./abis/ownable.json";
3 |
4 | const abis = {
5 | erc20: erc20Abi,
6 | ownable: ownableAbi,
7 | };
8 |
9 | export default abis;
10 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/src/abis/ownable.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [],
4 | "payable": false,
5 | "stateMutability": "nonpayable",
6 | "type": "constructor"
7 | },
8 | {
9 | "anonymous": false,
10 | "inputs": [
11 | {
12 | "indexed": true,
13 | "internalType": "address",
14 | "name": "previousOwner",
15 | "type": "address"
16 | },
17 | {
18 | "indexed": true,
19 | "internalType": "address",
20 | "name": "newOwner",
21 | "type": "address"
22 | }
23 | ],
24 | "name": "OwnershipTransferred",
25 | "type": "event"
26 | },
27 | {
28 | "constant": true,
29 | "inputs": [],
30 | "name": "owner",
31 | "outputs": [
32 | {
33 | "internalType": "address",
34 | "name": "",
35 | "type": "address"
36 | }
37 | ],
38 | "payable": false,
39 | "stateMutability": "view",
40 | "type": "function"
41 | },
42 | {
43 | "constant": true,
44 | "inputs": [],
45 | "name": "isOwner",
46 | "outputs": [
47 | {
48 | "internalType": "bool",
49 | "name": "",
50 | "type": "bool"
51 | }
52 | ],
53 | "payable": false,
54 | "stateMutability": "view",
55 | "type": "function"
56 | },
57 | {
58 | "constant": false,
59 | "inputs": [],
60 | "name": "renounceOwnership",
61 | "outputs": [],
62 | "payable": false,
63 | "stateMutability": "nonpayable",
64 | "type": "function"
65 | },
66 | {
67 | "constant": false,
68 | "inputs": [
69 | {
70 | "internalType": "address",
71 | "name": "newOwner",
72 | "type": "address"
73 | }
74 | ],
75 | "name": "transferOwnership",
76 | "outputs": [],
77 | "payable": false,
78 | "stateMutability": "nonpayable",
79 | "type": "function"
80 | }
81 | ]
82 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/src/addresses.js:
--------------------------------------------------------------------------------
1 | // This address points to a dummy ERC-20 contract. Replace it with your own smart contracts.
2 | const addresses = {
3 | ceaErc20: "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7",
4 | };
5 | export default addresses;
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/contracts/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as abis } from "./abis";
2 | export { default as addresses } from "./addresses";
3 |
4 | export * from "./addresses";
5 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/react-app",
3 | "version": "1.0.0",
4 | "homepage": "./",
5 | "browserslist": {
6 | "production": [
7 | ">0.2%",
8 | "not dead",
9 | "not op_mini all"
10 | ],
11 | "development": [
12 | "last 1 chrome version",
13 | "last 1 firefox version",
14 | "last 1 safari version"
15 | ]
16 | },
17 | "dependencies": {
18 | "@my-app/contracts": "^1.0.0",
19 | "@apollo/client": "^3.5.10",
20 | "@ethersproject/contracts": "^5.6.0",
21 | "@ethersproject/providers": "^5.6.0",
22 | "@testing-library/dom": "^8.11.3",
23 | "@testing-library/jest-dom": "^5.16.2",
24 | "@testing-library/react": "^12.1.4",
25 | "@testing-library/user-event": "^13.5.0",
26 | "@types/react": "^17.0.40",
27 | "@usedapp/core": "^0.12.1",
28 | "graphql": "^16.3.0",
29 | "ipfs-deploy": "^11.2.0",
30 | "react": "17.0.2",
31 | "react-dom": "17.0.2",
32 | "react-scripts": "4.0.3",
33 | "styled-components": "^5.3.3"
34 | },
35 | "eslintConfig": {
36 | "extends": [
37 | "react-app",
38 | "react-app/jest"
39 | ]
40 | },
41 | "scripts": {
42 | "build": "react-scripts build",
43 | "eject": "react-scripts eject",
44 | "ipfs": "yarn build && ipfs-deploy build/",
45 | "start": "react-scripts start",
46 | "test": "react-scripts test"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-og/packages/react-app/public/favicon.ico
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Ethereum App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-og/packages/react-app/public/logo192.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-og/packages/react-app/public/logo512.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Eth App",
3 | "name": "Create Eth App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render } from "@testing-library/react";
2 | import React from "react";
3 |
4 | import App from "./App";
5 |
6 | test("renders learn react link", () => {
7 | const { getByText } = render();
8 | const linkElement = getByText(/learn react/i);
9 | expect(linkElement).toBeInTheDocument();
10 | });
11 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/components/index.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 |
3 | export const Body = styled.div`
4 | align-items: center;
5 | color: white;
6 | display: flex;
7 | flex-direction: column;
8 | font-size: calc(10px + 2vmin);
9 | justify-content: center;
10 | margin-top: 40px;
11 | `;
12 |
13 | export const Button = styled.button`
14 | background-color: white;
15 | border: none;
16 | border-radius: 8px;
17 | color: #282c34;
18 | cursor: pointer;
19 | font-size: 16px;
20 | margin: 0px 20px;
21 | padding: 12px 24px;
22 | text-align: center;
23 | text-decoration: none;
24 | `;
25 |
26 | export const Container = styled.div`
27 | background-color: #282c34;
28 | display: flex;
29 | flex-direction: column;
30 | height: calc(100vh);
31 | `;
32 |
33 | export const Header = styled.header`
34 | align-items: center;
35 | background-color: #282c34;
36 | color: white;
37 | display: flex;
38 | flex-direction: row;
39 | justify-content: flex-end;
40 | min-height: 70px;
41 | `;
42 |
43 | export const Image = styled.img`
44 | height: 40vmin;
45 | margin-bottom: 16px;
46 | pointer-events: none;
47 | `;
48 |
49 | export const Link = styled.a.attrs({
50 | target: "_blank",
51 | rel: "noopener noreferrer",
52 | })`
53 | color: #61dafb;
54 | margin-top: 8px;
55 | `;
56 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/ethereumLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/frontend-integration/your-dapp-og/packages/react-app/src/ethereumLogo.png
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/graphql/subgraph.js:
--------------------------------------------------------------------------------
1 | import { gql } from "@apollo/client";
2 |
3 | // See more example queries on https://thegraph.com/explorer/subgraph/paulrberg/create-eth-app
4 | const GET_TRANSFERS = gql`
5 | {
6 | transfers(first: 10) {
7 | id
8 | from
9 | to
10 | value
11 | }
12 | }
13 | `;
14 |
15 | export default GET_TRANSFERS;
16 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
4 | "Droid Sans", "Helvetica Neue", sans-serif;
5 | -webkit-font-smoothing: antialiased;
6 | -moz-osx-font-smoothing: grayscale;
7 | }
8 |
9 | code {
10 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
11 | }
12 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/index.js:
--------------------------------------------------------------------------------
1 | import "./index.css";
2 |
3 | import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
4 | import { DAppProvider, Mainnet } from "@usedapp/core";
5 | import React from "react";
6 | import ReactDOM from "react-dom";
7 |
8 | import App from "./App";
9 |
10 | // Change this to your own Infura project id: https://infura.io/register
11 | const INFURA_PROJECT_ID = "defba93b47f748f09fcead8282b9e58e";
12 | const config = {
13 | readOnlyChainId: Mainnet.chainId,
14 | readOnlyUrls: {
15 | [Mainnet.chainId]: "https://mainnet.infura.io/v3/" + INFURA_PROJECT_ID,
16 | },
17 | }
18 |
19 | // You should replace this url with your own and put it into a .env file
20 | // See all subgraphs: https://thegraph.com/explorer/
21 | const client = new ApolloClient({
22 | cache: new InMemoryCache(),
23 | uri: "https://api.thegraph.com/subgraphs/name/paulrberg/create-eth-app",
24 | });
25 |
26 | ReactDOM.render(
27 |
28 |
29 |
30 |
31 |
32 |
33 | ,
34 | document.getElementById("root"),
35 | );
36 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/react-app/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import "@testing-library/jest-dom/extend-expect";
6 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/README.md:
--------------------------------------------------------------------------------
1 | ## @my-app/subgraph
2 |
3 | The Graph is a tool for for indexing events emitted on the Ethereum blockchain. It provides you with an easy-to-use GraphQL API.
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### Subgraph
10 |
11 | #### `yarn codegen`
12 |
13 | Generates AssemblyScript types for smart contract ABIs and the subgraph schema.
14 |
15 | #### `yarn build`
16 |
17 | Compiles the subgraph to WebAssembly.
18 |
19 | #### `yarn auth`
20 |
21 | Before deploying your subgraph, you need to sign up on the
22 | [Graph Explorer](https://thegraph.com/explorer/). There, you will be given an access token. Drop it in the command
23 | below:
24 |
25 | ```sh
26 | GRAPH_ACCESS_TOKEN=your-access-token-here yarn subgraph:auth
27 | ```
28 |
29 | #### `yarn deploy`
30 |
31 | Deploys the subgraph to the official Graph Node.
32 |
33 | Replace `paulrberg/create-eth-app` in the package.json script with your subgraph's name.
34 |
35 | You may also want to [read more about the hosted service](https://thegraph.com/docs/quick-start#hosted-service).
36 |
37 | ## Learn More
38 |
39 | To learn The Graph, check out the [The Graph documentation](https://thegraph.com/docs).
40 |
41 | ---
42 |
43 | 1. Generate types
44 | 2. Build distributable files
45 | 3. Deploy to the remote API
46 |
47 | ## Learn More
48 |
49 | You can learn more in the [The Graph documentation](https://thegraph.com/docs).
50 |
51 | Also consider joining [The Graph Discord server](https://discord.gg/vtvv7FP), where you can seek out help.
52 |
53 | ## Common Errors
54 |
55 | ### Failed to Compile
56 |
57 | > ✖ Failed to compile subgraph: Failed to compile data source mapping: Import file 'src/types/schema.ts' not found.
58 | > Error: Failed to compile data source mapping: Import file 'src/types/schema.ts' not found.
59 |
60 | Run the `yarn subgraph` and this error will go away.
61 |
62 | ### No Access Token
63 |
64 | > ✖ No access token provided
65 |
66 | Make sure that you followed the instructions listed above for [yarn auth](#yarn-auth).
67 |
68 | ### Failed to Deploy
69 |
70 | > ✖ Failed to deploy to Graph node https://api.thegraph.com/deploy/: Invalid account name or access token
71 |
72 | Make sure that you:
73 |
74 | 1. Signed up on the [Graph Explorer](https://thegraph.com/explorer)
75 | 2. Followed the instructions listed above for [yarn auth](#yarn-auth)
76 | 3. Replaced `paulrberg/create-eth-app` with your subgraph's name
77 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@my-app/subgraph",
3 | "version": "1.0.0",
4 | "dependencies": {
5 | "@graphprotocol/graph-cli": "0.28.0",
6 | "@graphprotocol/graph-ts": "0.26.0"
7 | },
8 | "license": "MIT",
9 | "scripts": {
10 | "auth": "graph auth https://api.thegraph.com/ $GRAPH_ACCESS_TOKEN",
11 | "build": "graph build",
12 | "codegen": "graph codegen --output-dir src/types/",
13 | "deploy": "graph deploy paulrberg/create-eth-app --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/schema.graphql:
--------------------------------------------------------------------------------
1 | type Token @entity {
2 | id: ID!
3 | decimals: Int
4 | name: String
5 | symbol: String
6 | }
7 |
8 | type Transfer @entity {
9 | id: ID!
10 | from: String!
11 | to: String!
12 | value: BigInt!
13 | }
14 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/src/mappings/tokens.ts:
--------------------------------------------------------------------------------
1 | import { Token } from "../types/schema";
2 |
3 | export function addToken(address: string): void {
4 | let token: Token | null = Token.load(address);
5 | if (token != null) {
6 | return;
7 | }
8 |
9 | token = new Token(address);
10 | if (address == "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7") {
11 | token.decimals = 18;
12 | token.name = "CeaErc20";
13 | token.symbol = "CEAERC20";
14 | } else {
15 | token.decimals = 0;
16 | token.name = null;
17 | token.symbol = null;
18 | }
19 |
20 | token.save();
21 | }
22 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/src/mappings/transfers.ts:
--------------------------------------------------------------------------------
1 | import { Address } from "@graphprotocol/graph-ts";
2 |
3 | import { Transfer as TransferEvent } from "../types/CeaErc20/erc20";
4 | import { Transfer } from "../types/schema";
5 | import { addToken } from "./tokens";
6 |
7 | export function handleTransfer(event: TransferEvent): void {
8 | let transactionHash: string = event.transaction.hash.toHex();
9 | let transfer = new Transfer(transactionHash);
10 | transfer.from = event.params.from.toHex();
11 | transfer.to = event.params.to.toHex();
12 | transfer.value = event.params.value;
13 | transfer.save();
14 |
15 | let to: Address | null = event.transaction.to;
16 | if (to) {
17 | addToken(to.toHex());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/frontend-integration/your-dapp-og/packages/subgraph/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.4
2 | description: Subgraph that indexes the blockchain data
3 | repository: https://github.com/sablierhq/sablier-subgraph
4 | schema:
5 | file: ./schema.graphql
6 | dataSources:
7 | - kind: ethereum/contract
8 | name: CeaErc20
9 | network: mainnet
10 | source:
11 | abi: erc20
12 | address: "0xa6dF0C88916f3e2831A329CE46566dDfBe9E74b7"
13 | mapping:
14 | kind: ethereum/events
15 | apiVersion: 0.0.6
16 | abis:
17 | - name: erc20
18 | file: ../contracts/src/abis/erc20.json
19 | entities:
20 | - Token
21 | - Transfer
22 | eventHandlers:
23 | - event: Transfer(indexed address,indexed address,uint256)
24 | handler: handleTransfer
25 | file: ./src/mappings/transfers.ts
26 | language: wasm/assemblyscript
27 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-sns-boilerplate-modded/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "epns-sns-template",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon"
9 | },
10 | "type": "commonjs",
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "bent": "^7.3.12",
16 | "dotenv": "^16.0.1",
17 | "express": "^4.18.1",
18 | "lodash": "^4.17.21",
19 | "node-fetch": "^2.6.7",
20 | "parse-url": "^8.0.0",
21 | "sns-payload-validator": "^1.0.4"
22 | },
23 | "devDependencies": {
24 | "nodemon": "^2.0.19"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-sns-boilerplate-og/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "epns-sns-template",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon"
9 | },
10 | "type": "commonjs",
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "bent": "^7.3.12",
16 | "dotenv": "^16.0.1",
17 | "express": "^4.18.1",
18 | "lodash": "^4.17.21",
19 | "node-fetch": "^2.6.7",
20 | "parse-url": "^8.0.0",
21 | "sns-payload-validator": "^1.0.4"
22 | },
23 | "devDependencies": {
24 | "nodemon": "^2.0.19"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/README.md:
--------------------------------------------------------------------------------
1 | ### Subgraph
2 |
3 | The Graph is a tool for for indexing events emitted on the Ethereum blockchain. It provides you with an easy-to-use GraphQL API.
4 |
5 | To learn more, check out the [The Graph documentation](https://thegraph.com/docs).
6 |
7 | #### `yarn subgraph:codegen`
8 |
9 | Generates AssemblyScript types for smart contract ABIs and the subgraph schema.
10 |
11 | #### `yarn subgraph:build`
12 |
13 | Compiles the subgraph to WebAssembly.
14 |
15 | #### `yarn subgraph:auth`
16 |
17 | Before deploying your subgraph, you need to sign up on the
18 | [Graph Explorer](https://thegraph.com/explorer/). There, you will be given an access token. Drop it in the command
19 | below:
20 |
21 | ```sh
22 | GRAPH_ACCESS_TOKEN=your-access-token-here yarn subgraph:auth
23 | ```
24 |
25 | #### `yarn subgraph:deploy`
26 |
27 | Deploys the subgraph to the official Graph Node.
28 |
29 | Replace `paulrberg/create-eth-app` in the package.json script with your subgraph's name.
30 |
31 | You may also want to [read more about the hosted service](https://thegraph.com/docs/quick-start#hosted-service).
32 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/networks.json:
--------------------------------------------------------------------------------
1 | {
2 | "kovan": {
3 | "PushToken": {
4 | "address": "0xc9e7A86dd5f3c3d92C516E2d05DcebaD16Bb6B07"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "push-token",
3 | "license": "UNLICENSED",
4 | "scripts": {
5 | "codegen": "graph codegen",
6 | "build": "graph build",
7 | "deploy": "graph deploy --node https://api.thegraph.com/deploy/ aiswaryawalter/push-token",
8 | "create-local": "graph create --node http://localhost:8020/ aiswaryawalter/push-token",
9 | "remove-local": "graph remove --node http://localhost:8020/ aiswaryawalter/push-token",
10 | "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 aiswaryawalter/push-token"
11 | },
12 | "dependencies": {
13 | "@graphprotocol/graph-cli": "0.29.2",
14 | "@graphprotocol/graph-ts": "0.26.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/schema.graphql:
--------------------------------------------------------------------------------
1 | type User @entity {
2 | id: ID!
3 | address: String!
4 | balance: BigInt!
5 | transactionCount: Int!
6 | }
7 |
8 | type Minter @entity {
9 | id: ID!
10 | address: String!
11 | totalMinted: BigInt!
12 | totalBurned: BigInt!
13 | }
14 |
15 | type UserCounter @entity {
16 | id: ID!
17 | count: Int!
18 | }
19 |
20 | type MinterCounter @entity {
21 | id: ID!
22 | count: Int!
23 | }
24 |
25 | type TransferCounter @entity {
26 | id: ID!
27 | count: Int!
28 | totalTransferred: BigInt!
29 | }
30 |
31 | type TotalSupply @entity {
32 | id: ID!
33 | supply: BigInt!
34 | minted: BigInt!
35 | burned: BigInt!
36 | }
37 |
38 | type EpnsNotificationCounter @entity {
39 | id: ID!
40 | totalCount: BigInt!
41 | }
42 |
43 | type EpnsPushNotification @entity {
44 | id: ID!
45 | notificationNumber: BigInt!
46 | recipient: String!
47 | notification: String!
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/src/EPNSNotification.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BigInt,
3 | log } from "@graphprotocol/graph-ts"
4 | import { EpnsNotificationCounter, EpnsPushNotification } from '../generated/schema'
5 | import { subgraphID } from "./mapping"
6 |
7 | export function sendEPNSNotification(recipient: string, notification: string): void
8 | {
9 | let id1 = subgraphID
10 | log.info('New id of EpnsNotificationCounter is: {}', [id1])
11 | let epnsNotificationCounter = EpnsNotificationCounter.load(id1)
12 | if (epnsNotificationCounter == null) {
13 | epnsNotificationCounter = new EpnsNotificationCounter(id1)
14 | epnsNotificationCounter.totalCount = BigInt.fromI32(0)
15 | }
16 | epnsNotificationCounter.totalCount = (epnsNotificationCounter.totalCount).plus(BigInt.fromI32(1))
17 |
18 | let count = epnsNotificationCounter.totalCount.toHexString()
19 | let id2 = `${subgraphID}+${count}`
20 | log.info('New id of EpnsPushNotification is: {}', [id2])
21 | let epnsPushNotification = EpnsPushNotification.load(id2)
22 | if (epnsPushNotification == null) {
23 | epnsPushNotification = new EpnsPushNotification(id2)
24 | }
25 | epnsPushNotification.recipient = recipient
26 | epnsPushNotification.notification = notification
27 | epnsPushNotification.notificationNumber = epnsNotificationCounter.totalCount
28 | epnsPushNotification.save()
29 | epnsNotificationCounter.save()
30 | }
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.2
2 | schema:
3 | file: ./schema.graphql
4 | dataSources:
5 | - kind: ethereum
6 | name: PushToken
7 | network: kovan
8 | source:
9 | address: "0xc9e7A86dd5f3c3d92C516E2d05DcebaD16Bb6B07"
10 | abi: PushToken
11 | startBlock: 31966621
12 | mapping:
13 | kind: ethereum/events
14 | apiVersion: 0.0.5
15 | language: wasm/assemblyscript
16 | entities:
17 | - Transfer
18 | - Approval
19 | abis:
20 | - name: PushToken
21 | file: ./abis/PushToken.json
22 | eventHandlers:
23 | - event: Transfer(indexed address,indexed address,uint256)
24 | handler: handleTransfer
25 | - event: Approval(indexed address,indexed address,uint256)
26 | handler: handleApproval
27 | file: ./src/mapping.ts
28 |
--------------------------------------------------------------------------------
/receiving-notifications/epns-subgraph-notif-boilerplate/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json",
3 | "include": ["src"]
4 | }
5 |
--------------------------------------------------------------------------------
/sdk-functionality/.env.sample:
--------------------------------------------------------------------------------
1 | # WALLET PRIVATE KEY
2 | WALLET_PRIVATE_KEY=your_channel_key
3 |
4 | # ENVIRONMENT OF PUSH NETWORK - prod, staging OR dev
5 | PUSH_NODE_NETWORK=staging
6 |
7 | # TO ENABLE API RESPONSES TO BE SHOWN OR HIDDEN - true OR false
8 | SHOW_API_RESPONSE=false
9 |
10 | # NFT CONTRACT ADDRESS
11 | NFT_CONTRACT_ADDRESS_1=your_nft_contract_address
12 |
13 | # NFT CHAIN ID
14 | NFT_CHAIN_ID_1=your_nft_chain_id
15 |
16 | # NFT TOKEN ID
17 | NFT_TOKEN_ID_1=your_nft_token_id
18 |
19 | # NFT HOLDER WALLET PRIVATE KEY
20 | NFT_HOLDER_WALLET_PRIVATE_KEY_1=your_nft_holder_wallet_private_key
21 |
22 | # NFT PROFILE WALLET PASSWORD
23 | NFT_PROFILE_PASSWORD_1=your_nft_profile_password
24 |
25 | # NFT CONTRACT ADDRESS
26 | NFT_CONTRACT_ADDRESS_2=your_nft_contract_address
27 |
28 | # NFT CHAIN ID
29 | NFT_CHAIN_ID_2=your_nft_chain_id
30 |
31 | # NFT TOKEN ID
32 | NFT_TOKEN_ID_2=your_nft_token_id
33 |
34 | # NFT HOLDER WALLET PRIVATE KEY
35 | NFT_HOLDER_WALLET_PRIVATE_KEY_2=your_nft_holder_wallet_private_key
36 |
37 | # NFT PROFILE WALLET PASSWORD
38 | NFT_PROFILE_PASSWORD_2=your_nft_profile_password
--------------------------------------------------------------------------------
/sdk-functionality/.gitignore:
--------------------------------------------------------------------------------
1 | .env
--------------------------------------------------------------------------------
/sdk-functionality/README.md:
--------------------------------------------------------------------------------
1 | # Push Protocol SDK
2 | ## Enable Web3 notifications, chat, group chat, token gating or social communications (video call, streaming, etc) in your dApp
3 |
4 | ## Important Links
5 | [Push Protocol Official Docs](https://docs.push.org/developers)
6 | [Push Protocol Package](https://www.npmjs.com/package/@pushprotocol/)
7 |
8 | ## Website and dApp
9 | [Push Protocol Website](https://push.org)
10 | [Push Protocol dApp](https://app.push.org)
--------------------------------------------------------------------------------
/sdk-functionality/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sdk-functionality",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.ts",
6 | "scripts": {
7 | "start": "ts-node index.ts"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@pushprotocol/restapi": "^1.2.12",
14 | "@pushprotocol/socket": "^0.5.0",
15 | "@types/node": "18.15.11",
16 | "dotenv": "^16.0.3",
17 | "ethers": "^5.6",
18 | "latest": "^0.2.0",
19 | "unique-names-generator": "^4.7.1"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-sdk-gasless/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about EPNS SDK](https://docs.epns.io/developers/developer-tooling/epns-sdk/sdk-packages-details/epnsproject-sdk-restapi/send-notifications)
4 | [JS SDK, Examples about varios things possible with SDK](https://socket.dev/npm/package/@epnsproject/sdk-restapi)
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about using subgraph notification](https://docs.epns.io/developers/developer-guides/sending-notifications/using-subgraph-gasless)
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | generated/
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 | lerna-debug.log*
11 |
12 | # Diagnostic reports (https://nodejs.org/api/report.html)
13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
14 |
15 | # Runtime data
16 | pids
17 | *.pid
18 | *.seed
19 | *.pid.lock
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 | *.lcov
27 |
28 | # nyc test coverage
29 | .nyc_output
30 |
31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
32 | .grunt
33 |
34 | # Bower dependency directory (https://bower.io/)
35 | bower_components
36 |
37 | # node-waf configuration
38 | .lock-wscript
39 |
40 | # Compiled binary addons (https://nodejs.org/api/addons.html)
41 | build/Release
42 |
43 | # Dependency directories
44 | node_modules/
45 | jspm_packages/
46 |
47 | # TypeScript v1 declaration files
48 | typings/
49 |
50 | # TypeScript cache
51 | *.tsbuildinfo
52 |
53 | # Optional npm cache directory
54 | .npm
55 |
56 | # Optional eslint cache
57 | .eslintcache
58 |
59 | # Microbundle cache
60 | .rpt2_cache/
61 | .rts2_cache_cjs/
62 | .rts2_cache_es/
63 | .rts2_cache_umd/
64 |
65 | # Optional REPL history
66 | .node_repl_history
67 |
68 | # Output of 'npm pack'
69 | *.tgz
70 |
71 | # Yarn Integrity file
72 | .yarn-integrity
73 |
74 | # dotenv environment variables file
75 | .env
76 | .env.test
77 |
78 | # parcel-bundler cache (https://parceljs.org/)
79 | .cache
80 |
81 | # Next.js build output
82 | .next
83 |
84 | # Nuxt.js build / generate output
85 | .nuxt
86 | dist
87 |
88 | # Gatsby files
89 | .cache/
90 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
91 | # https://nextjs.org/blog/next-9-1#public-directory-support
92 | # public
93 |
94 | # vuepress build output
95 | .vuepress/dist
96 |
97 | # Serverless directories
98 | .serverless/
99 |
100 | # FuseBox cache
101 | .fusebox/
102 |
103 | # DynamoDB Local files
104 | .dynamodb/
105 |
106 | # TernJS port file
107 | .tern-port
108 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about using subgraph notification](https://docs.epns.io/developers/developer-guides/sending-notifications/using-subgraph-gasless)
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/networks.json:
--------------------------------------------------------------------------------
1 | {
2 | "kovan": {
3 | "PushToken": {
4 | "address": "0xc9e7A86dd5f3c3d92C516E2d05DcebaD16Bb6B07"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "push-token",
3 | "license": "UNLICENSED",
4 | "scripts": {
5 | "codegen": "graph codegen",
6 | "build": "graph build",
7 | "deploy": "graph deploy --node https://api.thegraph.com/deploy/ aiswaryawalter/push-token",
8 | "create-local": "graph create --node http://localhost:8020/ aiswaryawalter/push-token",
9 | "remove-local": "graph remove --node http://localhost:8020/ aiswaryawalter/push-token",
10 | "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 aiswaryawalter/push-token"
11 | },
12 | "dependencies": {
13 | "@graphprotocol/graph-cli": "0.29.2",
14 | "@graphprotocol/graph-ts": "0.26.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/schema.graphql:
--------------------------------------------------------------------------------
1 | type EpnsNotificationCounter @entity {
2 | id: ID!
3 | totalCount: BigInt!
4 | }
5 |
6 | type EpnsPushNotification @entity {
7 | id: ID!
8 | notificationNumber: BigInt!
9 | recipient: String!
10 | notification: String!
11 | }
12 |
13 | type User @entity {
14 | id: ID!
15 | address: String!
16 | balance: BigInt!
17 | transactionCount: Int!
18 | }
19 |
20 | type Minter @entity {
21 | id: ID!
22 | address: String!
23 | totalMinted: BigInt!
24 | totalBurned: BigInt!
25 | }
26 |
27 | type UserCounter @entity {
28 | id: ID!
29 | count: Int!
30 | }
31 |
32 | type MinterCounter @entity {
33 | id: ID!
34 | count: Int!
35 | }
36 |
37 | type TransferCounter @entity {
38 | id: ID!
39 | count: Int!
40 | totalTransferred: BigInt!
41 | }
42 |
43 | type TotalSupply @entity {
44 | id: ID!
45 | supply: BigInt!
46 | minted: BigInt!
47 | burned: BigInt!
48 | }
49 |
50 | type EpnsNotificationCounter @entity {
51 | id: ID!
52 | totalCount: BigInt!
53 | }
54 |
55 | type EpnsPushNotification @entity {
56 | id: ID!
57 | notificationNumber: BigInt!
58 | recipient: String!
59 | notification: String!
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/src/EPNSNotification.ts:
--------------------------------------------------------------------------------
1 | import { BigInt, log } from "@graphprotocol/graph-ts";
2 | import {
3 | EpnsNotificationCounter,
4 | EpnsPushNotification
5 | } from "../generated/schema";
6 | import { subgraphID } from "./mapping";
7 |
8 | export function sendEPNSNotification(
9 | recipient: string,
10 | notification: string
11 | ): void {
12 | let id1 = subgraphID;
13 | log.info("New id of EpnsNotificationCounter is: {}", [id1]);
14 | let epnsNotificationCounter = EpnsNotificationCounter.load(id1);
15 | if (epnsNotificationCounter == null) {
16 | epnsNotificationCounter = new EpnsNotificationCounter(id1);
17 | epnsNotificationCounter.totalCount = BigInt.fromI32(0);
18 | }
19 | epnsNotificationCounter.totalCount = epnsNotificationCounter.totalCount.plus(
20 | BigInt.fromI32(1)
21 | );
22 |
23 | let count = epnsNotificationCounter.totalCount.toHexString();
24 | let id2 = `${subgraphID}+${count}`;
25 | log.info("New id of EpnsPushNotification is: {}", [id2]);
26 | let epnsPushNotification = EpnsPushNotification.load(id2);
27 | if (epnsPushNotification == null) {
28 | epnsPushNotification = new EpnsPushNotification(id2);
29 | }
30 | epnsPushNotification.recipient = recipient;
31 | epnsPushNotification.notification = notification;
32 | epnsPushNotification.notificationNumber = epnsNotificationCounter.totalCount;
33 | epnsPushNotification.save();
34 | epnsNotificationCounter.save();
35 | }
36 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/subgraph.yaml:
--------------------------------------------------------------------------------
1 | specVersion: 0.0.4
2 | schema:
3 | file: ./schema.graphql
4 | dataSources:
5 | - kind: ethereum
6 | name: PushToken
7 | network: kovan
8 | source:
9 | address: "0x3e876C849331995C5473d3a6CcAfD5C99f709784"
10 | abi: PushToken
11 | startBlock: 31966621
12 | mapping:
13 | kind: ethereum/events
14 | apiVersion: 0.0.5
15 | language: wasm/assemblyscript
16 | entities:
17 | - Transfer
18 | - Approval
19 | abis:
20 | - name: PushToken
21 | file: ./abis/PushToken.json
22 | eventHandlers:
23 | - event: Transfer(indexed address,indexed address,uint256)
24 | handler: handleTransfer
25 | - event: Approval(indexed address,indexed address,uint256)
26 | handler: handleApproval
27 | file: ./src/mapping.ts
28 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-modified/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json",
3 | "include": ["src"]
4 | }
5 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | /generated
3 | /build
4 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about using subgraph notification](https://docs.epns.io/developers/developer-guides/sending-notifications/using-subgraph-gasless)
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/abis/Burnable.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "constant": false,
4 | "inputs": [
5 | {
6 | "name": "value",
7 | "type": "uint256"
8 | }
9 | ],
10 | "name": "burn",
11 | "outputs": [],
12 | "payable": false,
13 | "stateMutability": "nonpayable",
14 | "type": "function"
15 | },
16 | {
17 | "constant": false,
18 | "inputs": [
19 | {
20 | "name": "burner",
21 | "type": "address"
22 | },
23 | {
24 | "name": "value",
25 | "type": "uint256"
26 | }
27 | ],
28 | "name": "burn",
29 | "outputs": [],
30 | "payable": false,
31 | "stateMutability": "nonpayable",
32 | "type": "function"
33 | },
34 | {
35 | "anonymous": false,
36 | "inputs": [
37 | {
38 | "indexed": true,
39 | "name": "burner",
40 | "type": "address"
41 | },
42 | {
43 | "indexed": false,
44 | "name": "value",
45 | "type": "uint256"
46 | }
47 | ],
48 | "name": "Burn",
49 | "type": "event",
50 | "_alias": "Burn"
51 | }
52 | ]
53 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/abis/Mintable.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "constant": false,
4 | "inputs": [
5 | {
6 | "name": "to",
7 | "type": "address"
8 | },
9 | {
10 | "name": "amount",
11 | "type": "uint256"
12 | }
13 | ],
14 | "name": "mint",
15 | "outputs": [],
16 | "payable": false,
17 | "stateMutability": "nonpayable",
18 | "type": "function"
19 | },
20 | {
21 | "constant": false,
22 | "inputs": [
23 | {
24 | "name": "amount",
25 | "type": "uint256"
26 | }
27 | ],
28 | "name": "mint",
29 | "outputs": [],
30 | "payable": false,
31 | "stateMutability": "nonpayable",
32 | "type": "function"
33 | },
34 | {
35 | "anonymous": false,
36 | "inputs": [
37 | {
38 | "indexed": true,
39 | "name": "to",
40 | "type": "address"
41 | },
42 | {
43 | "indexed": false,
44 | "name": "amount",
45 | "type": "uint256"
46 | }
47 | ],
48 | "name": "Mint",
49 | "type": "event",
50 | "_alias": "Mint"
51 | }
52 | ]
53 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/abis/Pausable.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "constant": true,
4 | "inputs": [],
5 | "name": "paused",
6 | "outputs": [
7 | {
8 | "name": "",
9 | "type": "bool"
10 | }
11 | ],
12 | "payable": false,
13 | "stateMutability": "view",
14 | "type": "function"
15 | },
16 | {
17 | "constant": false,
18 | "inputs": [],
19 | "name": "pause",
20 | "outputs": [],
21 | "payable": false,
22 | "stateMutability": "nonpayable",
23 | "type": "function"
24 | },
25 | {
26 | "constant": false,
27 | "inputs": [],
28 | "name": "unpause",
29 | "outputs": [],
30 | "payable": false,
31 | "stateMutability": "nonpayable",
32 | "type": "function"
33 | },
34 | {
35 | "anonymous": false,
36 | "inputs": [],
37 | "name": "Pause",
38 | "type": "event"
39 | },
40 | {
41 | "anonymous": false,
42 | "inputs": [],
43 | "name": "Unpause",
44 | "type": "event"
45 | },
46 | {
47 | "anonymous": false,
48 | "inputs": [
49 | {
50 | "indexed": false,
51 | "internalType": "address",
52 | "name": "account",
53 | "type": "address"
54 | }
55 | ],
56 | "name": "Paused",
57 | "type": "event"
58 | },
59 | {
60 | "anonymous": false,
61 | "inputs": [
62 | {
63 | "indexed": false,
64 | "internalType": "address",
65 | "name": "account",
66 | "type": "address"
67 | }
68 | ],
69 | "name": "Unpaused",
70 | "type": "event"
71 | }
72 | ]
73 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/abis/TokenRegistry.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": true,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "name": "param0",
8 | "type": "bytes"
9 | },
10 | {
11 | "indexed": true,
12 | "name": "param1",
13 | "type": "bytes"
14 | }
15 | ],
16 | "name": "Unknown",
17 | "type": "event"
18 | }
19 | ]
20 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/data/tokens-finance.json:
--------------------------------------------------------------------------------
1 | ["0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2","MakerDAO Token","MKR",18,null,null,6]
2 | ["0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359","Dai Stablecoin v1.0","DAI",18,null,null,6]
3 | ["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","USD Coin","USDC",6,null,null,0]
4 | ["0x0000000000085d4780b73119b644ae5ecd22b376","TrueUSD","TUSD",18,null,null,7]
5 | ["0x056fd409e1d7a124bd7017459dfea2f387b6d5cd","Gemini dollar","GUSD",2,null,null,3]
6 | ["0x8e870d67f660d95d5be530380d0ec0bd388289e1","Paxos Standard","PAX",18,null,null,0]
7 | ["0xdac17f958d2ee523a2206206994597c13d831ec7","Tether USD","USDT",6,null,null,1]
8 | ["0xe41d2489571d322189246dafa5ebde1f4699f498","0x Protocol Token","ZRX",18,null,null,1]
9 | ["0x1985365e9f78359a9b6ad760e32412f4a445e862","Reputation","REP",18,null,null,3]
10 | ["0x2260fac5e5542a773aa44fbcfedf7c193bc2c599","Wrapped BTC","WBTC",8,null,null,7]
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "erc20-subgraph",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "auth": "graph auth https://api.thegraph.com/deploy/",
7 | "codegen": "graph codegen",
8 | "build": "graph build",
9 | "deploy": "graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ graphprotocol/erc20-subgraph",
10 | "create-local": "graph create --node http://localhost:8020/ graphprotocol/erc20-subgraph",
11 | "remove-local": "graph remove --node http://localhost:8020/ graphprotocol/erc20-subgraph",
12 | "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 graphprotocol/erc20-subgraph"
13 | },
14 | "devDependencies": {
15 | "@graphprotocol/graph-cli": "0.18.0",
16 | "@graphprotocol/graph-ts": "0.18.1"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/scripts/tokens-uniswap.sh:
--------------------------------------------------------------------------------
1 | curl \
2 | -X POST \
3 | -H "Content-Type: application/json" \
4 | --data '{ "query": "{ uniswap(id: 1) { exchanges(first: 200, orderBy: ethLiquidity, orderDirection: desc) { tokenAddress tokenSymbol tokenName tokenDecimals } } }" }' \
5 | https://api.thegraph.com/subgraphs/name/graphprotocol/uniswap
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/src/config.ts:
--------------------------------------------------------------------------------
1 | export const REGISTRY_HASH = 'QmS91QaQozMhQzT68yRxXz7SL2a3snixX9WXiyVNPaVDt8' // data/tokens-finance.json
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/src/helpers/number.ts:
--------------------------------------------------------------------------------
1 | import { BigDecimal, BigInt } from '@graphprotocol/graph-ts'
2 |
3 | export let ZERO = BigInt.fromI32(0)
4 | export let ONE = BigInt.fromI32(1)
5 |
6 | export function toDecimal(value: BigInt, decimals: u32): BigDecimal {
7 | let precision = BigInt.fromI32(10)
8 | .pow(decimals)
9 | .toBigDecimal()
10 |
11 | return value.divDecimal(precision)
12 | }
13 |
--------------------------------------------------------------------------------
/sending-notifications/via-epns-subgraph/epns-subgraph-og/src/mappings/account.ts:
--------------------------------------------------------------------------------
1 | import { BigDecimal, Bytes, ethereum } from '@graphprotocol/graph-ts'
2 |
3 | import { Account, AccountBalance, AccountBalanceSnapshot, Token } from '../../generated/schema'
4 |
5 | import { ZERO } from '../helpers/number'
6 |
7 | export function getOrCreateAccount(accountAddress: Bytes): Account {
8 | let accountId = accountAddress.toHex()
9 | let existingAccount = Account.load(accountId)
10 |
11 | if (existingAccount != null) {
12 | return existingAccount as Account
13 | }
14 |
15 | let newAccount = new Account(accountId)
16 | newAccount.address = accountAddress
17 |
18 | return newAccount
19 | }
20 |
21 | function getOrCreateAccountBalance(account: Account, token: Token): AccountBalance {
22 | let balanceId = account.id + '-' + token.id
23 | let previousBalance = AccountBalance.load(balanceId)
24 |
25 | if (previousBalance != null) {
26 | return previousBalance as AccountBalance
27 | }
28 |
29 | let newBalance = new AccountBalance(balanceId)
30 | newBalance.account = account.id
31 | newBalance.token = token.id
32 | newBalance.amount = ZERO.toBigDecimal()
33 |
34 | return newBalance
35 | }
36 |
37 | export function increaseAccountBalance(account: Account, token: Token, amount: BigDecimal): AccountBalance {
38 | let balance = getOrCreateAccountBalance(account, token)
39 | balance.amount = balance.amount.plus(amount)
40 |
41 | return balance
42 | }
43 |
44 | export function decreaseAccountBalance(account: Account, token: Token, amount: BigDecimal): AccountBalance {
45 | let balance = getOrCreateAccountBalance(account, token)
46 | balance.amount = balance.amount.minus(amount)
47 |
48 | return balance
49 | }
50 |
51 | export function saveAccountBalanceSnapshot(balance: AccountBalance, eventId: string, event: ethereum.Event): void {
52 | let snapshot = new AccountBalanceSnapshot(balance.id + '-' + event.block.timestamp.toString())
53 | snapshot.account = balance.account
54 | snapshot.token = balance.token
55 | snapshot.amount = balance.amount
56 |
57 | snapshot.block = event.block.number
58 | snapshot.transaction = event.transaction.hash
59 | snapshot.timestamp = event.block.timestamp
60 |
61 | snapshot.event = eventId
62 |
63 | snapshot.save()
64 | }
65 |
--------------------------------------------------------------------------------
/sending-notifications/via-manual-dapp-gasless/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Sending web3 notifications manually](https://docs.epns.io/developers/developer-guides/sending-notifications/dapp-serverless-workflow)
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Creating your first channel](https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners)
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: circleci/node:10.15
6 | - image: circleci/mongo:latest
7 | steps:
8 | - checkout
9 | - run:
10 | name: install-npm
11 | command: npm install
12 | - save_cache:
13 | key: dependency-cache-{{ checksum "package.json" }}
14 | paths:
15 | - ./node_modules
16 | - run:
17 | name: test
18 | command: npm test
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.editorconfig:
--------------------------------------------------------------------------------
1 | ################################################
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.env.sample:
--------------------------------------------------------------------------------
1 | # MAKE A COPY OF THIS AND FILL WITH YOUR CREDENTIALS AND NAME IT .env (Remove .sample Part)
2 |
3 | # SHOWRUNNERS ENVIRONMENT: prod or staging or dev
4 | SHOWRUNNERS_ENV=staging
5 |
6 | ## NORMAL CONFIG
7 | # DEBUG | CAN BE 'debug' or 'prod'
8 | LOG_LEVEL=debug_or_prod # 'debug' or 'prod'
9 |
10 | # WEB3 ENDPOINTS | NEED ATLEAST INFURA OR ETHERSCAN OR ALCHEMY, REST CAN BE NULL
11 | INFURA_PROJECT_ID=your_infura_project_id
12 | INFURA_PROJECT_SECRET=your_infura_project_secret
13 |
14 | ## ADVANCED CONFIG
15 | # WEB3 ENDPOINTS | OPTIONAL IF YOU FILLED INFURA_PROJECT AND INFURA_PROJECT_SECRET, CAN SET IT TO NULL IF YOU WANT TO
16 | ETHERSCAN_API=your_etherscan_api_key_or_null
17 | ALCHEMY_API=your_alchemy_api_key_or_null
18 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*
2 |
3 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser
3 | extends: [
4 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
5 | 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
6 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
7 | ],
8 | parserOptions: {
9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
10 | sourceType: 'module', // Allows for the use of imports
11 | },
12 | rules: {
13 | '@typescript-eslint/explicit-member-accessibility': 0,
14 | '@typescript-eslint/explicit-function-return-type': 0,
15 | '@typescript-eslint/no-parameter-properties': 0,
16 | '@typescript-eslint/interface-name-prefix': 0
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.gitattributes:
--------------------------------------------------------------------------------
1 | *.json merge=json
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | printWidth: 120,
6 | tabWidth: 2,
7 | };
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/Procfile:
--------------------------------------------------------------------------------
1 | web: node build/app.js
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about Showrunners](https://docs.epns.io/developers/developer-guides/sending-notifications/using-showrunners-scaffold-gasless)
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | npm run build
3 | cp .env build/.env
4 | pm2 reload ecosystem.config.js --env production
5 | # EOF
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | redis:
4 | image: 'redis:latest'
5 | container_name: redis
6 | ports:
7 | - 6379:6379
8 | volumes:
9 | - ./external/redis:/data
10 |
11 | mongo:
12 | image: 'mongo:latest'
13 | container_name: mongodb
14 | ports:
15 | - 27017:27017
16 | volumes:
17 | - ./external/mongo:/data/db
18 |
19 | ipfs:
20 | image: ipfs/go-ipfs:latest
21 | volumes:
22 | - ./external/ipfs:/data
23 | ports:
24 | - "4001:4001"
25 | - "127.0.0.1:8080:8080"
26 | - "127.0.0.1:8081:8081"
27 | - "127.0.0.1:5001:5001"
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/ecosystem.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | apps : [{
3 | name: "EPNS Staging Showrunners",
4 | script: "build/app.js",
5 | instances: "max",
6 | max_memory_restart: "256M",
7 | env: {
8 | NODE_ENV: "development"
9 | },
10 | env_production: {
11 | NODE_ENV: "production"
12 | }
13 | }]
14 | };
15 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/logs/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": [
3 | "src",
4 | ".env"
5 | ],
6 | "ext": "js,ts,json",
7 | "ignore": [
8 | "src/**/*.spec.ts"
9 | ],
10 | "exec": "ts-node --transpile-only ./src/app.ts"
11 | }
12 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/public/assets/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/public/cache/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # npm install
3 | # npm run build
4 | # cp .env build/.env
5 | docker-compose up &
6 | cd build && node app.js &
7 | # EOF
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/index.ts:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 | import LoggerInstance from '../loaders/logger';
3 | import config from '../config'
4 |
5 | import fs from 'fs';
6 | const utils = require('../helpers/utilsHelper');
7 |
8 |
9 | //import mailing from './routes/mailing';
10 |
11 | // guaranteed to get dependencies
12 | export default () => {
13 | const app = Router();
14 |
15 | // -- SHOWRUNNERS ROUTES
16 | LoggerInstance.info(` -- Checking and Loading Dynamic Routes...`);
17 | const channelFolderPath = `${__dirname}/../showrunners/`
18 | const directories = utils.getDirectories(channelFolderPath)
19 |
20 | for (const channel of directories) {
21 | const absPath = `${channelFolderPath}${channel}/${channel}Routes.${config.fileSuffix}`
22 | const relativePath = `../showrunners/${channel}/${channel}Routes.${config.fileSuffix}`
23 |
24 | if (fs.existsSync(absPath)) {
25 | const cronning = require(absPath)
26 | cronning.default(app);
27 |
28 | LoggerInstance.info(` ✔️ ${relativePath} Loaded!`)
29 | }
30 | else {
31 | LoggerInstance.info(` ❌ ${relativePath} Not Found... skipped`)
32 | }
33 | }
34 |
35 | //WALLET MONITORING ROUTES
36 | LoggerInstance.info(` -- Checking and Loading Wallet Monitoring Routes...`);
37 | const absPath = `${__dirname}/routes/walletMonitoringRoutes.${config.fileSuffix}`
38 | const relativePath = `./routes/walletMonitoringRoutes.${config.fileSuffix}`
39 | const FLAG = Number(config.walletMonitoring);
40 |
41 | if (FLAG === 1) {
42 | LoggerInstance.info(` ✔️ Wallet Monitoring is ${FLAG}`)
43 | try{
44 | const cronning = require(absPath)
45 | cronning.default(app);
46 |
47 | LoggerInstance.info(` ✔️ ${relativePath} Loaded!`)
48 | }catch(err){
49 | LoggerInstance.info(` ❌ Aborting - Wallet Monitoring requires Master Wallet private key. Include 'MASTER_WALLET_PRIVATE_KEY' or change 'WALLET_MONITORING' to 0 in the env file`)
50 | process.exit(1)
51 | }
52 | }
53 | else if (FLAG === 0){
54 | LoggerInstance.info(` ❌ Wallet Monitoring is ${FLAG}... ${relativePath} skipped`)
55 | }
56 |
57 |
58 | // -- HELPERS
59 | // For mailing route
60 | //mailing(app);
61 |
62 | // Finally return app
63 | return app;
64 | }
65 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/middlewares/index.ts:
--------------------------------------------------------------------------------
1 | import onlyTrustedSource from './onlyTrustedSource';
2 | import onlyLocalhost from './onlyLocalhost';
3 |
4 | export default {
5 | onlyTrustedSource,
6 | onlyLocalhost,
7 | };
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/middlewares/onlyLocalhost.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 |
5 | var dns = require('dns');
6 | var os = require('os');
7 | var ifaces = os.networkInterfaces();
8 |
9 | /**
10 | * @param {*} req Express req Object
11 | * @param {*} res Express res Object
12 | * @param {*} next Express next Function
13 | */
14 | const onlyLocalhost = async (req, res, next) => {
15 | const Logger: Logger = Container.get('logger');
16 | try {
17 | // Check if ip is localhost and only continue
18 | var ip = req.connection.remoteAddress;
19 | var host = req.get('host');
20 |
21 | if (config.environment === 'production') {
22 | // Return with unauthorized error
23 | return res.sendStatus(401).json({ info: 'Only development config' });
24 | }
25 |
26 | checkLocalHost(ip)
27 | .then(result => {
28 | if (!result) {
29 | return res.sendStatus(401).json({ info: 'Only localhost connection allowed' });
30 | }
31 |
32 | return next();
33 | })
34 | .catch(e => {
35 | Logger.error('🔥 Error attaching Only Localhost middleware to req: %o', e);
36 | return next(e);
37 | });
38 | } catch (e) {
39 | Logger.error('🔥 Error attaching Only Localhost middleware to req: %o', e);
40 | return next(e);
41 | }
42 | };
43 |
44 | export const checkLocalHost = async (address) => {
45 | return new Promise((resolve, reject) => {
46 | dns.lookup(address, function(err, addr) {
47 | if(err) {
48 | resolve(false);
49 | return;
50 | }
51 | try {
52 | address = addr;
53 | Object.keys(ifaces).forEach(function (ifname) {
54 | ifaces[ifname].forEach(function (iface) {
55 | if(iface.address === address)
56 | resolve(true);
57 | });
58 | });
59 | resolve(false);
60 | }
61 | catch(err){
62 | reject(err);
63 | }
64 | })
65 | })
66 | }
67 |
68 | export default onlyLocalhost;
69 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/middlewares/onlyTrustedSource.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 |
5 | /**
6 | * @param {*} req Express req Object
7 | * @param {*} res Express res Object
8 | * @param {*} next Express next Function
9 | */
10 | const onlyTrustedSource = async (req, res, next) => {
11 | const Logger: Logger = Container.get('logger');
12 | try {
13 | // Check if ip is localhost and only continue
14 | var url = req.headers.origin;
15 |
16 | if (config.trusterURLs.indexOf(url) == -1) {
17 | // Not in the array
18 | return res.sendStatus(403).json({ info: 'Only meant for trusted urls' });
19 | }
20 |
21 | return next();
22 | } catch (e) {
23 | Logger.error('🔥 Error attaching Only Trusted Source middleware to url: %o | req: %o | err: %o', url, req, e);
24 | return next(e);
25 | }
26 | };
27 |
28 | export default onlyTrustedSource;
29 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/routes/mailing.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import EmailService from '../../services/emailService';
4 | import middlewares from '../middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 |
7 | const route = Router();
8 |
9 | export default (app: Router) => {
10 | app.use('/mailing', route);
11 |
12 | // to add an incoming payload
13 | route.post(
14 | '/send_mail',
15 | celebrate({
16 | body: Joi.object({
17 | from: Joi.string().required(),
18 | name: Joi.string().required(),
19 | topic: Joi.string().required(),
20 | sub: Joi.string().required(),
21 | msg: Joi.string().required(),
22 | }),
23 | }),
24 | middlewares.onlyTrustedSource,
25 | async (req: Request, res: Response, next: NextFunction) => {
26 | const Logger: any = Container.get('logger');
27 | Logger.debug('Calling /mailing/send_mail endpoint with body: %o', req.body);
28 | try {
29 | const email = Container.get(EmailService);
30 | const { success, msg } = await email.sendMailSES(
31 | req.body.from,
32 | req.body.name,
33 | req.body.topic,
34 | req.body.sub,
35 | req.body.msg,
36 | );
37 |
38 | return res.status(201).json({ success, msg });
39 | } catch (e) {
40 | Logger.error('🔥 error: %o', e);
41 | return next(e);
42 | }
43 | },
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/api/routes/walletMonitoringRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import walletMonitoringHelper from '../../services/walletMonitoring';
4 | import middlewares from '../middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 | import { Logger } from 'winston';
7 |
8 | const route = Router();
9 |
10 | export default (app: Router) => {
11 | app.use('/showrunners/wallet_monitoring', route);
12 |
13 | route.post(
14 | '/check_wallets',
15 | celebrate({
16 | body: Joi.object({
17 | simulate: [Joi.bool(), Joi.object()],
18 | }),
19 | }),
20 | middlewares.onlyLocalhost,
21 | async (req: Request, res: Response, next: NextFunction) => {
22 | const Logger: Logger= Container.get('logger');
23 | Logger.debug('Calling /showrunners/wallet_monitoring/check_wallets endpoint with body: %o', req.body )
24 | try {
25 | const walletMonitor = Container.get(walletMonitoringHelper);
26 | const result = await walletMonitor.processWallets(req.body.simulate);
27 |
28 | return res.status(201).json({result});
29 | } catch (e) {
30 | Logger.error('🔥 error: %o', e);
31 | return next(e);
32 | }
33 | },
34 | );
35 |
36 | route.post(
37 | '/check_main_wallet',
38 | celebrate({
39 | body: Joi.object({
40 | simulate: [Joi.bool(), Joi.object()],
41 | }),
42 | }),
43 | middlewares.onlyLocalhost,
44 | async (req: Request, res: Response, next: NextFunction) => {
45 | const Logger: Logger = Container.get('logger');
46 | Logger.debug('Calling /showrunners/wallet_monitoring/check_main_wallet endpoint with body: %o', req.body )
47 | try {
48 | const walletMonitor = Container.get(walletMonitoringHelper);
49 | const result = await walletMonitor.processMainWallet(req.body.simulate);
50 |
51 | return res.status(201).json({result});
52 | } catch (e) {
53 | Logger.error('🔥 error: %o', e);
54 | return next(e);
55 | }
56 | },
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/app.ts:
--------------------------------------------------------------------------------
1 | import 'reflect-metadata'; // We need this in order to use @Decorators
2 |
3 | import express from 'express';
4 |
5 | import EnvVerifierLoader from './loaders/envVerifier';
6 | import Logger from './loaders/logger';
7 |
8 | async function startServer() {
9 | // Check environment setup first
10 | Logger.info('✌️ Verifying ENV');
11 | await EnvVerifierLoader();
12 | Logger.info('✔️ ENV Verified / Generated and Loaded!');
13 | // Continue load
14 | const config = (await require('./config/index')).default;
15 |
16 | // load app
17 | const app = express();
18 |
19 | /**
20 | * A little hack here
21 | * Import/Export can only be used in 'top-level code'
22 | * Well, at least in node 10 without babel and at the time of writing
23 | * So we are using good old require.
24 | **/
25 | await require('./loaders').default({ expressApp: app });
26 |
27 | app.listen(config.port, err => {
28 | if (err) {
29 | Logger.error(err);
30 | process.exit(1);
31 | return;
32 | }
33 |
34 | Logger.info(`
35 | ################################################
36 |
37 |
38 | ███████╗██╗ ██╗ ██████╗ ██╗ ██╗██████╗ ██╗ ██╗███╗ ██╗███╗ ██╗███████╗██████╗ ███████╗ ███████╗████████╗ █████╗ ██████╗ ██╗███╗ ██╗ ██████╗
39 | ██╔════╝██║ ██║██╔═══██╗██║ ██║██╔══██╗██║ ██║████╗ ██║████╗ ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝ ██║████╗ ██║██╔════╝
40 | ███████╗███████║██║ ██║██║ █╗ ██║██████╔╝██║ ██║██╔██╗ ██║██╔██╗ ██║█████╗ ██████╔╝███████╗ ███████╗ ██║ ███████║██║ ███╗██║██╔██╗ ██║██║ ███╗
41 | ╚════██║██╔══██║██║ ██║██║███╗██║██╔══██╗██║ ██║██║╚██╗██║██║╚██╗██║██╔══╝ ██╔══██╗╚════██║ ╚════██║ ██║ ██╔══██║██║ ██║██║██║╚██╗██║██║ ██║
42 | ███████║██║ ██║╚██████╔╝╚███╔███╔╝██║ ██║╚██████╔╝██║ ╚████║██║ ╚████║███████╗██║ ██║███████║ ███████║ ██║ ██║ ██║╚██████╔╝██║██║ ╚████║╚██████╔╝
43 | ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝
44 |
45 |
46 | 🛡️ Server listening on port: ${config.port} 🛡️
47 |
48 | ################################################
49 | `);
50 | });
51 | }
52 |
53 | startServer();
54 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/decorators/eventDispatcher.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Originally taken from 'w3tecch/express-typescript-boilerplate'
3 | * Credits to the author
4 | */
5 |
6 | import { EventDispatcher as EventDispatcherClass } from 'event-dispatch';
7 | import { Container } from 'typedi';
8 |
9 | export function EventDispatcher() {
10 | return (object: any, propertyName: string, index?: number): void => {
11 | const eventDispatcher = new EventDispatcherClass();
12 | Container.registerHandler({ object, propertyName, index, value: () => eventDispatcher });
13 | };
14 | }
15 |
16 | export { EventDispatcher as EventDispatcherInterface } from 'event-dispatch';
17 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/helpers/dbHelper.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../config';
4 |
5 | var mysql = require('mysql');
6 | // const MySQLEvents = require('@rodrigogs/mysql-events');
7 |
8 | var pool = mysql.createPool({
9 | connectionLimit: 10,
10 | host: config.dbhost,
11 | user: config.dbuser,
12 | password: config.dbpass,
13 | database: config.dbname,
14 | });
15 | export default {
16 | pool,
17 | query: function() {
18 | const Logger: Logger = Container.get('logger');
19 |
20 | var sql_args = [];
21 | var args = [];
22 | for (var i = 0; i < arguments.length; i++) {
23 | args.push(arguments[i]);
24 | }
25 |
26 | var callback = args[args.length - 1]; //last arg is callback
27 | pool.getConnection(function(err, connection) {
28 | if (err) {
29 | Logger.error(err);
30 |
31 | return callback(err);
32 | }
33 |
34 | if (args.length > 2) {
35 | sql_args = args[1];
36 | }
37 |
38 | connection.query(args[0], sql_args, function(err, results) {
39 | connection.release(); // always put connection back in pool after last query
40 |
41 | if (err) {
42 | Logger.error(err);
43 |
44 | return callback(err);
45 | }
46 |
47 | callback(null, results);
48 | });
49 | });
50 | },
51 | };
52 |
53 | /* EXAMPLE
54 | var db = require('../helpers/dbHelper');
55 |
56 | db.query(
57 | 'Select * from `sessions` where `Active`=1 and Expires>?;',
58 | [~~(new Date()/1000)],
59 | function(err, results){
60 |
61 | if(err){
62 | console.log(err);
63 | }
64 | else{
65 | console.log(results);
66 | }
67 |
68 | }
69 | );
70 | */
71 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/helpers/showrunnersHelper.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 |
3 |
4 | export const showrunnersHelper = {
5 | // Check if Private Key is valid
6 | getValidWallet: async function(showrunnerName, wallets) {
7 | const Cache: any = Container.get('cached');
8 | const cacheKeyName = this.getCacheKeyName(showrunnerName);
9 |
10 | const numberOfWallets = Object.keys(wallets).length;
11 | let selectedWalletID = await Cache.getCache(cacheKeyName);
12 |
13 | if (selectedWalletID) {
14 | // Cache found, increment it and see if it fits
15 | selectedWalletID = parseInt(selectedWalletID) + 1;
16 |
17 | if (selectedWalletID > numberOfWallets) {
18 | selectedWalletID = 1; // Round robin back
19 | }
20 | } else {
21 | selectedWalletID = 1;
22 | }
23 |
24 | const result = await Cache.setCache(cacheKeyName, selectedWalletID);
25 |
26 | return {
27 | numOfWallets: numberOfWallets,
28 | currentWalletID: selectedWalletID,
29 | };
30 | },
31 | getCacheKeyName: function(showrunnerName) {
32 | return `${showrunnerName}WalletsMetaCacheKey`;
33 | },
34 | };
35 |
36 | export default showrunnersHelper;
37 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/interfaces/IGas.ts:
--------------------------------------------------------------------------------
1 | export interface IGas {
2 | _id: string;
3 | price: number;
4 | }
5 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/cache.ts:
--------------------------------------------------------------------------------
1 | const redis = require('async-redis');
2 | import config from '../config';
3 |
4 | class CacheInstance {
5 | private ReddisInstance;
6 | constructor() {
7 | this.ReddisInstance = redis.createClient(config.redisURL);
8 | }
9 | /**
10 | * Set cache
11 | * @description adds a part
12 | * @param {String} key Cache Key
13 | * @param {String} value Cache Value
14 | * @return {Promise<{ null }>}
15 | */
16 | public async setCache(key: String, value: Number) {
17 | return this.ReddisInstance.set(key, value);
18 | };
19 |
20 | /**
21 | * push lcache
22 | * @description adds to a cache like an array
23 | * @param {String} key Cache Key
24 | * @param {String} value Cache Value
25 | * @return {Promise<{ null }>}
26 | */
27 | public async pushLCache(key: String, value: Number) {
28 | return this.ReddisInstance.rpush(key, value);
29 | };
30 |
31 | /**
32 | * get lcache
33 | * @description get all items in a list
34 | * @param {String} key Cache Key
35 | * @return {Promise<{ null }>}
36 | */
37 | public async getLCache(key: String) {
38 | return this.ReddisInstance.lrange(key, 0, -1);
39 | };
40 |
41 | /**
42 | * Add caches
43 | * @description adds to already existing value in cache
44 | * @param {String} key Cache Key
45 | * @param {Number} value Value to be added
46 | * @return {Promise<{ null }>}
47 | */
48 | public async addCache(key: String, value: Number) {
49 | const prev: Number = Number(await this.getCache(key));
50 | if (prev != 0) {
51 | value = Number(prev) + Number(value);
52 | value = Number(value) / 2
53 | }
54 | return this.ReddisInstance.set(key, value);
55 | };
56 |
57 | /**
58 | * Remove cache
59 | * @description deletes a cache key and its associated values
60 | * @param {String} key Cache Key
61 | * @return {Promise<{ null }>}
62 | */
63 | public async removeCache(key: String) {
64 | return this.ReddisInstance.del(key);
65 | };
66 |
67 | /**
68 | * Get cache
69 | * @description retrieves the value of a cache key
70 | * @param {String} key Cache Key
71 | * @return {Promise<{ String }>}
72 | */
73 | public async getCache(key: String) {
74 | return this.ReddisInstance.get(key);
75 | };
76 |
77 | }
78 |
79 |
80 | export default new CacheInstance();
81 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/db.ts:
--------------------------------------------------------------------------------
1 | import db from '../helpers/dbHelper';
2 |
3 | export default () => {
4 | return db.pool;
5 | };
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/dbListener.ts:
--------------------------------------------------------------------------------
1 | const MySQLEvents = require('@rodrigogs/mysql-events');
2 |
3 | export default async ({ pool, logger }) => {
4 | try {
5 | const instance = new MySQLEvents(pool, {
6 | startAtEnd: true,
7 | });
8 |
9 | const response = await instance.start();
10 | } catch (e) {
11 | console.log(e);
12 | }
13 |
14 | // EXAMPLE
15 | // dbEvents.addTrigger({
16 | // name: 'Whole database instance',
17 | // expression: '*',
18 | // statement: MySQLEvents.STATEMENTS.ALL,
19 | // onEvent: (event) => {
20 | // console.log("Some Event");
21 | // console.log(event);
22 | // },
23 | // });
24 |
25 | // 1. SAMPLE SERVICE
26 | // Listen to Something for Some Data
27 | // logger.info('-- 🔮 Started Listening | INSERT | zzzz.tttt.*');
28 | // instance.addTrigger({
29 | // name: 'CHANNELS_INSERT',
30 | // expression: 'zzz.tttt.*',
31 | // statement: MySQLEvents.STATEMENTS.INSERT,
32 | // onEvent: async (event) => {
33 | // logger.info("🧿 DB Event: %s | %s -- %o | [%s]", event.type, event.schema + '.' + event.table, event.affectedColumns, new Date(event.timestamp).toLocaleString());
34 | //
35 | // await triggerBatchProcessSomething(event, logger);
36 | // },
37 | // });
38 | };
39 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/dependencyInjector.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import LoggerInstance from './logger';
3 | import CacheInstance from './cache';
4 |
5 |
6 | export default ({ models }: { models: { name: string; model: any }[] }) => {
7 | try {
8 | LoggerInstance.info('✌️ Loading Mongo DB Models');
9 |
10 | models.forEach(m => {
11 | LoggerInstance.info(' -- ✔️ Loading Mongo DB Model: %s', m)
12 | Container.set(m.name, m.model);
13 | });
14 |
15 | LoggerInstance.info('✔️ All Mongo DB Models loaded!');
16 |
17 | Container.set('logger', LoggerInstance);
18 | LoggerInstance.info('✔️ Logger Injected');
19 |
20 | Container.set('cached', CacheInstance);
21 | LoggerInstance.info('✔️ Cache (with Redis) Loaded! 🐳🐳🐳');
22 |
23 | // Container.set('dbpool', MysqlInstance)
24 | // LoggerInstance.info('✌️ Databse Injected');
25 |
26 | return null;
27 | } catch (e) {
28 | LoggerInstance.error('🔥 Error on dependency injector loader: %o', e);
29 | throw e;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/express.ts:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import bodyParser from 'body-parser';
3 | import cors from 'cors';
4 | import routes from '../api';
5 | import config from '../config';
6 |
7 |
8 | export default ({ app }: { app: express.Application }) => {
9 | /**
10 | * Health Check endpoints
11 | * @TODO Explain why they are here
12 | */
13 | app.get('/status', (req, res) => {
14 | res.status(200).end();
15 | });
16 | app.head('/status', (req, res) => {
17 | res.status(200).end();
18 | });
19 |
20 | // Useful if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
21 | // It shows the real origin IP in the heroku or Cloudwatch logs
22 | app.enable('trust proxy');
23 |
24 | // The magic package that prevents frontend developers going nuts
25 | // Alternate description:
26 | // Enable Cross Origin Resource Sharing to all origins by default
27 | app.use(cors());
28 |
29 | // Some sauce that always add since 2014
30 | // "Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it."
31 | // Maybe not needed anymore ?
32 | app.use(require('method-override')());
33 |
34 | // Middleware that transforms the raw string of req.body into json
35 | app.use(bodyParser.json());
36 |
37 | // Load API routes
38 | app.use(config.api.prefix, routes());
39 |
40 | // Load Static Files
41 | app.use(express.static(config.staticServePath));
42 |
43 | /// catch 404 and forward to error handler
44 | app.use((req, res, next) => {
45 | const err = new Error('Not Found');
46 | err['status'] = 404;
47 | next(err);
48 | });
49 |
50 | /// error handlers
51 | app.use((err, req, res, next) => {
52 | /**
53 | * Handle 401 thrown by express-jwt library
54 | */
55 | if (err.name === 'UnauthorizedError') {
56 | return res
57 | .status(err.status)
58 | .send({ message: err.message })
59 | .end();
60 | }
61 | return next(err);
62 | });
63 | app.use((err, req, res, next) => {
64 | res.status(err.status || 500);
65 | res.json({
66 | error: {
67 | info: err.message,
68 | },
69 | });
70 | });
71 | };
72 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/mongoose.ts:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose';
2 | import { Db } from 'mongodb';
3 | import config from '../config';
4 |
5 | export default async (): Promise => {
6 | const connection = await mongoose.connect(config.mongodb, {
7 | useNewUrlParser: true,
8 | useCreateIndex: true,
9 | useUnifiedTopology: true,
10 | });
11 | return connection.connection.db;
12 | };
13 |
14 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/redis.ts:
--------------------------------------------------------------------------------
1 | const redis = require('async-redis');
2 | import config from '../config';
3 |
4 | const ReddisInstance = redis.createClient({ config.redisURL });
5 |
6 | export default ReddisInstance;
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/loaders/webhooks.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | import config from '../config';
4 | import { Container } from 'typedi';
5 | import schedule from 'node-schedule';
6 | import { EventDispatcher, EventDispatcherInterface } from '../decorators/eventDispatcher';
7 | import { Router, Request, Response, NextFunction } from 'express';
8 |
9 | import fs from 'fs';
10 | const utils = require('../helpers/utilsHelper');
11 | const webhookHelper = require('../helpers/webhookHelper');
12 | const route = Router();
13 |
14 | export default async ({ logger, app }) => {
15 | // WEBHOOK SERVICE
16 | logger.info(` -- Checking and Loading Dynamic Webhooks...`);
17 | const channelFolderPath = `${__dirname}/../showrunners/`;
18 | const directories = utils.getDirectories(channelFolderPath);
19 |
20 | for (const channel of directories) {
21 | const absPath = `${channelFolderPath}${channel}/${channel}AWSSNS.${config.fileSuffix}`;
22 | const relativePath = `../showrunners/${channel}/${channel}AWSSNS.${config.fileSuffix}`;
23 |
24 | if (fs.existsSync(absPath)) {
25 | const webhook = await import(absPath);
26 | webhook.default(app);
27 | logger.info(` ✔️ ${relativePath} Loaded!`);
28 | } else {
29 | logger.info(` ❌ ${relativePath} Not Found... skipped`);
30 | }
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/README.md:
--------------------------------------------------------------------------------
1 | ## Sample Showrunners
2 |
3 | ```
4 | This folder includes sample code for showrunners channels. You can use those channels as reference or add your custom
5 | showrunners channel in the same folder. Each folder of showrunners channel contains {channelName}Keys.json in which you can
6 | add your Private keys to run the showrunners.
7 | ```
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/aave/aaveJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 |
21 | import AaveChannel from './aaveChannel';
22 |
23 | export default () => {
24 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
25 |
26 | const dailyRule = new schedule.RecurrenceRule();
27 | dailyRule.hour = 0;
28 | dailyRule.minute = 0;
29 | dailyRule.second = 0;
30 | dailyRule.dayOfWeek = new schedule.Range(0, 6);
31 |
32 | // AAVE CHANNEL RUNS EVERY 24 Hours
33 | logger.info(` 🛵 Scheduling Showrunner - Aave Channel [on 6 Hours] [${new Date(Date.now())}]`);
34 | schedule.scheduleJob({ start: startTime, rule: dailyRule }, async function () {
35 | const aaveChannel = Container.get(AaveChannel);
36 | const taskName = 'Aave users address checks and sendMessageToContract()';
37 |
38 | try {
39 | await aaveChannel.sendMessageToContract(false);
40 | logger.info(`[${new Date(Date.now())}] 🐣 Cron Task Completed -- ${taskName}`);
41 | }
42 | catch (err) {
43 | logger.error(`[${new Date(Date.now())}] ❌ Cron Task Failed -- ${taskName}`);
44 | logger.error(`[${new Date(Date.now())}] Error Object: %o`, err);
45 | }
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/aave/aaveKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/aave/aaveKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/aave/aaveSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "aaveLendingPoolDeployedContractPolygonMainnet": "0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf",
3 | "aaveLendingPoolDeployedContractPolygonMumbai": "0x9198F13B08E299d85E096929fA9781A1E3d5d827",
4 | "aaveLendingPoolDeployedContractMainnet": "0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9",
5 | "aaveLendingPoolDeployedContractKovan": "0xE0fBa4Fc209b4948668006B2bE61711b7f465bAe"
6 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/digible/digibleKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/digible/digibleKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/digible/digibleModel.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable prettier/prettier */
2 | import { model, Document, Schema } from 'mongoose';
3 |
4 | export interface DigibleData {
5 | latestBlockForDigiTrackEvent?: number;
6 | latestBlockForOfferRecieved?: number;
7 | latestBlockForOfferAccepted?: number;
8 | latestBlockForOfferCancelled?: number;
9 | }
10 |
11 | const digibleSchema = new Schema({
12 | _id: {
13 | type: String,
14 | },
15 | latestBlockForDigiTrackEvent: {
16 | type: Number,
17 | },
18 | latestBlockForOfferRecieved: {
19 | type: Number,
20 | },
21 | latestBlockForOfferAccepted: {
22 | type: Number,
23 | },
24 | latestBlockForOfferCancelled: {
25 | type: Number,
26 | },
27 | });
28 |
29 | export const digibleModel = model('digibleDB', digibleSchema);
30 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/digible/digibleSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "digiTrackContractAddressMainnet": "0x4168a4D108b24A347F19617BB95C25c8Eb9618de",
3 | "digiTrackContractAddressTestnet": "0x4168a4D108b24A347F19617BB95C25c8Eb9618de",
4 | "digiTradeContractAddressMainnet": "0x915338948fBF10583DD15C6FcCCF55565FF5b60f",
5 | "digiTradeContractAddressTestnet": "0x915338948fBF10583DD15C6FcCCF55565FF5b60f"
6 | }
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/ens/ensJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 |
21 | import EnsExpirationChannel from './ensChannel';
22 |
23 | export default () => {
24 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
25 |
26 | const dailyRule = new schedule.RecurrenceRule();
27 | dailyRule.hour = 0;
28 | dailyRule.minute = 0;
29 | dailyRule.second = 0;
30 | dailyRule.dayOfWeek = new schedule.Range(0, 6);
31 | const channel = Container.get(EnsExpirationChannel);
32 |
33 | //1.3 ENS TICKER CHANNEL
34 | channel.logInfo(` 🛵 Scheduling Showrunner - [on 24 Hours] [${new Date(Date.now())}]`);
35 | schedule.scheduleJob({ start: startTime, rule: dailyRule }, async function() {
36 | const taskName = `${channel.cSettings.name} checkDomainExpiryTask`;
37 |
38 | try {
39 | await channel.checkDomainExpiryTask(false);
40 | channel.logInfo(`🐣 Cron Task Completed -- ${taskName}`);
41 | } catch (err) {
42 | logger.error(`[${new Date(Date.now())}] ❌ Cron Task Failed -- ${taskName}`);
43 | logger.error(`[${new Date(Date.now())}] Error Object: %o`, err);
44 | }
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/ens/ensKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/ens/ensKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/ens/ensRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import EnsExiprationChannel from './ensChannel';
4 | import middlewares from '../../api/middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 | import { handleResponse } from '../../helpers/utilsHelper';
7 | import { Logger } from 'winston';
8 |
9 | const route = Router();
10 |
11 | export default (app: Router) => {
12 | app.use('/showrunners/ensv2', route);
13 |
14 | /**
15 | * Send Message
16 | * @description Send a notification via the ensdomain showrunner
17 | * @param {boolean} simulate whether to send the actual message or simulate message sending
18 | */
19 | route.post(
20 | '/test',
21 | celebrate({
22 | body: Joi.object({
23 | simulate: [Joi.bool(), Joi.object()],
24 | }),
25 | }),
26 | middlewares.onlyLocalhost,
27 | async (req: Request, res: Response, next: NextFunction) => {
28 | const logger: Logger = Container.get('logger');
29 | logger.debug('Calling /showrunners/ensv2/send_message endpoint with body: %o', req.body);
30 | try {
31 | const ensDomain = Container.get(EnsExiprationChannel);
32 | const data: any = await ensDomain.checkDomainExpiryTask(false);
33 | res.json({ success: true });
34 | } catch (e) {
35 | logger.error('🔥 error: %o', e);
36 | return handleResponse(res, 500, false, 'error', JSON.stringify(e));
37 | }
38 | },
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/ens/ensSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ensDeployedContract": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85",
3 | "ensEndpoint": "https://api.thegraph.com/subgraphs/name/ensdomains/ens"
4 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/helloWorldAWSSNS.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import HelloWorldChannel from './helloWorldChannel';
4 | import axios from 'axios';
5 | import { Logger } from 'winston';
6 | import { enableAWSWebhook } from '../../helpers/webhookHelper';
7 |
8 | const route = Router();
9 |
10 | export default (app: Router) => {
11 | const channel = Container.get(HelloWorldChannel);
12 | app.use('/showrunners/helloworld', route);
13 |
14 | // enable webhooks
15 | enableAWSWebhook(route, channel.webhookPayloadHandler.bind(channel)); // add the extra bind method to enable the use of 'this' inside the callback
16 | // enable webhooks
17 | };
18 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/helloWorldChannel.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Service } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 | import { EPNSChannel } from '../../helpers/epnschannel';
5 | import { mockMessages } from './messages';
6 |
7 | @Service()
8 | export default class HelloWorldChannel extends EPNSChannel {
9 | constructor(@Inject('logger') public logger: Logger) {
10 | super(logger, {
11 | networkToMonitor: config.web3MainnetNetwork,
12 | dirname: __dirname,
13 | name: 'Hello World',
14 | url: 'https://epns.io/',
15 | useOffChain: true,
16 | });
17 | }
18 | // Checks for profile Expiration and Sends notification to users
19 | // Whose Profile is about to be expired
20 | async helloWorld(simulate) {
21 | try {
22 | this.logInfo('Sending notification to evidence provider');
23 |
24 | // Notification Type: 1 for Broadcast, 3 for Subset, 4 for targeted
25 | // Read More: https://docs.epns.io/developers/developer-guides/sending-notifications/notification-payload-types/notification-standard-basics
26 | const notificationType = 1;
27 |
28 | // Omit for broadcast, single address for targeted and channel address or array of addresses for subset
29 | const recipients = this.channelAddress;
30 |
31 | for (const e of mockMessages.messages) {
32 | await this.sendNotification({
33 | recipient: recipients,
34 | title: e.title,
35 | message: e.msg,
36 | payloadTitle: e.title,
37 | payloadMsg: e.msg,
38 | notificationType: notificationType,
39 | cta: e.cta,
40 | image: null,
41 | simulate: simulate,
42 | });
43 | }
44 |
45 | return { success: true };
46 | } catch (error) {
47 | this.logError(error);
48 | }
49 | }
50 |
51 | /**
52 | * The method responsible for handling webhook payload
53 | * @param payload
54 | */
55 | public async webhookPayloadHandler(payload: any, simulate: any) {
56 | const { Message } = payload;
57 |
58 | // do something with the payload
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/helloWorldJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 | import HelloWorldChannel from './helloWorldChannel';
21 |
22 | export default () => {
23 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
24 |
25 | const fiveMinuteRule = new schedule.RecurrenceRule();
26 |
27 | fiveMinuteRule.minute = 5;
28 |
29 | const channel = Container.get(HelloWorldChannel);
30 | channel.logInfo(` 🛵 Scheduling Showrunner - ${channel.cSettings.name} Channel`);
31 |
32 | schedule.scheduleJob({ start: startTime, rule: fiveMinuteRule }, async function () {
33 | const taskName = `${channel.cSettings.name} event checks and helloWorld`;
34 |
35 | try {
36 | await channel.helloWorld(false);
37 |
38 | channel.logInfo(`🐣 Cron Task Completed -- ${taskName}`);
39 | } catch (err) {
40 | channel.logInfo(`❌ Cron Task Failed -- ${taskName}`);
41 | channel.logError(`Error Object: %o`);
42 | channel.logError(err);
43 | }
44 | });
45 | };
46 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/helloWorldKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "ec8592fa4c42ff67ab3ef22a66251498f3240fdf7c2e420a886476478fc65932_ALREADY_DOXXED",
4 | "CHAIN_ID": "eip155:80001_CHANNEL_FOR_POLYGON"
5 | }
6 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/helloWorldRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import middlewares from '../../api/middlewares';
4 | import { celebrate, Joi } from 'celebrate';
5 | import TestChannel from './helloWorldChannel';
6 |
7 | const route = Router();
8 |
9 | export default (app: Router) => {
10 | app.use('/showrunners/helloWorld', route);
11 |
12 | route.post(
13 | '/testnotif',
14 | celebrate({
15 | body: Joi.object({
16 | simulate: [Joi.bool(), Joi.object()],
17 | }),
18 | }),
19 | middlewares.onlyLocalhost,
20 | async (req: Request, res: Response, next: NextFunction) => {
21 | const Logger: any = Container.get('logger');
22 |
23 | try {
24 | const helloWorld = Container.get(TestChannel);
25 | helloWorld.helloWorld(req.body.simulate);
26 | return res.status(201).json({ success: true });
27 | } catch (e) {
28 | Logger.error('🔥 error: %o', e);
29 | return next(e);
30 | }
31 | },
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/helloWorld/messages.ts:
--------------------------------------------------------------------------------
1 | export const mockMessages = {
2 | messages: [
3 | {
4 | title: 'Hello World!',
5 | msg: `Hello Hackers ;)`,
6 | cta: 'https://epns.io',
7 | },
8 | ],
9 | };
10 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/proofOfHumanity/pohCacheModel.ts:
--------------------------------------------------------------------------------
1 | import { model, Schema, Document } from 'mongoose';
2 |
3 | export interface IPOHSchema {
4 | removalRequestBlockNo?: number;
5 | savedChallengeTimestamp?: number;
6 | savedEvidenceTimestamp?: number;
7 | }
8 | const POHDB = new Schema({
9 | _id: {
10 | type: String,
11 | },
12 | removalRequestBlockNo: {
13 | type: Number,
14 | },
15 | savedChallengeTimestamp: {
16 | type: Number,
17 | },
18 | savedEvidenceTimestamp: {
19 | type: Number,
20 | },
21 | });
22 |
23 | export const POHModel = model('POHDB', POHDB);
24 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/proofOfHumanity/proofOfHumanityKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
3 | }
4 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/proofOfHumanity/proofOfHumanityModel.ts:
--------------------------------------------------------------------------------
1 | import { model, Schema, Document } from 'mongoose';
2 | import { Submission } from './proofOfHumanityChannel';
3 |
4 | const POHSubmission = new Schema({
5 | _id: String,
6 | submissionTime: {
7 | type: String,
8 | required: true,
9 | },
10 | creationTime: {
11 | type: String,
12 | required: true,
13 | },
14 | name: {
15 | type: String,
16 | required: true,
17 | },
18 | registered: {
19 | type: Boolean,
20 | required: true,
21 | },
22 | status: {
23 | type: String,
24 | required: true,
25 | },
26 | });
27 |
28 | // Duplicate the ID field.
29 | POHSubmission.virtual('id').get(function() {
30 | return this._id;
31 | });
32 |
33 | POHSubmission.set('toJSON', {
34 | virtuals: true,
35 | });
36 | export const SubmissionModel = model('POHSubmission', POHSubmission);
37 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/sample_showrunners/proofOfHumanity/proofOfHumanitySettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "proofOfHumanityDeployedContract":"0xc5e9ddebb09cd64dfacab4011a0d5cedaf7c9bdb"
3 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/helloWorldAWSSNS.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import HelloWorldChannel from './helloWorldChannel';
4 | import axios from 'axios';
5 | import { Logger } from 'winston';
6 | import { enableAWSWebhook } from '../../helpers/webhookHelper';
7 |
8 | const route = Router();
9 |
10 | export default (app: Router) => {
11 | const channel = Container.get(HelloWorldChannel);
12 | app.use('/showrunners/helloworld', route);
13 |
14 | // enable webhooks
15 | enableAWSWebhook(route, channel.webhookPayloadHandler.bind(channel)); // add the extra bind method to enable the use of 'this' inside the callback
16 | // enable webhooks
17 | };
18 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/helloWorldChannel.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Service } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 | import { EPNSChannel } from '../../helpers/epnschannel';
5 | import { mockMessages } from './messages';
6 |
7 | @Service()
8 | export default class HelloWorldChannel extends EPNSChannel {
9 | constructor(@Inject('logger') public logger: Logger) {
10 | super(logger, {
11 | networkToMonitor: config.web3MainnetNetwork,
12 | dirname: __dirname,
13 | name: 'Hello World',
14 | url: 'https://epns.io/',
15 | useOffChain: true,
16 | });
17 | }
18 | // Checks for profile Expiration and Sends notification to users
19 | // Whose Profile is about to be expired
20 | async helloWorld(simulate) {
21 | try {
22 | this.logInfo('Sending notification to evidence provider');
23 |
24 | // Notification Type: 1 for Broadcast, 3 for Subset, 4 for targeted
25 | // Read More: https://docs.epns.io/developers/developer-guides/sending-notifications/notification-payload-types/notification-standard-basics
26 | const notificationType = 1;
27 |
28 | // Omit for broadcast, single address for targeted and channel address or array of addresses for subset
29 | const recipients = this.channelAddress;
30 |
31 | for (const e of mockMessages.messages) {
32 | await this.sendNotification({
33 | recipient: recipients,
34 | title: e.title,
35 | message: e.msg,
36 | payloadTitle: e.title,
37 | payloadMsg: e.msg,
38 | notificationType: notificationType,
39 | cta: e.cta,
40 | image: null,
41 | simulate: simulate,
42 | });
43 | }
44 |
45 | return { success: true };
46 | } catch (error) {
47 | this.logError(error);
48 | }
49 | }
50 |
51 | /**
52 | * The method responsible for handling webhook payload
53 | * @param payload
54 | */
55 | public async webhookPayloadHandler(payload: any, simulate: any) {
56 | const { Message } = payload;
57 |
58 | // do something with the payload
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/helloWorldJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 | import HelloWorldChannel from './helloWorldChannel';
21 |
22 | export default () => {
23 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
24 |
25 | const fiveMinuteRule = new schedule.RecurrenceRule();
26 |
27 | fiveMinuteRule.minute = 5;
28 |
29 | const channel = Container.get(HelloWorldChannel);
30 | channel.logInfo(` 🛵 Scheduling Showrunner - ${channel.cSettings.name} Channel`);
31 |
32 | schedule.scheduleJob({ start: startTime, rule: fiveMinuteRule }, async function () {
33 | const taskName = `${channel.cSettings.name} event checks and helloWorld`;
34 |
35 | try {
36 | await channel.helloWorld(false);
37 |
38 | channel.logInfo(`🐣 Cron Task Completed -- ${taskName}`);
39 | } catch (err) {
40 | channel.logInfo(`❌ Cron Task Failed -- ${taskName}`);
41 | channel.logError(`Error Object: %o`);
42 | channel.logError(err);
43 | }
44 | });
45 | };
46 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/helloWorldKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/helloWorldRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import middlewares from '../../api/middlewares';
4 | import { celebrate, Joi } from 'celebrate';
5 | import TestChannel from './helloWorldChannel';
6 |
7 | const route = Router();
8 |
9 | export default (app: Router) => {
10 | app.use('/showrunners/helloWorld', route);
11 |
12 | route.post(
13 | '/testnotif',
14 | celebrate({
15 | body: Joi.object({
16 | simulate: [Joi.bool(), Joi.object()],
17 | }),
18 | }),
19 | middlewares.onlyLocalhost,
20 | async (req: Request, res: Response, next: NextFunction) => {
21 | const Logger: any = Container.get('logger');
22 |
23 | try {
24 | const helloWorld = Container.get(TestChannel);
25 | helloWorld.helloWorld(req.body.simulate);
26 | return res.status(201).json({ success: true });
27 | } catch (e) {
28 | Logger.error('🔥 error: %o', e);
29 | return next(e);
30 | }
31 | },
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/showrunners/helloWorld/messages.ts:
--------------------------------------------------------------------------------
1 | export const mockMessages = {
2 | messages: [
3 | {
4 | title: 'Hello World!',
5 | msg: `Hello Hackers ;)`,
6 | cta: 'https://epns.io',
7 | },
8 | ],
9 | };
10 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/src/subscribers/events.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | // user: {
3 | // signUp: 'onUserSignUp',
4 | // signIn: 'onUserSignIn',
5 | // },
6 | };
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tests/.gitkeep
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tests/sample.test.ts:
--------------------------------------------------------------------------------
1 | describe('Sample Test', () => {
2 | it('can add 2 numbers', () => {
3 | expect(1 + 2).toBe(3);
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tests/services/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tests/services/.gitkeep
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-modified/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "lib": [
5 | "es2017",
6 | "esnext.asynciterable"
7 | ],
8 | "typeRoots": [
9 | "./node_modules/@types",
10 | "./src/types"
11 | ],
12 | "allowSyntheticDefaultImports": true,
13 | "experimentalDecorators": true,
14 | "emitDecoratorMetadata": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "moduleResolution": "node",
17 | "module": "commonjs",
18 | "pretty": true,
19 | "sourceMap": true,
20 | "outDir": "./build",
21 | "allowJs": true,
22 | "noEmit": false,
23 | "resolveJsonModule": true,
24 | "esModuleInterop": true
25 | },
26 | "include": [
27 | "./src/**/*",
28 | "./src/**/*.json"
29 | ],
30 | "exclude": [
31 | "node_modules",
32 | "tests"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: circleci/node:10.15
6 | - image: circleci/mongo:latest
7 | steps:
8 | - checkout
9 | - run:
10 | name: install-npm
11 | command: npm install
12 | - save_cache:
13 | key: dependency-cache-{{ checksum "package.json" }}
14 | paths:
15 | - ./node_modules
16 | - run:
17 | name: test
18 | command: npm test
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.editorconfig:
--------------------------------------------------------------------------------
1 | ################################################
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.env.sample:
--------------------------------------------------------------------------------
1 | # MAKE A COPY OF THIS AND FILL WITH YOUR CREDENTIALS AND NAME IT .env (Remove .sample Part)
2 |
3 | # SHOWRUNNERS ENVIRONMENT: prod or staging or dev
4 | SHOWRUNNERS_ENV=staging
5 |
6 | ## NORMAL CONFIG
7 | # DEBUG | CAN BE 'debug' or 'prod'
8 | LOG_LEVEL=debug_or_prod # 'debug' or 'prod'
9 |
10 | # WEB3 ENDPOINTS | NEED ATLEAST INFURA OR ETHERSCAN OR ALCHEMY, REST CAN BE NULL
11 | INFURA_PROJECT_ID=your_infura_project_id
12 | INFURA_PROJECT_SECRET=your_infura_project_secret
13 |
14 | ## ADVANCED CONFIG
15 | # WEB3 ENDPOINTS | OPTIONAL IF YOU FILLED INFURA_PROJECT AND INFURA_PROJECT_SECRET, CAN SET IT TO NULL IF YOU WANT TO
16 | ETHERSCAN_API=your_etherscan_api_key_or_null
17 | ALCHEMY_API=your_alchemy_api_key_or_null
18 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*
2 |
3 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser
3 | extends: [
4 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
5 | 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
6 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
7 | ],
8 | parserOptions: {
9 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
10 | sourceType: 'module', // Allows for the use of imports
11 | },
12 | rules: {
13 | '@typescript-eslint/explicit-member-accessibility': 0,
14 | '@typescript-eslint/explicit-function-return-type': 0,
15 | '@typescript-eslint/no-parameter-properties': 0,
16 | '@typescript-eslint/interface-name-prefix': 0
17 | },
18 | };
19 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.gitattributes:
--------------------------------------------------------------------------------
1 | *.json merge=json
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: true,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | printWidth: 120,
6 | tabWidth: 2,
7 | };
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/Procfile:
--------------------------------------------------------------------------------
1 | web: node build/app.js
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | [Read more about Showrunners](https://docs.epns.io/developers/developer-guides/sending-notifications/using-showrunners-scaffold-gasless])
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | npm run build
3 | cp .env build/.env
4 | pm2 reload ecosystem.config.js --env production
5 | # EOF
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | redis:
4 | image: 'redis:latest'
5 | container_name: redis
6 | ports:
7 | - 6379:6379
8 | volumes:
9 | - ./external/redis:/data
10 |
11 | mongo:
12 | image: 'mongo:latest'
13 | container_name: mongodb
14 | ports:
15 | - 27017:27017
16 | volumes:
17 | - ./external/mongo:/data/db
18 |
19 | ipfs:
20 | image: ipfs/go-ipfs:latest
21 | volumes:
22 | - ./external/ipfs:/data
23 | ports:
24 | - "4001:4001"
25 | - "127.0.0.1:8080:8080"
26 | - "127.0.0.1:8081:8081"
27 | - "127.0.0.1:5001:5001"
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/ecosystem.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | apps : [{
3 | name: "EPNS Staging Showrunners",
4 | script: "build/app.js",
5 | instances: "max",
6 | max_memory_restart: "256M",
7 | env: {
8 | NODE_ENV: "development"
9 | },
10 | env_production: {
11 | NODE_ENV: "production"
12 | }
13 | }]
14 | };
15 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/logs/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": [
3 | "src",
4 | ".env"
5 | ],
6 | "ext": "js,ts,json",
7 | "ignore": [
8 | "src/**/*.spec.ts"
9 | ],
10 | "exec": "ts-node --transpile-only ./src/app.ts"
11 | }
12 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/public/assets/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/public/cache/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # npm install
3 | # npm run build
4 | # cp .env build/.env
5 | docker-compose up &
6 | cd build && node app.js &
7 | # EOF
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/index.ts:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 | import LoggerInstance from '../loaders/logger';
3 | import config from '../config'
4 |
5 | import fs from 'fs';
6 | const utils = require('../helpers/utilsHelper');
7 |
8 |
9 | //import mailing from './routes/mailing';
10 |
11 | // guaranteed to get dependencies
12 | export default () => {
13 | const app = Router();
14 |
15 | // -- SHOWRUNNERS ROUTES
16 | LoggerInstance.info(` -- Checking and Loading Dynamic Routes...`);
17 | const channelFolderPath = `${__dirname}/../showrunners/`
18 | const directories = utils.getDirectories(channelFolderPath)
19 |
20 | for (const channel of directories) {
21 | const absPath = `${channelFolderPath}${channel}/${channel}Routes.${config.fileSuffix}`
22 | const relativePath = `../showrunners/${channel}/${channel}Routes.${config.fileSuffix}`
23 |
24 | if (fs.existsSync(absPath)) {
25 | const cronning = require(absPath)
26 | cronning.default(app);
27 |
28 | LoggerInstance.info(` ✔️ ${relativePath} Loaded!`)
29 | }
30 | else {
31 | LoggerInstance.info(` ❌ ${relativePath} Not Found... skipped`)
32 | }
33 | }
34 |
35 | //WALLET MONITORING ROUTES
36 | LoggerInstance.info(` -- Checking and Loading Wallet Monitoring Routes...`);
37 | const absPath = `${__dirname}/routes/walletMonitoringRoutes.${config.fileSuffix}`
38 | const relativePath = `./routes/walletMonitoringRoutes.${config.fileSuffix}`
39 | const FLAG = Number(config.walletMonitoring);
40 |
41 | if (FLAG === 1) {
42 | LoggerInstance.info(` ✔️ Wallet Monitoring is ${FLAG}`)
43 | try{
44 | const cronning = require(absPath)
45 | cronning.default(app);
46 |
47 | LoggerInstance.info(` ✔️ ${relativePath} Loaded!`)
48 | }catch(err){
49 | LoggerInstance.info(` ❌ Aborting - Wallet Monitoring requires Master Wallet private key. Include 'MASTER_WALLET_PRIVATE_KEY' or change 'WALLET_MONITORING' to 0 in the env file`)
50 | process.exit(1)
51 | }
52 | }
53 | else if (FLAG === 0){
54 | LoggerInstance.info(` ❌ Wallet Monitoring is ${FLAG}... ${relativePath} skipped`)
55 | }
56 |
57 |
58 | // -- HELPERS
59 | // For mailing route
60 | //mailing(app);
61 |
62 | // Finally return app
63 | return app;
64 | }
65 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/middlewares/index.ts:
--------------------------------------------------------------------------------
1 | import onlyTrustedSource from './onlyTrustedSource';
2 | import onlyLocalhost from './onlyLocalhost';
3 |
4 | export default {
5 | onlyTrustedSource,
6 | onlyLocalhost,
7 | };
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/middlewares/onlyLocalhost.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 |
5 | var dns = require('dns');
6 | var os = require('os');
7 | var ifaces = os.networkInterfaces();
8 |
9 | /**
10 | * @param {*} req Express req Object
11 | * @param {*} res Express res Object
12 | * @param {*} next Express next Function
13 | */
14 | const onlyLocalhost = async (req, res, next) => {
15 | const Logger: Logger = Container.get('logger');
16 | try {
17 | // Check if ip is localhost and only continue
18 | var ip = req.connection.remoteAddress;
19 | var host = req.get('host');
20 |
21 | if (config.environment === 'production') {
22 | // Return with unauthorized error
23 | return res.sendStatus(401).json({ info: 'Only development config' });
24 | }
25 |
26 | checkLocalHost(ip)
27 | .then(result => {
28 | if (!result) {
29 | return res.sendStatus(401).json({ info: 'Only localhost connection allowed' });
30 | }
31 |
32 | return next();
33 | })
34 | .catch(e => {
35 | Logger.error('🔥 Error attaching Only Localhost middleware to req: %o', e);
36 | return next(e);
37 | });
38 | } catch (e) {
39 | Logger.error('🔥 Error attaching Only Localhost middleware to req: %o', e);
40 | return next(e);
41 | }
42 | };
43 |
44 | export const checkLocalHost = async (address) => {
45 | return new Promise((resolve, reject) => {
46 | dns.lookup(address, function(err, addr) {
47 | if(err) {
48 | resolve(false);
49 | return;
50 | }
51 | try {
52 | address = addr;
53 | Object.keys(ifaces).forEach(function (ifname) {
54 | ifaces[ifname].forEach(function (iface) {
55 | if(iface.address === address)
56 | resolve(true);
57 | });
58 | });
59 | resolve(false);
60 | }
61 | catch(err){
62 | reject(err);
63 | }
64 | })
65 | })
66 | }
67 |
68 | export default onlyLocalhost;
69 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/middlewares/onlyTrustedSource.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 |
5 | /**
6 | * @param {*} req Express req Object
7 | * @param {*} res Express res Object
8 | * @param {*} next Express next Function
9 | */
10 | const onlyTrustedSource = async (req, res, next) => {
11 | const Logger: Logger = Container.get('logger');
12 | try {
13 | // Check if ip is localhost and only continue
14 | var url = req.headers.origin;
15 |
16 | if (config.trusterURLs.indexOf(url) == -1) {
17 | // Not in the array
18 | return res.sendStatus(403).json({ info: 'Only meant for trusted urls' });
19 | }
20 |
21 | return next();
22 | } catch (e) {
23 | Logger.error('🔥 Error attaching Only Trusted Source middleware to url: %o | req: %o | err: %o', url, req, e);
24 | return next(e);
25 | }
26 | };
27 |
28 | export default onlyTrustedSource;
29 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/routes/mailing.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import EmailService from '../../services/emailService';
4 | import middlewares from '../middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 |
7 | const route = Router();
8 |
9 | export default (app: Router) => {
10 | app.use('/mailing', route);
11 |
12 | // to add an incoming payload
13 | route.post(
14 | '/send_mail',
15 | celebrate({
16 | body: Joi.object({
17 | from: Joi.string().required(),
18 | name: Joi.string().required(),
19 | topic: Joi.string().required(),
20 | sub: Joi.string().required(),
21 | msg: Joi.string().required(),
22 | }),
23 | }),
24 | middlewares.onlyTrustedSource,
25 | async (req: Request, res: Response, next: NextFunction) => {
26 | const Logger: any = Container.get('logger');
27 | Logger.debug('Calling /mailing/send_mail endpoint with body: %o', req.body);
28 | try {
29 | const email = Container.get(EmailService);
30 | const { success, msg } = await email.sendMailSES(
31 | req.body.from,
32 | req.body.name,
33 | req.body.topic,
34 | req.body.sub,
35 | req.body.msg,
36 | );
37 |
38 | return res.status(201).json({ success, msg });
39 | } catch (e) {
40 | Logger.error('🔥 error: %o', e);
41 | return next(e);
42 | }
43 | },
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/api/routes/walletMonitoringRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import walletMonitoringHelper from '../../services/walletMonitoring';
4 | import middlewares from '../middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 | import { Logger } from 'winston';
7 |
8 | const route = Router();
9 |
10 | export default (app: Router) => {
11 | app.use('/showrunners/wallet_monitoring', route);
12 |
13 | route.post(
14 | '/check_wallets',
15 | celebrate({
16 | body: Joi.object({
17 | simulate: [Joi.bool(), Joi.object()],
18 | }),
19 | }),
20 | middlewares.onlyLocalhost,
21 | async (req: Request, res: Response, next: NextFunction) => {
22 | const Logger: Logger= Container.get('logger');
23 | Logger.debug('Calling /showrunners/wallet_monitoring/check_wallets endpoint with body: %o', req.body )
24 | try {
25 | const walletMonitor = Container.get(walletMonitoringHelper);
26 | const result = await walletMonitor.processWallets(req.body.simulate);
27 |
28 | return res.status(201).json({result});
29 | } catch (e) {
30 | Logger.error('🔥 error: %o', e);
31 | return next(e);
32 | }
33 | },
34 | );
35 |
36 | route.post(
37 | '/check_main_wallet',
38 | celebrate({
39 | body: Joi.object({
40 | simulate: [Joi.bool(), Joi.object()],
41 | }),
42 | }),
43 | middlewares.onlyLocalhost,
44 | async (req: Request, res: Response, next: NextFunction) => {
45 | const Logger: Logger = Container.get('logger');
46 | Logger.debug('Calling /showrunners/wallet_monitoring/check_main_wallet endpoint with body: %o', req.body )
47 | try {
48 | const walletMonitor = Container.get(walletMonitoringHelper);
49 | const result = await walletMonitor.processMainWallet(req.body.simulate);
50 |
51 | return res.status(201).json({result});
52 | } catch (e) {
53 | Logger.error('🔥 error: %o', e);
54 | return next(e);
55 | }
56 | },
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/app.ts:
--------------------------------------------------------------------------------
1 | import 'reflect-metadata'; // We need this in order to use @Decorators
2 |
3 | import express from 'express';
4 |
5 | import EnvVerifierLoader from './loaders/envVerifier';
6 | import Logger from './loaders/logger';
7 |
8 | async function startServer() {
9 | // Check environment setup first
10 | Logger.info('✌️ Verifying ENV');
11 | await EnvVerifierLoader();
12 | Logger.info('✔️ ENV Verified / Generated and Loaded!');
13 | // Continue load
14 | const config = (await require('./config/index')).default;
15 |
16 | // load app
17 | const app = express();
18 |
19 | /**
20 | * A little hack here
21 | * Import/Export can only be used in 'top-level code'
22 | * Well, at least in node 10 without babel and at the time of writing
23 | * So we are using good old require.
24 | **/
25 | await require('./loaders').default({ expressApp: app });
26 |
27 | app.listen(config.port, err => {
28 | if (err) {
29 | Logger.error(err);
30 | process.exit(1);
31 | return;
32 | }
33 |
34 | Logger.info(`
35 | ################################################
36 |
37 |
38 | ███████╗██╗ ██╗ ██████╗ ██╗ ██╗██████╗ ██╗ ██╗███╗ ██╗███╗ ██╗███████╗██████╗ ███████╗ ███████╗████████╗ █████╗ ██████╗ ██╗███╗ ██╗ ██████╗
39 | ██╔════╝██║ ██║██╔═══██╗██║ ██║██╔══██╗██║ ██║████╗ ██║████╗ ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝ ██║████╗ ██║██╔════╝
40 | ███████╗███████║██║ ██║██║ █╗ ██║██████╔╝██║ ██║██╔██╗ ██║██╔██╗ ██║█████╗ ██████╔╝███████╗ ███████╗ ██║ ███████║██║ ███╗██║██╔██╗ ██║██║ ███╗
41 | ╚════██║██╔══██║██║ ██║██║███╗██║██╔══██╗██║ ██║██║╚██╗██║██║╚██╗██║██╔══╝ ██╔══██╗╚════██║ ╚════██║ ██║ ██╔══██║██║ ██║██║██║╚██╗██║██║ ██║
42 | ███████║██║ ██║╚██████╔╝╚███╔███╔╝██║ ██║╚██████╔╝██║ ╚████║██║ ╚████║███████╗██║ ██║███████║ ███████║ ██║ ██║ ██║╚██████╔╝██║██║ ╚████║╚██████╔╝
43 | ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝
44 |
45 |
46 | 🛡️ Server listening on port: ${config.port} 🛡️
47 |
48 | ################################################
49 | `);
50 | });
51 | }
52 |
53 | startServer();
54 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/decorators/eventDispatcher.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Originally taken from 'w3tecch/express-typescript-boilerplate'
3 | * Credits to the author
4 | */
5 |
6 | import { EventDispatcher as EventDispatcherClass } from 'event-dispatch';
7 | import { Container } from 'typedi';
8 |
9 | export function EventDispatcher() {
10 | return (object: any, propertyName: string, index?: number): void => {
11 | const eventDispatcher = new EventDispatcherClass();
12 | Container.registerHandler({ object, propertyName, index, value: () => eventDispatcher });
13 | };
14 | }
15 |
16 | export { EventDispatcher as EventDispatcherInterface } from 'event-dispatch';
17 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/helpers/dbHelper.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../config';
4 |
5 | var mysql = require('mysql');
6 | // const MySQLEvents = require('@rodrigogs/mysql-events');
7 |
8 | var pool = mysql.createPool({
9 | connectionLimit: 10,
10 | host: config.dbhost,
11 | user: config.dbuser,
12 | password: config.dbpass,
13 | database: config.dbname,
14 | });
15 | export default {
16 | pool,
17 | query: function() {
18 | const Logger: Logger = Container.get('logger');
19 |
20 | var sql_args = [];
21 | var args = [];
22 | for (var i = 0; i < arguments.length; i++) {
23 | args.push(arguments[i]);
24 | }
25 |
26 | var callback = args[args.length - 1]; //last arg is callback
27 | pool.getConnection(function(err, connection) {
28 | if (err) {
29 | Logger.error(err);
30 |
31 | return callback(err);
32 | }
33 |
34 | if (args.length > 2) {
35 | sql_args = args[1];
36 | }
37 |
38 | connection.query(args[0], sql_args, function(err, results) {
39 | connection.release(); // always put connection back in pool after last query
40 |
41 | if (err) {
42 | Logger.error(err);
43 |
44 | return callback(err);
45 | }
46 |
47 | callback(null, results);
48 | });
49 | });
50 | },
51 | };
52 |
53 | /* EXAMPLE
54 | var db = require('../helpers/dbHelper');
55 |
56 | db.query(
57 | 'Select * from `sessions` where `Active`=1 and Expires>?;',
58 | [~~(new Date()/1000)],
59 | function(err, results){
60 |
61 | if(err){
62 | console.log(err);
63 | }
64 | else{
65 | console.log(results);
66 | }
67 |
68 | }
69 | );
70 | */
71 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/helpers/showrunnersHelper.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 |
3 |
4 | export const showrunnersHelper = {
5 | // Check if Private Key is valid
6 | getValidWallet: async function(showrunnerName, wallets) {
7 | const Cache: any = Container.get('cached');
8 | const cacheKeyName = this.getCacheKeyName(showrunnerName);
9 |
10 | const numberOfWallets = Object.keys(wallets).length;
11 | let selectedWalletID = await Cache.getCache(cacheKeyName);
12 |
13 | if (selectedWalletID) {
14 | // Cache found, increment it and see if it fits
15 | selectedWalletID = parseInt(selectedWalletID) + 1;
16 |
17 | if (selectedWalletID > numberOfWallets) {
18 | selectedWalletID = 1; // Round robin back
19 | }
20 | } else {
21 | selectedWalletID = 1;
22 | }
23 |
24 | const result = await Cache.setCache(cacheKeyName, selectedWalletID);
25 |
26 | return {
27 | numOfWallets: numberOfWallets,
28 | currentWalletID: selectedWalletID,
29 | };
30 | },
31 | getCacheKeyName: function(showrunnerName) {
32 | return `${showrunnerName}WalletsMetaCacheKey`;
33 | },
34 | };
35 |
36 | export default showrunnersHelper;
37 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/interfaces/IGas.ts:
--------------------------------------------------------------------------------
1 | export interface IGas {
2 | _id: string;
3 | price: number;
4 | }
5 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/cache.ts:
--------------------------------------------------------------------------------
1 | const redis = require('async-redis');
2 | import config from '../config';
3 |
4 | class CacheInstance {
5 | private ReddisInstance;
6 | constructor() {
7 | this.ReddisInstance = redis.createClient(config.redisURL);
8 | }
9 | /**
10 | * Set cache
11 | * @description adds a part
12 | * @param {String} key Cache Key
13 | * @param {String} value Cache Value
14 | * @return {Promise<{ null }>}
15 | */
16 | public async setCache(key: String, value: Number) {
17 | return this.ReddisInstance.set(key, value);
18 | };
19 |
20 | /**
21 | * push lcache
22 | * @description adds to a cache like an array
23 | * @param {String} key Cache Key
24 | * @param {String} value Cache Value
25 | * @return {Promise<{ null }>}
26 | */
27 | public async pushLCache(key: String, value: Number) {
28 | return this.ReddisInstance.rpush(key, value);
29 | };
30 |
31 | /**
32 | * get lcache
33 | * @description get all items in a list
34 | * @param {String} key Cache Key
35 | * @return {Promise<{ null }>}
36 | */
37 | public async getLCache(key: String) {
38 | return this.ReddisInstance.lrange(key, 0, -1);
39 | };
40 |
41 | /**
42 | * Add caches
43 | * @description adds to already existing value in cache
44 | * @param {String} key Cache Key
45 | * @param {Number} value Value to be added
46 | * @return {Promise<{ null }>}
47 | */
48 | public async addCache(key: String, value: Number) {
49 | const prev: Number = Number(await this.getCache(key));
50 | if (prev != 0) {
51 | value = Number(prev) + Number(value);
52 | value = Number(value) / 2
53 | }
54 | return this.ReddisInstance.set(key, value);
55 | };
56 |
57 | /**
58 | * Remove cache
59 | * @description deletes a cache key and its associated values
60 | * @param {String} key Cache Key
61 | * @return {Promise<{ null }>}
62 | */
63 | public async removeCache(key: String) {
64 | return this.ReddisInstance.del(key);
65 | };
66 |
67 | /**
68 | * Get cache
69 | * @description retrieves the value of a cache key
70 | * @param {String} key Cache Key
71 | * @return {Promise<{ String }>}
72 | */
73 | public async getCache(key: String) {
74 | return this.ReddisInstance.get(key);
75 | };
76 |
77 | }
78 |
79 |
80 | export default new CacheInstance();
81 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/db.ts:
--------------------------------------------------------------------------------
1 | import db from '../helpers/dbHelper';
2 |
3 | export default () => {
4 | return db.pool;
5 | };
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/dbListener.ts:
--------------------------------------------------------------------------------
1 | const MySQLEvents = require('@rodrigogs/mysql-events');
2 |
3 | export default async ({ pool, logger }) => {
4 | try {
5 | const instance = new MySQLEvents(pool, {
6 | startAtEnd: true,
7 | });
8 |
9 | const response = await instance.start();
10 | } catch (e) {
11 | console.log(e);
12 | }
13 |
14 | // EXAMPLE
15 | // dbEvents.addTrigger({
16 | // name: 'Whole database instance',
17 | // expression: '*',
18 | // statement: MySQLEvents.STATEMENTS.ALL,
19 | // onEvent: (event) => {
20 | // console.log("Some Event");
21 | // console.log(event);
22 | // },
23 | // });
24 |
25 | // 1. SAMPLE SERVICE
26 | // Listen to Something for Some Data
27 | // logger.info('-- 🔮 Started Listening | INSERT | zzzz.tttt.*');
28 | // instance.addTrigger({
29 | // name: 'CHANNELS_INSERT',
30 | // expression: 'zzz.tttt.*',
31 | // statement: MySQLEvents.STATEMENTS.INSERT,
32 | // onEvent: async (event) => {
33 | // logger.info("🧿 DB Event: %s | %s -- %o | [%s]", event.type, event.schema + '.' + event.table, event.affectedColumns, new Date(event.timestamp).toLocaleString());
34 | //
35 | // await triggerBatchProcessSomething(event, logger);
36 | // },
37 | // });
38 | };
39 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/dependencyInjector.ts:
--------------------------------------------------------------------------------
1 | import { Container } from 'typedi';
2 | import LoggerInstance from './logger';
3 | import CacheInstance from './cache';
4 |
5 |
6 | export default ({ models }: { models: { name: string; model: any }[] }) => {
7 | try {
8 | LoggerInstance.info('✌️ Loading Mongo DB Models');
9 |
10 | models.forEach(m => {
11 | LoggerInstance.info(' -- ✔️ Loading Mongo DB Model: %s', m)
12 | Container.set(m.name, m.model);
13 | });
14 |
15 | LoggerInstance.info('✔️ All Mongo DB Models loaded!');
16 |
17 | Container.set('logger', LoggerInstance);
18 | LoggerInstance.info('✔️ Logger Injected');
19 |
20 | Container.set('cached', CacheInstance);
21 | LoggerInstance.info('✔️ Cache (with Redis) Loaded! 🐳🐳🐳');
22 |
23 | // Container.set('dbpool', MysqlInstance)
24 | // LoggerInstance.info('✌️ Databse Injected');
25 |
26 | return null;
27 | } catch (e) {
28 | LoggerInstance.error('🔥 Error on dependency injector loader: %o', e);
29 | throw e;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/express.ts:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import bodyParser from 'body-parser';
3 | import cors from 'cors';
4 | import routes from '../api';
5 | import config from '../config';
6 |
7 |
8 | export default ({ app }: { app: express.Application }) => {
9 | /**
10 | * Health Check endpoints
11 | * @TODO Explain why they are here
12 | */
13 | app.get('/status', (req, res) => {
14 | res.status(200).end();
15 | });
16 | app.head('/status', (req, res) => {
17 | res.status(200).end();
18 | });
19 |
20 | // Useful if you're behind a reverse proxy (Heroku, Bluemix, AWS ELB, Nginx, etc)
21 | // It shows the real origin IP in the heroku or Cloudwatch logs
22 | app.enable('trust proxy');
23 |
24 | // The magic package that prevents frontend developers going nuts
25 | // Alternate description:
26 | // Enable Cross Origin Resource Sharing to all origins by default
27 | app.use(cors());
28 |
29 | // Some sauce that always add since 2014
30 | // "Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it."
31 | // Maybe not needed anymore ?
32 | app.use(require('method-override')());
33 |
34 | // Middleware that transforms the raw string of req.body into json
35 | app.use(bodyParser.json());
36 |
37 | // Load API routes
38 | app.use(config.api.prefix, routes());
39 |
40 | // Load Static Files
41 | app.use(express.static(config.staticServePath));
42 |
43 | /// catch 404 and forward to error handler
44 | app.use((req, res, next) => {
45 | const err = new Error('Not Found');
46 | err['status'] = 404;
47 | next(err);
48 | });
49 |
50 | /// error handlers
51 | app.use((err, req, res, next) => {
52 | /**
53 | * Handle 401 thrown by express-jwt library
54 | */
55 | if (err.name === 'UnauthorizedError') {
56 | return res
57 | .status(err.status)
58 | .send({ message: err.message })
59 | .end();
60 | }
61 | return next(err);
62 | });
63 | app.use((err, req, res, next) => {
64 | res.status(err.status || 500);
65 | res.json({
66 | error: {
67 | info: err.message,
68 | },
69 | });
70 | });
71 | };
72 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/mongoose.ts:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose';
2 | import { Db } from 'mongodb';
3 | import config from '../config';
4 |
5 | export default async (): Promise => {
6 | const connection = await mongoose.connect(config.mongodb, {
7 | useNewUrlParser: true,
8 | useCreateIndex: true,
9 | useUnifiedTopology: true,
10 | });
11 | return connection.connection.db;
12 | };
13 |
14 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/redis.ts:
--------------------------------------------------------------------------------
1 | const redis = require('async-redis');
2 | import config from '../config';
3 |
4 | const ReddisInstance = redis.createClient({ config.redisURL });
5 |
6 | export default ReddisInstance;
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/loaders/webhooks.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | import config from '../config';
4 | import { Container } from 'typedi';
5 | import schedule from 'node-schedule';
6 | import { EventDispatcher, EventDispatcherInterface } from '../decorators/eventDispatcher';
7 | import { Router, Request, Response, NextFunction } from 'express';
8 |
9 | import fs from 'fs';
10 | const utils = require('../helpers/utilsHelper');
11 | const webhookHelper = require('../helpers/webhookHelper');
12 | const route = Router();
13 |
14 | export default async ({ logger, app }) => {
15 | // WEBHOOK SERVICE
16 | logger.info(` -- Checking and Loading Dynamic Webhooks...`);
17 | const channelFolderPath = `${__dirname}/../showrunners/`;
18 | const directories = utils.getDirectories(channelFolderPath);
19 |
20 | for (const channel of directories) {
21 | const absPath = `${channelFolderPath}${channel}/${channel}AWSSNS.${config.fileSuffix}`;
22 | const relativePath = `../showrunners/${channel}/${channel}AWSSNS.${config.fileSuffix}`;
23 |
24 | if (fs.existsSync(absPath)) {
25 | const webhook = await import(absPath);
26 | webhook.default(app);
27 | logger.info(` ✔️ ${relativePath} Loaded!`);
28 | } else {
29 | logger.info(` ❌ ${relativePath} Not Found... skipped`);
30 | }
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/README.md:
--------------------------------------------------------------------------------
1 | ## Sample Showrunners
2 |
3 | ```
4 | This folder includes sample code for showrunners channels. You can use those channels as reference or add your custom
5 | showrunners channel in the same folder. Each folder of showrunners channel contains {channelName}Keys.json in which you can
6 | add your Private keys to run the showrunners.
7 | ```
8 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/aave/aaveJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 |
21 | import AaveChannel from './aaveChannel';
22 |
23 | export default () => {
24 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
25 |
26 | const dailyRule = new schedule.RecurrenceRule();
27 | dailyRule.hour = 0;
28 | dailyRule.minute = 0;
29 | dailyRule.second = 0;
30 | dailyRule.dayOfWeek = new schedule.Range(0, 6);
31 |
32 | // AAVE CHANNEL RUNS EVERY 24 Hours
33 | logger.info(` 🛵 Scheduling Showrunner - Aave Channel [on 6 Hours] [${new Date(Date.now())}]`);
34 | schedule.scheduleJob({ start: startTime, rule: dailyRule }, async function () {
35 | const aaveChannel = Container.get(AaveChannel);
36 | const taskName = 'Aave users address checks and sendMessageToContract()';
37 |
38 | try {
39 | await aaveChannel.sendMessageToContract(false);
40 | logger.info(`[${new Date(Date.now())}] 🐣 Cron Task Completed -- ${taskName}`);
41 | }
42 | catch (err) {
43 | logger.error(`[${new Date(Date.now())}] ❌ Cron Task Failed -- ${taskName}`);
44 | logger.error(`[${new Date(Date.now())}] Error Object: %o`, err);
45 | }
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/aave/aaveKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/aave/aaveKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/aave/aaveRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import middlewares from '../../api/middlewares';
4 | import { celebrate, Joi } from 'celebrate';
5 | import aaveChannel from './aaveChannel';
6 | import { Logger } from 'winston';
7 | import { handleResponse } from '../../helpers/utilsHelper';
8 |
9 | const route = Router();
10 |
11 | export default (app: Router) => {
12 | app.use('/showrunners/aave', route);
13 |
14 | /**
15 | * Send Message
16 | * @description Send a notification via the aave showrunner
17 | * @param {boolean} simulate whether to send the actual message or simulate message sending
18 | */
19 | route.post(
20 | '/send_message',
21 | celebrate({
22 | body: Joi.object({
23 | simulate: [Joi.bool(), Joi.object()],
24 | }),
25 | }),
26 | middlewares.onlyLocalhost,
27 | async (req: Request, res: Response, next: NextFunction) => {
28 | const logger: Logger = Container.get('logger');
29 | logger.debug('Calling /showrunners/aave/send_message endpoint with body: %o', req.body);
30 | try {
31 | const aave = Container.get(aaveChannel);
32 | const data = await aave.sendMessageToContract(req.body.simulate);
33 | return res.status(200).json({ success: true, data: data });
34 | } catch (e) {
35 | logger.error('🔥 error: %o', e);
36 | return handleResponse(res, 500, false, 'error', JSON.stringify(e));
37 | }
38 | },
39 | );
40 |
41 | route.post(
42 | '/checkHealthFactor',
43 | celebrate({
44 | body: Joi.object({
45 | simulate: [Joi.bool(), Joi.object()],
46 | }),
47 | }),
48 | middlewares.onlyLocalhost,
49 | async (req: Request, res: Response, next: NextFunction) => {
50 | const logger: Logger = Container.get('logger');
51 | logger.debug('Calling /showrunners/aave/send_message endpoint with body: %o', req.body);
52 | try {
53 | const aave = Container.get(aaveChannel);
54 | const data = await aave.checkHealthFactor(null, null, null, req.body.simulate);
55 |
56 | return res.status(200).json({ success: true, data: data });
57 | } catch (e) {
58 | logger.error('🔥 error: %o', e);
59 | return handleResponse(res, 500, false, 'error', JSON.stringify(e));
60 | }
61 | },
62 | );
63 | };
64 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/aave/aaveSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "aaveLendingPoolDeployedContractPolygonMainnet": "0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf",
3 | "aaveLendingPoolDeployedContractPolygonMumbai": "0x9198F13B08E299d85E096929fA9781A1E3d5d827",
4 | "aaveLendingPoolDeployedContractMainnet": "0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9",
5 | "aaveLendingPoolDeployedContractKovan": "0xE0fBa4Fc209b4948668006B2bE61711b7f465bAe"
6 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/digible/digibleKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/digible/digibleKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/digible/digibleModel.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable prettier/prettier */
2 | import { model, Document, Schema } from 'mongoose';
3 |
4 | export interface DigibleData {
5 | latestBlockForDigiTrackEvent?: number;
6 | latestBlockForOfferRecieved?: number;
7 | latestBlockForOfferAccepted?: number;
8 | latestBlockForOfferCancelled?: number;
9 | }
10 |
11 | const digibleSchema = new Schema({
12 | _id: {
13 | type: String,
14 | },
15 | latestBlockForDigiTrackEvent: {
16 | type: Number,
17 | },
18 | latestBlockForOfferRecieved: {
19 | type: Number,
20 | },
21 | latestBlockForOfferAccepted: {
22 | type: Number,
23 | },
24 | latestBlockForOfferCancelled: {
25 | type: Number,
26 | },
27 | });
28 |
29 | export const digibleModel = model('digibleDB', digibleSchema);
30 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/digible/digibleSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "digiTrackContractAddressMainnet": "0x4168a4D108b24A347F19617BB95C25c8Eb9618de",
3 | "digiTrackContractAddressTestnet": "0x4168a4D108b24A347F19617BB95C25c8Eb9618de",
4 | "digiTradeContractAddressMainnet": "0x915338948fBF10583DD15C6FcCCF55565FF5b60f",
5 | "digiTradeContractAddressTestnet": "0x915338948fBF10583DD15C6FcCCF55565FF5b60f"
6 | }
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/ens/ensJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 |
21 | import EnsExpirationChannel from './ensChannel';
22 |
23 | export default () => {
24 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
25 |
26 | const dailyRule = new schedule.RecurrenceRule();
27 | dailyRule.hour = 0;
28 | dailyRule.minute = 0;
29 | dailyRule.second = 0;
30 | dailyRule.dayOfWeek = new schedule.Range(0, 6);
31 | const channel = Container.get(EnsExpirationChannel);
32 |
33 | //1.3 ENS TICKER CHANNEL
34 | channel.logInfo(` 🛵 Scheduling Showrunner - [on 24 Hours] [${new Date(Date.now())}]`);
35 | schedule.scheduleJob({ start: startTime, rule: dailyRule }, async function() {
36 | const taskName = `${channel.cSettings.name} checkDomainExpiryTask`;
37 |
38 | try {
39 | await channel.checkDomainExpiryTask(false);
40 | channel.logInfo(`🐣 Cron Task Completed -- ${taskName}`);
41 | } catch (err) {
42 | logger.error(`[${new Date(Date.now())}] ❌ Cron Task Failed -- ${taskName}`);
43 | logger.error(`[${new Date(Date.now())}] Error Object: %o`, err);
44 | }
45 | });
46 | };
47 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/ens/ensKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/ens/ensKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/ens/ensRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import EnsExiprationChannel from './ensChannel';
4 | import middlewares from '../../api/middlewares';
5 | import { celebrate, Joi } from 'celebrate';
6 | import { handleResponse } from '../../helpers/utilsHelper';
7 | import { Logger } from 'winston';
8 |
9 | const route = Router();
10 |
11 | export default (app: Router) => {
12 | app.use('/showrunners/ensv2', route);
13 |
14 | /**
15 | * Send Message
16 | * @description Send a notification via the ensdomain showrunner
17 | * @param {boolean} simulate whether to send the actual message or simulate message sending
18 | */
19 | route.post(
20 | '/test',
21 | celebrate({
22 | body: Joi.object({
23 | simulate: [Joi.bool(), Joi.object()],
24 | }),
25 | }),
26 | middlewares.onlyLocalhost,
27 | async (req: Request, res: Response, next: NextFunction) => {
28 | const logger: Logger = Container.get('logger');
29 | logger.debug('Calling /showrunners/ensv2/send_message endpoint with body: %o', req.body);
30 | try {
31 | const ensDomain = Container.get(EnsExiprationChannel);
32 | const data: any = await ensDomain.checkDomainExpiryTask(false);
33 | res.json({ success: true });
34 | } catch (e) {
35 | logger.error('🔥 error: %o', e);
36 | return handleResponse(res, 500, false, 'error', JSON.stringify(e));
37 | }
38 | },
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/ens/ensSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ensDeployedContract": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85",
3 | "ensEndpoint": "https://api.thegraph.com/subgraphs/name/ensdomains/ens"
4 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldAWSSNS.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import HelloWorldChannel from './helloWorldChannel';
4 | import axios from 'axios';
5 | import { Logger } from 'winston';
6 | import { enableAWSWebhook } from '../../helpers/webhookHelper';
7 |
8 | const route = Router();
9 |
10 | export default (app: Router) => {
11 | const channel = Container.get(HelloWorldChannel);
12 | app.use('/showrunners/helloworld', route);
13 |
14 | // enable webhooks
15 | enableAWSWebhook(route, channel.webhookPayloadHandler.bind(channel)); // add the extra bind method to enable the use of 'this' inside the callback
16 | // enable webhooks
17 | };
18 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldChannel.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Service } from 'typedi';
2 | import { Logger } from 'winston';
3 | import config from '../../config';
4 | import { EPNSChannel } from '../../helpers/epnschannel';
5 | import { mockMessages } from './messages';
6 |
7 | @Service()
8 | export default class HelloWorldChannel extends EPNSChannel {
9 | constructor(@Inject('logger') public logger: Logger) {
10 | super(logger, {
11 | networkToMonitor: config.web3MainnetNetwork,
12 | dirname: __dirname,
13 | name: 'Hello World',
14 | url: 'https://epns.io/',
15 | useOffChain: true,
16 | });
17 | }
18 | // Checks for profile Expiration and Sends notification to users
19 | // Whose Profile is about to be expired
20 | async helloWorld(simulate) {
21 | try {
22 | this.logInfo('Sending notification to evidence provider');
23 |
24 | // Notification Type: 1 for Broadcast, 3 for Subset, 4 for targeted
25 | // Read More: https://docs.epns.io/developers/developer-guides/sending-notifications/notification-payload-types/notification-standard-basics
26 | const notificationType = 1;
27 |
28 | // Omit for broadcast, single address for targeted and channel address or array of addresses for subset
29 | const recipients = this.channelAddress;
30 |
31 | for (const e of mockMessages.messages) {
32 | await this.sendNotification({
33 | recipient: recipients,
34 | title: e.title,
35 | message: e.msg,
36 | payloadTitle: e.title,
37 | payloadMsg: e.msg,
38 | notificationType: notificationType,
39 | cta: e.cta,
40 | image: null,
41 | simulate: simulate,
42 | });
43 | }
44 |
45 | return { success: true };
46 | } catch (error) {
47 | this.logError(error);
48 | }
49 | }
50 |
51 | /**
52 | * The method responsible for handling webhook payload
53 | * @param payload
54 | */
55 | public async webhookPayloadHandler(payload: any, simulate: any) {
56 | const { Message } = payload;
57 |
58 | // do something with the payload
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldJobs.ts:
--------------------------------------------------------------------------------
1 | // Do Scheduling
2 | // https://github.com/node-schedule/node-schedule
3 | // * * * * * *
4 | // ┬ ┬ ┬ ┬ ┬ ┬
5 | // │ │ │ │ │ │
6 | // │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
7 | // │ │ │ │ └───── month (1 - 12)
8 | // │ │ │ └────────── day of month (1 - 31)
9 | // │ │ └─────────────── hour (0 - 23)
10 | // │ └──────────────────── minute (0 - 59)
11 | // └───────────────────────── second (0 - 59, OPTIONAL)
12 | // Execute a cron job every 5 Minutes = */5 * * * *
13 | // Starts from seconds = * * * * * *
14 |
15 | import config from '../../config';
16 | import logger from '../../loaders/logger';
17 |
18 | import { Container } from 'typedi';
19 | import schedule from 'node-schedule';
20 | import HelloWorldChannel from './helloWorldChannel';
21 |
22 | export default () => {
23 | const startTime = new Date(new Date().setHours(0, 0, 0, 0));
24 |
25 | const fiveMinuteRule = new schedule.RecurrenceRule();
26 |
27 | fiveMinuteRule.minute = 5;
28 |
29 | const channel = Container.get(HelloWorldChannel);
30 | channel.logInfo(` 🛵 Scheduling Showrunner - ${channel.cSettings.name} Channel`);
31 |
32 | schedule.scheduleJob({ start: startTime, rule: fiveMinuteRule }, async function () {
33 | const taskName = `${channel.cSettings.name} event checks and helloWorld`;
34 |
35 | try {
36 | await channel.helloWorld(false);
37 |
38 | channel.logInfo(`🐣 Cron Task Completed -- ${taskName}`);
39 | } catch (err) {
40 | channel.logInfo(`❌ Cron Task Failed -- ${taskName}`);
41 | channel.logError(`Error Object: %o`);
42 | channel.logError(err);
43 | }
44 | });
45 | };
46 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldKeys.example:
--------------------------------------------------------------------------------
1 | // THIS FILE ONLY CONTAIN EXAMPLES AND CAN BE SAFELY REMOVED
2 | // REMOVE COMMENTS AND UNNECESSARY JSON EXAMPLES WHEN COPYING THIS
3 | // NOTE: Both PRIVATE_KEY_NEW_STANDARD OR PRIVATE_KEY_OLD_STANDARD is supported
4 | // but recommended to follow NEW_STANDARD
5 | // ABOUT NEW STANDARD PARAMS
6 | // PK = represents your channel or channel delegate private key
7 | // READ MORE ABOUT CHANNELS / CHANNEL DELEGATES: https://docs.epns.io/developers/concepts/create-your-notif-channel
8 | // IMPORTANT: Your private key is only used to sign your notifications so that it can be validated by push nodes
9 | // READ MORE ABOUT HOW IT WORKS: https://docs.epns.io/developers/developer-tooling/showrunners-framework/how-to-setup-showrunners
10 | // CHAIN_ID = reprensents the multichain supported address
11 | // FOR ETHEREUM
12 | // CHAIN_ID = pass eip155:42 for Ethereum Kovan Address
13 | // CHAIN_ID = pass eip155:80001 for Polygon Mumbai Addresses
14 | // ----
15 | // FOR POLYGON
16 | // CHAIN_ID = pass eip155:1 for Ethereum Mainnet Addresses
17 | // CHAIN_ID = pass eip155:137 for Ethereum Mainnet Addresses
18 |
19 | // TEMPLATES, PICK ONLY ONE
20 | // ---
21 | // TEMPLATE FOR ETHEREUM ONLY STAGING CHANNEL
22 | // ---
23 | // {
24 | // "PRIVATE_KEY_NEW_STANDARD": {
25 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
26 | // "CHAIN_ID": "eip155:42"
27 | // },
28 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
29 | // }
30 |
31 | // ---
32 | // TEMPLATE FOR MULTICHAIN CHANNEL ON STAGING SUPPORTING POLYGON
33 | // ---
34 | // {
35 | // "PRIVATE_KEY_NEW_STANDARD": {
36 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
37 | // "CHAIN_ID": "eip155:80001"
38 | // },
39 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
40 | // }
41 |
42 | // ---
43 | // TEMPLATE FOR ETHEREUM ONLY MAINNET CHANNEL
44 | // ---
45 | // {
46 | // "PRIVATE_KEY_NEW_STANDARD": {
47 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
48 | // "CHAIN_ID": "eip155:1"
49 | // },
50 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
51 | // }
52 |
53 | // ---
54 | // TEMPLATE FOR MULTICHAIN CHANNEL ON MAINNET SUPPORTING POLYGON
55 | // ---
56 | // {
57 | // "PRIVATE_KEY_NEW_STANDARD": {
58 | // "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
59 | // "CHAIN_ID": "eip155:137"
60 | // },
61 | // "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
62 | // }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY_NEW_STANDARD": {
3 | "PK": "YOUR_CHANNEL_PRIVATE_KEY_HERE",
4 | "CHAIN_ID": "CHAIN_ID_HERE | SUPPORTED VALUES = eip155:1 or eip155:42 for Ethereum | eip155:137 or eip155:80001 for Polygon"
5 | },
6 | "PRIVATE_KEY_OLD_STANDARD": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
7 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/helloWorldRoutes.ts:
--------------------------------------------------------------------------------
1 | import { Router, Request, Response, NextFunction } from 'express';
2 | import { Container } from 'typedi';
3 | import middlewares from '../../api/middlewares';
4 | import { celebrate, Joi } from 'celebrate';
5 | import TestChannel from './helloWorldChannel';
6 |
7 | const route = Router();
8 |
9 | export default (app: Router) => {
10 | app.use('/showrunners/helloWorld', route);
11 |
12 | route.post(
13 | '/testnotif',
14 | celebrate({
15 | body: Joi.object({
16 | simulate: [Joi.bool(), Joi.object()],
17 | }),
18 | }),
19 | middlewares.onlyLocalhost,
20 | async (req: Request, res: Response, next: NextFunction) => {
21 | const Logger: any = Container.get('logger');
22 |
23 | try {
24 | const helloWorld = Container.get(TestChannel);
25 | helloWorld.helloWorld(req.body.simulate);
26 | return res.status(201).json({ success: true });
27 | } catch (e) {
28 | Logger.error('🔥 error: %o', e);
29 | return next(e);
30 | }
31 | },
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/helloWorld/messages.ts:
--------------------------------------------------------------------------------
1 | export const mockMessages = {
2 | messages: [
3 | {
4 | title: 'Hello World!',
5 | msg: `Hello Hackers ;)`,
6 | cta: 'https://epns.io',
7 | },
8 | ],
9 | };
10 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/proofOfHumanity/pohCacheModel.ts:
--------------------------------------------------------------------------------
1 | import { model, Schema, Document } from 'mongoose';
2 |
3 | export interface IPOHSchema {
4 | removalRequestBlockNo?: number;
5 | savedChallengeTimestamp?: number;
6 | savedEvidenceTimestamp?: number;
7 | }
8 | const POHDB = new Schema({
9 | _id: {
10 | type: String,
11 | },
12 | removalRequestBlockNo: {
13 | type: Number,
14 | },
15 | savedChallengeTimestamp: {
16 | type: Number,
17 | },
18 | savedEvidenceTimestamp: {
19 | type: Number,
20 | },
21 | });
22 |
23 | export const POHModel = model('POHDB', POHDB);
24 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/proofOfHumanity/proofOfHumanityKeys.json:
--------------------------------------------------------------------------------
1 | {
2 | "PRIVATE_KEY": "YOUR_CHANNEL_PRIVATE_KEY_HERE"
3 | }
4 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/proofOfHumanity/proofOfHumanityModel.ts:
--------------------------------------------------------------------------------
1 | import { model, Schema, Document } from 'mongoose';
2 | import { Submission } from './proofOfHumanityChannel';
3 |
4 | const POHSubmission = new Schema({
5 | _id: String,
6 | submissionTime: {
7 | type: String,
8 | required: true,
9 | },
10 | creationTime: {
11 | type: String,
12 | required: true,
13 | },
14 | name: {
15 | type: String,
16 | required: true,
17 | },
18 | registered: {
19 | type: Boolean,
20 | required: true,
21 | },
22 | status: {
23 | type: String,
24 | required: true,
25 | },
26 | });
27 |
28 | // Duplicate the ID field.
29 | POHSubmission.virtual('id').get(function() {
30 | return this._id;
31 | });
32 |
33 | POHSubmission.set('toJSON', {
34 | virtuals: true,
35 | });
36 | export const SubmissionModel = model('POHSubmission', POHSubmission);
37 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/sample_showrunners/proofOfHumanity/proofOfHumanitySettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "proofOfHumanityDeployedContract":"0xc5e9ddebb09cd64dfacab4011a0d5cedaf7c9bdb"
3 | }
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/showrunners/.keepfolderalive:
--------------------------------------------------------------------------------
1 | # The purpose of this file is to keep the folder alive on remote git
2 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/src/subscribers/events.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | // user: {
3 | // signUp: 'onUserSignUp',
4 | // signIn: 'onUserSignIn',
5 | // },
6 | };
7 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tests/.gitkeep
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tests/sample.test.ts:
--------------------------------------------------------------------------------
1 | describe('Sample Test', () => {
2 | it('can add 2 numbers', () => {
3 | expect(1 + 2).toBe(3);
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tests/services/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/push-protocol/push-for-hackers/98c2f792ca06eb1fa039ef5bbac44a174e4e15e7/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tests/services/.gitkeep
--------------------------------------------------------------------------------
/sending-notifications/via-showrunners-gasless/epns-showrunners-framework-og/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "lib": [
5 | "es2017",
6 | "esnext.asynciterable"
7 | ],
8 | "typeRoots": [
9 | "./node_modules/@types",
10 | "./src/types"
11 | ],
12 | "allowSyntheticDefaultImports": true,
13 | "experimentalDecorators": true,
14 | "emitDecoratorMetadata": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "moduleResolution": "node",
17 | "module": "commonjs",
18 | "pretty": true,
19 | "sourceMap": true,
20 | "outDir": "./build",
21 | "allowJs": true,
22 | "noEmit": false,
23 | "resolveJsonModule": true,
24 | "esModuleInterop": true
25 | },
26 | "include": [
27 | "./src/**/*",
28 | "./src/**/*.json"
29 | ],
30 | "exclude": [
31 | "node_modules",
32 | "tests"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/sending-notifications/via-smart-contract/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 | [Example of notification from smart contract on token transfer](https://docs.epns.io/developers/developer-guides/examples/notification-via-smart-contract-examples/token-transfer-notification-via-smart-contract-example)
--------------------------------------------------------------------------------
/sending-notifications/via-smart-contract/token-og.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.6.2;
2 |
3 | import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/ERC20.sol";
4 |
5 | contract Push is ERC20 {
6 | constructor ()
7 | ERC20("Push Token", "PUSH")
8 | public {
9 | _mint(msg.sender, 1000 * 10 ** uint(decimals()));
10 | }
11 |
12 | function transfer(address to, uint amount) override public returns (bool success) {
13 | address owner = _msgSender();
14 | _transfer(owner, to, amount);
15 |
16 | return true;
17 | }
18 | }
--------------------------------------------------------------------------------