├── .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 | } --------------------------------------------------------------------------------