diff --git a/.vscode/launch.json b/.vscode/launch.json index 01d5c12f..05d381b7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -54,7 +54,8 @@ "PORT": "", "BLUEBIRD_W_FORGOTTEN_RETURN": "0", "DISABLE_ORM_SYNC": "true", - "GENERATE_SHARED_TYPES": "false" + "GENERATE_SHARED_TYPES": "false", + "DATABASE_URL": "sqlite::memory:" } } ] diff --git a/package.json b/package.json index 2e688884..551d248f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "clean": "rm -rf build/*", "build": "npm run clean ; tsc ; echo \"Finished Building\"", "release": "semantic-release", - "heroku-prebuild": "yarn remove puppeteer puppeteer-extra puppeteer-extra-plugin-adblocker puppeteer-extra-plugin-stealth -D && yarn add puppeteer@^13.1.3 puppeteer-extra@^3.2.3 puppeteer-extra-plugin-adblocker@^2.12.0 puppeteer-extra-plugin-stealth@^2.9.0", "heroku-cleanup": "cp .yarnclean.ci .yarnclean && yarn autoclean --force", "########## Run ##########": "", "start": "NODE_ENV=local RUN_PRODUCTION=true ENABLE_GUNDB=false GENERATE_SHARED_TYPES=false node ./build/src/server.js", @@ -20,14 +19,8 @@ "local": "npm run kill-inspect && NODE_ENV=local PORT=3005 tsnd --exit-child --inspect=4005 --respawn --transpile-only --ignore-watch=src/types/meem.generated.ts --ignore-watch=src/types/meem.public.generated.ts src/server.ts", "########## DB Migrations ##########": "", "migration:create": "sequelize migration:create", - "db:migrate": "sequelize db:migrate", - "db:migrate:local": "NODE_ENV=local node ./node_modules/.bin/sequelize db:migrate", - "db:migrate:development": "NODE_ENV=development node ./node_modules/.bin/sequelize db:migrate", - "db:migrate:stage": "NODE_ENV=staging node ./node_modules/.bin/sequelize db:migrate", - "db:migrate:production": "NODE_ENV=production node ./node_modules/.bin/sequelize db:migrate", "########## Tests ##########": "", - "test": "NODE_ENV=local DISABLE_MIGRATIONS=true ALLOW_NON_SSL=true ORM_LOGGING=false LOG_LEVEL=debug TESTING=true ENABLE_GUNDB=false GENERATE_SHARED_TYPES=false DISCORD_ENABLE_LISTENERS=false PORT= mocha --exit -r ts-node/register/transpile-only 'src/**/*.test.ts'", - "#test": "DISABLE_ORM_SYNC=false NODE_ENV=local DISABLE_MIGRATIONS=true ALLOW_NON_SSL=true ORM_LOGGING=false LOG_LEVEL=debug TESTING=true ENABLE_GUNDB=false GENERATE_SHARED_TYPES=false PORT= DATABASE_URL=sqlite:./tmp/testing.db ENABLE_CONTRACT_LISTENERS=false ENABLE_TWITTER_LISTENERS=false mocha --exit -r ts-node/register/transpile-only 'src/**/*.test.ts'", + "test": "NODE_ENV=local DATABASE_URL=sqlite::memory: DISABLE_MIGRATIONS=true ALLOW_NON_SSL=true ORM_LOGGING=false LOG_LEVEL=debug TESTING=true ENABLE_GUNDB=false GENERATE_SHARED_TYPES=false DISCORD_ENABLE_LISTENERS=false PORT= mocha --exit -r ts-node/register/transpile-only 'src/**/*.test.ts'", "########## Serverless ##########": "", "deploy:dev": "SLS_DEBUG=* sls deploy -s dev", "deploy:staging": "SLS_DEBUG=* sls deploy -s staging", @@ -47,15 +40,6 @@ "postinstall": "if [ \"${RUN_POSTINSTALL:=\"false\"}\" = \"true\" ]; then npm run build; else echo \"Skipping postinstall RUN_POSTINSTALL is not set to true.\" && exit 0; fi", "kill-inspect": "kill-port 4005", "########## Meems ##########": "", - "#generateTypes": "typechain --target=ethers-v5 'src/abis/*.json' --out-dir='src/types'", - "fetchMeemABI": "tsnd --transpile-only src/scripts/fetchMeemABI.ts", - "fetchWhitelist": "tsnd --transpile-only src/scripts/fetchWhitelist.ts", - "fetchAccess": "tsnd --transpile-only src/scripts/fetchAccess.ts", - "fetchMeemIdABI": "tsnd --transpile-only src/scripts/fetchMeemIdABI.ts", - "fetchMeemMarketABI": "tsnd --transpile-only src/scripts/fetchMeemMarketABI.ts", - "fetchMeemContracts": "tsnd --transpile-only src/scripts/fetchMeemContracts.ts", - "fetchMeemIdContracts": "tsnd --transpile-only src/scripts/fetchMeemIdContracts.ts", - "fetchContracts": "yarn fetchMeemContracts && yarn fetchMeemIdContracts", "swagger": "npx swagger-inline 'src/types/shared/api/**/*.ts' --base 'src/types/shared/api/swaggerBase.yaml' --format .json > 'src/types/shared/api/meem-api.json'", "generateHasuraMetadata": "tsnd --transpile-only src/scripts/generateHasuraMetadata.ts", "migrateSymphony": "tsnd --transpile-only src/scripts/migrateSymphony.ts", @@ -63,7 +47,6 @@ }, "dependencies": { "@discordjs/rest": "^1.6.0", - "@guildxyz/sdk": "^1.1.1", "@kengoldfarb/log": "^1.0.3", "@meemproject/meem-contracts": "^0.17.1", "@meemproject/metadata": "^0.17.1", @@ -76,6 +59,7 @@ "@typechain/ethers-v5": "^10.1.0", "alchemy-sdk": "^2.1.1", "auth0": "^2.42.0", + "aws-sdk": "^2.1378.0", "bcrypt": "^5.0.1", "body-parser": "^1.20.0", "busboy": "^0.3.1", @@ -97,12 +81,10 @@ "openai": "^3.2.1", "pg": "^8.8.0", "sequelize": "^6.23.2", - "sharp": "^0.31.0", "slug": "^8.0.0", "string-argv": "^0.3.1", "superagent": "^8.0.0", "supertest": "^6.2.4", - "tslib": "^2.4.1", "twitter-api-sdk": "^1.2.1", "twitter-api-v2": "^1.12.7", "typechain": "^8.1.0", @@ -141,7 +123,6 @@ "@types/uuid": "^8.3.4", "@types/ws": "^8.5.3", "aws-lambda": "^1.0.7", - "aws-sdk": "^2.1225.0", "babel-eslint": "^10.1.0", "chai": "^4.3.6", "chai-as-promised": "^7.1.1", @@ -172,4 +153,4 @@ "optionalDependencies": { "fsevents": "^2.3.2" } -} +} \ No newline at end of file diff --git a/serverless.yml b/serverless.yml index f0c4eb6a..4c1aa8b8 100644 --- a/serverless.yml +++ b/serverless.yml @@ -44,21 +44,7 @@ provider: TWITTER_BEARER_TOKEN: ${env:TWITTER_BEARER_TOKEN, ''} TWITTER_AUTH_CALLBACK_URL: ${env:TWITTER_AUTH_CALLBACK_URL, ''} ENABLE_VERBOSE_ERRORS: ${env:ENABLE_VERBOSE_ERRORS, 'false'} - TWITTER_WALLET_PRIVATE_KEY: ${env:TWITTER_WALLET_PRIVATE_KEY, ''} - TWITTER_PROJECT_TOKEN_ID: ${env:TWITTER_PROJECT_TOKEN_ID, ''} DEFAULT_PAGINATION_LIMIT: ${env:DEFAULT_PAGINATION_LIMIT, '20'} - MINT_GAS_LIMIT: ${env:MINT_GAS_LIMIT, '6000000'} - IPFS_CONTENT_GATEWAY_URL: ${env:IPFS_CONTENT_GATEWAY_URL, 'https://gateway.pinata.cloud'} - PINATA_API_KEY: ${env:PINATA_API_KEY, ''} - PINATA_API_SECRET: ${env:PINATA_API_SECRET, ''} - TWITTER_INTEGRATION_ID: ${env:TWITTER_INTEGRATION_ID, ''} - MEEM_BUNDLE_ID: ${env:MEEM_BUNDLE_ID, ''} - MEEM_PROXY_CONTRACT_ID: ${env:MEEM_PROXY_CONTRACT_ID, ''} - LAMBDA_REINITIALIZE_FUNCTION_NAME: ${env:LAMBDA_REINITIALIZE_FUNCTION_NAME, ''} - GNOSIS_MASTER_CONTRACT_ADDRESS: ${env:GNOSIS_MASTER_CONTRACT_ADDRESS, ''} - GNOSIS_PROXY_CONTRACT_ADDRESS: ${env:GNOSIS_PROXY_CONTRACT_ADDRESS, ''} - UPGRADE_AGREEMENT_FUNCTION_NAME: ${env:UPGRADE_AGREEMENT_FUNCTION_NAME, ''} - GNOSIS_DEFAULT_CALLBACK_HANDLER: ${env:GNOSIS_DEFAULT_CALLBACK_HANDLER, ''} TWITTER_IDENTITY_INTEGRATION_ID: ${env:TWITTER_IDENTITY_INTEGRATION_ID, ''} DISCORD_IDENTITY_INTEGRATION_ID: ${env:DISCORD_IDENTITY_INTEGRATION_ID, ''} EMAIL_IDENTITY_INTEGRATION_ID: ${env:EMAIL_IDENTITY_INTEGRATION_ID, ''} @@ -66,7 +52,6 @@ provider: AUTH0_CLIENT_ID: ${env:AUTH0_CLIENT_ID, ''} AUTH0_CLIENT_SECRET: ${env:AUTH0_CLIENT_SECRET, ''} AUTH0_VERIFY_EMAIL_CALLBACK_URL: ${env:AUTH0_VERIFY_EMAIL_CALLBACK_URL, ''} - CHAIN_IDS: ${env:CHAIN_IDS, ''} JSON_RPC_MAINNET: ${env:JSON_RPC_MAINNET, ''} ALCHEMY_API_KEY_MAINNET: ${env:ALCHEMY_API_KEY_MAINNET, ''} ALCHEMY_API_KEY_RINKEBY: ${env:ALCHEMY_API_KEY_RINKEBY, ''} @@ -75,11 +60,6 @@ provider: ALCHEMY_API_KEY_ARBITRUM_GOERLI: ${env:ALCHEMY_API_KEY_ARBITRUM_GOERLI, ''} ALCHEMY_API_KEY_OPTIMISM_GOERLI: ${env:ALCHEMY_API_KEY_OPTIMISM_GOERLI, ''} ALCHEMY_API_KEY_MUMBAI: ${env:ALCHEMY_API_KEY_MUMBAI, ''} - ARBITRUM_GAS_MULTIPLIER: ${env:ARBITRUM_GAS_MULTIPLIER, ''} - MIN_GASE_PRICE_GWEI: ${env:MIN_GASE_PRICE_GWEI, '2'} - SQS_QUEUE_URL: ${env:SQS_QUEUE_URL, ''} - SQS_QUEUE_ARN: ${env:SQS_QUEUE_ARN, ''} - TABLELAND_CONTROLLER_BUNDLE_ID: ${env:TABLELAND_CONTROLLER_BUNDLE_ID, ''} SEGMENT_WRITE_KEY: ${env:SEGMENT_WRITE_KEY, ''} ENCRYPTION_KEY: ${env:ENCRYPTION_KEY, ''} TWITTER_OAUTH_CALLBACK_URL: ${env:TWITTER_OAUTH_CALLBACK_URL, ''} diff --git a/src/abis/GnosisSafe.json b/src/abis/GnosisSafe.json deleted file mode 100644 index 4606438d..00000000 --- a/src/abis/GnosisSafe.json +++ /dev/null @@ -1,1033 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "AddedOwner", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "approvedHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ApproveHash", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "handler", - "type": "address" - } - ], - "name": "ChangedFallbackHandler", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "guard", - "type": "address" - } - ], - "name": "ChangedGuard", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "threshold", - "type": "uint256" - } - ], - "name": "ChangedThreshold", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "DisabledModule", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "EnabledModule", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes32", - "name": "txHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "payment", - "type": "uint256" - } - ], - "name": "ExecutionFailure", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "ExecutionFromModuleFailure", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "ExecutionFromModuleSuccess", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "bytes32", - "name": "txHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "payment", - "type": "uint256" - } - ], - "name": "ExecutionSuccess", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "RemovedOwner", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "SafeReceived", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "indexed": false, - "internalType": "address[]", - "name": "owners", - "type": "address[]" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "threshold", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "initializer", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "fallbackHandler", - "type": "address" - } - ], - "name": "SafeSetup", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - } - ], - "name": "SignMsg", - "type": "event" - }, - { - "stateMutability": "nonpayable", - "type": "fallback" - }, - { - "inputs": [], - "name": "VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "addOwnerWithThreshold", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hashToApprove", - "type": "bytes32" - } - ], - "name": "approveHash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "approvedHashes", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "changeThreshold", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "requiredSignatures", - "type": "uint256" - } - ], - "name": "checkNSignatures", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "dataHash", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "name": "checkSignatures", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "prevModule", - "type": "address" - }, - { - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "disableModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "domainSeparator", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "enableModule", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "safeTxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "baseGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "gasToken", - "type": "address" - }, - { - "internalType": "address", - "name": "refundReceiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_nonce", - "type": "uint256" - } - ], - "name": "encodeTransactionData", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "safeTxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "baseGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "gasToken", - "type": "address" - }, - { - "internalType": "address payable", - "name": "refundReceiver", - "type": "address" - }, - { - "internalType": "bytes", - "name": "signatures", - "type": "bytes" - } - ], - "name": "execTransaction", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - } - ], - "name": "execTransactionFromModule", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - } - ], - "name": "execTransactionFromModuleReturnData", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "returnData", - "type": "bytes" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "getChainId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "start", - "type": "address" - }, - { - "internalType": "uint256", - "name": "pageSize", - "type": "uint256" - } - ], - "name": "getModulesPaginated", - "outputs": [ - { - "internalType": "address[]", - "name": "array", - "type": "address[]" - }, - { - "internalType": "address", - "name": "next", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getOwners", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "getStorageAt", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getThreshold", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "safeTxGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "baseGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasPrice", - "type": "uint256" - }, - { - "internalType": "address", - "name": "gasToken", - "type": "address" - }, - { - "internalType": "address", - "name": "refundReceiver", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_nonce", - "type": "uint256" - } - ], - "name": "getTransactionHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "module", - "type": "address" - } - ], - "name": "isModuleEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "isOwner", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "nonce", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "prevOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - } - ], - "name": "removeOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "enum Enum.Operation", - "name": "operation", - "type": "uint8" - } - ], - "name": "requiredTxGas", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "handler", - "type": "address" - } - ], - "name": "setFallbackHandler", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "guard", - "type": "address" - } - ], - "name": "setGuard", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_owners", - "type": "address[]" - }, - { - "internalType": "uint256", - "name": "_threshold", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "address", - "name": "fallbackHandler", - "type": "address" - }, - { - "internalType": "address", - "name": "paymentToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "payment", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "paymentReceiver", - "type": "address" - } - ], - "name": "setup", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "signedMessages", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "targetContract", - "type": "address" - }, - { - "internalType": "bytes", - "name": "calldataPayload", - "type": "bytes" - } - ], - "name": "simulateAndRevert", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "prevOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "oldOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "swapOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] \ No newline at end of file diff --git a/src/abis/GnosisSafeProxy.json b/src/abis/GnosisSafeProxy.json deleted file mode 100644 index ca9d98b0..00000000 --- a/src/abis/GnosisSafeProxy.json +++ /dev/null @@ -1,163 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "contract GnosisSafeProxy", - "name": "proxy", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "singleton", - "type": "address" - } - ], - "name": "ProxyCreation", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_singleton", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initializer", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "saltNonce", - "type": "uint256" - } - ], - "name": "calculateCreateProxyWithNonceAddress", - "outputs": [ - { - "internalType": "contract GnosisSafeProxy", - "name": "proxy", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "singleton", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "createProxy", - "outputs": [ - { - "internalType": "contract GnosisSafeProxy", - "name": "proxy", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_singleton", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initializer", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "saltNonce", - "type": "uint256" - }, - { - "internalType": "contract IProxyCreationCallback", - "name": "callback", - "type": "address" - } - ], - "name": "createProxyWithCallback", - "outputs": [ - { - "internalType": "contract GnosisSafeProxy", - "name": "proxy", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_singleton", - "type": "address" - }, - { - "internalType": "bytes", - "name": "initializer", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "saltNonce", - "type": "uint256" - } - ], - "name": "createProxyWithNonce", - "outputs": [ - { - "internalType": "contract GnosisSafeProxy", - "name": "proxy", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proxyCreationCode", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "proxyRuntimeCode", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "pure", - "type": "function" - } -] \ No newline at end of file diff --git a/src/abis/Meem.json b/src/abis/Meem.json deleted file mode 100644 index 6ec46cb3..00000000 --- a/src/abis/Meem.json +++ /dev/null @@ -1 +0,0 @@ -[{"name":"MeemAdminContractSet","type":"event","inputs":[{"name":"adminContract","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"MeemRoleGranted","type":"event","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"user","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"MeemRoleRevoked","type":"event","inputs":[{"name":"role","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"user","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"ADMIN_ROLE","type":"function","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"pure"},{"name":"UPGRADER_ROLE","type":"function","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"pure"},{"name":"adminContract","type":"function","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"bulkSetRoles","type":"function","inputs":[{"name":"items","type":"tuple[]","components":[{"name":"user","type":"address","internalType":"address"},{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"hasRole","type":"bool","internalType":"bool"}],"internalType":"struct SetRoleItem[]"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"canUpgradeContract","type":"function","inputs":[{"name":"upgrader","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"getRoles","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"address[]","internalType":"address[]"}],"stateMutability":"view"},{"name":"grantRole","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"user","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"hasAssignedRole","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"user","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"hasRole","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"user","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"requireRole","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"user","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"view"},{"name":"revokeRole","type":"function","inputs":[{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"user","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setAdminContract","type":"function","inputs":[{"name":"newAdminContract","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"MeemSplitsSet","type":"event","inputs":[{"name":"tokenId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"splits","type":"tuple[]","indexed":false,"components":[{"name":"toAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"lockedBy","type":"address","internalType":"address"}],"internalType":"struct Split[]"}],"anonymous":false},{"name":"RoyaltiesSet","type":"event","inputs":[{"name":"tokenId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"royalties","type":"tuple[]","indexed":false,"components":[{"name":"account","type":"address","internalType":"address payable"},{"name":"value","type":"uint96","internalType":"uint96"}],"internalType":"struct Part[]"}],"anonymous":false},{"name":"getRaribleV2Royalties","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple[]","components":[{"name":"account","type":"address","internalType":"address payable"},{"name":"value","type":"uint96","internalType":"uint96"}],"internalType":"struct Part[]"}],"stateMutability":"view"},{"name":"handleSaleDistribution","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"payable"},{"name":"lockSplits","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setSplits","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"splits","type":"tuple[]","components":[{"name":"toAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"lockedBy","type":"address","internalType":"address"}],"internalType":"struct Split[]"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"MeemContractInfoSet","type":"event","inputs":[{"name":"contractAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"MeemContractInitialized","type":"event","inputs":[{"name":"contractAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"MeemContractURISet","type":"event","inputs":[{"name":"contractAddress","type":"address","indexed":true,"internalType":"address"}],"anonymous":false},{"name":"contractURI","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"getContractInfo","type":"function","inputs":[],"outputs":[{"name":"","type":"tuple","components":[{"name":"symbol","type":"string","internalType":"string"},{"name":"name","type":"string","internalType":"string"},{"name":"contractURI","type":"string","internalType":"string"},{"name":"maxSupply","type":"uint256","internalType":"uint256"},{"name":"mintPermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"},{"name":"splits","type":"tuple[]","components":[{"name":"toAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"lockedBy","type":"address","internalType":"address"}],"internalType":"struct Split[]"},{"name":"isTransferLocked","type":"bool","internalType":"bool"}],"internalType":"struct ContractInfo"}],"stateMutability":"view"},{"name":"initialize","type":"function","inputs":[{"name":"params","type":"tuple","components":[{"name":"symbol","type":"string","internalType":"string"},{"name":"name","type":"string","internalType":"string"},{"name":"contractURI","type":"string","internalType":"string"},{"name":"roles","type":"tuple[]","components":[{"name":"user","type":"address","internalType":"address"},{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"hasRole","type":"bool","internalType":"bool"}],"internalType":"struct SetRoleItem[]"},{"name":"maxSupply","type":"uint256","internalType":"uint256"},{"name":"mintPermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"},{"name":"splits","type":"tuple[]","components":[{"name":"toAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"lockedBy","type":"address","internalType":"address"}],"internalType":"struct Split[]"},{"name":"isTransferLocked","type":"bool","internalType":"bool"}],"internalType":"struct InitParams"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"reinitialize","type":"function","inputs":[{"name":"params","type":"tuple","components":[{"name":"symbol","type":"string","internalType":"string"},{"name":"name","type":"string","internalType":"string"},{"name":"contractURI","type":"string","internalType":"string"},{"name":"roles","type":"tuple[]","components":[{"name":"user","type":"address","internalType":"address"},{"name":"role","type":"bytes32","internalType":"bytes32"},{"name":"hasRole","type":"bool","internalType":"bool"}],"internalType":"struct SetRoleItem[]"},{"name":"maxSupply","type":"uint256","internalType":"uint256"},{"name":"mintPermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"},{"name":"splits","type":"tuple[]","components":[{"name":"toAddress","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"lockedBy","type":"address","internalType":"address"}],"internalType":"struct Split[]"},{"name":"isTransferLocked","type":"bool","internalType":"bool"}],"internalType":"struct InitParams"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setContractInfo","type":"function","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"symbol","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setContractInfo","type":"function","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"symbol","type":"string","internalType":"string"},{"name":"newContractURI","type":"string","internalType":"string"},{"name":"maxSupply","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setContractInfo","type":"function","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"symbol","type":"string","internalType":"string"},{"name":"newContractURI","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setContractURI","type":"function","inputs":[{"name":"newContractURI","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"Approval","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"ApprovalForAll","type":"event","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"operator","type":"address","indexed":true,"internalType":"address"},{"name":"approved","type":"bool","indexed":false,"internalType":"bool"}],"anonymous":false},{"name":"MeemTransfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"Transfer","type":"event","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"tokenId","type":"uint256","indexed":true,"internalType":"uint256"}],"anonymous":false},{"name":"approve","type":"function","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"balanceOf","type":"function","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"bulkBurn","type":"function","inputs":[{"name":"tokenIds","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"bulkMint","type":"function","inputs":[{"name":"bulkParams","type":"tuple[]","components":[{"name":"to","type":"address","internalType":"address"},{"name":"tokenURI","type":"string","internalType":"string"},{"name":"tokenType","type":"uint8","internalType":"enum TokenType"}],"internalType":"struct MintParameters[]"}],"outputs":[],"stateMutability":"payable"},{"name":"burn","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"getApproved","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"getMeem","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple","components":[{"name":"owner","type":"address","internalType":"address"},{"name":"tokenType","type":"uint8","internalType":"enum TokenType"},{"name":"mintedBy","type":"address","internalType":"address"},{"name":"mintedAt","type":"uint256","internalType":"uint256"}],"internalType":"struct Meem"}],"stateMutability":"view"},{"name":"isApprovedForAll","type":"function","inputs":[{"name":"account","type":"address","internalType":"address"},{"name":"operator","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"mint","type":"function","inputs":[{"name":"params","type":"tuple","components":[{"name":"to","type":"address","internalType":"address"},{"name":"tokenURI","type":"string","internalType":"string"},{"name":"tokenType","type":"uint8","internalType":"enum TokenType"}],"internalType":"struct MintParameters"}],"outputs":[],"stateMutability":"payable"},{"name":"mintWithProof","type":"function","inputs":[{"name":"params","type":"tuple","components":[{"name":"to","type":"address","internalType":"address"},{"name":"tokenURI","type":"string","internalType":"string"},{"name":"tokenType","type":"uint8","internalType":"enum TokenType"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}],"internalType":"struct MintWithProofParameters"}],"outputs":[],"stateMutability":"payable"},{"name":"name","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"ownerOf","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"name":"requireCanMint","type":"function","inputs":[{"name":"params","type":"tuple","components":[{"name":"minter","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"proof","type":"bytes32[]","internalType":"bytes32[]"}],"internalType":"struct RequireCanMintParams"}],"outputs":[],"stateMutability":"payable"},{"name":"requireCanTransfer","type":"function","inputs":[{"name":"msgSender","type":"address","internalType":"address"},{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"requireTokenAdmin","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"addy","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"view"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"safeTransferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"name":"setApprovalForAll","type":"function","inputs":[{"name":"operator","type":"address","internalType":"address"},{"name":"status","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"supportsInterface","type":"function","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"name":"symbol","type":"function","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"tokenByIndex","type":"function","inputs":[{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"tokenOfOwnerByIndex","type":"function","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"index","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"tokenURI","type":"function","inputs":[{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"name":"totalSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"transferFrom","type":"function","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"tokenId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"payable"},{"name":"MeemMaxSupplyLocked","type":"event","inputs":[],"anonymous":false},{"name":"MeemMaxSupplySet","type":"event","inputs":[{"name":"maxSupply","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"name":"MeemMintPermissionsSet","type":"event","inputs":[{"name":"mintPermissions","type":"tuple[]","indexed":false,"components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"}],"anonymous":false},{"name":"MINTER_ROLE","type":"function","inputs":[],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"pure"},{"name":"maxSupply","type":"function","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"name":"setIsTransferrable","type":"function","inputs":[{"name":"isTransferrable","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setMaxSupply","type":"function","inputs":[{"name":"newMaxSupply","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"setMintingPermissions","type":"function","inputs":[{"name":"newPermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"}],"outputs":[],"stateMutability":"nonpayable"},{"name":"validatePermissions","type":"function","inputs":[{"name":"basePermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"},{"name":"overridePermissions","type":"tuple[]","components":[{"name":"permission","type":"uint8","internalType":"enum Permission"},{"name":"addresses","type":"address[]","internalType":"address[]"},{"name":"numTokens","type":"uint256","internalType":"uint256"},{"name":"costWei","type":"uint256","internalType":"uint256"},{"name":"mintStartTimestamp","type":"uint256","internalType":"uint256"},{"name":"mintEndTimestamp","type":"uint256","internalType":"uint256"},{"name":"merkleRoot","type":"bytes32","internalType":"bytes32"}],"internalType":"struct MeemPermission[]"}],"outputs":[],"stateMutability":"pure"}] \ No newline at end of file diff --git a/src/abis/PKPNFT.json b/src/abis/PKPNFT.json deleted file mode 100644 index 6f6c8843..00000000 --- a/src/abis/PKPNFT.json +++ /dev/null @@ -1,938 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "contractBalance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "exists", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "freeMintId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "ipfsCID", - "type": "bytes" - }, - { - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "freeMintGrantAndBurnNext", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "freeMintId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "freeMintNext", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "freeMintId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "freeMintSigTest", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "freeMintSigner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getEthAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getPubkey", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - } - ], - "name": "getUnmintedRoutedTokenIdCount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "mintCost", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "ipfsCID", - "type": "bytes" - } - ], - "name": "mintGrantAndBurnNext", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "ipfsCID", - "type": "bytes" - } - ], - "name": "mintGrantAndBurnSpecific", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - } - ], - "name": "mintNext", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "mintSpecific", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pkpPermissions", - "outputs": [ - { - "internalType": "contract PKPPermissions", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "keyType", - "type": "uint256" - } - ], - "name": "pkpRouted", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "prefixed", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "redeemedFreeMintIds", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "router", - "outputs": [ - { - "internalType": "contract PubkeyRouter", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newFreeMintSigner", - "type": "address" - } - ], - "name": "setFreeMintSigner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "newMintCost", - "type": "uint256" - } - ], - "name": "setMintCost", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pkpPermissionsAddress", - "type": "address" - } - ], - "name": "setPkpPermissionsAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "routerAddress", - "type": "address" - } - ], - "name": "setRouterAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "tokenByIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "tokenOfOwnerByIndex", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "unmintedRoutedTokenIds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] \ No newline at end of file diff --git a/src/config/default.ts b/src/config/default.ts index 4a813943..20df4747 100644 --- a/src/config/default.ts +++ b/src/config/default.ts @@ -1,5 +1,4 @@ import path from 'path' -import { MeemAPI } from '../types/meem.generated' import errors from './errors' // eslint-disable-next-line @@ -13,9 +12,6 @@ export default { MEEM_DOMAIN: process.env.MEEM_DOMAIN ?? 'https://app.meem.wtf', SERVER_LISTENING: process.env.SERVER_LISTENING !== 'false', SERVER_ADMIN_KEY: process.env.SERVER_ADMIN_KEY ?? 'xGugNAB2PEX4uY4sPF', - // JWT_SECRET: - // process.env.JWT_SECRET ?? - // 'ac741f40d71a2564e08180f5eb1cc9dd28e288ed75b33c34cba2fc18a3c31a64e719835877c7a6db9fdae8054037053172aba56f4dabc5f1b', JWT_RSA_PUBLIC_KEY: process.env.JWT_RSA_PUBLIC_KEY ?? '', JWT_RSA_PRIVATE_KEY: process.env.JWT_RSA_PRIVATE_KEY ?? '', JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN @@ -26,12 +22,7 @@ export default { ENABLE_REQUEST_LOGGING: process.env.ENABLE_REQUEST_LOGGING === 'true', GENERATE_SHARED_TYPES: process.env.GENERATE_SHARED_TYPES === 'true', TESTING: process.env.TESTING === 'true', - DISABLE_RATE_LIMIT: process.env.DISABLE_RATE_LIMIT === 'true', - DATABASE_URL: process.env.DATABASE_URL ?? 'sqlite::memory:', - // DATABASE_URL_TESTING: - // process.env.DATABASE_URL_TESTING || - // `sqlite:${__dirname}/../../tmp/testing.db`, DISABLE_MIGRATIONS: process.env.DISABLE_MIGRATIONS === 'true', DISABLE_ORM_SYNC: process.env.DISABLE_ORM_SYNC === 'true', DATABASE_POOL_MAX: process.env.DATABASE_POOL_MAX @@ -43,6 +34,13 @@ export default { DATABASE_POOL_IDLE: process.env.DATABASE_POOL_IDLE ? +process.env.DATABASE_POOL_IDLE : 10000, + ADMIN_ROLE: + '0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775', + MINTER_ROLE: + '0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6', + UPGRADER_ROLE: + '0x189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3', + WALLET_PRIVATE_KEY: process.env.WALLET_PRIVATE_KEY ?? '', ORM_DISABLE: process.env.ORM_DISABLE === 'true', ORM_FORCE_SYNC: process.env.ORM_FORCE_SYNC === 'true', ORM_DISABLE_SSL: process.env.ORM_DISABLE_SSL === 'true', @@ -54,41 +52,16 @@ export default { CORS_DEFAULT_ORIGIN: process.env.CORS_DEFAULT_ORIGIN ?? 'meem.wtf', CORS_ALLOWED_ORIGINS: process.env.CORS_ALLOWED_ORIGINS ? process.env.CORS_ALLOWED_ORIGINS.split(',').map(o => o.trim()) - : ['clubs.link'], - - REDIS_URL: process.env.REDIS_URL, - REDIS_ENABLED: process.env.REDIS_ENABLED !== 'false', - // Default cache TTL in seconds - REDIS_DEFAULT_TTL: process.env.REDIS_DEFAULT_TTL - ? +process.env.REDIS_DEFAULT_TTL - : 300, - // Only needed if redis is being shared by multiple API instances on different environments - REDIS_KEY_PREFIX: process.env.REDIS_KEY_PREFIX, + : ['meem.wtf'], AWS_WEBSOCKET_GATEWAY_URL: process.env.AWS_WEBSOCKET_GATEWAY_URL, SERVERLESS_LOG_FULL_REQUEST: process.env.SERVERLESS_LOG_FULL_REQUEST, APP_AWS_ACCESS_KEY_ID: process.env.APP_AWS_ACCESS_KEY_ID ?? '', APP_AWS_SECRET_ACCESS_KEY: process.env.APP_AWS_SECRET_ACCESS_KEY ?? '', - CHAIN_IDS: process.env.CHAIN_IDS - ? process.env.CHAIN_IDS.split(',').map(cid => +cid.trim()) - : [5], - NETWORK: process.env.NETWORK - ? (process.env.NETWORK as MeemAPI.NetworkName) - : ('' as MeemAPI.NetworkName), - WALLET_PRIVATE_KEY: process.env.WALLET_PRIVATE_KEY ?? '', - TWITTER_WALLET_PRIVATE_KEY: process.env.TWITTER_WALLET_PRIVATE_KEY ?? '', - MEEM_PROXY_ADDRESS: process.env.MEEM_PROXY_ADDRESS ?? '', - MEEM_ID_PROXY_ADDRESS: process.env.MEEM_ID_PROXY_ADDRESS ?? '', - TWITTER_PROJECT_TOKEN_ID: process.env.TWITTER_PROJECT_TOKEN_ID ?? '', - IPFS_CONTENT_GATEWAY_URL: - process.env.IPFS_CONTENT_GATEWAY_URL ?? 'https://meem.mypinata.cloud', - GITHUB_KEY: process.env.GITHUB_KEY ?? '', - ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY ?? '', DYNAMODB_SOCKETS_TABLE: process.env.DYNAMODB_SOCKETS_TABLE ?? '', DYNAMODB_TWEET_CHECKPOINTS_TABLE: process.env.DYNAMODB_TWEET_CHECKPOINTS_TABLE ?? '', ENABLE_TEST_ENDPOINTS: process.env.ENABLE_TEST_ENDPOINTS === 'true', WEBSOCKETS_ENABLED: process.env.WEBSOCKETS_ENABLED === 'true', - DISABLE_ASYNC_MINTING: process.env.DISABLE_ASYNC_MINTING === 'true', S3_BUCKET: process.env.S3_BUCKET ?? '', MAX_GAS_PRICE_GWEI: process.env.MAX_GAS_PRICE_GWEI ? +process.env.MAX_GAS_PRICE_GWEI @@ -99,34 +72,12 @@ export default { GAS_ESTIMATE_THRESHOLD_GWEI: process.env.GAS_ESTIMATE_THRESHOLD_GWEI ? +process.env.GAS_ESTIMATE_THRESHOLD_GWEI : 10, - ENABLE_TWITTER_LISTENERS: process.env.ENABLE_TWITTER_LISTENERS === 'true', - ENABLE_PROVIDER_LISTENERS: process.env.ENABLE_PROVIDER_LISTENERS === 'true', ENABLE_VERBOSE_ERRORS: process.env.ENABLE_VERBOSE_ERRORS === 'true', DEFAULT_PAGINATION_LIMIT: process.env.DEFAULT_PAGINATION_LIMIT ? +process.env.DEFAULT_PAGINATION_LIMIT : 20, - ENABLE_PUPPETEER: process.env.ENABLE_PUPPETEER === 'true', - MINT_GAS_LIMIT: process.env.MINT_GAS_LIMIT - ? process.env.MINT_GAS_LIMIT - : '6000000', PINATA_API_KEY: process.env.PINATA_API_KEY ?? '', PINATA_API_SECRET: process.env.PINATA_API_SECRET ?? '', - TABLELAND_CONTROLLER_BUNDLE_ID: - process.env.TABLELAND_CONTROLLER_BUNDLE_ID ?? '', - MEEM_BUNDLE_ID: process.env.MEEM_BUNDLE_ID ?? '', - MEEM_PROXY_CONTRACT_ID: process.env.MEEM_PROXY_CONTRACT_ID ?? '', - ADMIN_ROLE: - '0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775', - MINTER_ROLE: - '0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6', - UPGRADER_ROLE: - '0x189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e3', - GNOSIS_MASTER_CONTRACT_ADDRESS: - process.env.GNOSIS_MASTER_CONTRACT_ADDRESS ?? '', - GNOSIS_PROXY_CONTRACT_ADDRESS: - process.env.GNOSIS_PROXY_CONTRACT_ADDRESS ?? '', - GNOSIS_DEFAULT_CALLBACK_HANDLER: - process.env.GNOSIS_DEFAULT_CALLBACK_HANDLER ?? '', DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID ?? '', DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET ?? '', DISCORD_AUTH_CALLBACK_URL: process.env.DISCORD_AUTH_CALLBACK_URL ?? '', @@ -145,10 +96,6 @@ export default { PG_LOCK_TIMEOUT: process.env.PG_LOCK_TIMEOUT ? +process.env.PG_LOCK_TIMEOUT : 60000, - WALLET_LOCK_KEY: process.env.WALLET_LOCK_KEY ?? 'apiWallet', - ARBITRUM_GAS_MULTIPLIER: process.env.ARBITRUM_GAS_MULTIPLIER - ? +process.env.ARBITRUM_GAS_MULTIPLIER - : 6, JSON_RPC_MAINNET: process.env.JSON_RPC_MAINNET ?? '', JSON_RPC_CELO: process.env.JSON_RPC_CELO ?? 'https://rpc.ankr.com/celo', ALCHEMY_API_KEY_MAINNET: process.env.ALCHEMY_API_KEY_MAINNET ?? '', @@ -161,13 +108,6 @@ export default { process.env.ALCHEMY_API_KEY_OPTIMISM_GOERLI ?? '', ALCHEMY_API_KEY_MUMBAI: process.env.ALCHEMY_API_KEY_MUMBAI ?? '', JSON_RPC_HARDHAT: process.env.JSON_RPC_HARDHAT ?? 'http://127.0.0.1:8545', - PKP_CONTRACT_ADDRESS: - process.env.PKP_CONTRACT_ADDRESS ?? - '0x86062B7a01B8b2e22619dBE0C15cbe3F7EBd0E92', - PKP_MINT_COST: process.env.PKP_MINT_COST ?? '0.0001', - SQS_QUEUE_URL: process.env.SQS_QUEUE_URL ?? '', - ENABLE_SQS_CONSUMER: process.env.ENABLE_SQS_CONSUMER === 'true', - GUN_DB_PEERS: process.env.GUN_DB_PEERS ?? '', SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY ?? '', DISCORD_PUBLIC_KEY: process.env.DISCORD_PUBLIC_KEY ?? '', DISCORD_APP_ID: process.env.DISCORD_APP_ID ?? '', @@ -207,5 +147,7 @@ export default { MEEM_HELPDESK_SUPABASE_SUBDOMAIN: process.env.MEEM_HELPDESK_SUPABASE_SUBDOMAIN ?? '', MEEM_HELPDESK_DISCORD_CHANNEL_ID: - process.env.MEEM_HELPDESK_DISCORD_CHANNEL_ID ?? '' + process.env.MEEM_HELPDESK_DISCORD_CHANNEL_ID ?? '', + AWS_SMTP_ACCESS_KEY_ID: process.env.AWS_SMTP_ACCESS_KEY_ID ?? '', + AWS_SMTP_SECRET_ACCESS_KEY: process.env.AWS_SMTP_SECRET_ACCESS_KEY ?? '' } diff --git a/src/config/errors.ts b/src/config/errors.ts index fe3a5a93..34e8e1c2 100644 --- a/src/config/errors.ts +++ b/src/config/errors.ts @@ -475,6 +475,12 @@ const errors = { 'Something went wrong minting. Check that you have the correct permissions and try again.', friendlyReason: 'Something went wrong minting. Check that you have the correct permissions and try again.' + }, + INVITE_NOT_FOUND: { + httpCode: 404, + status: 'failure', + reason: 'The invite could not be found', + friendlyReason: 'The invite could not be found' } } diff --git a/src/controllers/AdminController.ts b/src/controllers/AdminController.ts index cfea6786..800397f6 100644 --- a/src/controllers/AdminController.ts +++ b/src/controllers/AdminController.ts @@ -214,12 +214,4 @@ export default class AdminController { status: 'success' }) } - - public static async syncPins(req: Request, res: Response): Promise { - await services.web3.syncPins() - - return res.json({ - status: 'success' - }) - } } diff --git a/src/controllers/AgreementController.ts b/src/controllers/AgreementController.ts index 52460c3c..964dad02 100644 --- a/src/controllers/AgreementController.ts +++ b/src/controllers/AgreementController.ts @@ -1,6 +1,8 @@ import { ethers } from 'ethers' import { Response } from 'express' import { Op } from 'sequelize' +import { v4 as uuidv4 } from 'uuid' +import { transactionalTemplate } from '../lib/emailTemplate' import { IAuthenticatedRequest, IRequest, IResponse } from '../types/app' import { MeemAPI } from '../types/meem.generated' export default class AgreementController { @@ -29,7 +31,7 @@ export default class AgreementController { req: IRequest, res: IResponse ): Promise { - const { name, metadata, isOnChain, chainId, tokenMetadata } = req.body + const { name, metadata, tokenMetadata } = req.body if (!req.wallet) { throw new Error('USER_NOT_LOGGED_IN') @@ -49,68 +51,41 @@ export default class AgreementController { await req.wallet.enforceTXLimit() - let result: - | { - deployContractTxId: string - cutTxId: string - mintTxId: string | undefined - adminRoleDeployContractTxId: string | undefined - adminRoleCutTxId: string | undefined - adminRoleMintTxId: string | undefined - setAdminRoleTxId: string | undefined - } - | { - agreementId: string - slug: string - adminAgreementId?: string - } - - if (isOnChain) { - if (!chainId) { - throw new Error('MISSING_PARAMETERS') - } - result = await services.agreement.createAgreement({ - ...req.body, - chainId, - senderWalletAddress: req.wallet.address + const { agreement, adminAgreement } = + await services.agreement.createAgreementWithoutContract({ + body: req.body, + owner: req.wallet }) - } else { - const { agreement, adminAgreement } = - await services.agreement.createAgreementWithoutContract({ - body: req.body, - owner: req.wallet - }) - await Promise.all([ - services.agreement.bulkMint({ - agreementId: agreement.id, - mintedBy: req.wallet.address, - tokens: [ - { - to: req.wallet.address, - metadata: tokenMetadata - } - ] - }), - adminAgreement - ? services.agreement.bulkMint({ - agreementId: agreement.id, - agreementRoleId: adminAgreement.id, - mintedBy: req.wallet.address, - tokens: [ - { - to: req.wallet.address, - metadata: tokenMetadata - } - ] - }) - : Promise.resolve(null) - ]) - result = { + await Promise.all([ + services.agreement.bulkMint({ agreementId: agreement.id, - slug: agreement.slug, - adminAgreementId: adminAgreement?.id - } + mintedBy: req.wallet.address, + tokens: [ + { + to: req.wallet.address, + metadata: tokenMetadata + } + ] + }), + adminAgreement + ? services.agreement.bulkMint({ + agreementId: agreement.id, + agreementRoleId: adminAgreement.id, + mintedBy: req.wallet.address, + tokens: [ + { + to: req.wallet.address, + metadata: tokenMetadata + } + ] + }) + : Promise.resolve(null) + ]) + const result = { + agreementId: agreement.id, + slug: agreement.slug, + adminAgreementId: adminAgreement?.id } return res.json(result) @@ -160,48 +135,6 @@ export default class AgreementController { }) } - public static async setAgreementAdminRole( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - await req.wallet.enforceTXLimit() - - const { agreementId } = req.params - - const result = await services.agreement.setAgreemetAdminRole({ - adminAgreementRoleId: req.body.adminAgreementRoleId, - agreementId, - senderWalletAddress: req.wallet.address - }) - - return res.json(result) - } - - public static async createAgreementSafe( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - await req.wallet.enforceTXLimit() - - const { agreementId } = req.params - - const result = await services.agreement.createAgreementSafe({ - ...req.body, - agreementId, - senderWalletAddress: req.wallet.address - }) - - return res.json(result) - } - public static async setAgreementSafeAddress( req: IRequest, res: IResponse @@ -239,27 +172,6 @@ export default class AgreementController { }) } - public static async upgradeAgreement( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - await req.wallet.enforceTXLimit() - - const { agreementId } = req.params - - const result = await services.agreement.upgradeAgreement({ - ...req.body, - agreementId, - senderWalletAddress: req.wallet.address - }) - - return res.json(result) - } - public static async getMintingProof( req: IRequest, res: IResponse @@ -393,4 +305,158 @@ export default class AgreementController { isAdmin }) } + + public static async sendInvites( + req: IAuthenticatedRequest, + res: IResponse + ): Promise { + if (!req.wallet) { + throw new Error('USER_NOT_LOGGED_IN') + } + + const { agreementId } = req.params + const { to } = req.body + + const agreement = await orm.models.Agreement.findOne({ + where: { + id: agreementId + } + }) + + if (!agreement) { + throw new Error('AGREEMENT_NOT_FOUND') + } + + const isAdmin = await agreement.isAdmin(req.wallet.address) + + if (!isAdmin) { + throw new Error('NOT_AUTHORIZED') + } + + const walletAddresses: string[] = [] + const emails: string[] = [] + + to.forEach(t => { + if (ethers.utils.isAddress(t)) { + walletAddresses.push(ethers.utils.getAddress(t)) + } else { + emails.push(t) + } + }) + + const [agreementTokens, currentTokenId, wallets] = await Promise.all([ + orm.models.AgreementToken.findAll({ + where: { + AgreementId: agreement.id + }, + include: [ + { + model: orm.models.Wallet, + as: 'Owner', + where: { + address: { + [Op.in]: walletAddresses + } + } + } + ] + }), + orm.models.AgreementToken.count({ + where: { + AgreementId: agreement.id + } + }), + orm.models.Wallet.findAll({ + where: { + address: { + [Op.in]: walletAddresses + } + } + }) + ]) + + const newAgreementTokens: Record[] = [] + let tokenId = currentTokenId + 1 + for (let i = 0; i < walletAddresses.length; i++) { + const walletAddress = walletAddresses[i] + let wallet = wallets.find(w => w.address === walletAddress) + if (!wallet) { + wallet = await orm.models.Wallet.create({ + address: walletAddress + }) + } + const agreementToken = agreementTokens.find(t => t.OwnerId === wallet?.id) + + if (!agreementToken) { + newAgreementTokens.push({ + id: uuidv4(), + tokenId, + AgreementId: agreement.id, + OwnerId: wallet.id + }) + + tokenId++ + } + } + + await orm.models.AgreementToken.bulkCreate(newAgreementTokens) + const invitesData: Record[] = [] + const subject = `You have been invited to join ${agreement.name}` + + for (let i = 0; i < emails.length; i++) { + const email = emails[i] + + const code = uuidv4() + + invitesData.push({ + id: uuidv4(), + code, + AgreementId: agreement.id + }) + + await services.aws.sendEmail({ + to: [email], + subject, + body: transactionalTemplate({ + bodyText: `Click the button below to accept the invite and join ${agreement.name}`, + ctaText: 'Accept Invite', + ctaUrl: `${config.MEEM_DOMAIN}/invite?code=${code}`, + subject, + title: `Join ${agreement.name}` + }) + }) + } + + await orm.models.Invite.bulkCreate(invitesData) + + return res.json({ + status: 'success' + }) + } + + public static async acceptInvite( + req: IAuthenticatedRequest, + res: IResponse + ): Promise { + if (!req.wallet) { + throw new Error('USER_NOT_LOGGED_IN') + } + + const { code } = req.body + + const { agreement, agreementToken, agreementRole, agreementRoleToken } = + await services.agreement.acceptInvite({ + code, + wallet: req.wallet + }) + + return res.json({ + agreementId: agreement.id, + agreementTokenId: agreementToken.id, + name: agreement.name, + slug: agreement.slug, + agreementRoleId: agreementRole?.id, + agreementRoleTokenId: agreementRoleToken?.id + }) + } } diff --git a/src/controllers/AgreementExtensionController.ts b/src/controllers/AgreementExtensionController.ts deleted file mode 100644 index 178a10bc..00000000 --- a/src/controllers/AgreementExtensionController.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { IFacetVersion } from '@meemproject/meem-contracts' -import { ethers } from 'ethers' -import { Response } from 'express' -import _ from 'lodash' -import { IRequest, IResponse } from '../types/app' -import { MeemAPI } from '../types/meem.generated' -export default class AgreementExtensionController { - public static async createAgreementExtension( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - const { - extensionId, - isInitialized, - isSetupComplete, - metadata, - externalLink /*, widget */ - } = req.body - - if (!extensionId) { - throw new Error('MISSING_PARAMETERS') - } - - const agreement = await orm.models.Agreement.findOne({ - where: { - id: req.params.agreementId - } - }) - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - const isAdmin = await agreement.isAdmin(req.wallet.address) - - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } - - const extension = await orm.models.Extension.findOne({ - where: { - id: extensionId - } - }) - - if (!extension) { - throw new Error('EXTENSION_NOT_FOUND') - } - - const existingAgreementExtension = - await orm.models.AgreementExtension.findOne({ - where: { - AgreementId: agreement.id, - ExtensionId: extension.id - } - }) - - if (existingAgreementExtension) { - throw new Error('EXTENSION_ALREADY_ADDED') - } - - // TODO: Validate widget/role/custom extension metadata? - // try { - // const metadataValidator = new Validator({ - // meem_metadata_type: 'Meem_AgreementExtension', - // meem_metadata_version: metadata.meem_metadata_version - // }) - // const metadataValidatorResult = metadataValidator.validate(metadata) - - // if (!metadataValidatorResult.valid) { - // log.crit(metadataValidatorResult.errors.map((e: any) => e.message)) - // throw new Error('INVALID_METADATA') - // } - // } catch (e) { - // log.crit(e) - // throw new Error('INVALID_METADATA') - // } - - const [dbContract, bundle] = await Promise.all([ - orm.models.Contract.findOne({ - where: { - id: config.MEEM_PROXY_CONTRACT_ID - } - }), - orm.models.Bundle.findOne({ - where: { - id: config.TABLELAND_CONTROLLER_BUNDLE_ID - }, - include: [ - { - model: orm.models.BundleContract, - include: [ - { - model: orm.models.Contract, - include: [ - { - model: orm.models.ContractInstance, - where: { - chainId: agreement.chainId - } - } - ] - } - ] - } - ] - }) - ]) - - const t = await orm.sequelize.transaction() - - if (!dbContract || !bundle) { - throw new Error('CONTRACT_NOT_FOUND') - } - - const agreementExtension = await orm.models.AgreementExtension.build({ - AgreementId: agreement.id, - ExtensionId: extension.id, - metadata, - isInitialized: isInitialized ?? false, - isSetupComplete: isSetupComplete ?? false - }) - - const txIds: string[] = [] - - const toVersion: IFacetVersion[] = [] - - bundle?.BundleContracts?.forEach(bc => { - if ( - !bc.Contract?.ContractInstances || - !bc.Contract?.ContractInstances[0] - ) { - throw new Error('CONTRACT_INSTANCE_NOT_FOUND') - } - toVersion.push({ - address: bc.Contract.ContractInstances[0].address, - functionSelectors: bc.functionSelectors - }) - }) - - // TODO: Finish tableland creation process - if (extension.storageDefinition.tableland?.tables) { - for ( - let i = 0; - i < extension.storageDefinition.tableland.tables.length; - i++ - ) { - const def = extension.storageDefinition.tableland.tables[i] - - const iFace = new ethers.utils.Interface(bundle.abi) - - // By default we'll let any agreement member insert data and let admins manage - const functionCall = iFace.encodeFunctionData('initialize', [ - { - ...def.permissions, - insertRoleContract: agreement.address, - adminRoleContract: - agreement.adminContractAddress ?? ethers.constants.AddressZero - } - ]) - - const { wallet } = await services.ethers.getProvider({ - chainId: agreement.chainId - }) - - // Create the tableland table - const txId = await services.ethers.queueCreateTablelandTable({ - chainId: agreement.chainId, - tableName: def.name, - columns: def.schema, - agreementExtensionId: agreementExtension.id, - abi: dbContract.abi, - args: [req.wallet.address, [req.wallet.address, wallet.address]], - bytecode: dbContract.bytecode, - fromVersion: [], - toVersion, - functionCall - }) - - txIds.push(txId) - } - } - - agreementExtension.metadata = { - ...agreementExtension.metadata, - transactions: txIds.map(txId => ({ - TransactionId: txId, - status: MeemAPI.TransactionStatus.Pending - })) - } - - const promises: Promise[] = [ - agreementExtension.save({ - transaction: t - }) - ] - - if (externalLink) { - promises.push( - orm.models.AgreementExtensionLink.create( - { - AgreementExtensionId: agreementExtension.id, - url: externalLink.url, - label: externalLink.label, - visibility: externalLink.visibility - }, - { - transaction: t - } - ) - ) - } - - if ( - extension.widgetDefinition && - extension.widgetDefinition.widgets && - extension.widgetDefinition.widgets.length > 0 - ) { - extension.widgetDefinition.widgets.forEach(w => { - promises.push( - orm.models.AgreementExtensionWidget.create( - { - AgreementExtensionId: agreementExtension.id, - metadata: w.metadata, - visibility: w.visibility - }, - { - transaction: t - } - ) - ) - }) - } - - // if (widget) { - // promises.push( - // orm.models.AgreementExtensionWidget.create( - // { - // AgreementExtensionId: agreementExtension.id, - // metadata: widget.metadata, - // visibility: widget.visibility - // }, - // { - // transaction: t - // } - // ) - // ) - // } - - await Promise.all(promises) - await t.commit() - - return res.json({ - status: 'success', - txIds - }) - } - - public static async updateAgreementExtension( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - const { agreementId, agreementExtensionId } = req.params - const { isInitialized, isSetupComplete, metadata, externalLink, widget } = - req.body - - if (!agreementId || !agreementExtensionId) { - throw new Error('INVALID_PARAMETERS') - } - - const agreement = await orm.models.Agreement.findOne({ - where: { - id: agreementId - } - }) - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - const isAdmin = await agreement.isAdmin(req.wallet.address) - - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } - - const agreementExtension = await orm.models.AgreementExtension.findOne({ - where: { - id: agreementExtensionId - }, - include: [ - { - model: orm.models.AgreementExtensionLink - }, - { - model: orm.models.AgreementExtensionWidget - } - ] - }) - - if (!agreementExtension) { - throw new Error('EXTENSION_NOT_FOUND') - } - - // TODO: Validate extension metadata? - // try { - // const metadataValidator = new Validator({ - // meem_metadata_type: 'Meem_AgreementExtension', - // meem_metadata_version: metadata.meem_metadata_version - // }) - // const metadataValidatorResult = metadataValidator.validate(metadata) - - // if (!metadataValidatorResult.valid) { - // log.crit(metadataValidatorResult.errors.map((e: any) => e.message)) - // throw new Error('INVALID_METADATA') - // } - // } catch (e) { - // log.crit(e) - // throw new Error('INVALID_METADATA') - // } - - const t = await orm.sequelize.transaction() - - const promises: Promise[] = [] - - if (metadata) { - agreementExtension.metadata = metadata - promises.push(agreementExtension.save({ transaction: t })) - } - - if (!_.isUndefined(isInitialized)) { - agreementExtension.isInitialized = isInitialized - promises.push(agreementExtension.save({ transaction: t })) - } - - if (!_.isUndefined(isSetupComplete)) { - agreementExtension.isSetupComplete = isSetupComplete - promises.push(agreementExtension.save({ transaction: t })) - } - - if (!_.isUndefined(externalLink)) { - if (externalLink && agreementExtension.AgreementExtensionLink) { - agreementExtension.AgreementExtensionLink.isEnabled = !_.isUndefined( - externalLink.isEnabled - ) - ? externalLink.isEnabled - : agreementExtension.AgreementExtensionLink.isEnabled - agreementExtension.AgreementExtensionLink.label = - externalLink.label ?? agreementExtension.AgreementExtensionLink.label - agreementExtension.AgreementExtensionLink.url = - externalLink.url ?? agreementExtension.AgreementExtensionLink.url - agreementExtension.AgreementExtensionLink.visibility = - externalLink.visibility ?? - agreementExtension.AgreementExtensionLink.visibility - promises.push( - agreementExtension.AgreementExtensionLink.save({ transaction: t }) - ) - } else if ( - externalLink === null && - agreementExtension.AgreementExtensionLink - ) { - await agreementExtension.AgreementExtensionLink.destroy() - } else if (externalLink) { - promises.push( - orm.models.AgreementExtensionLink.create( - { - AgreementExtensionId: agreementExtension.id, - url: externalLink.url, - label: externalLink.label - }, - { - transaction: t - } - ) - ) - } - } - - if (!_.isUndefined(widget)) { - if (widget && agreementExtension.AgreementExtensionWidget) { - agreementExtension.AgreementExtensionWidget.isEnabled = !_.isUndefined( - widget.isEnabled - ) - ? widget.isEnabled - : agreementExtension.AgreementExtensionWidget.isEnabled - agreementExtension.AgreementExtensionWidget.metadata = - widget.metadata ?? - agreementExtension.AgreementExtensionWidget.metadata - agreementExtension.AgreementExtensionWidget.visibility = - widget.visibility ?? - agreementExtension.AgreementExtensionWidget.visibility - promises.push( - agreementExtension.AgreementExtensionWidget.save({ transaction: t }) - ) - } else if ( - widget === null && - agreementExtension.AgreementExtensionWidget - ) { - await agreementExtension.AgreementExtensionWidget.destroy() - } else if (widget) { - promises.push( - orm.models.AgreementExtensionWidget.create( - { - AgreementExtensionId: agreementExtension.id, - isEnabled: widget.isEnabled, - metadata: widget.metadata - }, - { - transaction: t - } - ) - ) - } - } - - await Promise.all(promises) - await t.commit() - - return res.json({ - status: 'success' - }) - } -} diff --git a/src/controllers/AgreementRoleController.ts b/src/controllers/AgreementRoleController.ts index a2e97301..0131070d 100644 --- a/src/controllers/AgreementRoleController.ts +++ b/src/controllers/AgreementRoleController.ts @@ -2,100 +2,55 @@ import { Response } from 'express' import { IRequest, IResponse } from '../types/app' import { MeemAPI } from '../types/meem.generated' export default class AgreementRoleController { - // public static async createAgreementGuild( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // const { agreementId } = req.params - - // if (!agreementId) { - // throw new Error('SERVER_ERROR') - // } - - // const agreementGuild = await services.guild.createAgreementGuild({ - // agreementId: agreementId as string - // }) - - // return res.json({ - // agreementGuild - // }) - // } - - // public static async deleteAgreementGuild( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // const { agreementId } = req.params - - // if (!agreementId) { - // throw new Error('SERVER_ERROR') - // } - - // const agreementGuild = await services.guild.deleteAgreementGuild({ - // agreementId: agreementId as string - // }) - - // return res.json({ - // agreementGuild - // }) - // } - public static async createAgreementRole( - req: IRequest, - res: IResponse + _req: IRequest, + _res: IResponse ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - if (!req.body.name) { - throw new Error('MISSING_PARAMETERS') - } + throw new Error('DEPRECATED') + // if (!req.wallet) { + // throw new Error('USER_NOT_LOGGED_IN') + // } - if (!req.body.metadata) { - throw new Error('MISSING_PARAMETERS') - } + // if (!req.body.name) { + // throw new Error('MISSING_PARAMETERS') + // } - await req.wallet.enforceTXLimit() + // if (!req.body.metadata) { + // throw new Error('MISSING_PARAMETERS') + // } - const agreement = await orm.models.Agreement.findOne({ - where: { - id: req.params.agreementId - }, - include: [ - { - model: orm.models.Wallet, - as: 'Owner' - } - ] - }) + // await req.wallet.enforceTXLimit() + + // const agreement = await orm.models.Agreement.findOne({ + // where: { + // id: req.params.agreementId + // }, + // include: [ + // { + // model: orm.models.Wallet, + // as: 'Owner' + // } + // ] + // }) + + // if (!agreement) { + // throw new Error('AGREEMENT_NOT_FOUND') + // } - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } + // const isAdmin = await agreement.isAdmin(req.wallet.address) - const isAdmin = await agreement.isAdmin(req.wallet.address) + // if (!isAdmin) { + // throw new Error('NOT_AUTHORIZED') + // } - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } + // const result = await services.agreement.createAgreement({ + // ...req.body, + // admins: agreement.Owner?.address ? [agreement.Owner?.address] : [], + // chainId: agreement.chainId, + // senderWalletAddress: req.wallet.address + // }) - const result = await services.agreement.createAgreement({ - ...req.body, - admins: agreement.Owner?.address ? [agreement.Owner?.address] : [], - chainId: agreement.chainId, - senderWalletAddress: req.wallet.address - }) - - return res.json(result) + // return res.json(result) } public static async reinitialize( @@ -120,28 +75,6 @@ export default class AgreementRoleController { return res.json(result) } - public static async upgradeAgreementRole( - req: IRequest, - res: IResponse - ): Promise { - if (!req.wallet) { - throw new Error('USER_NOT_LOGGED_IN') - } - - await req.wallet.enforceTXLimit() - - const { agreementId, agreementRoleId } = req.params - - const result = await services.agreement.upgradeAgreement({ - ...req.body, - agreementId, - agreementRoleId, - senderWalletAddress: req.wallet.address - }) - - return res.json(result) - } - public static async deleteAgreementRole( req: IRequest, res: IResponse @@ -181,22 +114,6 @@ export default class AgreementRoleController { const promises: Promise[] = [] const t = await orm.sequelize.transaction() - // if (agreementRole?.guildRoleId) { - // await services.guild.deleteAgreementGuildRole({ - // guildRoleId: agreementRole.guildRoleId, - // agreementId: agreement.id - // }) - // } - - // promises.push( - // orm.models.AgreementRolePermission.destroy({ - // where: { - // AgreementRoleId: agreementRole.id - // }, - // transaction: t - // }) - // ) - promises.push( orm.models.AgreementRole.destroy({ where: { @@ -214,58 +131,6 @@ export default class AgreementRoleController { }) } - // public static async getAgreementGuild( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // try { - // const guildResponse = await services.guild.getAgreementGuild({ - // agreementId: req.params.agreementId - // }) - - // let guildPlatforms: any = guildResponse?.guildPlatforms - - // if (guildPlatforms) { - // guildPlatforms = await Promise.all( - // guildPlatforms.map(async (gp: any) => { - // const gpData = gp - - // if (gpData.platformId === 1) { - // const discordDataResponse = await request.post( - // `https://api.guild.xyz/v1/discord/server/${gp.platformGuildId}` - // ) - // gpData.platformGuildData = { - // ...gpData.platformGuildData, - // ...discordDataResponse.body - // } - // } - - // return gpData - // }) - // ) - // } - - // const guild = guildResponse - // ? { - // id: guildResponse.id, - // name: guildResponse.name, - // guildPlatforms - // } - // : null - - // return res.json({ - // guild - // }) - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - public static async bulkMint( req: IRequest, res: IResponse @@ -375,134 +240,4 @@ export default class AgreementRoleController { role: roles[0] }) } - - // public static async getUserAgreementRolesAccess( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // try { - // const rolesAccess = await services.agreement.getUserAgreementRolesAccess({ - // agreementId: req.params.agreementId, - // walletAddress: req.wallet.address - // }) - // return res.json(rolesAccess) - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - - // public static async getJoinGuildMessage( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: req.params.agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild - // } - // ] - // }) - - // if (!agreement || !agreement.AgreementGuild) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - - // const payload = { - // guildId: agreement.AgreementGuild.guildId, - // platforms: [] - // } - // const msg = 'Please sign this message.' - // const chainId = undefined // services.guild.getGuildChain(agreement.chainId) - // const addr = req.wallet.address - // const method = 1 // Guild method for authentication - // const nonce = randomBytes(32).toString('base64') - // const hash = - // Object.keys(payload).length > 0 - // ? keccak256(toUtf8Bytes(JSON.stringify(payload))) - // : undefined - // const ts = Date.now().toString() - - // const messageToSign = `${msg}\n\nAddress: ${addr}\nMethod: ${method}${ - // chainId ? `\nChainId: ${chainId}` : '' - // }${hash ? `\nHash: ${hash}` : ''}\nNonce: ${nonce}\nTimestamp: ${ts}` - - // return res.json({ - // message: messageToSign, - // params: { chainId, msg, method, addr, nonce, hash, ts } - // }) - // } - - // public static async joinAgreementGuild( - // req: IRequest, - // res: IResponse - // ): Promise { - // if (!req.wallet) { - // throw new Error('USER_NOT_LOGGED_IN') - // } - - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: req.params.agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild - // } - // ] - // }) - - // if (!agreement || !agreement.AgreementGuild) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - - // // If user does not have a token, mint it before joining guild or request will fail. - // if (req.body.mintToken) { - // try { - // await services.meem.mintOriginalMeem({ - // agreementAddress: agreement.address, - // to: req.wallet.address.toLowerCase(), - // metadata: agreement.metadata, - // mintedBy: req.wallet.address.toLowerCase(), - // chainId: agreement.chainId - // }) - // } catch (e) { - // log.crit(e) - // sockets?.emitError(config.errors.MINT_FAILED, req.wallet.address) - // } - // } - - // try { - // const response = await request - // .post(`https://api.guild.xyz/v1/user/join`) - // .send({ - // payload: { - // guildId: agreement.AgreementGuild.guildId, - // platforms: [] - // }, - // params: req.body.params, - // sig: req.body.sig - // }) - - // log.debug(response.body) - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - - // return res.json({ - // status: 'success' - // }) - // } } diff --git a/src/controllers/MeemController.ts b/src/controllers/MeemController.ts deleted file mode 100644 index 1e1fb65c..00000000 --- a/src/controllers/MeemController.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Readable } from 'stream' -import { IRequest, IResponse } from '../types/app' -import { MeemAPI } from '../types/meem.generated' - -export default class MeemController { - public static async getIPFSFile( - req: IRequest, - res: IResponse - ): Promise { - const { filename } = req.query - const { body, type } = await services.ipfs.getIPFSFile(filename) - - if (type === 'application/json') { - return res.json({ metadata: { ...body } }) - } - - res.setHeader('content-type', type) - return res.end(body, 'binary') - } - - public static async saveToIPFS( - req: IRequest, - res: IResponse - ): Promise { - const { data, json } = req.body - const body = data ? { file: Readable.from(data) } : { json } - - if (body.file) { - // Pinata hack https://github.com/PinataCloud/Pinata-SDK/issues/28 - // @ts-ignore - body.file.path = 'data.txt' - } - - const result = await services.web3.saveToPinata(body) - - return res.json({ - ipfsHash: result.IpfsHash - }) - } -} diff --git a/src/controllers/TestController.ts b/src/controllers/TestController.ts index 0e945c3e..acf02f47 100644 --- a/src/controllers/TestController.ts +++ b/src/controllers/TestController.ts @@ -1,78 +1,7 @@ -/* eslint-disable no-unused-vars */ -/* eslint-disable no-console */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { Validator } from '@meemproject/metadata' -import { Wallet as AlchemyWallet } from 'alchemy-sdk' -import { TextChannel } from 'discord.js' -import { ethers, ethers as Ethers } from 'ethers' -import { encodeSingle, TransactionType } from 'ethers-multisend' import { Request, Response } from 'express' -import keccak256 from 'keccak256' -import { DateTime, Duration } from 'luxon' -import { MerkleTree } from 'merkletreejs' -import { Op } from 'sequelize' -import GnosisSafeABI from '../abis/GnosisSafe.json' -import GnosisSafeProxyABI from '../abis/GnosisSafeProxy.json' -import meemABI from '../abis/Meem.json' -import { prompt1, prompt2 } from '../lib/gptPrompts' -import { Constructor } from '../serverless/cron' -import { Mycontract__factory } from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' +import { transactionalTemplate } from '../lib/emailTemplate' export default class TestController { - public static async testSummary( - req: Request, - res: Response - ): Promise { - const client = services.discord.client - const guild = await client.guilds.fetch('887371146171920475') - const channel = (await guild.channels.fetch( - '888127909468962856' - )) as TextChannel - - const messages = await channel.messages.fetch({ - limit: 50 - }) - - const formattedMessages: Record[] = [] - - messages.forEach(message => { - formattedMessages.push(services.discord.parseMessageForWebhook(message)) - }) - - const completion = await services.openai.getCompletion({ - messages: [ - { - role: 'system', - content: prompt2({ - brandName: 'Tiffany and Co', - brandVoice: 'Absurd and weird' - }) - }, - { - role: 'user', - content: `Here's a bunch of messages in JSON to curate and create a newsletter: ${JSON.stringify( - formattedMessages - )}` - } - ] - }) - // const completion = await services.openai.getCompletion({ - // messages: [ - // { - // role: 'user', - // content: `Hello` - // } - // ] - // }) - - return res.json({ - status: 'success', - stopReason: completion.data.choices[0].finish_reason, - completion: completion.data.choices[0].message - }) - } - public static async testWebhook( req: Request, res: Response @@ -88,276 +17,35 @@ export default class TestController { }) } - public static async testCron(req: Request, res: Response): Promise { - // eslint-disable-next-line - const cronConstructor = require(`../cron/jobs/${req.query.job}`) - .default as Constructor - // eslint-disable-next-line - const cronjob = new cronConstructor() - await cronjob.run() - - return res.json({ - status: 'success' - }) - } - - public static async syncContract(req: Request, res: Response) { - await services.contractEvents.meemHandleContractInitialized({ - address: req.query.address as string, - chainId: +(req.query.chainId as string) as number - }) - - return res.json({ - status: 'success' - }) - } - - public static async metadata(req: Request, res: Response) { - const metadata = { - meem_metadata_type: 'MeemAgreement_Contract', - meem_metadata_version: '20221116', - name: 'metadataaaa', - description: 'asdfasdf', - image: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAABbBJREFUSEuNlV1sHFcVx38zd+bO7Le9drzruEmc1nEDCU3b0ECUNFJVoqpRVbUBCR6IeKCtoA/AU9UHHngrKA+ACkII1IeWKPQBgSoVlAItlH63MbZC0oakLbGdeLNrr/djdmfn86LxmNCQpuKsrkaanTm/O+d/7v9oSinFJ8Ta3ypaXzFoycM6aMkSaMn1E0K7HkDFMSro4q28S9CcAe88eryMigMQI2BuQS/twh69Bc0eQTfMj8V8LCAOPLz5PxNcOk5GnsXc/CkofgasarrzYBV6Z1ELs/Q6wzBymMzUFxFW/hrIVYCkGqHbZvDP49jOLzF37oWhe4DtwBBgrCeIgB4wD/2/Ep7+A/1gP/Lmb2CVJ9HWypjGVQC/38E9eZSM/yzyzm+CvAOUAVG4XnuRvAKsa6ILSJb6AOZ+TLe+FXP3E1jlrVcgVwAqCmnN/JzM5R9g730ARg4AXppQCYj0FJbkT0TXQjDiFIYNvX/BP56h3dlPdt8TmNnSf78gEbR77gXs9x5F3r4HqrtoL9VYrnURhqQyOUamUIA46ZzkPUXou9QXGvRaDqWyxdjkBPSbRG/+jlb+Ucqf/zaaYaYlitwOK79/iLGJ03hjezgzd5HZV9/HG4QodO64Zzu3HtyOsdaSCiU05k8t8tLxWfrdAaalM7Wjym37phmK5+nO1DAPPY89emMKcObfQfzxEJnbt1Hr5Tj51iLlG/KMbyoSxpAfTnZYQl8XLzk4rcs9GvMOUmp0Vlw+OLPCzdOjTE/lEWdmWJk8Snn3EbQ4ClX99V9QufA43LgN35R4Uie7QSKKJmQExAr6EUQqaYtUl6wAQ4dBBN0IZ8VD74dkYg1t6UMuBfdSfeBnaFHgqdpz32HcO4Y2NgGGAKlBUeDHiqYTokudkYqFkEkXJRrHtBo+g35EKSPIJiAnAi9ON9FeptacpnLkBFrku+rSr7/CGC8iS6PrnaI4ebbLG3MdWq0Ab6C468EqBw5X1rryzCur/PapBeJIUSia7N6RZ/+uEnryZRpE7iqNZoWxh95OAYvHvkwlfgkrOwyhSeRFvPxunyawcdImMATVzTZTn86sHeSleZ/zp3tIpagvuOhOxBd25LBtA2RMFLZZao+z8ZG30hJd+M23qDSfIVMYRnNlWteihIoFVQnDic+otfthYnW2QLcErARQ8+HyAFY8kDpkYvygxUVvJ5MP/ykVefEvP6Uw9xiFkSFEaEMowNagJKEsIZ/sTCeO4cNzDmE/YHwiQ842EKs+rHrQi0AolOnjOqtczB3mpq8+lbZp8/zrdJ89RKWqsOw8mrLAzkDehIIJtoDEERTM1wPOzbVYen+Vg3dXqFazsOzBwAPl4ocDWvUu7md/xKYDD6cAv9/m3NNfY9w/QW60gJQSzSpCNgtSgpGKl1xb/YBTbzRYOtvhwN4NVG8qguuC2yYMPJyWw+LyKFu+/gL56nQKiOOI+uxz9J4/QqkiKAxbSNtGs3Jg5EAkHqSjpODvs03eefkSd0/lmJzKo48INL1P0HdxugHOkkO88zE23ftddMP6iJuGfRovfp/GK0cpj1uUyhJpCnTTQBMSNAN0g36omD3VZfbtFvfdmWPzlMB3A9rtEHfZR9t4kIkHn0Qv3HCtXce9JWonvkdr9mlGNtpk8wLL1NGFhhA6Co2FmuJiHQxDsX2ThpQRjhPRrw9gw+cYv/+HmJVb1m39f+ZBgoydRZb/9iSN137CUFlg5w2kpWOu6+AMdJJfzorxvJBeN8RpB+Sm7mP0rseR1duuJL9m4PxnCim/Q2fuV6zOHKO3OEM2IzCkjjA1hK6IY0XggdsPEcWtDN/6JYb2PILIp2X5aFx/6Ec+sdvAW3iT3oVXGdTew+821oaNyJSwNmwjv2UP9uZ9GKUtaEbm/x/6Vz2p4rWkKg5RgbN2GDQzB7qJlhiTlhrg9eLfsEqucvpaG8kAAAAASUVORK5CYII=', - associations: [], - external_url: '', - application_instructions: '' - } - - const contractMetadataValidator = new Validator(metadata) - const contractMetadataValidatorResult = - contractMetadataValidator.validate(metadata) - - return res.json({ - status: 'success', - contractMetadataValidatorResult - }) - } - - public static async testGnosis(req: Request, res: Response) { - const masterContractAddress = '0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552' - const proxyContractAddress = '0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2' - const topic = - '0x141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a8' - const safeOwners: string[] = [ - '0xbA343C26ad4387345edBB3256e62f4bB73d68a04', - '0xde19C037a85A609ec33Fc747bE9Db8809175C3a5' - ] - const threshold = 1 - - // gnosisSafeAbi is the Gnosis Safe ABI in JSON format, - // you can find an example here: https://github.com/gnosis/safe-deployments/blob/main/src/assets/v1.1.1/gnosis_safe.json#L16 - const { provider, wallet } = await services.ethers.getProvider({ - chainId: +(req.query.chainId as string) as number - }) - - const proxyContract = new ethers.Contract( - proxyContractAddress, - GnosisSafeProxyABI, - wallet - ) - const gnosisInterface = new ethers.utils.Interface(GnosisSafeABI) - const safeSetupData = gnosisInterface.encodeFunctionData('setup', [ - safeOwners, - threshold, - '0x0000000000000000000000000000000000000000', - '0x', - '0x0000000000000000000000000000000000000000', - '0x0000000000000000000000000000000000000000', - '0', - '0x0000000000000000000000000000000000000000' - ]) - - // safeContractFactory is an instance of the "Contract" type from Ethers JS - // see https://docs.ethers.io/v5/getting-started/#getting-started--contracts - // for more details. - // You're going to need the address of a Safe contract factory and the ABI, - // which can be found here: https://github.com/gnosis/safe-deployments/blob/main/src/assets/v1.1.1/proxy_factory.json#L16 - const tx = await proxyContract.createProxy( - masterContractAddress, - safeSetupData - ) - - await tx.wait() - - const receipt = await provider.core.getTransactionReceipt(tx.hash) - - if (receipt) { - // Find the newly created Safe contract address in the transaction receipt - for (let i = 0; i < receipt.logs.length; i += 1) { - const receiptLog = receipt.logs[i] - const foundTopic = receiptLog.topics.find(t => t === topic) - if (foundTopic) { - log.info(`address: ${receiptLog.address}`) - break - } - } - } - - console.log(tx) - - return res.json({ - status: 'success', - tx - }) - } - - public static async testHash(req: Request, res: Response) { - const addresses = [ - '0xbA343C26ad4387345edBB3256e62f4bB73d68a04', - '0xE7EDF0FeAebaF19Ad799eA9246E7bd8a38002d89', - '0xEC41a0AAea12ad8F588e5aD0e71A837d83e05792' - ] - - const hashedAddress = keccak256( - '0xbA343C26ad4387345edBB3256e62f4bB73d68a04' - ) - - const leaves = addresses.map(a => keccak256(a)) - const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }) - const rootHash = merkleTree.getRoot().toString('hex') - const proof = merkleTree.getHexProof(hashedAddress) - - // const isVerified = merkleTree.verify(proof, hashedAddress, rootHash) - const tree = new MerkleTree([], keccak256, { sortPairs: true }) - const isVerified = tree.verify(proof, hashedAddress, rootHash) - - return res.json({ - status: 'success', - rootHash, - isVerified, - merkleTree: merkleTree.toString(), - proof + public static async testEmail( + req: Request, + res: Response + ): Promise { + await services.aws.sendEmail({ + to: ['ken@meem.wtf'], + body: '

Testing email

', + subject: 'Testing email' }) - } - - public static async releaseLock(req: Request, res: Response) { - await services.ethers.releaseLock(+(req.query.chainId as string)) return res.json({ status: 'success' }) } - public static async mintPKP(req: Request, res: Response) { - const tx = await services.lit.mintPKP() - - return res.json({ - status: 'success', - tx - }) - } - - public static async getEthAddress(req: Request, res: Response) { - const ethAddress = await services.lit.getEthAddress( - req.query.tokenId as string - ) - - return res.json({ - status: 'success', - ethAddress - }) - } - - public static async testPinata(req: Request, res: Response) { - const result = await services.web3.saveToPinata({ - json: { - meem_metadata_type: 'Meem_AgreementContract', - meem_metadata_version: '20221116', - name: 'aqer', - description: 'asdfgscfg', - image: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAABe1JREFUSEuNlX2MHHUZxz/zujO729u9u3259y1XDlu5vogepUUaCK1VYyEaDkmMFSOU6B/GaGI0QWNMmhD4Byx/aDDEENoiAomNaSlyJWKhLS3Xpiexe0df7nrcda97e7t7uzM7MzszZnZX02pL/E1+mV8y83u+z8v3eb6C7/s+n7Ian323tT0Qgp9FEIItIQTvT1nCzQB8z8N3lrEW/4lTGAfrY0Qvj+85IHWCkkGMrSfUuRZRTyDKyg1hbgjgORbWzBjO3H50NYsysAba1kKoq+m5swTVLP7lM1RKMaTkKGJmB584EbqjCmG5EWZjXQcQZKNulqhN7ker/B5leBPEtwOrgTggt665QBWYAfNv+BOHOLE8ytHOnWzri7CuU0EQmiDXAdhGGfPDZ9DtP6Le831QR8CXwau3DEvBFaBVE1EG0aO8dJqDFwboWvsg/5jI8e3V7cQi6vUAvlunOP479NzTaHc9CB2bwauBF9hUQQhyfE0EQS0EG6jw7nmZQ8Yoj9/RwW+PL/L1Hpm7+tsaUTQiCAq6PPUW2rkfoK4fgfZhkGqgSKBqgARO4FALIGBVcJRsCgt5nv9gmNiGR9nRJ/N+AU6dnGb3vX1EQlITwDXLLB58jFT3BPTdDYoPmggRGcfykBUZQVUhcDggdRBMAGKWuZBz+cX4KGvveYB1HfBxHva9c45929MMptqbAJWZU0hvfRV93SC0d4HiQodGYb7CX/dnkRSRbY8OE0tFwfOxLJujr2bJn5snecftPKv/mmLvFm6Jwtk8FGYu88rQBTaNfBHBc+v+wrEXSF/6GawagnAIwhJeWGTs1Ysc//M0lgnbnxhi8yOrECXIvpvjjafPQtUltaaL8W1P8YfIdxoRmgJsrZ1gNwcYGf0lgutY/pUDP6Lb2ovQ0wu6CjGJxaLDwZeniaV1jJKD6/s89ONbkSIKYy9cZHaqwsDqNmZOL9D++RFeH9rNhD3ISub57uJv+JwzS+Z7byK4tunPvfIIKXEMNZ0CXYM2kYVFm6lsjTX3dYLpcvbYEpvub0eKSJx6u0CiL0z3migfHVogLlqsSKS5UksQd0ska+cpV7rp2nWyCTC792GSwtto6TREV+CFfURFRFBkkD2QBOp1AVnyG21Qd1tn1wdXwLNd/IqJYHiIjoNTKpK72kvPE6eaKZp+7Yckyy8S7U+xUI4wecmkf8Cno1tFiqqIuoSgSs2eaM0633bxTBfXcCjmbC6d9xnMhOlN2Ji5HPPlDax8fKxZ5MvvPE904ie0r4ySnYty+PwW2pOd6PYUulhAC1WRRBtBcBssxZOoezI1W8Ow4xjKIIv5CtsGT7B+VZXluRJzoYcZ+taLTZouTh2j+Kcv0zNgU65rnKh+k8TmJ9FlD9co41pF3FoJ16k1GkGQNSStDTnUhhCKYtZFCiefY2NkHwm9Rn7awvrCc/Rv2dUEcIwS2Zd20uu+iZbU+WBS56K7lcztG+nsu422RApNDyNLMvg+Tt3BMAwq+Rz52UmmP/qQW5QjbPqsgbVkMTOfIvPYYVZ03dYE8DyXhTMHqB7cSaJfxvLhL0eKVE2B8IpO1EgcKdSGJIcaHVy3LByrhGMWMZaLRDTYsTVOVJUozCzjDv+Uga88iSiHrpmmdYOFI0+xePQZ0gMaVV/l7KTB/BUDwfMQRZBa4uV5UA+KIUik0zrrPxMhFqpTmjOh50v0fWMPYrTvBnpQnWf+8K8on3mJrkwYR1a5mHP5JGdRrdbxAlo27ApEwjK96RCD3TIhHIqzBiTvpPuBZ1HS61pj/b/0oEGQyiz5v+8hf2wPiaSMGlWp+RIVS8C0mizVQtCmgS65OFWHYt5Gv/VrJO77OWrXhv8Y/x/B+bfM+XaZ8pmXWTq9F3NuvOGtqolIikDwuK5HveZhmB5iNEN8w0PE79yF1ErLteJ8c9F3bTzzKtbl4xjT71G7ksWuXAXfQ9JihJKriGQ2og3cjRzLIMj6/y/61/3pew3m+F4d36k0aCooERAVhGC0CoGM3nz9C9/4y2/ZQHoyAAAAAElFTkSuQmCC', - associations: [], - external_url: '', - application_instructions: [] - } - }) - - return res.json({ - status: 'success', - result - }) - } - - public static async testTxEncoding(req: Request, res: Response) { - // const functionSignature = ethers.utils - // .id('mint((address,string,uint8))') - // .substring(0, 10) - const m = await services.agreement.getAgreementContract({ - chainId: 5, - address: '0xf5a0fD628AFe07D8c3736762Bd65Ae009F23e335' - }) - - const encoded = encodeSingle({ - id: '1', - abi: JSON.stringify(meemABI), - functionSignature: 'bulkMint((address,string,uint8)[])', - to: '0xf5a0fD628AFe07D8c3736762Bd65Ae009F23e335', - value: '0', - inputValues: { - bulkParams: [ - { - to: '0xbA343C26ad4387345edBB3256e62f4bB73d68a04', - tokenType: '0', - tokenURI: 'ipfs://QmTFk4Wgka3VfwpMJzjbHA9ZsKjG7bbRcbbDoPnHYVV3Gv' - }, - { - to: '0x1e6c71F7338276524D646dB2F04a49fA88458cF2', - tokenType: '0', - tokenURI: 'ipfs://QmTFk4Wgka3VfwpMJzjbHA9ZsKjG7bbRcbbDoPnHYVV3Gv' - } - ] - }, - type: TransactionType.callContract - }) - // const x = m.interface.functions['setMaxSupply(uint256)'].format() - - const encoded2 = encodeSingle({ - id: '1', - abi: JSON.stringify(meemABI), - functionSignature: 'mint((address,string,uint8))', - to: '0xf5a0fD628AFe07D8c3736762Bd65Ae009F23e335', - value: '0', - inputValues: { - params: [ - '0xbA343C26ad4387345edBB3256e62f4bB73d68a04', - 'https://meem.wtf', - '0' - ] - }, - type: TransactionType.callContract - }) - - // console.log({ x, encoded }) - - return res.json({ - status: 'success', - encoded, - encoded2, - meemABI - }) - } - - public static async testCallback(req: Request, res: Response) { - log.debug({ - query: req.query, - body: req.body - }) - return res.json({ - status: 'success' + public static async testEmailHtml( + req: Request, + res: Response + ): Promise { + const html = transactionalTemplate({ + subject: 'Testing email', + inboxPreview: "Here's an inbox preview of the message.", + title: 'Testing email', + bodyText: + 'Ut reprehenderit qui. Animi numquam laborum est recusandae. Sequi iusto nisi assumenda vel est numquam aut. Eius adipisci voluptatem distinctio magnam sed nemo non quas eligendi. Facilis officia et et deleniti consequuntur vel.\n\nLibero magni rem vel. Quo est dignissimos ea ut enim et qui. Dignissimos ratione qui quisquam fuga quos ut delectus quia. Quia nihil a voluptatem ullam. Et veniam maiores consequatur vel et odit et repellat. Quasi accusamus quis.\n\n Quo eius rerum voluptatum doloremque qui nisi explicabo ipsam ipsa. Eum iste molestiae qui facilis velit nisi alias molestias sint. Voluptatem voluptatem rerum consequatur eum quidem perspiciatis. Voluptatum iure modi qui alias eius distinctio at.', + ctaText: 'Click here to do something', + ctaUrl: 'https://meem.wtf' }) - } - public static async testDecrypt(req: Request, res: Response) { - const decrypted = await services.data.decrypt({ - strToDecrypt: req.query.s as string, - privateKey: config.ENCRYPTION_KEY - }) - return res.json({ - status: 'success', - decrypted - }) + return res.send(html) } } diff --git a/src/core/Configuration.ts b/src/core/Configuration.ts index 5d86ab7b..6c82d5a4 100644 --- a/src/core/Configuration.ts +++ b/src/core/Configuration.ts @@ -21,6 +21,7 @@ export default class Configuration { public async load(): Promise { const file = path.join(this.currentPath, 'config', this.env()) const dotenvpath = path.join(process.cwd(), '.env') + await this.dotenv(dotenvpath) const defaultConfig = (await import('../config/default')).default diff --git a/src/core/start.ts b/src/core/start.ts index 6898fdeb..738eac15 100644 --- a/src/core/start.ts +++ b/src/core/start.ts @@ -4,7 +4,6 @@ import log, { LogLevel } from '@kengoldfarb/log' import express, { Express } from 'express' import globby from 'globby' import fetch from 'node-fetch' -import ProviderListener from '../listeners/ProviderListener' import Configuration from './Configuration' import errorMiddleware from './errorMiddleware' import Orm from './Orm' @@ -174,30 +173,6 @@ export default async function start(options?: { errorMiddleware(app) g.listeners = {} - if (config.ENABLE_PROVIDER_LISTENERS) { - g.listeners = { - ...g.listeners, - provider: new ProviderListener() - } - - g.listeners.provider.start() - } else { - log.debug('Provider listener disabled') - } - - // if (config.ENABLE_TWITTER_LISTENERS) { - // g.listeners = { - // twitter: new TwitterListener() - // } - - // g.listeners.twitter.start() - // } - - if (config.ENABLE_SQS_CONSUMER) { - // eslint-disable-next-line global-require - require('../lib/SQSConsumer') - } - // Fetch polyfill g.fetch = fetch diff --git a/src/cron/jobs/AgreementCron.ts b/src/cron/jobs/AgreementCron.ts deleted file mode 100644 index 41ce1d67..00000000 --- a/src/cron/jobs/AgreementCron.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* eslint-disable no-param-reassign */ -/* eslint-disable no-await-in-loop */ -/* eslint-disable import/no-extraneous-dependencies */ -import { diamondABI } from '@meemproject/meem-contracts' -import { Alchemy, Wallet as AlchemyWallet } from 'alchemy-sdk' -import Cron from 'cron' -import { ethers } from 'ethers' -import { DateTime } from 'luxon' -import { Op } from 'sequelize' -import { wait } from '../../lib/utils' -import Wallet from '../../models/Wallet' -import CronJob from '../CronJob' - -export default class MeemContractCron extends CronJob { - private job?: Cron.CronJob - - public start() { - this.job = new Cron.CronJob({ - cronTime: '00 * * * * *', - onTick: this.run, - context: this - }) - - this.job.start() - } - - public async run() { - log.info('Running MeemContractCron!') - log.info(new Date()) - - const agreements = await orm.models.Agreement.findAll({ - where: { - [Op.or]: [ - { - ownerFetchedAt: null - }, - { - ownerFetchedAt: { - [Op.gt]: DateTime.now() - .plus({ - days: 7 - }) - .toJSDate() - } - } - ] - }, - order: [['ownerFetchedAt', 'ASC NULLS FIRST']], - limit: 20 - }) - - const providers: Record = {} - - for (let i = 0; i < agreements.length; i++) { - const agreement = agreements[i] - try { - if (!providers[agreement.chainId]) { - const { provider } = await services.ethers.getProvider({ - chainId: agreement.chainId - }) - providers[agreement.chainId] = provider - } - - const signer = new AlchemyWallet( - config.WALLET_PRIVATE_KEY, - providers[agreement.chainId] - ) - - const instance = new ethers.Contract( - agreement.address, - diamondABI, - signer - ) - - const owner = await instance.owner() - - // Find wallet - let wallet = await orm.models.Wallet.findByAddress(owner) - - if (!wallet) { - wallet = orm.models.Wallet.build({ - owner - }) - } - if (wallet.id !== agreement.OwnerId) { - agreement.OwnerId = wallet.id - } - } catch (e) { - log.warn(e) - } - - agreement.ownerFetchedAt = new Date() - await agreement.save() - await wait(1000) - } - } -} diff --git a/src/cron/jobs/ENSCron.ts b/src/cron/jobs/ENSCron.ts deleted file mode 100644 index 8044a487..00000000 --- a/src/cron/jobs/ENSCron.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable no-param-reassign */ -/* eslint-disable no-await-in-loop */ -/* eslint-disable import/no-extraneous-dependencies */ -import Cron from 'cron' -import { DateTime } from 'luxon' -import { Op } from 'sequelize' -import { wait } from '../../lib/utils' -import CronJob from '../CronJob' - -export default class ENSCron extends CronJob { - private job?: Cron.CronJob - - public start() { - this.job = new Cron.CronJob({ - cronTime: '00 * * * * *', - onTick: this.run, - context: this - }) - - this.job.start() - } - - public async run() { - log.info('Running ENSCron!') - log.info(new Date()) - const [agreements, wallets] = await Promise.all([ - orm.models.Agreement.findAll({ - where: { - [Op.or]: [ - { - ensFetchedAt: null - }, - { - ensFetchedAt: { - [Op.gt]: DateTime.now() - .plus({ - days: 7 - }) - .toJSDate() - } - } - ] - }, - order: [['ensFetchedAt', 'ASC NULLS FIRST']], - limit: 20 - }), - orm.models.Wallet.findAll({ - where: { - [Op.or]: [ - { - ensFetchedAt: null - }, - { - ensFetchedAt: { - [Op.gt]: DateTime.now() - .plus({ - days: 7 - }) - .toJSDate() - } - } - ] - }, - order: [['ensFetchedAt', 'ASC NULLS FIRST']], - limit: 20 - }) - ]) - - const itemsToCheck = [...agreements, ...wallets] - - for (let i = 0; i < itemsToCheck.length; i += 1) { - const item = itemsToCheck[i] - try { - const ens = await services.ethers.lookupAddress(item.address) - log.debug({ address: item.address, ens }) - if (ens) { - item.ens = ens - } - } catch (e) { - log.warn(e) - } - item.ensFetchedAt = DateTime.now().toJSDate() - await item.save() - // Limit the number of requests to avoid alchemy rate-limiting - await wait(1000) - } - } -} diff --git a/src/cron/jobs/PromptsCron.ts.OLD b/src/cron/jobs/PromptsCron.ts.OLD deleted file mode 100644 index 13e12eca..00000000 --- a/src/cron/jobs/PromptsCron.ts.OLD +++ /dev/null @@ -1,24 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Cron from 'cron' -import CronJob from '../CronJob' - -export default class PromptsCron extends CronJob { - private job?: Cron.CronJob - - public start() { - this.job = new Cron.CronJob({ - cronTime: '00 * * * * *', - onTick: this.run, - context: this - }) - - this.job.start() - } - - public async run() { - log.info('Running PromptsCron!') - log.info(new Date()) - await services.prompts.endCurrentPrompt() - await services.prompts.sendNextPrompt() - } -} diff --git a/src/cron/jobs/TwitterCron.ts.OLD b/src/cron/jobs/TwitterCron.ts.OLD deleted file mode 100644 index 2e5b5f0d..00000000 --- a/src/cron/jobs/TwitterCron.ts.OLD +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable no-param-reassign */ -import Cron from 'cron' -import CronJob from '../CronJob' - -export default class TwitterCron extends CronJob { - private job?: Cron.CronJob - - public start() { - this.job = new Cron.CronJob({ - cronTime: '00 * * * * *', - onTick: this.run, - context: this - }) - - this.job.start() - } - - public async run() { - log.info('Running TwitterCron!') - log.info(new Date()) - await services.twitter.checkForMissedTweets() - } -} diff --git a/src/hasura/tables.ts b/src/hasura/tables.ts deleted file mode 100644 index 9ee9009b..00000000 --- a/src/hasura/tables.ts +++ /dev/null @@ -1,2029 +0,0 @@ -export const tables = [ - { - table: { - name: 'AgreementExtensionLinks', - schema: 'public' - }, - object_relationships: [ - { - name: 'AgreementExtension', - using: { - foreign_key_constraint_on: 'AgreementExtensionId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'isEnabled', - 'label', - 'url', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - visibility: { - _eq: 'anyone' - } - } - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'isEnabled', - 'label', - 'url', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - _and: [ - { - AgreementExtension: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - }, - { - visibility: { - _in: ['token-holders', 'anyone'] - } - } - ] - } - } - }, - { - role: 'user', - permission: { - columns: [ - 'isEnabled', - 'label', - 'url', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - visibility: { - _eq: 'anyone' - } - } - } - } - ] - }, - { - table: { - name: 'AgreementExtensionRoles', - schema: 'public' - }, - object_relationships: [ - { - name: 'AgreementExtension', - using: { - foreign_key_constraint_on: 'AgreementExtensionId' - } - }, - { - name: 'AgreementRole', - using: { - foreign_key_constraint_on: 'AgreementRoleId' - } - } - ] - }, - { - table: { - name: 'AgreementExtensionStorages', - schema: 'public' - } - }, - { - table: { - name: 'AgreementExtensionWidgets', - schema: 'public' - }, - object_relationships: [ - { - name: 'AgreementExtension', - using: { - foreign_key_constraint_on: 'AgreementExtensionId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'isEnabled', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - visibility: { - _eq: 'anyone' - } - } - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'isEnabled', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - _and: [ - { - AgreementExtension: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - }, - { - visibility: { - _in: ['token-holders', 'anyone'] - } - } - ] - } - } - }, - { - role: 'user', - permission: { - columns: [ - 'isEnabled', - 'visibility', - 'metadata', - 'createdAt', - 'updatedAt', - 'AgreementExtensionId', - 'id' - ], - filter: { - visibility: { - _eq: 'anyone' - } - } - } - } - ] - }, - { - table: { - name: 'AgreementExtensions', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'AgreementRole', - using: { - foreign_key_constraint_on: 'AgreementRoleId' - } - }, - { - name: 'Extension', - using: { - foreign_key_constraint_on: 'ExtensionId' - } - } - ], - array_relationships: [ - { - name: 'AgreementExtensionLinks', - using: { - foreign_key_constraint_on: { - column: 'AgreementExtensionId', - table: { - name: 'AgreementExtensionLinks', - schema: 'public' - } - } - } - }, - { - name: 'AgreementExtensionRoles', - using: { - foreign_key_constraint_on: { - column: 'AgreementExtensionId', - table: { - name: 'AgreementExtensionRoles', - schema: 'public' - } - } - } - }, - { - name: 'AgreementExtensionWidgets', - using: { - foreign_key_constraint_on: { - column: 'AgreementExtensionId', - table: { - name: 'AgreementExtensionWidgets', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoleExtensions', - using: { - foreign_key_constraint_on: { - column: 'AgreementExtensionId', - table: { - name: 'AgreementRoleExtensions', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'AgreementId', - 'AgreementRoleId', - 'ExtensionId', - 'createdAt', - 'id', - 'isInitialized', - 'isSetupComplete', - 'metadata', - 'updatedAt' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'AgreementId', - 'AgreementRoleId', - 'ExtensionId', - 'createdAt', - 'id', - 'isInitialized', - 'isSetupComplete', - 'metadata', - 'updatedAt' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'AgreementId', - 'AgreementRoleId', - 'ExtensionId', - 'createdAt', - 'id', - 'isInitialized', - 'isSetupComplete', - 'metadata', - 'updatedAt' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'AgreementRoleExtensions', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'AgreementExtension', - using: { - foreign_key_constraint_on: 'AgreementExtensionId' - } - }, - { - name: 'AgreementRole', - using: { - foreign_key_constraint_on: 'AgreementRoleId' - } - }, - { - name: 'Extension', - using: { - foreign_key_constraint_on: 'ExtensionId' - } - } - ] - }, - { - table: { - name: 'AgreementRoleTokenTransfers', - schema: 'public' - }, - object_relationships: [ - { - name: 'AgreementRoleToken', - using: { - foreign_key_constraint_on: 'AgreementRoleTokenId' - } - } - ] - }, - { - table: { - name: 'AgreementRoleTokens', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'AgreementRole', - using: { - foreign_key_constraint_on: 'AgreementRoleId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'OwnerId' - } - } - ], - array_relationships: [ - { - name: 'AgreementRoleTokenTransfers', - using: { - foreign_key_constraint_on: { - column: 'AgreementRoleTokenId', - table: { - name: 'AgreementRoleTokenTransfers', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'mutualClubMember', - permission: { - columns: [ - 'mintedBy', - 'tokenId', - 'metadata', - 'tokenURI', - 'createdAt', - 'mintedAt', - 'updatedAt', - 'AgreementId', - 'AgreementRoleId', - 'id', - 'OwnerId' - ], - filter: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - } - } - ] - }, - { - table: { - name: 'AgreementRoleWallets', - schema: 'public' - } - }, - { - table: { - name: 'AgreementRoles', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'AgreementExtension', - using: { - foreign_key_constraint_on: { - column: 'AgreementRoleId', - table: { - name: 'AgreementExtensions', - schema: 'public' - } - } - } - }, - { - name: 'Transaction', - using: { - foreign_key_constraint_on: 'TransactionId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'OwnerId' - } - } - ], - array_relationships: [ - { - name: 'AgreementRoleExtensions', - using: { - foreign_key_constraint_on: { - column: 'AgreementRoleId', - table: { - name: 'AgreementRoleExtensions', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoleTokens', - using: { - foreign_key_constraint_on: { - column: 'AgreementRoleId', - table: { - name: 'AgreementRoleTokens', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'isAdminRole', - 'isTransferrable', - 'address', - 'adminContractAddress', - 'ens', - 'maxSupply', - 'name', - 'slug', - 'symbol', - 'chainId', - 'metadata', - 'mintPermissions', - 'splits', - 'contractURI', - 'createdAt', - 'ensFetchedAt', - 'ownerFetchedAt', - 'updatedAt', - 'AgreementId', - 'id', - 'OwnerId', - 'TransactionId' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'isAdminRole', - 'isTransferrable', - 'address', - 'adminContractAddress', - 'ens', - 'maxSupply', - 'name', - 'slug', - 'symbol', - 'chainId', - 'metadata', - 'mintPermissions', - 'splits', - 'contractURI', - 'createdAt', - 'ensFetchedAt', - 'ownerFetchedAt', - 'updatedAt', - 'AgreementId', - 'id', - 'OwnerId', - 'TransactionId' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'isAdminRole', - 'isTransferrable', - 'address', - 'adminContractAddress', - 'ens', - 'maxSupply', - 'name', - 'slug', - 'symbol', - 'chainId', - 'metadata', - 'mintPermissions', - 'splits', - 'contractURI', - 'createdAt', - 'ensFetchedAt', - 'ownerFetchedAt', - 'updatedAt', - 'AgreementId', - 'id', - 'OwnerId', - 'TransactionId' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'AgreementTokenTransfers', - schema: 'public' - }, - object_relationships: [ - { - name: 'AgreementToken', - using: { - foreign_key_constraint_on: 'AgreementTokenId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'from', - 'to', - 'transactionHash', - 'createdAt', - 'transferredAt', - 'updatedAt', - 'AgreementTokenId', - 'id' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'from', - 'to', - 'transactionHash', - 'createdAt', - 'transferredAt', - 'updatedAt', - 'AgreementTokenId', - 'id' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'from', - 'to', - 'transactionHash', - 'createdAt', - 'transferredAt', - 'updatedAt', - 'AgreementTokenId', - 'id' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'AgreementTokens', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'Transaction', - using: { - foreign_key_constraint_on: 'TransactionId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'OwnerId' - } - } - ], - array_relationships: [ - { - name: 'AgreementTokenTransfers', - using: { - foreign_key_constraint_on: { - column: 'AgreementTokenId', - table: { - name: 'AgreementTokenTransfers', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'AgreementId', - 'OwnerId', - 'createdAt', - 'id', - 'metadata', - 'mintedAt', - 'mintedBy', - 'tokenId', - 'tokenURI' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'AgreementId', - 'OwnerId', - 'createdAt', - 'id', - 'metadata', - 'mintedAt', - 'mintedBy', - 'tokenId', - 'tokenURI' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'AgreementId', - 'OwnerId', - 'createdAt', - 'id', - 'metadata', - 'mintedAt', - 'mintedBy', - 'tokenId', - 'tokenURI' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'AgreementWallets', - schema: 'public' - }, - object_relationships: [ - { - name: 'Agreement', - using: { - foreign_key_constraint_on: 'AgreementId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'WalletId' - } - } - ], - select_permissions: [ - { - role: 'mutualClubMember', - permission: { - columns: ['AgreementId', 'WalletId', 'createdAt', 'id', 'role'], - filter: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - } - }, - { - role: 'user', - permission: { - columns: ['AgreementId', 'WalletId', 'createdAt', 'id', 'role'], - filter: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - } - } - ] - }, - { - table: { - name: 'Agreements', - schema: 'public' - }, - object_relationships: [ - { - name: 'Transaction', - using: { - foreign_key_constraint_on: 'TransactionId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'OwnerId' - } - } - ], - array_relationships: [ - { - name: 'AgreementExtensions', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementExtensions', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoleExtensions', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementRoleExtensions', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoleTokens', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementRoleTokens', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoles', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementRoles', - schema: 'public' - } - } - } - }, - { - name: 'AgreementTokens', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementTokens', - schema: 'public' - } - } - } - }, - { - name: 'AgreementWallets', - using: { - foreign_key_constraint_on: { - column: 'AgreementId', - table: { - name: 'AgreementWallets', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'address', - 'chainId', - 'contractURI', - 'createdAt', - 'ens', - 'id', - 'isLaunched', - 'isTransferrable', - 'maxSupply', - 'metadata', - 'mintPermissions', - 'name', - 'slug', - 'splits', - 'symbol' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'OwnerId', - 'address', - 'adminContractAddress', - 'chainId', - 'contractURI', - 'createdAt', - 'ens', - 'ensFetchedAt', - 'gnosisSafeAddress', - 'id', - 'isLaunched', - 'isTransferrable', - 'maxSupply', - 'metadata', - 'mintPermissions', - 'name', - 'ownerFetchedAt', - 'slug', - 'splits', - 'symbol', - 'updatedAt' - ], - filter: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - }, - { - role: 'user', - permission: { - columns: [ - 'OwnerId', - 'address', - 'adminContractAddress', - 'chainId', - 'contractURI', - 'createdAt', - 'ens', - 'gnosisSafeAddress', - 'id', - 'isLaunched', - 'isTransferrable', - 'maxSupply', - 'metadata', - 'mintPermissions', - 'name', - 'slug', - 'splits', - 'symbol' - ], - filter: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - } - ] - }, - { - table: { - name: 'BundleContracts', - schema: 'public' - }, - object_relationships: [ - { - name: 'Bundle', - using: { - foreign_key_constraint_on: 'BundleId' - } - }, - { - name: 'Contract', - using: { - foreign_key_constraint_on: 'ContractId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'order', - 'functionSelectors', - 'createdAt', - 'updatedAt', - 'BundleId', - 'ContractId', - 'id' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'Bundles', - schema: 'public' - }, - object_relationships: [ - { - name: 'Creator', - using: { - foreign_key_constraint_on: 'CreatorId' - } - } - ], - array_relationships: [ - { - name: 'BundleContracts', - using: { - foreign_key_constraint_on: { - column: 'BundleId', - table: { - name: 'BundleContracts', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'name', - 'abi', - 'description', - 'types', - 'createdAt', - 'updatedAt', - 'CreatorId', - 'id' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'ChainNonces', - schema: 'public' - } - }, - { - table: { - name: 'ContractInstances', - schema: 'public' - }, - object_relationships: [ - { - name: 'Contract', - using: { - foreign_key_constraint_on: 'ContractId' - } - } - ], - array_relationships: [ - { - name: 'WalletContractInstances', - using: { - foreign_key_constraint_on: { - column: 'ContractInstanceId', - table: { - name: 'WalletContractInstances', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'address', - 'chainId', - 'createdAt', - 'updatedAt', - 'ContractId', - 'id' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'Contracts', - schema: 'public' - }, - object_relationships: [ - { - name: 'Creator', - using: { - foreign_key_constraint_on: 'CreatorId' - } - } - ], - array_relationships: [ - { - name: 'BundleContracts', - using: { - foreign_key_constraint_on: { - column: 'ContractId', - table: { - name: 'BundleContracts', - schema: 'public' - } - } - } - }, - { - name: 'ContractInstances', - using: { - foreign_key_constraint_on: { - column: 'ContractId', - table: { - name: 'ContractInstances', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'contractType', - 'name', - 'version', - 'abi', - 'functionSelectors', - 'bytecode', - 'description', - 'createdAt', - 'updatedAt', - 'CreatorId', - 'id' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'Extensions', - schema: 'public' - }, - array_relationships: [ - { - name: 'AgreementExtensions', - using: { - foreign_key_constraint_on: { - column: 'ExtensionId', - table: { - name: 'AgreementExtensions', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoleExtensions', - using: { - foreign_key_constraint_on: { - column: 'ExtensionId', - table: { - name: 'AgreementRoleExtensions', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'capabilities', - 'category', - 'createdAt', - 'description', - 'guideUrl', - 'icon', - 'id', - 'isSetupRequired', - 'name', - 'slug', - 'storageDefinition', - 'updatedAt', - 'widgetDefinition' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'capabilities', - 'category', - 'createdAt', - 'description', - 'guideUrl', - 'icon', - 'id', - 'isSetupRequired', - 'name', - 'slug', - 'storageDefinition', - 'updatedAt', - 'widgetDefinition' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'capabilities', - 'category', - 'createdAt', - 'description', - 'guideUrl', - 'icon', - 'id', - 'isSetupRequired', - 'name', - 'slug', - 'storageDefinition', - 'updatedAt', - 'widgetDefinition' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'IdentityProviders', - schema: 'public' - }, - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'connectionId', - 'connectionName', - 'description', - 'icon', - 'id', - 'name' - ], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'connectionId', - 'connectionName', - 'description', - 'icon', - 'id', - 'name' - ], - filter: {} - } - }, - { - role: 'user', - permission: { - columns: [ - 'connectionId', - 'connectionName', - 'description', - 'icon', - 'id', - 'name' - ], - filter: {} - } - } - ] - }, - { - table: { - name: 'Integrations', - schema: 'public' - }, - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'description', - 'guideUrl', - 'icon', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt', - 'id' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'description', - 'guideUrl', - 'icon', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt', - 'id' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: [ - 'description', - 'guideUrl', - 'icon', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt', - 'id' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'RolePermissions', - schema: 'public' - }, - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'description', - 'id', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'description', - 'id', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: [ - 'description', - 'id', - 'name', - 'createdAt', - 'deletedAt', - 'updatedAt' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'SequelizeMeta', - schema: 'public' - } - }, - { - table: { - name: 'Transactions', - schema: 'public' - }, - object_relationships: [ - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'WalletId' - } - } - ], - array_relationships: [ - { - name: 'AgreementRoles', - using: { - foreign_key_constraint_on: { - column: 'TransactionId', - table: { - name: 'AgreementRoles', - schema: 'public' - } - } - } - }, - { - name: 'AgreementTokens', - using: { - foreign_key_constraint_on: { - column: 'TransactionId', - table: { - name: 'AgreementTokens', - schema: 'public' - } - } - } - }, - { - name: 'Agreements', - using: { - foreign_key_constraint_on: { - column: 'TransactionId', - table: { - name: 'Agreements', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'WalletId', - 'chainId', - 'createdAt', - 'hash', - 'id', - 'status', - 'transactionInput', - 'transactionType', - 'updatedAt' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: [ - 'WalletId', - 'chainId', - 'createdAt', - 'hash', - 'id', - 'status', - 'transactionInput', - 'transactionType', - 'updatedAt' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'Transfers', - schema: 'public' - }, - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'from', - 'to', - 'transactionHash', - 'createdAt', - 'deletedAt', - 'transferredAt', - 'updatedAt', - 'id', - 'MeemId' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: [ - 'from', - 'to', - 'transactionHash', - 'createdAt', - 'deletedAt', - 'transferredAt', - 'updatedAt', - 'id', - 'MeemId' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'UserIdentities', - schema: 'public' - }, - object_relationships: [ - { - name: 'IdentityProvider', - using: { - foreign_key_constraint_on: 'IdentityProviderId' - } - }, - { - name: 'User', - using: { - foreign_key_constraint_on: 'UserId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'IdentityProviderId', - 'UserId', - 'id', - 'metadata', - 'visibility' - ], - filter: { - visibility: { - _eq: 'anyone' - } - } - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'IdentityProviderId', - 'UserId', - 'id', - 'metadata', - 'visibility' - ], - filter: { - _or: [ - { - visibility: { - _eq: 'anyone' - } - }, - { - _and: [ - { - visibility: { - _eq: 'mutualClubMembers' - } - }, - { - User: { - Wallets: { - AgreementTokens: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-user-id' - } - } - } - } - } - } - } - ] - } - ] - } - } - }, - { - role: 'user', - permission: { - columns: [ - 'IdentityProviderId', - 'UserId', - 'id', - 'metadata', - 'visibility' - ], - filter: { - UserId: { - _eq: 'x-hasura-user-id' - } - } - } - } - ] - }, - { - table: { - name: 'Users', - schema: 'public' - }, - object_relationships: [ - { - name: 'DefaultWallet', - using: { - foreign_key_constraint_on: 'DefaultWalletId' - } - } - ], - array_relationships: [ - { - name: 'UserIdentities', - using: { - foreign_key_constraint_on: { - column: 'UserId', - table: { - name: 'UserIdentities', - schema: 'public' - } - } - } - }, - { - name: 'Wallets', - using: { - foreign_key_constraint_on: { - column: 'UserId', - table: { - name: 'Wallets', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: ['displayName', 'id', 'profilePicUrl'], - filter: {} - } - }, - { - role: 'mutualClubMember', - permission: { - columns: ['DefaultWalletId', 'displayName', 'id', 'profilePicUrl'], - filter: { - Wallets: { - AgreementTokens: { - Agreement: { - AgreementTokens: { - OwnerId: { - _eq: 'x-hasura-wallet-id' - } - } - } - } - } - } - } - }, - { - role: 'user', - permission: { - columns: [ - 'displayName', - 'profilePicUrl', - 'createdAt', - 'updatedAt', - 'DefaultWalletId', - 'id' - ], - filter: { - id: { - _eq: 'x-hasura-user-id' - } - } - } - } - ] - }, - { - table: { - name: 'WalletContractInstances', - schema: 'public' - }, - object_relationships: [ - { - name: 'ContractInstance', - using: { - foreign_key_constraint_on: 'ContractInstanceId' - } - }, - { - name: 'Wallet', - using: { - foreign_key_constraint_on: 'WalletId' - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: [ - 'name', - 'note', - 'createdAt', - 'updatedAt', - 'ContractInstanceId', - 'id', - 'WalletId' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'mutualClubMember', - permission: { - columns: [ - 'name', - 'note', - 'createdAt', - 'updatedAt', - 'ContractInstanceId', - 'id', - 'WalletId' - ], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: [ - 'name', - 'note', - 'createdAt', - 'updatedAt', - 'ContractInstanceId', - 'id', - 'WalletId' - ], - filter: {}, - allow_aggregations: true - } - } - ] - }, - { - table: { - name: 'Wallets', - schema: 'public' - }, - object_relationships: [ - { - name: 'User', - using: { - foreign_key_constraint_on: 'UserId' - } - } - ], - array_relationships: [ - { - name: 'AgreementRoleTokens', - using: { - foreign_key_constraint_on: { - column: 'OwnerId', - table: { - name: 'AgreementRoleTokens', - schema: 'public' - } - } - } - }, - { - name: 'AgreementRoles', - using: { - foreign_key_constraint_on: { - column: 'OwnerId', - table: { - name: 'AgreementRoles', - schema: 'public' - } - } - } - }, - { - name: 'AgreementTokens', - using: { - foreign_key_constraint_on: { - column: 'OwnerId', - table: { - name: 'AgreementTokens', - schema: 'public' - } - } - } - }, - { - name: 'AgreementWallets', - using: { - foreign_key_constraint_on: { - column: 'WalletId', - table: { - name: 'AgreementWallets', - schema: 'public' - } - } - } - }, - { - name: 'Agreements', - using: { - foreign_key_constraint_on: { - column: 'OwnerId', - table: { - name: 'Agreements', - schema: 'public' - } - } - } - }, - { - name: 'Bundles', - using: { - foreign_key_constraint_on: { - column: 'CreatorId', - table: { - name: 'Bundles', - schema: 'public' - } - } - } - }, - { - name: 'Contracts', - using: { - foreign_key_constraint_on: { - column: 'CreatorId', - table: { - name: 'Contracts', - schema: 'public' - } - } - } - }, - { - name: 'Transactions', - using: { - foreign_key_constraint_on: { - column: 'WalletId', - table: { - name: 'Transactions', - schema: 'public' - } - } - } - }, - { - name: 'Users', - using: { - foreign_key_constraint_on: { - column: 'DefaultWalletId', - table: { - name: 'Users', - schema: 'public' - } - } - } - }, - { - name: 'WalletContractInstances', - using: { - foreign_key_constraint_on: { - column: 'WalletId', - table: { - name: 'WalletContractInstances', - schema: 'public' - } - } - } - } - ], - select_permissions: [ - { - role: 'anonymous', - permission: { - columns: ['address', 'ens', 'id'], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'mutualClubMember', - permission: { - columns: ['address', 'ens', 'id'], - filter: {}, - allow_aggregations: true - } - }, - { - role: 'user', - permission: { - columns: ['address', 'apiKey', 'dailyTXLimit', 'ens', 'id'], - filter: { - id: { - _eq: 'x-hasura-wallet-id' - } - }, - allow_aggregations: true - } - } - ] - } -] diff --git a/src/lib/ReconnectingWebsocketProvider.ts b/src/lib/ReconnectingWebsocketProvider.ts deleted file mode 100644 index c6d4b296..00000000 --- a/src/lib/ReconnectingWebsocketProvider.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* eslint-disable max-classes-per-file */ -/* eslint-disable no-underscore-dangle */ -/* eslint-disable @typescript-eslint/naming-convention */ - -// Fixes issue of websocket not reconnecting -// https://github.com/ethers-io/ethers.js/issues/1053 - -import { providers } from 'ethers' - -const EXPECTED_PONG_BACK = 15000 -const KEEP_ALIVE_CHECK_INTERVAL = 7500 - -// Used to "trick" TypeScript into treating a Proxy as the intended proxied class -export const fakeBaseClass = (): new () => Pick => - class {} as any - -// @ts-ignore -export class ReconnectingWebSocketProvider extends fakeBaseClass() { - private underlyingProvider!: providers.WebSocketProvider - - // Define a handler that forwards all "get" access to the underlying provider - private handler = { - get(target: ReconnectingWebSocketProvider, prop: string, receiver: any) { - return Reflect.get(target.underlyingProvider, prop, receiver) - } - } - - public constructor( - private url: string, - private network?: providers.Networkish - ) { - super() - this.connect() - return new Proxy(this, this.handler) - } - - private connect() { - // Copy old events - const events = this.underlyingProvider?._events ?? [] - - // Instantiate new provider with same url - this.underlyingProvider = new providers.WebSocketProvider( - this.url, - this.network - ) - - let pingTimeout: NodeJS.Timeout - let keepAliveInterval: NodeJS.Timer - - this.underlyingProvider._websocket.on('open', () => { - // Send ping messages on an interval - keepAliveInterval = setInterval(() => { - this.underlyingProvider._websocket.ping() - - // Terminate if a pong message is not received timely - pingTimeout = setTimeout( - () => this.underlyingProvider._websocket.terminate(), - EXPECTED_PONG_BACK - ) - }, KEEP_ALIVE_CHECK_INTERVAL) - - // Add old events to new provider - events.forEach(event => { - this.underlyingProvider._events.push(event) - this.underlyingProvider._startEvent(event) - }) - }) - - // Clear timers and reconnect on close - this.underlyingProvider._websocket.on('close', () => { - clearInterval(keepAliveInterval) - clearTimeout(pingTimeout) - this.connect() - }) - - // Clear ping timer when pong is received - this.underlyingProvider._websocket.on('pong', () => { - clearInterval(pingTimeout) - }) - } -} diff --git a/src/lib/SQSConsumer.ts b/src/lib/SQSConsumer.ts deleted file mode 100644 index 0af5faa0..00000000 --- a/src/lib/SQSConsumer.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import https from 'https' -import AWS from 'aws-sdk' -import { Consumer } from 'sqs-consumer' - -AWS.config.update({ - region: 'us-east-1', - accessKeyId: config.APP_AWS_ACCESS_KEY_ID, - secretAccessKey: config.APP_AWS_SECRET_ACCESS_KEY -}) - -const app = Consumer.create({ - queueUrl: config.SQS_QUEUE_URL, - handleMessageBatch: async records => { - const promises: Promise[] = [] - - records.forEach(record => { - if (typeof record.Body === 'string') { - try { - const e = JSON.parse(record.Body) - promises.push(services.queue.handleEvent({ event: e })) - } catch (e) { - log.warn(e) - } - } - }) - - const results = await Promise.allSettled(promises) - results.forEach(result => { - if (result.status === 'rejected') { - log.warn(result.reason) - } - }) - }, - sqs: new AWS.SQS({ - httpOptions: { - agent: new https.Agent({ - keepAlive: true - }) - } - }) -}) - -app.on('error', err => { - log.crit(err.message) -}) - -app.on('processing_error', err => { - log.crit(err.message) -}) - -app.on('timeout_error', err => { - log.crit(err.message) -}) - -app.start() - -log.superInfo('SQS Consumer Listening') diff --git a/src/lib/emailTemplate.ts b/src/lib/emailTemplate.ts new file mode 100644 index 00000000..a6f834f0 --- /dev/null +++ b/src/lib/emailTemplate.ts @@ -0,0 +1,391 @@ +export const transactionalTemplate = (options: { + subject: string + inboxPreview?: string + title: string + bodyText: string + ctaText?: string + ctaUrl?: string +}) => ` + + + + + + + + + + ${ + options.subject + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +` diff --git a/src/lib/errorHandler.ts b/src/lib/errorHandler.ts index c8a6ef26..0da40d44 100644 --- a/src/lib/errorHandler.ts +++ b/src/lib/errorHandler.ts @@ -63,19 +63,6 @@ function errorHandler(res: Response, errorKey: any) { log.debug(errorKey) switch (typeof errorKey) { case 'object': - if (errorKey?.error?.error?.body) { - let errStr = 'UNKNOWN_CONTRACT_ERROR' - try { - const body = JSON.parse(errorKey.error.error.body) - log.warn(body) - const inter = services.meem.meemInterface() - const errInfo = inter.parseError(body.error.data) - errStr = errorcodeToErrorString(errInfo.name) - } catch (e) { - // Unable to parse - } - return handleStringErrorKey(res, errStr) - } if (errorKey.message) { return handleStringErrorKey(res, errorKey.message) } diff --git a/src/lib/extensions.ts b/src/lib/extensions.ts index 61d35de1..5cd3defa 100644 --- a/src/lib/extensions.ts +++ b/src/lib/extensions.ts @@ -1,503 +1,4 @@ export default [ - { - id: 'ddbc4b66-be57-4031-acbf-f53b40d4cd6f', - name: 'Guild', - description: 'Sync your roles with Guild.xyz', - icon: 'integration-guild.png', - guideUrl: '', - slug: 'guild', - createdAt: '2022-06-08 21:42:45.558+00', - updatedAt: '2022-12-14 13:44:09.181+00', - category: 'roleManagement', - capabilities: ['auth', 'link'], - storageDefinition: {}, - widgetDefinition: {} - }, - // { - // id: 'c1eaf1c5-10a2-416a-8917-41a6ad82a52e', - // name: 'Discourse', - // description: "Link to your community's Discourse forum", - // icon: 'integration-calendar.png', - // guideUrl: '', - // slug: 'discourse', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '790cc58d-3551-4649-8995-9e2166623e41', - // name: 'Email', - // description: "Add your community's primary email address", - // icon: 'integration-email.png', - // guideUrl: '', - // slug: 'email', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '3d193628-b685-4063-a82c-b03132f52aaf', - // name: 'Etsy', - // description: "Link to your community's Etsy shop", - // icon: 'integration-etsy.png', - // guideUrl: '', - // slug: 'etsy', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - { - id: 'c0478003-8ae7-4b24-9517-a459ba1f35a5', - name: 'Discussions', - description: 'Discuss things!', - icon: 'integration-discussions.png', - guideUrl: '', - slug: 'discussions', - createdAt: '2022-12-21 19:04:05.671+00', - updatedAt: '2023-01-05 18:10:17.718+00', - category: 'communications', - capabilities: ['dapp', 'widget'], - storageDefinition: {}, - widgetDefinition: { - widgets: [{ metadata: {}, visibility: 'token-holders' }] - } - }, - // { - // id: '98dc0377-ba51-4069-bad8-7113d4f68009', - // name: 'Twitter', - // description: 'Add a link to your community Twitter', - // icon: 'integration-twitter.png', - // guideUrl: '', - // slug: 'twitter', - // createdAt: '2022-06-08 21:42:45.558+00', - // updatedAt: '2023-01-13 17:46:40.643+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'bdc15af0-c526-4efd-9c40-315231f8da88', - // name: 'Android', - // description: "Add a link to your community's Android app on the Play Store", - // icon: 'integration-android.png', - // guideUrl: '', - // slug: 'android', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '37237078-baea-4b2e-af9b-49d2eaee0863', - // name: 'Calendar', - // description: "Add a link to your community's calendar of events", - // icon: 'integration-calendar.png', - // guideUrl: '', - // slug: 'calendar', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '3ca56c91-7d13-439e-9fa8-b658b8deaa4b', - // name: 'Clarity', - // description: 'Simple docs and tasks for decentralized teams', - // icon: 'integration-clarity.png', - // guideUrl: '', - // slug: 'clarity', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'e516a7d9-4b0a-4fef-ae7e-954de9b3ad69', - // name: 'Google Drive', - // description: "Link to your community's shared Google Drive", - // icon: 'integration-gdrive.png', - // guideUrl: '', - // slug: 'gdrive', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'ef49de65-4421-495a-b292-f7d12feac2fd', - // name: 'Discord', - // description: 'Add a link to your community Discord server', - // icon: 'integration-discord.png', - // guideUrl: '', - // slug: 'discord', - // createdAt: '2022-06-08 21:42:45.558+00', - // updatedAt: '2023-01-13 17:46:40.756+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '2637286f-7cbe-45b2-b700-05bd356702ae', - // name: 'GitHub', - // description: "Add a link to your community's GitHub organization", - // icon: 'integration-github.png', - // guideUrl: '', - // slug: 'github', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'c947aeda-8a2b-43d5-b4c8-b88ba787fd7b', - // name: 'Gnosis', - // description: - // 'The most trusted platform to manage digital assets on Ethereum and multiple EVMs. ', - // icon: 'integration-gnosis.png', - // guideUrl: '', - // slug: 'gnosis', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '99d5a1ac-1fc7-48ce-8b23-0ac6ab749607', - // name: 'Instagram', - // description: "Add a link to your community's Instagram account", - // icon: 'integration-instagram.png', - // guideUrl: '', - // slug: 'instagram', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '72f412e9-1f39-4815-8a6e-8505360a949d', - // name: 'iOS', - // description: "Add a link to your community's iOS app on the App Store", - // icon: 'integration-ios.png', - // guideUrl: '', - // slug: 'ios', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '6607a4af-a2a8-426f-832a-3bcd91b675b7', - // name: 'LinkedIn', - // description: "Add a link to your community's LinkedIn profile", - // icon: 'integration-linkedin.png', - // guideUrl: '', - // slug: 'linkedin', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '2fd6276c-c804-485e-9f0f-520f35fef525', - // name: 'Mirror', - // description: 'The home for web3 publishing', - // icon: 'integration-mirror.png', - // guideUrl: '', - // slug: 'mirror', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'a422b3ac-f689-4a4c-bb83-a13267a5a33f', - // name: 'Myco', - // description: - // 'Myco makes it easy to earn money with friends by helping you assemble, collaborate, and launch social networks together.', - // icon: 'integration-myco.png', - // guideUrl: '', - // slug: 'myco', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'ed417875-46a4-4f96-90a1-94cc15f11f6e', - // name: 'Notion', - // description: "Add a link to your community's Notion page", - // icon: 'integration-notion.png', - // guideUrl: '', - // slug: 'notion', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '1ad969b2-4697-4b22-a244-e95e2a377dc3', - // name: 'OpenSea', - // description: "Add a link to your community's OpenSea profile", - // icon: 'integration-opensea.png', - // guideUrl: '', - // slug: 'opensea', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'f82e86f2-fd17-4f9d-9f7c-6f5f72cd0829', - // name: 'Address', - // description: - // "Add a map link for your community's gathering place or headquarters", - // icon: 'integration-address.png', - // guideUrl: '', - // slug: 'address', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '53d1f3f4-a1bb-44b5-996a-9084a825dc48', - // name: 'Paragraph', - // description: - // 'Write content, grow your audience and foster a community - no matter if your readers are on web2 or web3.', - // icon: 'integration-paragraph.png', - // guideUrl: '', - // slug: 'paragraph', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '8a8e00a2-ce97-46c0-86fd-215ca436653c', - // name: 'Phone', - // description: "Add your community's main phone number", - // icon: 'integration-phone.png', - // guideUrl: '', - // slug: 'phone', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '254e5165-f7fc-4aef-a7aa-7d08828acee0', - // name: 'Reddit', - // description: "Add a link to your community's subreddit", - // icon: 'integration-reddit.png', - // guideUrl: '', - // slug: 'reddit', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '07b583bf-45c7-48bf-a16b-14f1d6669f3e', - // name: 'Slack', - // description: "Add a link to your community's Slack server", - // icon: 'integration-slack.png', - // guideUrl: '', - // slug: 'slack', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '2a090f0c-fd8f-4a94-b4ef-a57e9c0846f7', - // name: 'Sliksafe', - // description: 'Decentralized File Sync with end-to-end encryption', - // icon: 'integration-sliksafe.png', - // guideUrl: '', - // slug: 'sliksafe', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '0ab1cf7b-a93c-40bf-b375-c08ace5ecb2b', - // name: 'Telegram', - // description: "Add a link to your community's Telegram group", - // icon: 'integration-telegram.png', - // guideUrl: '', - // slug: 'telegram', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '5ad0578a-acab-47ed-be84-10f36f95ef81', - // name: 'Tellie', - // description: 'The fastest, easiest site builder for creators.', - // icon: 'integration-tellie.png', - // guideUrl: '', - // slug: 'tellie', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '92ecc93b-98d5-4e30-a51b-96256abcc485', - // name: 'Vimeo', - // description: "Add a link to your community's Vimeo profile", - // icon: 'integration-vimeo.png', - // guideUrl: '', - // slug: 'vimeo', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '496fa303-eab6-4e9b-b9c4-3a8e3cf2e090', - // name: 'Website', - // description: "Add a link to your community's website", - // icon: 'integration-website.png', - // guideUrl: '', - // slug: 'website', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'dba87c3b-db42-44d1-a5a2-6e1fdec8d7ac', - // name: 'WhatsApp', - // description: "Add a link to your community's WhatsApp group", - // icon: 'integration-whatsapp.png', - // guideUrl: '', - // slug: 'whatsapp', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: 'd64d6649-0786-44a3-852b-3f83b48bcf39', - // name: 'Gather Town', - // description: - // 'Build digital Spaces for your distributed team to make virtual interactions more human.', - // icon: 'integration-gathertown.png', - // guideUrl: '', - // slug: 'gather-town', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '306147e1-06a3-4321-859e-9778d420861c', - // name: 'Gitcoin', - // description: - // "Gitcoin is where the world's leading web3 projects are born, validated, & funded", - // icon: 'integration-gitcoin.png', - // guideUrl: '', - // slug: 'gitcoin', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '98a8494c-718a-4d99-874b-0da3541a6a94', - // name: 'YouTube', - // description: "Add a link to your community's YouTube channel", - // icon: 'integration-youtube.png', - // guideUrl: '', - // slug: 'youtube', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, - // { - // id: '48cc017d-71e9-4b0a-9d4d-1a781515f2bc', - // name: 'Metropolis', - // description: - // 'Extensible and modular DAO implementation built around small working groups called pods', - // icon: 'integration-metropolis.png', - // guideUrl: '', - // slug: 'metropolis', - // createdAt: '2023-01-19 10:30:45.558+00', - // updatedAt: '2023-01-19 10:30:45.558+00', - // category: 'basics', - // capabilities: ['link'], - // storageDefinition: {}, - // widgetDefinition: {} - // }, { id: 'd891826d-561d-4a97-8735-7e7f22ab6431', slug: 'symphony', diff --git a/src/lib/gptPrompts.ts b/src/lib/gptPrompts.ts deleted file mode 100644 index db16e308..00000000 --- a/src/lib/gptPrompts.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const prompt1 = - "You are a content curator. You will be ingesting messages from the chat rooms of a community. You will then analyze the messages for the best content. You should consider the emoji reactions for each message as well as surrounding context and discussion. Finally, you should summarize the best content and links into a newsletter format where the writer's voice is playful and engaging. You should also include a few jokes and memes." - -export const prompt2 = (options: { brandName: string; brandVoice: string }) => { - const { brandName, brandVoice } = options - - return `You are a content curator. You will be ingesting messages from the chat rooms of the ${brandName} community. You will then analyze the messages for the best content. You should consider the emoji reactions for each message as well as surrounding context and discussion. Finally, you should summarize the best content and links into a newsletter format where the writer's voice can be described as: ${brandVoice}` -} - -export const compressor = (options: { text: string }) => { - const { text } = options - return `Compressor: compress the following text in a way that fits in a tweet (ideally) and such that you (GPT-4) can reconstruct the intention of the human who wrote text as close as possible to the original intention. This is for yourself. It does not need to be human readable or understandable. Abuse of language mixing, abbreviations, symbols (unicode and emoji), or any other encodings or internal representations is all permissible, as long as it, if pasted in a new inference cycle, will yield near-identical results as the original text: ${text}` -} diff --git a/src/lib/meem-access-testing.json b/src/lib/meem-access-testing.json deleted file mode 100644 index 4eaf8562..00000000 --- a/src/lib/meem-access-testing.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "addresses": {}, - "tokens": { - "0x6444070d9b4776a2363d1bac287571db11d692eb": { - "chain": 1, - "allAddresses": true, - "name": "NFT Faucet", - "description": "NOT REAL NFT. FOR TESTING PURPOSES ONLY.", - "creator": "Meem Project", - "license": "unknown", - "websiteURL": "https://meem.wtf" - }, - "0xbbc36838b7b9C5A052f51477FEA23F1Ec4aAcf0c": { - "chain": 1, - "allAddresses": true, - "name": "NFT Faucet", - "description": "NOT REAL NFT. FOR TESTING PURPOSES ONLY.", - "creator": "Meem Project", - "license": "unknown", - "websiteURL": "https://meem.wtf" - }, - "0x87e5882fa0ea7e391b7e31E8b23a8a38F35C84Ac": { - "chain": 4, - "allAddresses": true, - "name": "NFT Faucet", - "description": "NOT REAL NFT. FOR TESTING PURPOSES ONLY.", - "creator": "Meem Project", - "license": "unknown", - "websiteURL": "https://meem.wtf" - } - } -} \ No newline at end of file diff --git a/src/lib/meem-access.json b/src/lib/meem-access.json deleted file mode 100644 index 78e66342..00000000 --- a/src/lib/meem-access.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "addresses": { - "0xE7EDF0FeAebaF19Ad799eA9246E7bd8a38002d89": { - "allTokens": true, - "tokens": [] - }, - "0xEC41a0AAea12ad8F588e5aD0e71A837d83e05792": { - "allTokens": true, - "tokens": [] - }, - "0x1EcE5F31d84aD3f56DD07B26fBD59816126D8aB5": { - "allTokens": true, - "tokens": [] - } - }, - "tokens": { - "0x1CB1A5e65610AEFF2551A50f76a87a7d3fB649C6": { - "chain": 0, - "allAddresses": true, - "name": "CrypToadz by GREMPLIN", - "description": "CrypToadz are small amphibious creatures that roam the swampy basin of what was formerly known as Uniswamp. Unfortunately, approximately six weeks ago the Evil King Gremplin descended upon Uniswamp and dispatched the CrypToadz leader Colonel Floorbin, exiling him to Gooch Island. Following the fall of Colonel Floorbin, the Evil King Gremplin declared his divine right to rule over all CrypToadz in the Metaverse. The Evil King Gremplin's first order was to rename Uniswamp to GREMPLAND. The Evil King Gremplin rules over the CrypToadz along with his army of Fronkz. The Toadz have been known to refer to the Evil King Gremplin's reign as \"THE CROAKENING\". Help rid the Toadz of the rule of Evil King Gremplin by choosing how many to free during minting.", - "creator": "GREMPLIN", - "license": "cc0", - "licenseURL": "https://creativecommons.org/publicdomain/zero/1.0/", - "terms": "To the extent possible under law, Gremplin has waived all copyright and related or neighboring rights to CrypToadz by Gremplin. This work is published from: United States.", - "termsURL": "https://cryptoadz.io/", - "websiteURL": "https://cryptoadz.io/" - } - } -} \ No newline at end of file diff --git a/src/listeners/ProviderListener.ts b/src/listeners/ProviderListener.ts deleted file mode 100644 index 3f54827b..00000000 --- a/src/listeners/ProviderListener.ts +++ /dev/null @@ -1,304 +0,0 @@ -// import { Meem } from '@meemproject/meem-contracts' -import { Alchemy } from 'alchemy-sdk' -import { Contract, utils } from 'ethers' -import { DateTime } from 'luxon' -import meemABI from '../abis/Meem.json' -import { - MeemAdminContractSetEvent, - MeemRoleGrantedEvent, - MeemRoleRevokedEvent, - MeemSplitsSetEvent, - MeemTransferEvent -} from '../types/Meem' -// import { -// MeemClippedEventObject, -// MeemCopiesPerWalletLockedEventObject, -// MeemCopiesPerWalletSetEventObject, -// MeemPropertiesSetEventObject, -// MeemRemixesPerWalletLockedEventObject, -// MeemRemixesPerWalletSetEventObject, -// MeemSplitsSet_uint256_uint8_tuple_array_EventObject, -// MeemTokenReactionAddedEventObject, -// MeemTokenReactionRemovedEventObject, -// MeemTokenReactionTypesSetEventObject, -// MeemTotalCopiesLockedEventObject, -// MeemTotalCopiesSetEventObject, -// MeemTotalRemixesLockedEventObject, -// MeemTotalRemixesSetEventObject, -// MeemTransferEventObject, -// MeemUnClippedEventObject -// } from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' - -export default class ProviderListener { - // private providers: providers.Provider[] = [] - private providers: Alchemy[] = [] - - private hasSetupListners = false - - public async start() { - for (let i = 0; i < config.CHAIN_IDS.length; i++) { - const chainId = config.CHAIN_IDS[i] - const { provider } = await services.ethers.getProvider({ - chainId - }) - this.providers.push(provider) - } - - this.setupListners() - .then(() => {}) - .catch(e => { - log.crit(e) - }) - } - - private async setupListners() { - try { - if (!this.providers) { - log.crit("ProviderListener can't listen. Provider not defined") - return - } - if (this.hasSetupListners) { - log.warn('ProviderListener has already setup listners') - return - } - // this.provider.on('block', async blockNumber => { - // try { - // console.log(`Block: ${blockNumber}`) - // } catch (e) { - // log.crit(e) - // } - // }) - - const genericAgreement = new Contract(MeemAPI.zeroAddress, meemABI) - - // const eventNames = Object.keys(genericAgreement.interface.events) - - // See genericAgreement.interface.events for all available events - // genericAgreement.interface.events - const eventIds = { - // MeemDiamondCreated: utils.id('MeemDiamondCreated()'), - // OwnershipTransferred: utils.id('OwnershipTransferred(address,address)'), - MeemRoleGranted: utils.id('MeemRoleGranted(bytes32,address)'), - MeemRoleRevoked: utils.id('MeemRoleRevoked(bytes32,address)'), - // MeemTokenClipped: utils.id('MeemTokenClipped(uint256,address)'), - // MeemTokenUnClipped: utils.id('MeemTokenUnClipped(uint256,address)'), - // Approval: utils.id('Approval(address,address,uint256)'), - // ApprovalForAll: utils.id('ApprovalForAll(address,address,bool)'), - MeemTransfer: utils.id('MeemTransfer(address,address,uint256)'), - // Transfer: utils.id('Transfer(address,address,uint256)'), - MeemSplitsSet: utils.id('MeemSplitsSet(uint256,tuple[])'), - // RoyaltiesSet: utils.id('RoyaltiesSet(uint256,tuple[])'), - MeemContractInfoSet: utils.id('MeemContractInfoSet(address)'), - MeemContractInitialized: utils.id('MeemContractInitialized(address)'), - MeemContractURISet: utils.id('MeemContractURISet(address)'), - MeemMaxSupplyLocked: utils.id('MeemMaxSupplyLocked(uint256)'), - MeemMaxSupplySet: utils.id('MeemMaxSupplySet(uint256)'), - MeemMintPermissionsSet: utils.id('MeemMintPermissionsSet(tuple[])'), - MeemAdminContractSet: utils.id('MeemAdminContractSet(address)') - // MeemContractInitialized: utils.id('MeemContractInitialized(address)'), - // MeemTransfer: utils.id('MeemTransfer(address,address,uint256)'), - // MeemPropertiesSet: utils.id('MeemPropertiesSet(uint256,uint8,tuple)'), - // MeemSplitsSet: utils.id('MeemSplitsSet(uint256,uint8,tuple[])'), - // MeemTotalCopiesSet: utils.id( - // 'MeemTotalCopiesSet(uint256,uint8,int256)' - // ), - // MeemTotalCopiesLocked: utils.id( - // 'MeemTotalCopiesLocked(uint256,uint8,address)' - // ), - // MeemCopiesPerWalletLocked: utils.id( - // 'MeemCopiesPerWalletLocked(uint256,uint8,address)' - // ), - // MeemCopiesPerWalletSet: utils.id( - // 'MeemCopiesPerWalletSet(uint256,uint8,int256)' - // ), - // MeemTotalRemixesLocked: utils.id( - // 'MeemTotalRemixesLocked(uint256,uint8,address)' - // ), - // MeemTotalRemixesSet: utils.id( - // 'MeemTotalRemixesSet(uint256,uint8,int256)' - // ), - // MeemRemixesPerWalletLocked: utils.id( - // 'MeemRemixesPerWalletLocked(uint256,uint8,address)' - // ), - // MeemRemixesPerWalletSet: utils.id( - // 'MeemRemixesPerWalletSet(uint256,uint8,int256)' - // ), - // MeemTokenReactionAdded: utils.id( - // 'MeemTokenReactionAdded(uint256,address,string,uint256)' - // ), - // MeemTokenReactionRemoved: utils.id( - // 'MeemTokenReactionRemoved(uint256,address,string,uint256)' - // ), - // MeemTokenReactionTypesSet: utils.id( - // 'MeemTokenReactionTypesSet(uint256,string[])' - // ), - // MeemClipped: utils.id('MeemClipped(uint256,address)'), - // MeemUnClipped: utils.id('MeemUnClipped(uint256,address)'), - // // New events - // MeemContractInfoSet: utils.id('MeemContractInfoSet(address)'), - // MeemContractURISet: utils.id('MeemContractURISet(address)') - // event MeemRoleGranted(bytes32 indexed role, address indexed user); - // event MeemRoleRevoked(bytes32 indexed role, address indexed user); - // event MintPermissionsSet(MeemPermission[] mintPermissions); - // event MaxSupplySet(uint256 maxSupply); - // event MaxSupplyLocked(); - // event TokenReactionAdded( - // uint256 tokenId, - // address addy, - // string reaction, - // uint256 newTotalReactions - // ); - - // event TokenReactionRemoved( - // uint256 tokenId, - // address addy, - // string reaction, - // uint256 newTotalReactions - // ); - - // event MeemSplitsSet(uint256 tokenId, Split[] splits); - } - - log.debug(eventIds) - - const topics = [Object.values(eventIds)] - - for (let i = 0; i < this.providers.length; i++) { - const provider = this.providers[i] - provider.ws.on( - { - topics - }, - // eslint-disable-next-line @typescript-eslint/no-loop-func - async rawLog => { - try { - /* - TODO: Handle log - get transaction, find the contract address, add the contract address to our DB of contracts that we listen for - log = { - blockNumber: 10583485, - blockHash: '0x7a918ddd1c5ff6ef5ddd72a789452d86da85a91a1824529e2ac6c94e09d3dcbf', - transactionIndex: 49, - removed: false, - address: '0x3FC5cDffD74d9EeebAcB2A7dd94714023662abbf', - data: '0x0000000000000000000000003fc5cdffd74d9eeebacb2a7dd94714023662abbf', - topics: [ - '0x273c08f8f7c609a33a4029ada1508fb7e43c5e434c66274c739d21dc1bb8171f' - ], - transactionHash: '0x272cafd2ad24cbf36af4a1c2b8756e9ebb83b928640b41ef1021e3dbd853930f', - logIndex: 87 - } - */ - - const block = await provider.core.getBlock(rawLog.blockHash) - - const parsedLog = genericAgreement.interface.parseLog({ - data: rawLog.data, - topics: rawLog.topics - }) - - const network = await provider.core.getNetwork() - - log.debug(parsedLog) - - const eventData = parsedLog.args - - switch (parsedLog.topic) { - case eventIds.MeemContractInitialized: { - await services.contractEvents.meemHandleContractInitialized({ - address: rawLog.address, - chainId: network.chainId, - transactionHash: rawLog.transactionHash - }) - break - } - case eventIds.MeemRoleGranted: { - await services.contractEvents.meemHandleRoleGranted({ - address: rawLog.address, - transactionHash: rawLog.transactionHash, - transactionTimestamp: - block?.timestamp || DateTime.now().toSeconds(), - eventData: eventData as MeemRoleGrantedEvent['args'], - chainId: network.chainId - }) - break - } - case eventIds.MeemRoleRevoked: { - await services.contractEvents.meemHandleRoleRevoked({ - address: rawLog.address, - transactionHash: rawLog.transactionHash, - transactionTimestamp: - block?.timestamp || DateTime.now().toSeconds(), - eventData: eventData as MeemRoleRevokedEvent['args'], - chainId: network.chainId - }) - break - } - case eventIds.MeemTransfer: { - await services.contractEvents.meemHandleTransfer({ - address: rawLog.address, - transactionHash: rawLog.transactionHash, - transactionTimestamp: - block?.timestamp || DateTime.now().toSeconds(), - eventData: eventData as MeemTransferEvent['args'], - chainId: network.chainId - }) - break - } - case eventIds.MeemSplitsSet: { - await services.contractEvents.meemHandleSplitsSet({ - address: rawLog.address, - eventData: eventData as MeemSplitsSetEvent['args'], - chainId: network.chainId - }) - break - } - - case eventIds.MeemAdminContractSet: { - await services.contractEvents.meemHandleAdminContractSet({ - address: rawLog.address, - eventData: eventData as MeemAdminContractSetEvent['args'], - chainId: network.chainId - }) - break - } - default: - break - } - - /* - Handle parsed data - - parsedLog = { - eventFragment: { - name: 'MeemContractInitialized', - anonymous: false, - inputs: [Array], - type: 'event', - _isFragment: true, - constructor: [Function], - format: [Function (anonymous)] - }, - name: 'MeemContractInitialized', - signature: 'MeemContractInitialized(address)', - topic: '0x273c08f8f7c609a33a4029ada1508fb7e43c5e434c66274c739d21dc1bb8171f', - args: [ - '0x3FC5cDffD74d9EeebAcB2A7dd94714023662abbf', - contractAddress: '0x3FC5cDffD74d9EeebAcB2A7dd94714023662abbf' - ] - } - */ - } catch (e) { - log.crit(e) - } - } - ) - } - - this.hasSetupListners = true - log.info('ProviderListener set up') - } catch (e) { - log.crit(e) - } - } -} diff --git a/src/models/Invite.ts b/src/models/Invite.ts new file mode 100644 index 00000000..c78b37dd --- /dev/null +++ b/src/models/Invite.ts @@ -0,0 +1,45 @@ +import { DataTypes } from 'sequelize' +import { BaseModel } from '../core/BaseModel' +import type { IModels } from '../types/models' +import type Agreement from './Agreement' + +export default class Invite extends BaseModel { + public static readonly modelName = 'Invite' + + public static get indexes() { + return [ + { + name: 'Invite_AgreementId', + fields: ['AgreementId'] + }, + { + name: 'Invite_code', + fields: ['code'] + } + ] + } + + public static readonly attributes = { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + code: { + type: DataTypes.STRING, + allowNull: false + } + } + + public id!: string + + public code!: string + + public AgreementId!: string | null + + public Agreement?: Agreement | null + + public static associate(models: IModels) { + this.belongsTo(models.Agreement) + } +} diff --git a/src/models/Wallet.ts b/src/models/Wallet.ts index 26c5a757..faa3c179 100644 --- a/src/models/Wallet.ts +++ b/src/models/Wallet.ts @@ -1,4 +1,3 @@ -import { DateTime } from 'luxon' import { Op, DataTypes } from 'sequelize' import ModelWithAddress from '../core/ModelWithAddress' import type { IModels } from '../types/models' @@ -142,22 +141,23 @@ export default class Wallet extends ModelWithAddress { } public async enforceTXLimit() { + return // -1 is unlimited transactions - if (this.dailyTXLimit === -1) { - return - } - - const numTransactions = await orm.models.Transaction.count({ - where: { - WalletId: this.id, - createdAt: { - [Op.gte]: DateTime.now().minus({ hours: 24 }).toJSDate() - } - } - }) - - if (numTransactions + 1 > this.dailyTXLimit) { - throw new Error('TX_LIMIT_EXCEEDED') - } + // if (this.dailyTXLimit === -1) { + // return + // } + + // const numTransactions = await orm.models.Transaction.count({ + // where: { + // WalletId: this.id, + // createdAt: { + // [Op.gte]: DateTime.now().minus({ hours: 24 }).toJSDate() + // } + // } + // }) + + // if (numTransactions + 1 > this.dailyTXLimit) { + // throw new Error('TX_LIMIT_EXCEEDED') + // } } } diff --git a/src/routers/adminRouter.ts b/src/routers/adminRouter.ts index 79b1ae70..76128834 100644 --- a/src/routers/adminRouter.ts +++ b/src/routers/adminRouter.ts @@ -22,18 +22,9 @@ export default (app: Express, _express: typeof coreExpress) => { router.getAsync('/runMigrations', AdminController.runMigrations) router.getAsync('/runSync', AdminController.runSync) - // router.getAsync('/agreementSync', AdminController.agreementSync) - // router.getAsync('/meemSync', AdminController.meemSync) - // router.getAsync('/meemSyncReactions', AdminController.meemSyncReactions) - // router.getAsync( - // '/syncDbMeemIdsToContract', - // AdminController.syncDbMeemIdsToContract - // ) router.getAsync('/syncExtensions', AdminController.syncExtensions) - // router.getAsync('/syncPermissions', AdminController.syncPermissions) router.getAsync( '/seedIdentityProviders', AdminController.seedIdentityProviders ) - router.getAsync('/syncPins', AdminController.syncPins) } diff --git a/src/routers/apiRouter.ts b/src/routers/apiRouter.ts index 8d549a62..c487b6c4 100644 --- a/src/routers/apiRouter.ts +++ b/src/routers/apiRouter.ts @@ -1,11 +1,9 @@ import coreExpress, { Express } from 'express' import AgreementController from '../controllers/AgreementController' -import AgreementExtensionController from '../controllers/AgreementExtensionController' import AgreementRoleController from '../controllers/AgreementRoleController' import ConfigController from '../controllers/ConfigController' import DiscordController from '../controllers/DiscordController' import EPMController from '../controllers/EPMController' -import MeemController from '../controllers/MeemController' import MeemIdController from '../controllers/MeemIdController' import TestController from '../controllers/TestController' import TypesController from '../controllers/TypesController' @@ -41,11 +39,21 @@ export default (app: Express, _express: typeof coreExpress) => { /** Agreements and Roles Routes */ + router.postAsync( + '/acceptInvite', + userLoggedInPolicy, + AgreementController.acceptInvite + ) router.postAsync('/agreements', AgreementController.createAgreement) router.postAsync( '/agreements/isSlugAvailable', AgreementController.isSlugAvailable ) + router.postAsync( + '/agreements/:agreementId/invite', + userLoggedInPolicy, + AgreementController.sendInvites + ) router.postAsync( '/agreements/:agreementId/reinitialize', AgreementController.reInitialize @@ -54,18 +62,10 @@ export default (app: Express, _express: typeof coreExpress) => { '/agreements/:agreementId', AgreementController.updateAgreement ) - router.postAsync( - '/agreements/:agreementId/safe', - AgreementController.createAgreementSafe - ) router.patchAsync( '/agreements/:agreementId/safe', AgreementController.setAgreementSafeAddress ) - router.patchAsync( - '/agreements/:agreementId/setAdminRole', - AgreementController.setAgreementAdminRole - ) router.postAsync( '/agreements/:agreementId/bulkMint', AgreementController.bulkMint @@ -75,10 +75,6 @@ export default (app: Express, _express: typeof coreExpress) => { userLoggedInPolicy, AgreementController.bulkBurn ) - router.postAsync( - '/agreements/:agreementId/upgrade', - AgreementController.upgradeAgreement - ) router.getAsync( '/agreements/:agreementId/proof', AgreementController.getMintingProof @@ -87,14 +83,6 @@ export default (app: Express, _express: typeof coreExpress) => { '/agreements/:agreementId/isAdmin', AgreementController.checkIsAgreementAdmin ) - router.postAsync( - '/agreements/:agreementId/extensions', - AgreementExtensionController.createAgreementExtension - ) - router.putAsync( - '/agreements/:agreementId/extensions/:agreementExtensionId', - AgreementExtensionController.updateAgreementExtension - ) router.getAsync( '/agreements/:agreementId/roles', AgreementRoleController.getAgreementRoles @@ -124,10 +112,6 @@ export default (app: Express, _express: typeof coreExpress) => { '/agreements/:agreementId/roles/:agreementRoleId/bulkBurn', AgreementRoleController.bulkBurn ) - router.postAsync( - '/agreements/:agreementId/roles/:agreementRoleId/upgrade', - AgreementController.upgradeAgreement - ) /** EPM Routes */ @@ -165,8 +149,6 @@ export default (app: Express, _express: typeof coreExpress) => { /** Misc Routes */ router.getAsync('/config', ConfigController.getConfig) - router.getAsync('/ipfs', MeemController.getIPFSFile) - router.postAsync('/ipfs', MeemController.saveToIPFS) router.postAsync('/generateTypes', TypesController.generateTypes) router.getAsync('/meem-api.json', TypesController.getOpenAPIFile) @@ -175,19 +157,7 @@ export default (app: Express, _express: typeof coreExpress) => { router.postAsync('/test/webhook', TestController.testWebhook) if (config.ENABLE_TEST_ENDPOINTS) { - router.getAsync('/test/gnosis', TestController.testGnosis) - router.getAsync('/test/testCron', TestController.testCron) - router.getAsync('/test/syncContract', TestController.syncContract) - router.getAsync('/test/metadata', TestController.metadata) - router.getAsync('/test/hash', TestController.testHash) - router.getAsync('/test/releaseLock', TestController.releaseLock) - router.getAsync('/test/mintPKP', TestController.mintPKP) - router.getAsync('/test/getEthAddress', TestController.getEthAddress) - router.getAsync('/test/txEncoding', TestController.testTxEncoding) - router.getAsync('/test/testPinata', TestController.testPinata) - router.getAsync('/test/callback', TestController.testCallback) - router.postAsync('/test/callback', TestController.testCallback) - router.getAsync('/test/summary', TestController.testSummary) - router.getAsync('/test/decrypt', TestController.testDecrypt) + router.getAsync('/test/email', TestController.testEmail) + router.getAsync('/test/emailHtml', TestController.testEmailHtml) } } diff --git a/src/scripts/fetchAccess.ts b/src/scripts/fetchAccess.ts deleted file mode 100644 index 197a4c9c..00000000 --- a/src/scripts/fetchAccess.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable no-console */ -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function downloadMeemABI() { - const { text } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-registry/master/meem-access.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'lib')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'lib', 'meem-access.json'), - text - ) - - const { text: testingText } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-registry/master/meem-access-testing.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'lib')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'lib', 'meem-access-testing.json'), - testingText - ) -} - -downloadMeemABI() - .then(() => { - console.log(`Meem access list downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchMeemABI.ts b/src/scripts/fetchMeemABI.ts deleted file mode 100644 index 5bfa0ac0..00000000 --- a/src/scripts/fetchMeemABI.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable no-console */ -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function downloadMeemABI() { - const { text } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-contracts/master/types/Meem.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'abis')) - await fs.writeFile(path.join(process.cwd(), 'src', 'abis', 'Meem.json'), text) -} - -downloadMeemABI() - .then(() => { - console.log(`Meem ABI downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchMeemContracts.ts b/src/scripts/fetchMeemContracts.ts deleted file mode 100644 index 8f519fc9..00000000 --- a/src/scripts/fetchMeemContracts.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable no-await-in-loop */ -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function fetchAgreements() { - const { body } = await request - .get( - 'https://api.github.com/repos/meemproject/meem-contracts/git/trees/master?recursive=1' - ) - .set('User-Agent', 'script') - - // console.log(body) - - const tree = body.tree as { - path: string - mode: string - type: string - sha: string - url: string - }[] - - for (let i = 0; i < tree.length; i += 1) { - const file = tree[i] - if (/^contracts/.test(file.path)) { - const filePath = path.join(process.cwd(), 'contracts', 'meem', file.path) - if (/\.sol/.test(file.path)) { - console.log(`Writing file: ${file.path}`) - const { text } = await request.get( - `https://raw.githubusercontent.com/meemproject/meem-contracts/master/${file.path}` - ) - - await fs.writeFile(filePath, text) - } else { - await fs.ensureDir(filePath) - } - } - } - - // await fs.ensureDir(path.join(process.cwd(), 'src', 'abis')) - // await fs.writeFile(path.join(process.cwd(), 'src', 'abis', 'Meem.json'), text) -} - -fetchAgreements() - .then(() => { - console.log(`Meem Contracts downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchMeemIdABI.ts b/src/scripts/fetchMeemIdABI.ts deleted file mode 100644 index f90c849a..00000000 --- a/src/scripts/fetchMeemIdABI.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable import/no-extraneous-dependencies */ - -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function downloadMeemABI() { - const { text } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-id-contracts/master/types/MeemID.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'abis')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'abis', 'MeemID.json'), - text - ) -} - -downloadMeemABI() - .then(() => { - console.log(`Meem ID ABI downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchMeemIdContracts.ts b/src/scripts/fetchMeemIdContracts.ts deleted file mode 100644 index 33a63fa6..00000000 --- a/src/scripts/fetchMeemIdContracts.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable no-await-in-loop */ -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function fetchMeemIdContracts() { - const { body } = await request - .get( - 'https://api.github.com/repos/meemproject/meem-id-contracts/git/trees/master?recursive=1' - ) - .set('User-Agent', 'script') - - // console.log(body) - - const tree = body.tree as { - path: string - mode: string - type: string - sha: string - url: string - }[] - - for (let i = 0; i < tree.length; i += 1) { - const file = tree[i] - if (/^contracts/.test(file.path)) { - const filePath = path.join( - process.cwd(), - 'contracts', - 'meemId', - file.path - ) - if (/\.sol/.test(file.path)) { - console.log(`Writing file: ${file.path}`) - const { text } = await request.get( - `https://raw.githubusercontent.com/meemproject/meem-id-contracts/master/${file.path}` - ) - - await fs.writeFile(filePath, text) - } else { - await fs.ensureDir(filePath) - } - } - } - - // await fs.ensureDir(path.join(process.cwd(), 'src', 'abis')) - // await fs.writeFile(path.join(process.cwd(), 'src', 'abis', 'Meem.json'), text) -} - -fetchMeemIdContracts() - .then(() => { - console.log(`MeemId Contracts downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchMeemMarketABI.ts b/src/scripts/fetchMeemMarketABI.ts deleted file mode 100644 index 0fee9f55..00000000 --- a/src/scripts/fetchMeemMarketABI.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable import/no-extraneous-dependencies */ - -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function downloadMeemABI() { - const { text } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-market-contracts/master/types/MeemMarket.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'abis')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'abis', 'MeemMarket.json'), - text - ) -} - -downloadMeemABI() - .then(() => { - console.log(`Meem Market ABI downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/fetchWhitelist.ts b/src/scripts/fetchWhitelist.ts deleted file mode 100644 index d1226c6c..00000000 --- a/src/scripts/fetchWhitelist.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable no-console */ -import path from 'path' -import fs from 'fs-extra' -import request from 'superagent' - -async function downloadMeemABI() { - const { text } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-registry/master/meem-whitelist.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'lib')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'lib', 'meem-whitelist.json'), - text - ) - - const { text: testingText } = await request.get( - 'https://raw.githubusercontent.com/meemproject/meem-registry/master/meem-whitelist-testing.json' - ) - - await fs.ensureDir(path.join(process.cwd(), 'src', 'lib')) - await fs.writeFile( - path.join(process.cwd(), 'src', 'lib', 'meem-whitelist-testing.json'), - testingText - ) -} - -downloadMeemABI() - .then(() => { - console.log(`Meem Whitelist downloaded`) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/scripts/generateHasuraMetadata.ts b/src/scripts/generateHasuraMetadata.ts deleted file mode 100644 index 6514cd7f..00000000 --- a/src/scripts/generateHasuraMetadata.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable no-console */ -import path from 'path' -import log from '@kengoldfarb/log' -import dotenv from 'dotenv' -import fs from 'fs-extra' -import { tables } from '../hasura/tables' - -const run = async () => { - const dotenvpath = path.join(process.cwd(), '.env') - await dotenv.config({ path: dotenvpath }) - - const metadata = { - resource_version: 330, - metadata: { - version: 3, - sources: [ - { - name: process.env.HASURA_DATABASE_NAME, - kind: 'postgres', - tables, - configuration: { - connection_info: { - database_url: process.env.HASURA_DATABASE_URL, - isolation_level: 'read-committed', - pool_settings: { - connection_lifetime: 600, - total_max_connections: 10 - }, - use_prepared_statements: false - } - } - } - ], - api_limits: { - disabled: false, - time_limit: { - global: 10, - per_role: {} - } - }, - backend_configs: { - dataconnector: { - athena: { - uri: 'http://localhost:8081/api/v1/athena' - }, - snowflake: { - uri: 'http://localhost:8081/api/v1/snowflake' - } - } - } - } - } - - const now = Math.floor(new Date().getTime() / 1000) - - const directory = path.join(process.cwd(), 'tmp', 'hasura') - - await fs.ensureDir(directory) - const filename = path.join(directory, `metadata-${now}.json`) - await fs.writeFile(filename, JSON.stringify(metadata)) - - log.info(`🎉🎉🎉 Generated hasura metadata at: ${filename}`) -} - -run() - .then(() => {}) - .catch(e => { - log.crit(e) - }) diff --git a/src/scripts/migrateSymphony.ts b/src/scripts/migrateSymphony.ts deleted file mode 100644 index 49c67253..00000000 --- a/src/scripts/migrateSymphony.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-disable no-await-in-loop */ -import path from 'path' -import log from '@kengoldfarb/log' -import dotenv from 'dotenv' -import pg from 'pg' - -function objToInsert(obj: Record) { - const keys = Object.keys(obj) - const values = Object.values(obj) - const keyString = keys.map(k => `"${k}"`).join(', ') - const valueString = values - .map(value => { - if (value === null) { - return 'null' - } else if (value instanceof Date) { - return `'${value.toISOString()}'` - } else if (typeof value === 'object') { - return `'${JSON.stringify(value)}'` - } - - return `'${value.replace("'", '')}'` - }) - .join(', ') - return `(${keyString}) VALUES (${valueString})` -} - -const run = async () => { - const dotenvpath = path.join(process.cwd(), '.env') - await dotenv.config({ path: dotenvpath }) - console.log('did dotenv') - - const client = new pg.Client(process.env.DATABASE_URL) - const symClient = new pg.Client(process.env.SYMPHONY_DATABASE_URL) - await client.connect() - await symClient.connect() - console.log('initialized clients') - - const agreementDiscords = await symClient.query( - 'SELECT * FROM "AgreementDiscords"' - ) - const agreementSlacks = await symClient.query( - 'SELECT * FROM "AgreementSlacks"' - ) - const agreementTwitters = await symClient.query( - 'SELECT * FROM "AgreementTwitters"' - ) - const discords = await symClient.query('SELECT * FROM "Discords"') - const messages = await symClient.query('SELECT * FROM "Messages"') - const rules = await symClient.query('SELECT * FROM "Rules"') - const slacks = await symClient.query('SELECT * FROM "Slacks"') - const twitters = await symClient.query('SELECT * FROM "Twitters"') - - console.log('got result') - - const agreementDiscordInserts = agreementDiscords.rows.map(row => { - const agreementId = row.agreementId - delete row.agreementId - return { ...row, AgreementId: agreementId } - }) - - const agreementSlackInserts = agreementSlacks.rows.map(row => { - const agreementId = row.agreementId - delete row.agreementId - return { ...row, AgreementId: agreementId } - }) - - const agreementTwitterInserts = agreementTwitters.rows.map(row => { - const agreementId = row.agreementId - delete row.agreementId - return { ...row, AgreementId: agreementId } - }) - - const discordInserts = discords.rows.map(row => { - return { ...row } - }) - - const slackInserts = slacks.rows.map(row => { - return { ...row } - }) - - const twitterInserts = twitters.rows.map(row => { - return { ...row } - }) - - const ruleInserts = rules.rows.map(row => { - const agreementId = row.agreementId - delete row.agreementId - return { ...row, AgreementId: agreementId } - }) - - const messageInserts = messages.rows.map(row => { - const agreementId = row.agreementId - delete row.agreementId - return { ...row, AgreementId: agreementId } - }) - - for (let i = 0; i < discords.rows.length; i++) { - await client.query( - `INSERT INTO "Discords" ${objToInsert(discordInserts[i])}` - ) - } - - for (let i = 0; i < slacks.rows.length; i++) { - await client.query(`INSERT INTO "Slacks" ${objToInsert(slackInserts[i])}`) - } - - for (let i = 0; i < twitters.rows.length; i++) { - await client.query( - `INSERT INTO "Twitters" ${objToInsert(twitterInserts[i])}` - ) - } - - for (let i = 0; i < agreementDiscordInserts.length; i++) { - await client.query( - `INSERT INTO "AgreementDiscords" ${objToInsert( - agreementDiscordInserts[i] - )}` - ) - } - - for (let i = 0; i < agreementSlackInserts.length; i++) { - await client.query( - `INSERT INTO "AgreementSlacks" ${objToInsert(agreementSlackInserts[i])}` - ) - } - - for (let i = 0; i < agreementTwitterInserts.length; i++) { - await client.query( - `INSERT INTO "AgreementTwitters" ${objToInsert( - agreementTwitterInserts[i] - )}` - ) - } - - for (let i = 0; i < ruleInserts.length; i++) { - await client.query(`INSERT INTO "Rules" ${objToInsert(ruleInserts[i])}`) - } - - for (let i = 0; i < messageInserts.length; i++) { - await client.query( - `INSERT INTO "Messages" ${objToInsert(messageInserts[i])}` - ) - } - - log.info(`🎉🎉🎉 Migrated symphony data`) -} - -run() - .then(() => { - log.info('All done!') - process.exit(0) - }) - .catch(e => { - console.log(e) - }) diff --git a/src/serverless/queue.ts b/src/serverless/queue.ts deleted file mode 100644 index 1f4e283d..00000000 --- a/src/serverless/queue.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-disable global-require */ -/* eslint-disable @typescript-eslint/no-var-requires */ -import util from 'util' -// eslint-disable-next-line import/no-extraneous-dependencies -import { SQSHandler } from 'aws-lambda' -import start from '../core/start' - -let app: Express.Application - -export const handle: SQSHandler = async (event, context) => { - // eslint-disable-next-line no-console - console.log(util.inspect({ event }, true, 999, true)) - context.callbackWaitsForEmptyEventLoop = false - - try { - if (!app) { - const result = await start({ - isListeningDisabled: true - }) - app = result.app - } - - const records = event.Records - - for (let i = 0; i < records.length; i++) { - try { - const record = records[i] - const e = JSON.parse(record.body) - await services.queue.handleEvent({ event: e }) - } catch (e) { - log.warn(e) - } - } - } catch (e) { - // eslint-disable-next-line no-console - console.log(e) - } -} diff --git a/src/services/Agreement.ts b/src/services/Agreement.ts index 10ac509c..f0ee48ba 100644 --- a/src/services/Agreement.ts +++ b/src/services/Agreement.ts @@ -1,28 +1,15 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { - getCuts, - IFacetVersion, - diamondABI, - getMerkleInfo -} from '@meemproject/meem-contracts' -import { Validator } from '@meemproject/metadata' +import { getMerkleInfo } from '@meemproject/meem-contracts' // eslint-disable-next-line import/named import { ethers } from 'ethers' import _ from 'lodash' import { Op } from 'sequelize' import slug from 'slug' import { v4 as uuidv4 } from 'uuid' -import GnosisSafeABI from '../abis/GnosisSafe.json' -import GnosisSafeProxyABI from '../abis/GnosisSafeProxy.json' import type Agreement from '../models/Agreement' import AgreementRole from '../models/AgreementRole' import Wallet from '../models/Wallet' -import { - InitParamsStruct, - Mycontract, - Mycontract__factory, - SetRoleItemStruct -} from '../types/Meem' +import { InitParamsStruct, Mycontract, SetRoleItemStruct } from '../types/Meem' import { MeemAPI } from '../types/meem.generated' import { IAgreementRole } from '../types/shared/meem.shared' @@ -131,7 +118,7 @@ export default class AgreementService { const agreementOrRole = agreementRole ?? agreement - const { wallet, contractInitParams, fullMintPermissions } = + const { contractInitParams, fullMintPermissions } = await this.prepareInitValues({ ...data, chainId: agreementOrRole.chainId, @@ -148,11 +135,6 @@ export default class AgreementService { contractInitParams.contractURI = `ipfs://${result.IpfsHash}` } - const agreementOrRoleContract = Mycontract__factory.connect( - agreementOrRole.address, - wallet - ) - // Even if reinitializing role, check parent agreement for admin role. const isAdmin = await agreement.isAdmin(senderWalletAddress) @@ -164,36 +146,6 @@ export default class AgreementService { await agreementOrRole.save() - log.debug(contractInitParams) - - // TODO: REMOVE const tx = await services.ethers.runTransaction({ - // chainId: agreementOrRole.chainId, - // fn: agreement.reinitialize.bind(agreement), - // params: [contractInitParams], - // gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT) - // }) - if (agreementOrRole.isOnChain) { - const chainId = agreementOrRole.chainId - - const agreementContract = await services.agreement.getAgreementContract({ - chainId, - address: ethers.constants.AddressZero - }) - - const txId = await services.ethers.queueTransaction({ - chainId, - functionSignature: - agreementContract.interface.functions[ - 'reinitialize((string,string,string,(address,bytes32,bool)[],uint256,(uint8,address[],uint256,uint256,uint256,uint256,bytes32)[],(address,uint256,address)[],bool))' - ].format(), - contractAddress: agreementOrRoleContract.address, - inputValues: { - params: contractInitParams - } - }) - return { txId } - } - return {} } @@ -248,262 +200,6 @@ export default class AgreementService { return { agreement, adminAgreement } } - public static async createAgreement( - data: ( - | MeemAPI.v1.CreateAgreement.IRequestBody - | MeemAPI.v1.CreateAgreementRole.IRequestBody - ) & { - senderWalletAddress: string - chainId: number - shouldCreateAdminRole?: boolean - parentContractTxtId?: string - } - ) { - const { - shouldMintTokens, - tokenMetadata, - shouldCreateAdminRole, - senderWalletAddress, - members, - metadata, - chainId, - parentContractTxtId - } = data - - const [dbContract, bundle] = await Promise.all([ - orm.models.Contract.findOne({ - where: { - id: config.MEEM_PROXY_CONTRACT_ID - } - }), - orm.models.Bundle.findOne({ - where: { - id: config.MEEM_BUNDLE_ID - }, - include: [ - { - model: orm.models.BundleContract, - include: [ - { - model: orm.models.Contract, - include: [ - { - model: orm.models.ContractInstance, - where: { - chainId - } - } - ] - } - ] - } - ] - }) - ]) - - if (!dbContract) { - throw new Error('CONTRACT_NOT_FOUND') - } - - if (!bundle) { - throw new Error('BUNDLE_NOT_FOUND') - } - - // Validate metadata - const contractMetadataValidator = new Validator(metadata) - const contractMetadataValidatorResult = - contractMetadataValidator.validate(metadata) - - if (!contractMetadataValidatorResult.valid) { - log.crit( - contractMetadataValidatorResult.errors.map((e: any) => e.message) - ) - throw new Error('INVALID_METADATA') - } - - const { wallet, senderWallet, contractInitParams, cleanAdmins } = - await this.prepareInitValues({ ...data, chainId }) - - const builtData: { - to: string - metadata: MeemAPI.IMeemMetadataLike - ipfs?: string - }[] = [] - - if (shouldMintTokens && tokenMetadata) { - const addresses = (members ?? []).filter( - a => a.toLowerCase() !== wallet.address.toLowerCase() - ) - - const tokens = addresses.map(a => { - return { - to: a, - metadata: tokenMetadata - } - }) - - // Validate metadata - tokens.forEach(token => { - if (!token.to) { - throw new Error('MISSING_ACCOUNT_ADDRESS') - } - - if (!token.metadata) { - throw new Error('INVALID_METADATA') - } - - const validator = new Validator(token.metadata) - const validatorResult = validator.validate(token.metadata) - - if (!validatorResult.valid) { - log.crit(validatorResult.errors.map((e: any) => e.message)) - throw new Error('INVALID_METADATA') - } - - builtData.push({ - ...token, - metadata: token.metadata - }) - }) - } - - const deployContractTxId = await services.ethers.queueContractDeployment({ - chainId, - abi: dbContract.abi, - bytecode: dbContract.bytecode, - args: [senderWallet.address, [senderWallet.address, wallet.address]] - }) - - const toVersion: IFacetVersion[] = [] - - bundle.BundleContracts?.forEach(bc => { - const contractInstance = - bc.Contract?.ContractInstances && bc.Contract?.ContractInstances[0] - if (!contractInstance) { - throw new Error('FACET_NOT_DEPLOYED') - } - - toVersion.push({ - address: contractInstance.address, - functionSelectors: bc.functionSelectors - }) - }) - - const cutTxId = await services.ethers.queueDiamondCut({ - bundleABI: bundle.abi, - chainId, - contractTxId: deployContractTxId, - fromVersion: [], - toVersion, - abi: dbContract.abi, - contractInitParams, - metadata, - senderWalletAddress, - parentContractTxtId - }) - - let mintTxId - - if (shouldMintTokens && tokenMetadata) { - const agreementContract = await services.agreement.getAgreementContract({ - chainId, - address: ethers.constants.AddressZero - }) - - // Pin to IPFS - for (let i = 0; i < builtData.length; i++) { - const item = builtData[i] - const result = await services.web3.saveToPinata({ - json: { ...item.metadata } - }) - item.ipfs = `ipfs://${result.IpfsHash}` - } - - const bulkParams: Parameters[0] = builtData.map( - item => ({ - to: item.to, - tokenType: MeemAPI.MeemType.Original, - tokenURI: (item.ipfs as string) ?? '' - }) - ) - - mintTxId = await services.ethers.queueTransaction({ - chainId, - functionSignature: - agreementContract.interface.functions[ - 'bulkMint((address,string,uint8)[])' - ].format(), - contractTxId: deployContractTxId, - inputValues: { - bulkParams - } - }) - } - - let adminRoleContractTxIds: - | { - deployContractTxId: string - cutTxId: string - mintTxId?: string - } - | undefined - let setAdminRoleTxId - - if (shouldCreateAdminRole) { - const createAdminRoleResult: { - deployContractTxId: string - cutTxId: string - mintTxId?: string - } = await this.createAgreement({ - name: `${metadata.name} Admin Role`, - chainId, - maxSupply: '0', - admins: cleanAdmins.map(a => a.user), - members: cleanAdmins.map(a => a.user), - parentContractTxtId: deployContractTxId, - metadata: { - meem_metadata_type: 'Meem_AgreementRoleContract', - meem_metadata_version: '20221116', - image: metadata.image, - name: `${metadata.name} Admin Role`, - description: `Admin role for the ${metadata.name} agreement.`, - meem_agreement_address: '', // This will be set in the transaction queue - external_url: '' - }, - senderWalletAddress, - shouldMintTokens: true, - tokenMetadata: { - meem_metadata_type: 'Meem_AgreementRoleToken', - meem_metadata_version: '20221116', - name: `${metadata.name} Admin Role`, - description: `Admin role for the ${metadata.name} agreement.`, - external_url: '' - } - }) - - adminRoleContractTxIds = createAdminRoleResult - - setAdminRoleTxId = await services.ethers.queueTransaction({ - chainId, - functionSignature: 'setAdminContract(address)', - contractTxId: deployContractTxId, - inputValues: { - newAdminContractTxId: adminRoleContractTxIds.deployContractTxId - } - }) - } - - return { - deployContractTxId, - cutTxId, - mintTxId, - adminRoleDeployContractTxId: adminRoleContractTxIds?.deployContractTxId, - adminRoleCutTxId: adminRoleContractTxIds?.cutTxId, - adminRoleMintTxId: adminRoleContractTxIds?.mintTxId, - setAdminRoleTxId - } - } - public static async prepareInitValues( data: Omit< MeemAPI.v1.ReInitializeAgreement.IRequestBody, @@ -570,16 +266,16 @@ export default class AgreementService { throw new Error('INVALID_METADATA') } - const contractMetadataValidator = new Validator(metadata) - const contractMetadataValidatorResult = - contractMetadataValidator.validate(metadata) + // const contractMetadataValidator = new Validator(metadata) + // const contractMetadataValidatorResult = + // contractMetadataValidator.validate(metadata) - if (!contractMetadataValidatorResult.valid) { - log.crit( - contractMetadataValidatorResult.errors.map((e: any) => e.message) - ) - throw new Error('INVALID_METADATA') - } + // if (!contractMetadataValidatorResult.valid) { + // log.crit( + // contractMetadataValidatorResult.errors.map((e: any) => e.message) + // ) + // throw new Error('INVALID_METADATA') + // } const { provider, wallet } = await services.ethers.getProvider({ chainId @@ -809,18 +505,18 @@ export default class AgreementService { throw new Error('INVALID_METADATA') } - const validator = new Validator({ - meem_metadata_type: agreementRoleId - ? 'Meem_AgreementRoleToken' - : 'Meem_AgreementToken', - meem_metadata_version: token.metadata.meem_metadata_version - }) - const validatorResult = validator.validate(token.metadata) + // const validator = new Validator({ + // meem_metadata_type: agreementRoleId + // ? 'Meem_AgreementRoleToken' + // : 'Meem_AgreementToken', + // meem_metadata_version: token.metadata.meem_metadata_version + // }) + // const validatorResult = validator.validate(token.metadata) - if (!validatorResult.valid) { - log.crit(validatorResult.errors.map((e: any) => e.message)) - throw new Error('INVALID_METADATA') - } + // if (!validatorResult.valid) { + // log.crit(validatorResult.errors.map((e: any) => e.message)) + // throw new Error('INVALID_METADATA') + // } toAddresses.push(token.to) @@ -851,104 +547,76 @@ export default class AgreementService { log.debug('Bulk Minting w/ params', { bulkParams }) - // const mintTx = await services.ethers.runTransaction({ - // chainId: agreement.chainId, - // fn: contract.bulkMint.bind(contract), - // params: mintParams, - // gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT) - // }) - - const chainId = agreement.chainId - - const agreementContract = await services.agreement.getAgreementContract({ - chainId, - address: ethers.constants.AddressZero - }) - let txId: string | undefined - if (agreement.isOnChain) { - txId = await services.ethers.queueTransaction({ - chainId, - functionSignature: - agreementContract.interface.functions[ - 'bulkMint((address,string,uint8)[])' - ].format(), - contractAddress: agreementRole?.address ?? agreement.address, - inputValues: { - bulkParams - } - }) - } else { - let [tokenId, wallets] = await Promise.all([ - agreementRole - ? orm.models.AgreementRoleToken.count({ - where: { - AgreementId: agreementRole.id - } - }) - : orm.models.AgreementToken.count({ - where: { - AgreementId: agreement.id - } - }), - orm.models.Wallet.findAll({ - where: { - address: { - [Op.in]: toAddresses + let [tokenId, wallets] = await Promise.all([ + agreementRole + ? orm.models.AgreementRoleToken.count({ + where: { + AgreementId: agreementRole.id } + }) + : orm.models.AgreementToken.count({ + where: { + AgreementId: agreement.id + } + }), + orm.models.Wallet.findAll({ + where: { + address: { + [Op.in]: toAddresses } - }) - ]) - - const missingWalletAddresses = toAddresses.filter(a => { - const foundWallet = wallets.find(w => w.address === a) - if (foundWallet) { - return false } - - return true }) + ]) - if (missingWalletAddresses.length > 0) { - await orm.models.Wallet.bulkCreate( - missingWalletAddresses.map(a => ({ address: a })) - ) - - wallets = await orm.models.Wallet.findAll({ - where: { - address: { - [Op.in]: toAddresses - } - } - }) + const missingWalletAddresses = toAddresses.filter(a => { + const foundWallet = wallets.find(w => w.address === a) + if (foundWallet) { + return false } - const now = new Date() - const insertData = builtData.map(item => { - const itemId = tokenId + 1 - tokenId++ - const wallet = wallets.find(w => w.address === item.to) - if (!wallet) { - log.crit('Wallet not found', { item }) - } - return { - id: uuidv4(), - tokenId: services.web3.toBigNumber(itemId), - tokenURI: item.ipfs ?? '', - mintedAt: now, - metadata: item.metadata, - mintedBy, - AgreementId: agreement.id, - AgreementRoleId: agreementRole?.id, - OwnerId: wallet?.id + return true + }) + + if (missingWalletAddresses.length > 0) { + await orm.models.Wallet.bulkCreate( + missingWalletAddresses.map(a => ({ address: a })) + ) + + wallets = await orm.models.Wallet.findAll({ + where: { + address: { + [Op.in]: toAddresses + } } }) - if (agreementRole) { - await orm.models.AgreementRoleToken.bulkCreate(insertData) - } else { - await orm.models.AgreementToken.bulkCreate(insertData) + } + + const now = new Date() + const insertData = builtData.map(item => { + const itemId = tokenId + 1 + tokenId++ + const wallet = wallets.find(w => w.address === item.to) + if (!wallet) { + log.crit('Wallet not found', { item }) } + return { + id: uuidv4(), + tokenId: services.web3.toBigNumber(itemId), + tokenURI: item.ipfs ?? '', + mintedAt: now, + metadata: item.metadata, + mintedBy, + AgreementId: agreement.id, + AgreementRoleId: agreementRole?.id, + OwnerId: wallet?.id + } + }) + if (agreementRole) { + await orm.models.AgreementRoleToken.bulkCreate(insertData) + } else { + await orm.models.AgreementToken.bulkCreate(insertData) } return { txId } @@ -992,13 +660,6 @@ export default class AgreementService { log.debug('Bulk burning tokens', { tokenIds }) - const chainId = agreement.chainId - - const agreementContract = await services.agreement.getAgreementContract({ - chainId, - address: ethers.constants.AddressZero - }) - let txId: string | undefined if (agreementRole && !agreementRole.isOnChain) { @@ -1019,100 +680,11 @@ export default class AgreementService { } } }) - } else { - txId = await services.ethers.queueTransaction({ - chainId, - functionSignature: - agreementContract.interface.functions['bulkBurn(uint256[])'].format(), - contractAddress: agreementRole?.address ?? agreement.address, - inputValues: { - tokenIds: tokenIds.map(t => ethers.BigNumber.from(t).toHexString()) - } - }) } return { txId } } - // Adapted from https://forum.openzeppelin.com/t/creating-gnosis-safes-via-the-api/12031/2 - // Gnosis safe deployments / abi: https://github.com/safe-global/safe-deployments/blob/main/src/assets/v1.3.0/gnosis_safe.json - // Gnosis proxy factory deployments / abi: https://github.com/safe-global/safe-deployments/blob/main/src/assets/v1.3.0/proxy_factory.json - public static async createAgreementSafe( - options: MeemAPI.v1.CreateAgreementSafe.IRequestBody & { - agreementId: string - senderWalletAddress: string - } - ) { - const { agreementId, safeOwners, senderWalletAddress, chainId } = options - const [agreement, senderWallet] = await Promise.all([ - orm.models.Agreement.findOne({ - where: { - id: agreementId - } - }), - orm.models.Wallet.findByAddress(senderWalletAddress) - ]) - - if (!senderWallet) { - throw new Error('WALLET_NOT_FOUND') - } - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - if (agreement.gnosisSafeAddress) { - throw new Error('CLUB_SAFE_ALREADY_EXISTS') - } - - const isAdmin = await agreement.isAdmin(senderWalletAddress) - - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } - - // This is one of the topics emitted when a gnosis safe is created - // const topic = - // '0x141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a8' - - const threshold = options.threshold ?? 1 - - const gnosisInterface = new ethers.utils.Interface(GnosisSafeABI) - const safeSetupData = gnosisInterface.encodeFunctionData('setup', [ - // Owners - safeOwners, - // Threshold of signers - threshold, - // to - '0x0000000000000000000000000000000000000000', - // data - '0x', - // Fallback handler - config.GNOSIS_DEFAULT_CALLBACK_HANDLER, - // Payment token - '0x0000000000000000000000000000000000000000', - // Payment - '0', - // Payment receiver - '0x0000000000000000000000000000000000000000' - ]) - - const txId = await services.ethers.queueTransaction({ - eventName: MeemAPI.QueueEvent.DeploySafe, - agreementId: agreement.id, - chainId: chainId ?? agreement.chainId, - functionSignature: 'createProxy(address,bytes)', - contractAddress: config.GNOSIS_PROXY_CONTRACT_ADDRESS, - abi: GnosisSafeProxyABI, - inputValues: { - singleton: config.GNOSIS_MASTER_CONTRACT_ADDRESS, - data: safeSetupData - } - }) - - return { txId } - } - public static async updateAgreement(options: { agreementId: string senderWalletAddress: string @@ -1156,188 +728,6 @@ export default class AgreementService { return agreement } - public static async setAgreemetAdminRole(options: { - agreementId: string - adminAgreementRoleId: string - senderWalletAddress: string - }) { - const { agreementId, adminAgreementRoleId, senderWalletAddress } = options - const [agreement, agreementRole, senderWallet] = await Promise.all([ - orm.models.Agreement.findOne({ - where: { - id: agreementId - } - }), - orm.models.AgreementRole.findOne({ - where: { - id: adminAgreementRoleId - } - }), - orm.models.Wallet.findByAddress(senderWalletAddress) - ]) - - if (!senderWallet) { - throw new Error('WALLET_NOT_FOUND') - } - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - if (!agreementRole) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - const isAdmin = await agreement.isAdmin(senderWalletAddress) - - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } - - const txId = await services.ethers.queueTransaction({ - chainId: agreement.chainId, - functionSignature: 'setAdminContract(address)', - contractAddress: agreement.address, - inputValues: { - newAdminContract: agreementRole.address - } - }) - - return { txId } - } - - public static async upgradeAgreement( - options: MeemAPI.v1.UpgradeAgreement.IRequestBody & { - agreementId: string - agreementRoleId?: string - senderWalletAddress: string - } - ) { - const { agreementId, agreementRoleId, senderWalletAddress } = options - const [agreementOrRole, senderWallet] = await Promise.all([ - agreementRoleId - ? orm.models.AgreementRole.findOne({ - where: { - id: agreementRoleId - }, - include: [orm.models.Wallet] - }) - : orm.models.Agreement.findOne({ - where: { - id: agreementId - }, - include: [orm.models.Wallet] - }), - - orm.models.Wallet.findByAddress(senderWalletAddress) - ]) - - if (!agreementOrRole) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - if (!senderWallet) { - throw new Error('WALLET_NOT_FOUND') - } - - const [bundle, isAdmin] = await Promise.all([ - orm.models.Bundle.findOne({ - where: { - id: config.MEEM_BUNDLE_ID - }, - include: [ - { - model: orm.models.BundleContract, - include: [ - { - model: orm.models.Contract, - include: [ - { - model: orm.models.ContractInstance, - where: { - chainId: agreementOrRole.chainId - } - } - ] - } - ] - } - ] - }), - agreementOrRole.isAdmin(senderWalletAddress) - ]) - - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } - - const fromVersion: IFacetVersion[] = [] - const toVersion: IFacetVersion[] = [] - - const { wallet } = await services.ethers.getProvider({ - chainId: agreementOrRole.chainId - }) - - const diamond = new ethers.Contract( - agreementOrRole.address, - diamondABI, - wallet - ) - - const facets = await diamond.facets() - facets.forEach((facet: { target: string; selectors: string[] }) => { - fromVersion.push({ - address: facet.target, - functionSelectors: facet.selectors - }) - }) - - bundle?.BundleContracts?.forEach(bc => { - if ( - !bc.Contract?.ContractInstances || - !bc.Contract?.ContractInstances[0] - ) { - throw new Error('CONTRACT_INSTANCE_NOT_FOUND') - } - toVersion.push({ - address: bc.Contract.ContractInstances[0].address, - functionSelectors: bc.functionSelectors - }) - }) - // const tx = await upgrade({ - // signer, - // proxyContractAddress: agreement.address, - // toVersion, - // fromVersion, - // overrides: { - // gasPrice: services.web3.gweiToWei(recommendedGwei).toNumber() - // } - // }) - const cuts = getCuts({ - proxyContractAddress: agreementOrRole.address, - toVersion, - fromVersion - }) - - if (cuts.length === 0) { - throw new Error('CONTRACT_ALREADY_UP_TO_DATE') - } - - const txId = await services.ethers.queueTransaction({ - chainId: agreementOrRole.chainId, - functionSignature: - 'diamondCut((address, uint8, bytes4[])[], address, bytes)', - contractAddress: agreementOrRole.address, - inputValues: { - _diamondCut: cuts, - _init: ethers.constants.AddressZero, - _calldata: '0x' - } - }) - - return { txId } - } - public static async getAgreementRoles(options: { agreementId: string agreementRoleId?: string @@ -1368,20 +758,6 @@ export default class AgreementService { const roles: IAgreementRole[] = await Promise.all( agreementRoles.map(async mcRole => { const role: any = mcRole.toJSON() - - // if (mcRole.guildRoleId) { - // const guildRoleResponse = await guildRole.get(mcRole.guildRoleId) - - // role.guildRole = guildRoleResponse - - // if (agreementRoleId) { - // role.members = await Promise.all( - // (role.guildRole?.members ?? []).map((m: string) => - // services.meemId.getMeemIdentityForAddress(m) - // ) - // ) - // } - // } return role }) ) @@ -1389,179 +765,93 @@ export default class AgreementService { return roles } - // public static async getUserAgreementRolesAccess(options: { - // agreementId: string - // walletAddress: string - // agreementRoleId?: string - // }): Promise<{ - // hasRolesAccess: boolean - // roles: IAgreementRole[] - // }> { - // const { agreementId, walletAddress, agreementRoleId } = options - // const meemIdentity = await orm.models.User.findOne({ - // include: [ - // { - // model: orm.models.Wallet, - // where: { - // address: walletAddress - // }, - // attributes: ['id', 'address', 'ens'], - // through: { - // attributes: [] - // } - // }, - // { - // model: orm.models.Wallet, - // as: 'DefaultWallet', - // attributes: ['id', 'address', 'ens'] - // } - // ] - // }) - // if (!meemIdentity) { - // log.crit('MeemIdentity not found') - // throw new Error('SERVER_ERROR') - // } - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild - // }, - // { - // model: orm.models.AgreementRole, - // ...(agreementRoleId && { - // where: { - // id: agreementRoleId - // } - // }), - // include: [ - // { - // model: orm.models.RolePermission, - // attributes: ['id'], - // through: { - // attributes: [] - // } - // } - // ] - // } - // ] - // }) - // const agreementRoles = agreement?.AgreementRoles ?? [] - // if (!agreement || !agreement.AgreementGuild) { - // throw new Error('SERVER_ERROR') - // } - // const guildUserMembershipResponse = await guild.getUserMemberships( - // agreement.AgreementGuild.guildId, - // walletAddress - // ) - // const rolesIdsWithAccess = guildUserMembershipResponse - // .filter(r => r.access) - // .map(r => r.roleId) - // if (rolesIdsWithAccess.length < 1) { - // return { - // hasRolesAccess: false, - // roles: [] - // } - // } - // let roles: IAgreementRole[] = await Promise.all( - // agreementRoles.map(async mcRole => { - // const role: any = mcRole.toJSON() - // return role - // }) - // ) - // roles = roles.filter((r: IAgreementRole) => { - // if (!r.guildRoleId && !r.guildRole) { - // return false - // } - // return r.guildRole.members.includes(walletAddress) - // }) - // return { - // hasRolesAccess: true, - // roles - // } - // } - - public static async updateagreementOrRoleAdmins(options: { - agreementId: string - admins: string[] - senderWallet: Wallet - }) { - const { agreementId, admins, senderWallet } = options + public static async acceptInvite(options: { code: string; wallet: Wallet }) { + const { code, wallet } = options + if (!code) { + throw new Error('MISSING_PARAMETERS') + } - const agreement = await orm.models.Agreement.findOne({ + const invite = await orm.models.Invite.findOne({ where: { - id: agreementId + code }, - include: [ - { - model: orm.models.AgreementRole - } - ] + include: [orm.models.Agreement] }) - if (!agreement) { - throw new Error('SERVER_ERROR') + if (!invite || !invite.Agreement) { + throw new Error('INVITE_NOT_FOUND') } - const isAdmin = await agreement.isAdmin(senderWallet.address) + const agreementId = invite.AgreementId + const agreement = invite.Agreement - if (!isAdmin) { - throw new Error('NOT_AUTHORIZED') - } + const result = await Promise.all([ + orm.models.AgreementToken.findOne({ + where: { + AgreementId: agreementId, + OwnerId: wallet.id + } + }), + orm.models.AgreementToken.count({ + where: { + AgreementId: agreementId + } + }), + orm.models.AgreementRole.findOne({ + where: { + AgreementId: agreementId, + isAdminRole: true + } + }), + orm.models.AgreementRole.count({ + where: { + AgreementId: agreementId, + isAdminRole: true + } + }) + ]) - const { wallet } = await services.ethers.getProvider({ - chainId: agreement.chainId - }) + let agreementToken = result[0] + const tokenId = result[1] + const agreementRole = result[2] + const agreementRoleTokenId = result[3] - // TODO: Allow removal of Meem address - const cleanAdmins = _.uniqBy( - [...admins, wallet.address.toLowerCase()], - a => a && a.toLowerCase() - ).map(a => ({ - role: config.ADMIN_ROLE, - user: a, - hasRole: true - })) + if (!agreementToken) { + const createResult = await Promise.all([ + orm.models.AgreementToken.create({ + tokenId: services.web3.toBigNumber(tokenId + 1).toHexString(), + tokenURI: '', + AgreementId: agreementId, + mintedAt: new Date(), + OwnerId: wallet.id + }), + invite.destroy() + ]) - if (cleanAdmins.length > 0) { - throw new Error('NO_ADMIN_CHANGES') + agreementToken = createResult[0] } + let agreementRoleToken = agreementRole + ? await orm.models.AgreementRoleToken.findOne({ + where: { + AgreementRoleId: agreementRole.id, + OwnerId: wallet.id + } + }) + : null - const chainId = agreement.chainId - - const agreementContract = await services.agreement.getAgreementContract({ - chainId, - address: ethers.constants.AddressZero - }) - - const txId = await services.ethers.queueTransaction({ - chainId, - functionSignature: - agreementContract.interface.functions[ - 'bulkSetRoles((address,bytes32,bool)[])' - ].format(), - contractAddress: agreement.address, - inputValues: { - items: cleanAdmins - } - }) - - return { txId } - } - - public static async getAgreementContract(options: { - address: string - chainId: number - }): Promise { - const { address, chainId } = options - const { wallet } = await services.ethers.getProvider({ - chainId - }) - - const contract = Mycontract__factory.connect(address, wallet) + if (!agreementRoleToken && agreementRole) { + agreementRoleToken = await orm.models.AgreementRoleToken.create({ + tokenId: services.web3 + .toBigNumber(agreementRoleTokenId + 1) + .toHexString(), + tokenURI: '', + AgreementId: agreementId, + AgreementRoleId: agreementRole.id, + mintedAt: new Date(), + OwnerId: wallet.id + }) + } - return contract + return { agreement, agreementToken, agreementRole, agreementRoleToken } } } diff --git a/src/services/Aws.ts b/src/services/Aws.ts new file mode 100644 index 00000000..b9b51aca --- /dev/null +++ b/src/services/Aws.ts @@ -0,0 +1,53 @@ +import AWS from 'aws-sdk' +import type { SendEmailRequest } from 'aws-sdk/clients/ses' +import { PromiseResult } from 'aws-sdk/lib/request' + +export default class AwsService { + public static async sendEmail(options: { + to: string[] + from?: string + subject: string + body: string + }): Promise> { + const { to, from, subject, body } = options + if (config.TESTING) { + // @ts-ignore + return + } + + const ses = new AWS.SES({ + region: 'us-east-1', + + credentials: { + accessKeyId: config.APP_AWS_ACCESS_KEY_ID, + secretAccessKey: config.APP_AWS_SECRET_ACCESS_KEY + } + }) + const params: SendEmailRequest = { + Destination: { + ToAddresses: to + }, + Message: { + Body: { + Html: { + Charset: 'UTF-8', + // Data: transactionalTemplate({ + // subject, + // inboxPreview: "Here's an inbox preview of the message." + // }) + Data: body + } + }, + Subject: { + Charset: 'UTF-8', + Data: subject + } + }, + Source: from ?? 'Meem ' + } + + const result = await ses.sendEmail(params).promise() + + return result + } +} diff --git a/src/services/ContractEvents.ts b/src/services/ContractEvents.ts deleted file mode 100644 index b3c833ec..00000000 --- a/src/services/ContractEvents.ts +++ /dev/null @@ -1,1533 +0,0 @@ -import { diamondABI } from '@meemproject/meem-contracts' -import { MeemMetadataLike, Validator } from '@meemproject/metadata' -import { Analytics } from '@segment/analytics-node' -import { ethers } from 'ethers' -// import { IGunChainReference } from 'gun/types/chain' -import { DateTime } from 'luxon' -import { Op } from 'sequelize' -import { v4 as uuidv4 } from 'uuid' -// import meemABI from '../abis/Meem.json' -// import { wait } from '../lib/utils' -import Agreement from '../models/Agreement' -import AgreementRole from '../models/AgreementRole' -import AgreementRoleToken from '../models/AgreementRoleToken' -import AgreementToken from '../models/AgreementToken' -import Wallet from '../models/Wallet' -import { - ContractInfoStruct, - MeemPermissionStruct, - MeemSplitsSetEvent, - MeemTransferEvent, - SplitStructOutput, - Mycontract, - MeemAdminContractSetEvent, - MeemRoleRevokedEvent, - MeemRoleGrantedEvent -} from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' -import { IMeemMetadataLike } from '../types/shared/meem.shared' - -const analytics = new Analytics({ writeKey: config.SEGMENT_WRITE_KEY }) - -export default class ContractEvent { - // TODO: sync reactions? - // public static async meemSyncReactions() { - // log.debug('Syncing reactions...') - // const provider = await services.ethers.getProvider() - - // const genericAgreement = new Contract(MeemAPI.zeroAddress, meemABI) - // // ) as unknown as AgreementType - - // const topics = { - // MeemTokenReactionAdded: `MeemTokenReactionAdded(uint256,address,string,uint256)`, - // MeemTokenReactionRemoved: `MeemTokenReactionRemoved(uint256,address,string,uint256)` - // } - - // const logs = await provider.getLogs({ - // fromBlock: 0, - // toBlock: 'latest', - // topics: [ - // [ - // utils.id(topics.MeemTokenReactionAdded), - // utils.id(topics.MeemTokenReactionRemoved) - // ] - // ] - // }) - - // log.debug(`Syncing ${logs.length} reaction added/remvoed events`) - - // for (let i = 0; i < logs.length; i += 1) { - // try { - // const parsedLog = genericAgreement.interface.parseLog({ - // data: logs[i].data, - // topics: logs[i].topics - // }) - - // // eslint-disable-next-line no-await-in-loop - // const block = await provider.getBlock(logs[i].blockHash) - - // if (parsedLog.topic === topics.MeemTokenReactionAdded) { - // const eventData = - // parsedLog.args as unknown as MeemTokenReactionAddedEventObject - // // eslint-disable-next-line no-await-in-loop - // await this.meemHandleTokenReactionAdded({ - // address: logs[i].address, - // transactionTimestamp: - // block?.timestamp || DateTime.now().toSeconds(), - // eventData - // }) - // } else if (parsedLog.topic === topics.MeemTokenReactionRemoved) { - // const eventData = - // parsedLog.args as unknown as MeemTokenReactionRemovedEventObject - // // eslint-disable-next-line no-await-in-loop - // await this.meemHandleTokenReactionRemoved({ - // address: logs[i].address, - // eventData - // }) - // } - // log.debug(logs[i].blockNumber) - // } catch (e) { - // log.crit(e) - // } - // } - // } - - // public static async agreementSync(specificEvents?: Log[]) { - // log.debug('Syncing Agreements...') - // const provider = await services.ethers.getProvider() - // const logs = - // specificEvents ?? - // (await provider.getLogs({ - // fromBlock: 0, - // toBlock: 'latest', - // topics: [[utils.id('AgreementInitialized(address)')]] - // })) - - // log.debug(`Syncing ${logs.length} initialized events`) - - // const failedEvents: Log[] = [] - - // for (let i = 0; i < logs.length; i += 1) { - // try { - // log.debug(`Syncing ${i + 1} / ${logs.length} events`) - - // // eslint-disable-next-line no-await-in-loop - // await this.meemHandleContractInitialized({ - // address: logs[i].address - // }) - // // eslint-disable-next-line no-await-in-loop - // await wait(500) - // } catch (e) { - // failedEvents.push(logs[i]) - // log.crit(e) - // log.debug(logs[i]) - // } - // } - - // if (failedEvents.length > 0) { - // log.debug(`Completed with ${failedEvents.length} failed events`) - // // log.debug(`Retrying ${failedEvents.length} events`) - // // await this.agreementSync(failedEvents) - // } - // } - - // public static async meemSync(specificEvents?: Log[]) { - // log.debug('Syncing meems...') - // const provider = await services.ethers.getProvider() - - // const genericAgreement = new Contract( - // MeemAPI.zeroAddress, - // meemABI - // ) as unknown as Mycontract - - // const logs = - // specificEvents ?? - // (await provider.getLogs({ - // fromBlock: 0, - // toBlock: 'latest', - // topics: [[utils.id('MeemTransfer(address,address,uint256)')]] - // })) - - // const failedEvents: Log[] = [] - - // for (let i = 0; i < logs.length; i += 1) { - // try { - // log.debug(`Syncing ${i + 1} / ${logs.length} events`) - - // const parsedLog = genericAgreement.interface.parseLog({ - // data: logs[i].data, - // topics: logs[i].topics - // }) - - // const eventData = parsedLog.args as MeemTransferEvent['args'] - - // // eslint-disable-next-line no-await-in-loop - // const block = await provider.getBlock(logs[i].blockHash) - // // eslint-disable-next-line no-await-in-loop - // await this.meemHandleTransfer({ - // address: logs[i].address, - // transactionHash: logs[i].transactionHash, - // transactionTimestamp: block.timestamp, - // eventData - // }) - // // eslint-disable-next-line no-await-in-loop - // await wait(500) - // } catch (e) { - // failedEvents.push(logs[i]) - // log.crit(e) - // log.debug(logs[i]) - // } - // } - - // if (failedEvents.length > 0) { - // log.debug(`Completed with ${failedEvents.length} failed events`) - // // log.debug(`Retrying ${failedEvents.length} events`) - // // await this.meemSync(failedEvents) - // } - // } - - public static async meemHandleContractInitialized(args: { - address: string - chainId: number - transactionHash?: string - }): Promise { - const { address, chainId, transactionHash } = args - const agreementOrRoleContract = (await services.meem.getAgreement({ - address, - chainId - })) as unknown as Mycontract - - let contractInfo: ContractInfoStruct - - try { - contractInfo = await agreementOrRoleContract.getContractInfo() - } catch (e) { - log.debug(e) - log.debug('getContractInfo function not available. Skipping') - return null - } - - const { wallet } = await services.ethers.getProvider({ chainId }) - - const instance = new ethers.Contract(address, diamondABI, wallet) - - const [metadata, ownerAddress] = await Promise.all([ - services.meem.getErc721Metadata( - contractInfo.contractURI as string - ) as unknown as IMeemMetadataLike, - instance.owner() - ]) - - if (metadata.meem_metadata_type) { - // Don't index contract if not a valid meem_contract_type - const contractMetadataValidator = new Validator(metadata) - const contractMetadataValidatorResult = - contractMetadataValidator.validate(metadata) - - if (!contractMetadataValidatorResult.valid) { - log.crit( - contractMetadataValidatorResult.errors.map((e: any) => e.message) - ) - return null - } - } else { - log.crit('Invalid metadata.') - return null - } - - const isRoleAgreement = - metadata.meem_metadata_type === 'Meem_AgreementRoleContract' - - const existingAgreementOrRole = isRoleAgreement - ? await orm.models.AgreementRole.findOne({ - where: { - address, - chainId - } - }) - : await orm.models.Agreement.findOne({ - where: { - address, - chainId - } - }) - - let roleParentAgreementId - - if (isRoleAgreement && metadata.meem_agreement_address) { - const agreement = await orm.models.Agreement.findOne({ - where: { - address: metadata.meem_agreement_address, - chainId - } - }) - roleParentAgreementId = agreement?.id - } - - let slug = existingAgreementOrRole?.slug ?? uuidv4() - - if (!existingAgreementOrRole || !slug) { - try { - slug = await services.agreement.generateSlug({ - baseSlug: contractInfo.name as string, - agreementId: roleParentAgreementId, - chainId - }) - } catch (e) { - log.crit('Something went wrong while creating slug', e) - } - } - - const mintPermissions = contractInfo.mintPermissions.map(p => ({ - permission: p.permission, - addresses: p.addresses, - numTokens: ethers.BigNumber.from(p.numTokens).toHexString(), - mintEndTimestamp: ethers.BigNumber.from(p.mintEndTimestamp).toNumber(), - mintStartTimestamp: ethers.BigNumber.from( - p.mintStartTimestamp - ).toNumber(), - costWei: ethers.BigNumber.from(p.costWei).toHexString(), - merkleRoot: p.merkleRoot - })) - - // Merge addresses by merkle root if we can - if (existingAgreementOrRole) { - mintPermissions.forEach(mp => { - const existingMintPermission = - existingAgreementOrRole.mintPermissions.find( - emp => emp.merkleRoot === mp.merkleRoot - ) - if (existingMintPermission) { - // eslint-disable-next-line no-param-reassign - mp.addresses = existingMintPermission.addresses - } - }) - } - - const [transaction, owner] = await Promise.all([ - orm.models.Transaction.findOne({ - where: { - hash: transactionHash - } - }), - orm.models.Wallet.findByAddress(ownerAddress) - ]) - - const agreementOrRoleData = { - slug, - symbol: contractInfo.symbol, - name: contractInfo.name, - contractURI: contractInfo.contractURI, - address, - metadata, - maxSupply: contractInfo.maxSupply, - mintPermissions, - splits: contractInfo.splits.map(s => ({ - toAddress: s.toAddress, - amount: ethers.BigNumber.from(s.amount).toNumber(), - lockedBy: s.lockedBy - })), - isTransferrable: !contractInfo.isTransferLocked, - chainId, - OwnerId: owner?.id, - TransactionId: transaction?.id - } - - const t = await orm.sequelize.transaction() - - let agreementOrRole: Agreement | AgreementRole - - if (!existingAgreementOrRole) { - if (isRoleAgreement) { - agreementOrRole = await orm.models.AgreementRole.create({ - ...agreementOrRoleData, - AgreementId: roleParentAgreementId ?? null - }) - } else { - agreementOrRole = await orm.models.Agreement.create(agreementOrRoleData) - analytics.track({ - ...(owner?.UserId - ? { userId: owner.UserId } - : { anonymousId: uuidv4() }), - event: 'Community Created', - properties: { - communityId: agreementOrRole.id, - communityName: agreementOrRole.name - } - }) - } - } else { - agreementOrRole = await existingAgreementOrRole.update( - agreementOrRoleData - ) - } - - const adminRole = await agreementOrRoleContract.ADMIN_ROLE() - - let admins: string[] = [] - - try { - admins = await agreementOrRoleContract.getRoles(adminRole) - } catch (e) { - log.error('getRoles function not available') - } - - const [adminWallets, currentAdminsToRemove] = await Promise.all([ - orm.models.Wallet.findAllBy({ - addresses: admins, - ...(isRoleAgreement - ? { agreementRoleId: agreementOrRole.id } - : { agreementId: agreementOrRole.id }) - }), - isRoleAgreement - ? orm.models.AgreementRoleWallet.findAll({ - where: { - role: adminRole - }, - include: [ - { - model: orm.models.AgreementRole, - where: orm.sequelize.where( - orm.sequelize.fn( - 'lower', - orm.sequelize.col('AgreementRole.address') - ), - agreementOrRole.address.toLowerCase() - ) - }, - { - model: orm.models.Wallet, - where: orm.sequelize.where( - orm.sequelize.fn( - 'lower', - orm.sequelize.col('Wallet.address') - ), - { [Op.notIn]: admins.map(w => w.toLowerCase()) } - ) - } - ] - }) - : orm.models.AgreementWallet.findAll({ - where: { - role: adminRole - }, - include: [ - { - model: orm.models.Agreement, - where: orm.sequelize.where( - orm.sequelize.fn( - 'lower', - orm.sequelize.col('Agreement.address') - ), - agreementOrRole.address.toLowerCase() - ) - }, - { - model: orm.models.Wallet, - where: orm.sequelize.where( - orm.sequelize.fn( - 'lower', - orm.sequelize.col('Wallet.address') - ), - { [Op.notIn]: admins.map(w => w.toLowerCase()) } - ) - } - ] - }) - ]) - - const walletsData: { - id: string - address: string - isDefault: boolean - }[] = [] - - const walletContractsData: { - AgreementId?: string - AgreementRoleId?: string - WalletId: string - role: string - }[] = [] - - admins.forEach(adminAddress => { - const adminWallet = adminWallets.find( - aw => aw.address.toLowerCase() === adminAddress.toLowerCase() - ) - - const agreementWallet = - adminWallet?.AgreementWallets && adminWallet?.AgreementWallets[0] - - if (!adminWallet) { - // Create the wallet - const walletId = uuidv4() - walletsData.push({ - id: walletId, - address: adminAddress.toLowerCase(), - isDefault: true - }) - - walletContractsData.push({ - ...(isRoleAgreement - ? { AgreementRoleId: agreementOrRole.id } - : { AgreementId: agreementOrRole.id }), - WalletId: walletId, - role: adminRole - }) - } else if (adminWallet && !agreementWallet) { - // Create the association - walletContractsData.push({ - ...(isRoleAgreement - ? { AgreementRoleId: agreementOrRole.id } - : { AgreementId: agreementOrRole.id }), - WalletId: adminWallet.id, - role: adminRole - }) - } - }) - - log.debug(`Syncing Agreement data: ${agreementOrRole.address}`) - - const promises: Promise[] = [] - if (currentAdminsToRemove.length > 0) { - promises.push( - isRoleAgreement - ? orm.models.AgreementRoleWallet.destroy({ - where: { - id: currentAdminsToRemove.map(a => a.id) - }, - transaction: t - }) - : orm.models.AgreementWallet.destroy({ - where: { - id: currentAdminsToRemove.map(a => a.id) - }, - transaction: t - }) - ) - } - if (walletsData.length > 0) { - promises.push( - orm.models.Wallet.bulkCreate(walletsData, { - transaction: t - }) - ) - } - - await Promise.all(promises) - - if (walletContractsData.length > 0) { - if (isRoleAgreement) { - await orm.models.AgreementRoleWallet.bulkCreate(walletContractsData, { - transaction: t - }) - } else { - await orm.models.AgreementWallet.bulkCreate(walletContractsData, { - transaction: t - }) - } - } - - await t.commit() - - // Update ENS - if (!isRoleAgreement) { - await services.meemId.updateENS(agreementOrRole as Agreement) - } - - return agreementOrRole - } - - public static async meemHandleSplitsSet(_args: { - address: string - eventData: MeemSplitsSetEvent['args'] - chainId: number - }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { splits } = args.eventData - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }) - // if (meem) { - // const prop = - // propertyType === MeemAPI.PropertyType.Meem - // ? meem.Properties - // : meem.ChildProperties - // if (!prop) { - // log.crit('Invalid propertyType') - // return - // } - // prop.splits = this.meemSplitsDataToModelData(splits) - // await prop.save() - // } - } - - // TODO: update to handle agreement and agreement roles - public static async meemHandleAdminContractSet(args: { - address: string - eventData: MeemAdminContractSetEvent['args'] - chainId: number - }) { - const { address, eventData, chainId } = args - let agreement = await orm.models.Agreement.findByAddress(address) - - if (!agreement) { - agreement = (await this.meemHandleContractInitialized({ - address, - chainId - })) as Agreement - } - - if (!agreement) { - log.crit('Unable to find or create Agreement') - return - } - - agreement.adminContractAddress = eventData.adminContract - - await agreement.save() - - let newAdminAgreementRole = await orm.models.AgreementRole.findOne({ - where: { - address: eventData.adminContract, - chainId - } - }) - - const existingAdminAgreementRole = await orm.models.AgreementRole.findOne({ - where: { - AgreementId: agreement.id, - isAdminRole: true - } - }) - - if (!newAdminAgreementRole) { - newAdminAgreementRole = (await this.meemHandleContractInitialized({ - address, - chainId - })) as AgreementRole - } - - if (!newAdminAgreementRole) { - log.crit('Unable to find or create AgreementRole') - return - } - - const t = await orm.sequelize.transaction() - const promises: Promise[] = [] - - newAdminAgreementRole.isAdminRole = true - promises.push(newAdminAgreementRole.save({ transaction: t })) - - if (existingAdminAgreementRole) { - existingAdminAgreementRole.isAdminRole = false - promises.push(existingAdminAgreementRole.save({ transaction: t })) - } - - await Promise.all(promises) - await t.commit() - } - - // public static async meemHandlePropertiesSet(args: { - // address: string - // eventData: MeemPropertiesSetEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { propertyType, props } = args.eventData - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // }, - // { - // model: orm.models.MeemProperties, - // as: 'Properties' - // }, - // { - // model: orm.models.MeemProperties, - // as: 'ChildProperties' - // } - // ] - // }) - - // if (meem && propertyType === MeemAPI.PropertyType.Meem) { - // await meem.Properties?.update(this.meemPropertiesDataToModelData(props)) - // } else if (meem && propertyType === MeemAPI.PropertyType.Child) { - // await meem.ChildProperties?.update( - // this.meemPropertiesDataToModelData(props) - // ) - // } - // } - - // public static async meemHandlePermissionsSet(args: { - // address: string - // eventData: MeemPermissionsSetEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { propertyType, permissionType, permission } = args.eventData - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // }, - // { - // model: orm.models.MeemProperties, - // as: 'Properties' - // }, - // { - // model: orm.models.MeemProperties, - // as: 'ChildProperties' - // } - // ] - // }) - - // if (meem) { - // const prop = - // propertyType === MeemAPI.PropertyType.Meem - // ? meem.Properties - // : meem.ChildProperties - // if (!prop) { - // log.warn(`Missing MeemProperties for token: ${tokenId}`) - // return - // } - // switch (permissionType) { - // case MeemAPI.PermissionType.Copy: - // prop.copyPermissions = this.meemPermissionsDataToModelData(permission) - // break - - // case MeemAPI.PermissionType.Read: - // prop.readPermissions = this.meemPermissionsDataToModelData(permission) - // break - - // case MeemAPI.PermissionType.Remix: - // prop.remixPermissions = - // this.meemPermissionsDataToModelData(permission) - // break - - // default: - // break - // } - // await prop.save() - // } - // } - - // public static async meemHandleTokenClipped(args: { - // address: string - // transactionTimestamp: number - // eventData: MeemClippedEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { addy } = args.eventData - - // const [wallet, meem] = await Promise.all([ - // orm.models.Wallet.findByAddress(addy) as unknown as Wallet | null, - // orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }) - // ]) - - // const clipping = await orm.models.Clipping.findOne({ - // where: { - // address: addy, - // MeemIdentificationId: wallet?.MeemIdentificationId ?? null, - // MeemId: meem?.id ?? null - // } - // }) - - // if (clipping) { - // throw new Error('ALREADY_CLIPPED') - // } - - // await orm.models.Clipping.create({ - // address: addy, - // MeemIdentificationId: wallet?.MeemIdentificationId ?? null, - // MeemId: meem?.id ?? null, - // clippedAt: DateTime.fromSeconds(args.transactionTimestamp).toJSDate() - // }) - // } - - // public static async meemHandleTokenUnClipped(args: { - // address: string - // eventData: MeemUnClippedEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { addy } = args.eventData - - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }) - - // if (!meem) { - // throw new Error('MEEM_NOT_FOUND') - // } - - // await orm.models.Clipping.destroy({ - // where: { - // MeemId: meem.id, - // address: addy - // } - // }) - // } - - // public static async meemHandleTokenReactionAdded(args: { - // address: string - // transactionTimestamp: number - // eventData: MeemTokenReactionAddedEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { addy, reaction, newTotalReactions } = args.eventData - // log.debug(`Adding "${reaction}" reaction for ${addy} on token ${tokenId}`) - - // const [meem, wallet] = await Promise.all([ - // orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }), - // orm.models.Wallet.findByAddress(addy) - // ]) - - // if (!meem) { - // throw new Error('MEEM_NOT_FOUND') - // } - - // meem.reactionCounts[reaction] = newTotalReactions.toNumber() - // meem.changed('reactionCounts', true) - - // await meem.save() - - // const existingReaction = await orm.models.Reaction.findOne({ - // where: { - // address: addy, - // reaction, - // MeemId: meem.id - // } - // }) - - // if (existingReaction) { - // log.warn(`Address ${addy} Already reacted to meem: ${tokenId}`) - // return - // } - - // await orm.models.Reaction.create({ - // reaction, - // address: addy, - // MeemId: meem.id, - // MeemIdentification: wallet?.MeemIdentificationId ?? null, - // reactedAt: DateTime.fromSeconds(args.transactionTimestamp).toJSDate() - // }) - // } - - // public static async meemHandleTokenReactionRemoved(args: { - // address: string - // eventData: MeemTokenReactionRemovedEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { addy, reaction, newTotalReactions } = args.eventData - - // log.debug(`Removing "${reaction}" reaction for ${addy} on token ${tokenId}`) - - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }) - - // if (!meem) { - // throw new Error('MEEM_NOT_FOUND') - // } - - // meem.reactionCounts[reaction] = newTotalReactions.toNumber() - // meem.changed('reactionCounts', true) - - // await Promise.all([ - // orm.models.Reaction.destroy({ - // where: { - // address: addy, - // reaction, - // MeemId: meem.id - // } - // }), - // meem.save() - // ]) - // } - - // public static async meemHandleTokenReactionTypesSet(args: { - // address: string - // eventData: MeemTokenReactionTypesSetEventObject - // }) { - // const tokenId = args.eventData.tokenId.toHexString() - // const { reactionTypes } = args.eventData - - // log.debug(`Reaction types set for token ${tokenId}`) - - // const meem = await orm.models.AgreementToken.findOne({ - // where: { - // tokenId - // }, - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // address: args.address - // } - // } - // ] - // }) - - // if (!meem) { - // throw new Error('MEEM_NOT_FOUND') - // } - - // meem.reactionTypes = reactionTypes - // await meem.save() - // } - - public static async meemHandleRoleGranted(args: { - address: string - transactionHash: string - transactionTimestamp: number - eventData: MeemRoleGrantedEvent['args'] - chainId: number - }) { - const { chainId, address } = args - - const agreementOrRoleContract = - await services.agreement.getAgreementContract({ - address, - chainId - }) - - const contractURI = await agreementOrRoleContract.contractURI() - const metadata = (await services.meem.getErc721Metadata( - contractURI - )) as MeemMetadataLike - - // const adminRole = await agreementOrRoleContract.ADMIN_ROLE() - - const wallet = await orm.models.Wallet.findByAddress( - args.eventData.user - ) - - if (!wallet) { - throw new Error('WALLET_NOT_FOUND') - } - - if (metadata.meem_metadata_type === 'Meem_AgreementContract') { - const agreement = await orm.models.Agreement.findOne({ - where: { - address, - chainId: args.chainId - } - }) - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - await orm.models.AgreementWallet.create({ - AgreementId: agreement.id, - WalletId: wallet.id, - role: args.eventData.role - }) - } else if (metadata.meem_metadata_type === 'Meem_AgreementRoleContract') { - const agreementRole = await orm.models.AgreementRole.findOne({ - where: { - address, - chainId: args.chainId - } - }) - - if (!agreementRole) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - await orm.models.AgreementRoleWallet.create({ - AgreementId: agreementRole.Agreement.id, - AgreementRoleId: agreementRole.id, - WalletId: wallet.id, - role: args.eventData.role - }) - } - } - - public static async meemHandleRoleRevoked(args: { - address: string - transactionHash: string - transactionTimestamp: number - eventData: MeemRoleRevokedEvent['args'] - chainId: number - }) { - const { chainId, address } = args - - const agreementOrRoleContract = - await services.agreement.getAgreementContract({ - address, - chainId - }) - - const contractURI = await agreementOrRoleContract.contractURI() - const metadata = (await services.meem.getErc721Metadata( - contractURI - )) as MeemMetadataLike - - // const adminRole = await agreementOrRoleContract.ADMIN_ROLE() - - const wallet = await orm.models.Wallet.findByAddress( - args.eventData.user - ) - - if (!wallet) { - throw new Error('WALLET_NOT_FOUND') - } - - if (metadata.meem_metadata_type === 'Meem_AgreementContract') { - const agreement = await orm.models.Agreement.findOne({ - where: { - address, - chainId: args.chainId - } - }) - - if (!agreement) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - const agreementWallet = await orm.models.AgreementWallet.findOne({ - where: { - AgreementId: agreement.id, - WalletId: wallet.id - } - }) - - await agreementWallet?.destroy() - } else if (metadata.meem_metadata_type === 'Meem_AgreementRoleContract') { - const agreementRole = await orm.models.AgreementRole.findOne({ - where: { - address, - chainId: args.chainId - } - }) - - if (!agreementRole) { - throw new Error('AGREEMENT_NOT_FOUND') - } - - const agreementWallet = await orm.models.AgreementRoleWallet.findOne({ - where: { - AgreementRoleId: agreementRole.id, - WalletId: wallet.id - } - }) - - await agreementWallet?.destroy() - } - } - - public static async meemHandleTransfer(args: { - address: string - transactionHash: string - transactionTimestamp: number - eventData: MeemTransferEvent['args'] - chainId: number - }) { - const tokenId = args.eventData.tokenId.toHexString() - const { chainId, address, transactionHash } = args - - const agreement = await services.agreement.getAgreementContract({ - address, - chainId - }) - - const contractURI = await agreement.contractURI() - const metadata = (await services.meem.getErc721Metadata( - contractURI - )) as MeemMetadataLike - - if (metadata.meem_metadata_type === 'Meem_AgreementContract') { - let token = await orm.models.AgreementToken.findOne({ - where: { - tokenId - }, - include: [ - { - model: orm.models.Agreement, - where: { - address: args.address - } - } - ] - }) - - if (!token) { - log.debug(`Creating new token: ${tokenId}`) - token = await this.createNewAgreementToken({ - address: args.address, - tokenId, - chainId, - transactionHash - }) - } else { - log.debug(`Updating token: ${tokenId}`) - let wallet = await orm.models.Wallet.findByAddress( - args.eventData.to - ) - - if (!wallet) { - wallet = await orm.models.Wallet.create({ - address: args.eventData.to - }) - } - - token.OwnerId = wallet.id - await token.save() - } - - const transferredAt = DateTime.fromSeconds( - args.transactionTimestamp - ).toJSDate() - - await orm.models.AgreementTokenTransfer.create({ - from: args.eventData.from, - to: args.eventData.to, - transactionHash, - transferredAt, - AgreementTokenId: token.id - }) - } else if (metadata.meem_metadata_type === 'Meem_AgreementRoleContract') { - let token = await orm.models.AgreementRoleToken.findOne({ - where: { - tokenId - }, - include: [ - { - model: orm.models.AgreementRole, - where: { - address: args.address - } - } - ] - }) - - if (!token) { - log.debug(`Creating new token: ${tokenId}`) - token = await this.createNewAgreementRoleToken({ - address: args.address, - tokenId, - chainId - }) - } else { - log.debug(`Updating token: ${tokenId}`) - let wallet = await orm.models.Wallet.findByAddress( - args.eventData.to - ) - - if (!wallet) { - wallet = await orm.models.Wallet.create({ - address: args.eventData.to - }) - } - - token.OwnerId = wallet.id - await token.save() - } - - const transferredAt = DateTime.fromSeconds( - args.transactionTimestamp - ).toJSDate() - - await orm.models.AgreementRoleTokenTransfer.create({ - from: args.eventData.from, - to: args.eventData.to, - transactionHash: args.transactionHash, - transferredAt, - AgreementRoleTokenId: token.id - }) - } - } - - public static async createNewAgreementToken(options: { - address: string - tokenId: string - chainId: number - transactionHash: string - }) { - const { address, tokenId, chainId, transactionHash } = options - const agreement = await services.agreement.getAgreementContract({ - address, - chainId - }) - - const transaction = await orm.models.Transaction.findOne({ - where: { - hash: transactionHash - } - }) - - log.debug(`Fetching AgreementToken from contract: ${tokenId}`) - - // Fetch the token data and create it - const [tokenData, tokenURI] = await Promise.all([ - agreement.getMeem(tokenId), - agreement.tokenURI(tokenId) - ]) - - log.debug(`AgreementToken found`, tokenURI, tokenData) - - let [agreementData, wallet] = await Promise.all([ - orm.models.Agreement.findOne({ - where: { - address, - chainId - } - }), - orm.models.Wallet.findByAddress(tokenData.owner) - ]) - - if (!agreementData) { - agreementData = (await this.meemHandleContractInitialized({ - address, - chainId - })) as Agreement - if (!agreementData) { - throw new Error('AGREEMENT_NOT_FOUND') - } - } - - if (!wallet) { - wallet = await orm.models.Wallet.create({ - address: tokenData.owner - }) - } - - const metadata = (await services.meem.getErc721Metadata( - tokenURI - )) as MeemAPI.IMeemMetadataLike - - const data: Record = { - id: uuidv4(), - tokenId, - tokenURI, - mintedAt: DateTime.fromSeconds(tokenData.mintedAt.toNumber()).toJSDate(), - metadata, - mintedBy: tokenData.mintedBy, - AgreementId: agreementData.id, - OwnerId: wallet.id, - TransactionId: transaction?.id - } - - log.debug(`Saving AgreementToken to db: ${tokenId}`) - const t = await orm.sequelize.transaction() - - const createUpdatePromises: Promise[] = [ - orm.models.AgreementToken.create(data, { transaction: t }) - ] - - const [token] = await Promise.all(createUpdatePromises) - - await t.commit() - - return token - } - - public static async createNewAgreementRoleToken(options: { - address: string - tokenId: string - chainId: number - }) { - const { address, tokenId, chainId } = options - const agreementContract = await services.agreement.getAgreementContract({ - address, - chainId - }) - - log.debug(`Fetching AgreementRoleToken from contract: ${tokenId}`) - - // Fetch the meem data and create it - const [tokenData, tokenURI] = await Promise.all([ - agreementContract.getMeem(tokenId), - agreementContract.tokenURI(tokenId) - ]) - - log.debug(`AgreementRoleToken found`, tokenURI, tokenData) - - let [agreementRoleData, wallet] = await Promise.all([ - orm.models.AgreementRole.findOne({ - where: { - address, - chainId - }, - include: [ - { - model: orm.models.Agreement - } - ] - }), - orm.models.Wallet.findByAddress(tokenData.owner) - ]) - - if (!agreementRoleData) { - agreementRoleData = (await this.meemHandleContractInitialized({ - address, - chainId - })) as AgreementRole | null - if (!agreementRoleData) { - throw new Error('AGREEMENT_ROLE_NOT_FOUND') - } - } - - if (!wallet) { - wallet = await orm.models.Wallet.create({ - address: tokenData.owner - }) - } - - const metadata = (await services.meem.getErc721Metadata( - tokenURI - )) as MeemAPI.IMeemMetadataLike - - const data: Record = { - id: uuidv4(), - tokenId, - tokenURI, - mintedAt: DateTime.fromSeconds(tokenData.mintedAt.toNumber()).toJSDate(), - metadata, - mintedBy: tokenData.mintedBy, - AgreementId: agreementRoleData.Agreement.id, - AgreementRoleId: agreementRoleData.id, - OwnerId: wallet.id - } - - log.debug(`Saving AgreementRoleToken to db: ${tokenId}`) - const t = await orm.sequelize.transaction() - - const createUpdatePromises: Promise[] = [ - orm.models.AgreementRoleToken.create(data, { transaction: t }) - ] - - const [token] = await Promise.all(createUpdatePromises) - - await t.commit() - - return token - } - - // public static saveToGun(options: { - // paths: string[] - // from?: IGunChainReference - // data: any - // }): IGunChainReference { - // // return new Promise((resolve, reject) => { - // const { paths, data, from } = options - // let item: IGunChainReference = gun.user() - - // if (paths.length === 0) { - // throw new Error('Paths must be set') - // } - - // paths.forEach(path => { - // if (from && !item) { - // item = from.get(path) - // } else if (item) { - // item = item.get(path) - // } else { - // item = gun.user().get(path) - // } - // }) - - // const dataObject = this.toPureObject(data) - - // Object.keys(dataObject).forEach(key => { - // const val = dataObject[key] - // if (typeof val === 'object') { - // this.saveToGun({ paths: [key], from: item, data: val }) - // } else if (Object.prototype.toString.call(val) === '[object Date]') { - // item.get(key).put(((val as Date).getTime() / 1000) as any, ack => { - // if (ack.ok) { - // log.debug(`Gun sync: ${paths.join('/')}/${key}`) - // } else if (ack.err) { - // log.crit(ack.err) - // } - // }) - // } else { - // item.get(key).put(val, ack => { - // if (ack.ok) { - // log.debug(`Gun sync: ${paths.join('/')}/${key}`) - // } else if (ack.err) { - // log.crit(`Error saving: ${key}`, val) - // log.crit(ack.err) - // } - // }) - // } - // }) - - // return item - // } - - // private static async updateMeem(options: { meem: Meem }) { - // const { meem } = options - // log.debug(`Syncing meem tokenId: ${meem.tokenId}`) - // const agreement = await services.meem.getAgreement({ - // address: meem.Agreement.address - // }) - // // Fetch the meem data and create it - // const [meemData, tokenURI] = await Promise.all([ - // agreement.getMeem(meem.tokenId), - // agreement.tokenURI(meem.tokenId) - // ]) - - // const metadata = (await services.meem.getErc721Metadata( - // tokenURI - // )) as MeemAPI.IMeemMetadataLike - - // // meem.data = meemData.data - // meem.metadata = metadata - // meem.owner = meemData.owner - // meem.mintedAt = DateTime.fromSeconds( - // meemData.mintedAt.toNumber() - // ).toJSDate() - // meem.mintedBy = meemData.mintedBy - // // meem.uriLockedBy = meemData.uriLockedBy - // await meem.save() - // } - - // private static meemPropertiesDataToModelData( - // props: MeemPropertiesStructOutput - // ) { - // return { - // totalCopies: props.totalCopies.toHexString(), - // totalCopiesLockedBy: props.totalCopiesLockedBy, - // copiesPerWallet: props.copiesPerWallet.toHexString(), - // copiesPerWalletLockedBy: props.copiesPerWalletLockedBy, - // totalRemixes: props.totalRemixes.toHexString(), - // totalRemixesLockedBy: props.totalRemixesLockedBy, - // remixesPerWallet: props.remixesPerWallet.toHexString(), - // remixesPerWalletLockedBy: props.remixesPerWalletLockedBy, - // copyPermissions: this.meemPermissionsDataToModelData( - // props.copyPermissions - // ), - // remixPermissions: this.meemPermissionsDataToModelData( - // props.remixPermissions - // ), - // readPermissions: this.meemPermissionsDataToModelData( - // props.readPermissions - // ), - // copyPermissionsLockedBy: props.copyPermissionsLockedBy, - // remixPermissionsLockedBy: props.remixPermissionsLockedBy, - // readPermissionsLockedBy: props.readPermissionsLockedBy, - // splits: this.meemSplitsDataToModelData(props.splits), - // splitsLockedBy: props.splitsLockedBy, - // isTransferrable: props.isTransferrable, - // isTransferrableLockedBy: props.isTransferrableLockedBy, - // mintStartAt: props.mintStartTimestamp.toHexString(), - // mintEndAt: props.mintEndTimestamp.toHexString(), - // mintDatesLockedBy: props.mintDatesLockedBy, - // transferLockupUntil: !props.transferLockupUntil.isZero - // ? props.transferLockupUntil.toHexString() - // : null, - // transferLockupUntilLockedBy: props.transferLockupUntilLockedBy - // } - // } - - private static meemSplitsDataToModelData(splits: SplitStructOutput[]) { - return splits.map(s => ({ - toAddress: s.toAddress, - amount: s.amount.toNumber(), - lockedBy: s.lockedBy - })) - } - - private static meemPermissionsDataToModelData(perms: MeemPermissionStruct[]) { - return perms.map(p => ({ - permission: p.permission, - addresses: p.addresses, - numTokens: ethers.BigNumber.from(p.numTokens).toHexString(), - // lockedBy: p.lockedBy, - costWei: ethers.BigNumber.from(p.costWei).toHexString() - })) - } - - public static toPureObject(d: any) { - // let data: Record = {} - - // if (Array.isArray(d)) { - // d.forEach((val, i) => { - // data[`a${i}`] = val - // }) - // } else { - // data = { ...d } - // } - - const data = { ...d } - - Object.keys(data).forEach(key => { - const val = data[key] - if (Array.isArray(val) || typeof val === 'object') { - data[key] = this.toPureObject(val) - } else if (Object.prototype.toString.call(val) === '[object Date]') { - data[key] = (val as Date).toString() - } else if (typeof val === 'string') { - data[key] = val.replace(/\n/g, '/n') - } - }) - - return data - } -} diff --git a/src/services/Ethers.ts b/src/services/Ethers.ts index 706b2cde..d16ef747 100644 --- a/src/services/Ethers.ts +++ b/src/services/Ethers.ts @@ -1,13 +1,8 @@ /* eslint-disable global-require */ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable import/no-extraneous-dependencies */ -import { IFacetVersion } from '@meemproject/meem-contracts' import { Alchemy, Network, Wallet } from 'alchemy-sdk' import { ethers } from 'ethers' -import { v4 as uuidv4 } from 'uuid' -import { InitParamsStruct } from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' -import { ICreateTablelandTableInput } from './Queue' export default class EthersService { public static shouldInitialize = true @@ -181,369 +176,4 @@ export default class EthersService { return sigHashes } - - public async queueCreateTablelandTable(options: { - chainId: number - tableName: string - columns: { - [columnName: string]: MeemAPI.StorageDataType - } - agreementExtensionId: string - abi: Record[] - bytecode: string - args: any[] - functionCall: string - fromVersion: IFacetVersion[] - toVersion: IFacetVersion[] - }) { - const { - chainId, - tableName, - columns, - agreementExtensionId, - args, - abi, - bytecode, - functionCall, - fromVersion, - toVersion - } = options - - const txId = uuidv4() - - const transactionInput: ICreateTablelandTableInput = { - tableName, - columns, - agreementExtensionId, - args, - bytecode, - functionCall, - fromVersion, - toVersion - } - - await services.queue.sendMessage({ - Id: txId, - MessageBody: JSON.stringify({ - id: txId, - eventName: MeemAPI.QueueEvent.CreateTablelandTable, - chainId, - customABI: abi, - transactionInput - }), - MessageGroupId: '1' - }) - - return txId - } - - public async queueDiamondCut(options: { - chainId: number - abi: Record[] - bundleABI: Record[] - fromVersion: IFacetVersion[] - toVersion: IFacetVersion[] - contractInitParams: InitParamsStruct - senderWalletAddress: string - metadata: MeemAPI.IMeemMetadataLike - contractTxId?: string - contractAddress?: string - parentContractTxtId?: string - }) { - const { - chainId, - abi, - bundleABI, - fromVersion, - toVersion, - contractAddress, - contractTxId, - contractInitParams, - metadata, - senderWalletAddress, - parentContractTxtId - } = options - - if (!contractAddress && !contractTxId) { - throw new Error('MISSING_PARAMETERS') - } - - const cutTxId = uuidv4() - - await services.queue.sendMessage({ - Id: cutTxId, - MessageBody: JSON.stringify({ - id: cutTxId, - eventName: MeemAPI.QueueEvent.DiamondCut, - chainId, - customABI: abi, - transactionInput: { - bundleABI, - fromVersion, - toVersion, - contractTxId, - contractAddress, - contractInitParams, - metadata, - senderWalletAddress, - parentContractTxtId - } - }), - MessageGroupId: '1' - }) - - return cutTxId - } - - public async queueContractDeployment(options: { - chainId: number - abi: Record[] - bytecode: string - args: any[] - }) { - const { chainId, abi, bytecode, args } = options - - const txId = uuidv4() - - await services.queue.sendMessage({ - Id: txId, - MessageBody: JSON.stringify({ - id: txId, - eventName: MeemAPI.QueueEvent.DeployContract, - chainId, - customABI: abi, - transactionInput: { - args, - bytecode - } - }), - MessageGroupId: '1' - }) - - return txId - } - - public async queueTransaction(options: { - abi?: Record[] - functionSignature: string - contractTxId?: string - contractAddress?: string - inputValues: Record - chainId: number - eventName?: MeemAPI.QueueEvent - /** Necessary when QueueEvent == DeploySafe */ - agreementId?: string - }) { - const { - abi, - functionSignature, - contractAddress, - contractTxId, - inputValues, - chainId, - eventName, - agreementId - } = options - - if (!contractAddress && !contractTxId) { - throw new Error('MISSING_PARAMETERS') - } - - const id = uuidv4() - - await services.queue.sendMessage({ - Id: id, - MessageBody: JSON.stringify({ - id, - eventName: eventName ?? MeemAPI.QueueEvent.CallContract, - agreementId, - chainId, - customABI: abi, - transactionInput: { - contractAddress, - contractTxId, - functionSignature, - inputValues - } - }), - MessageGroupId: '1' - }) - - return id - } - - public async runTransaction any>(options: { - /** The chain */ - chainId: number - /** The function to run */ - fn: T - /** The function parameters */ - params: Parameters - - /** Explicitly set the gas limit */ - gasLimit?: ethers.BigNumberish | Promise | undefined - }): Promise> { - const { chainId, fn, params, gasLimit } = options - try { - await this.acquireLock(chainId) - let nonce = 0 - let chainNonce = await orm.models.ChainNonce.findOne({ - where: { - chainId - } - }) - - if (chainNonce) { - nonce = chainNonce.nonce - } else { - chainNonce = orm.models.ChainNonce.build({ - nonce, - chainId - }) - } - - const { wallet, provider } = await services.ethers.getProvider({ - chainId - }) - - const providerTxCount = await provider.core.getTransactionCount( - wallet.address, - 'latest' - ) - - const providerNonce = providerTxCount - 1 - - if (providerNonce > nonce) { - nonce = providerNonce - } - - const newNonce = providerTxCount > 0 ? nonce + 1 : 0 - - let { recommendedGwei } = await services.web3.getGasEstimate({ - chainId - }) - - if (recommendedGwei > config.MAX_GAS_PRICE_GWEI) { - // throw new Error('GAS_PRICE_TOO_HIGH') - log.warn(`Recommended fee over max: ${recommendedGwei}`) - recommendedGwei = config.MAX_GAS_PRICE_GWEI - } - - const overrides: ethers.Overrides = { - nonce: newNonce, - gasPrice: services.web3.gweiToWei(recommendedGwei).toNumber() - } - - if (gasLimit) { - overrides.gasLimit = - chainId === 421613 - ? ethers.BigNumber.from(gasLimit).mul( - config.ARBITRUM_GAS_MULTIPLIER - ) - : gasLimit - } else if (chainId === 421613) { - // Add additional gas for arbitrum - overrides.gasLimit = ethers.BigNumber.from(config.MINT_GAS_LIMIT).mul( - config.ARBITRUM_GAS_MULTIPLIER - ) - } - - log.debug(overrides) - - const result = await fn(...params, overrides) - - chainNonce.nonce = newNonce - await chainNonce.save() - - await this.releaseLock(chainId) - - return result - } catch (e) { - await this.releaseLock(chainId) - throw e - } - } - - public async aquireLockAndNonce(chainId: number) { - await this.acquireLock(chainId) - let nonce = 0 - let chainNonce = await orm.models.ChainNonce.findOne({ - where: { - chainId - } - }) - - if (chainNonce) { - nonce = chainNonce.nonce - } else { - chainNonce = orm.models.ChainNonce.build({ - nonce, - chainId - }) - } - - const { wallet, provider } = await services.ethers.getProvider({ - chainId - }) - - const providerTxCount = await provider.core.getTransactionCount( - wallet.address, - 'latest' - ) - - const providerNonce = providerTxCount - 1 - - if (providerNonce > nonce) { - nonce = providerNonce - } - - const newNonce = providerTxCount > 0 ? nonce + 1 : 0 - - return { nonce: newNonce } - } - - public async releaseLockAndNonce(options: { - chainId: number - nonce: number - }) { - const { chainId, nonce } = options - const chainNonce = await orm.models.ChainNonce.findOne({ - where: { - chainId - } - }) - - const promises: Promise[] = [] - - if (!chainNonce) { - promises.push( - orm.models.ChainNonce.create({ - chainId, - nonce - }) - ) - } else { - chainNonce.nonce = nonce - promises.push(chainNonce.save()) - } - - promises.push(this.releaseLock(chainId)) - await Promise.all(promises) - } - - public async acquireLock(chainId: number) { - try { - await orm.acquireLock(`${config.WALLET_LOCK_KEY}_${chainId}`) - } catch (e) { - log.warn(e) - } - } - - public async releaseLock(chainId: number) { - try { - await orm.releaseLock(`${config.WALLET_LOCK_KEY}_${chainId}`) - } catch (e) { - log.warn(e) - } - } } diff --git a/src/services/Git.ts b/src/services/Git.ts deleted file mode 100644 index 70633087..00000000 --- a/src/services/Git.ts +++ /dev/null @@ -1,130 +0,0 @@ -// import { Octokit } from '@octokit/rest' -// import request from 'superagent' -// import { MeemAPI } from '../types/meem.generated' -// import { IMeemMetadataLike } from '../types/shared/meem.shared' - -// https://www.reddit.com/r/ipfs/comments/lvwn4o/ipfs_http_gateways_ranked_by_performance/ - -export default class GitService { - // public static async saveMeemMetadata(data: { - // meemId: string - // imageBase64: string - // metadata: MeemAPI.ICreateMeemMetadata - // }): Promise<{ metadata: MeemAPI.IMeemMetadataLike; tokenURI: string }> { - // const branchName = - // config.NETWORK === MeemAPI.NetworkName.Rinkeby ? `test` : `master` - // const octokit = new Octokit({ - // auth: config.GITHUB_KEY - // }) - // const master = await octokit.git.getRef({ - // owner: 'meemproject', - // repo: 'metadata', - // ref: `heads/${branchName}` - // }) - // const treeItems: { - // path: string - // mode: '100644' - // type: 'blob' - // sha: string - // }[] = [] - // const imageGit = await octokit.git.createBlob({ - // owner: 'meemproject', - // repo: 'metadata', - // content: data.imageBase64, - // encoding: 'base64' - // }) - // treeItems.push({ - // path: `meem/images/${data.meemId}.png`, - // sha: imageGit.data.sha, - // mode: '100644', - // type: 'blob' - // }) - // const image = `https://raw.githubusercontent.com/meemproject/metadata/${branchName}/meem/images/${data.meemId}.png` - // const storedMetadata: IMeemMetadataLike = { - // ...data.metadata, - // meem_id: data.metadata.meem_id ?? '', - // external_url: data.metadata.external_url ?? '', - // image, - // image_original: image - // } - // const metadataGit = await octokit.git.createBlob({ - // owner: 'meemproject', - // repo: 'metadata', - // content: JSON.stringify(storedMetadata), - // encoding: 'utf-8' - // }) - // treeItems.push({ - // path: `meem/${data.meemId}.json`, - // sha: metadataGit.data.sha, - // mode: '100644', - // type: 'blob' - // }) - // const tree = await octokit.git.createTree({ - // owner: 'meemproject', - // repo: 'metadata', - // tree: treeItems, - // base_tree: master.data.object.sha - // }) - // const commit = await octokit.git.createCommit({ - // owner: 'meemproject', - // repo: 'metadata', - // message: `New Meem Created: ${data.meemId}`, - // tree: tree.data.sha, - // parents: [master.data.object.sha] - // }) - // await octokit.git.updateRef({ - // owner: 'meemproject', - // repo: 'metadata', - // ref: `heads/${branchName}`, - // sha: commit.data.sha - // }) - // return { - // metadata: storedMetadata, - // tokenURI: `https://raw.githubusercontent.com/meemproject/metadata/${branchName}/meem/${data.meemId}.json` - // } - // } - // public static async updateMeemMetadata(data: { - // tokenURI: string - // generation: number - // tokenId: number - // metadataId: string - // }): Promise { - // const branchName = - // config.NETWORK === MeemAPI.NetworkName.Rinkeby ? `test` : `master` - // const result = await request.get(data.tokenURI) - // const metadata = JSON.parse(result.text) - // metadata.meem_properties.generation = data.generation - // metadata.meem_properties.token_id = data.tokenId - // metadata.external_url = `${config.MEEM_DOMAIN}/meems/${data.tokenId}` - // metadata.attributes = [ - // { - // display_type: 'number', - // trait_type: 'Meem Generation', - // value: data.generation - // } - // ] - // const octokit = new Octokit({ - // auth: config.GITHUB_KEY - // }) - // const fileBlob = await octokit.repos.getContent({ - // owner: 'meemproject', - // repo: 'metadata', - // ref: `heads/${branchName}`, - // path: `meem/${data.metadataId}.json` - // }) - // const { sha } = fileBlob.data as any - // const metadataString = JSON.stringify(metadata) - // const base64EncodedMetadata = Buffer.from(metadataString).toString('base64') - // await octokit.repos.createOrUpdateFileContents({ - // owner: 'meemproject', - // repo: 'metadata', - // content: base64EncodedMetadata, - // encoding: 'utf-8', - // branch: branchName, - // path: `meem/${data.metadataId}.json`, - // message: `Meem Updated: ${data.metadataId}`, - // sha - // }) - // return metadata - // } -} diff --git a/src/services/Guild.ts b/src/services/Guild.ts deleted file mode 100644 index 73324772..00000000 --- a/src/services/Guild.ts +++ /dev/null @@ -1,754 +0,0 @@ -// import { -// Chain, -// GetGuildResponse, -// guild, -// role as guildRole -// } from '@guildxyz/sdk' -// // eslint-disable-next-line import/no-extraneous-dependencies -// import AWS from 'aws-sdk' -// import type { Bytes } from 'ethers' -// import _ from 'lodash' -// import Agreement from '../models/Agreement' -// import AgreementGuild from '../models/AgreementGuild' -// import AgreementRole from '../models/AgreementRole' -// import Meem from '../models/AgreementToken' -// import { Mycontract__factory } from '../types/Meem' - -export default class GuildService { - // public static getGuildChain(chainId: number): Chain { - // switch (chainId) { - // case 1: - // return 'ETHEREUM' - // break - // case 4: - // return 'RINKEBY' as Chain - // break - // case 5: - // return 'GOERLI' - // break - // case 137: - // return 'POLYGON' - // break - // case 420: - // return 'OPTIMISM' - // break - // case 421613: - // return 'ARBITRUM' - // break - // default: - // return 'POLYGON' - // } - // } - // public static async createAgreementGuild(data: { - // agreementId: string - // adminAddresses?: string[] - // }): Promise<{ - // agreementGuild: AgreementGuild - // agreementRoles: AgreementRole[] - // }> { - // const { agreementId } = data - // let adminAddresses = data.adminAddresses - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild, - // include: [ - // { - // model: orm.models.AgreementRole - // } - // ] - // } - // ] - // }) - // if (!agreement) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // if (agreement.AgreementGuild) { - // return { - // agreementGuild: agreement.AgreementGuild, - // agreementRoles: agreement.AgreementGuild?.AgreementRoles ?? [] - // } - // } - // const { wallet } = await services.ethers.getProvider({ - // chainId: agreement.chainId - // }) - // const sign = (signableMessage: string | Bytes) => - // wallet.signMessage(signableMessage) - // if (!adminAddresses) { - // const adminWallets = await orm.models.AgreementWallet.findAll({ - // where: { - // AgreementId: agreement.id, - // role: config.ADMIN_ROLE - // }, - // include: [orm.models.Wallet] - // }) - // adminAddresses = adminWallets.map(aw => aw.Wallet?.address ?? '') - // } - // adminAddresses = adminAddresses.filter( - // a => a !== '' && a !== wallet.address.toLowerCase() - // ) - // try { - // const guildChain = this.getGuildChain(agreement.chainId) - // const createGuildResponse = await guild.create(wallet.address, sign, { - // name: agreement.name, - // description: `Agreement Guild Details - Contract Address: ${agreement.address} | Chain ID: ${agreement.chainId}`, - // roles: [ - // { - // name: `Token Holder`, - // logic: 'OR', - // requirements: [ - // { - // type: 'ERC721', - // chain: guildChain, - // address: agreement.address, - // data: { - // minAmount: 1 - // } - // } - // ] - // } - // ] - // }) - // const agreementGuild = await orm.models.AgreementGuild.create({ - // guildId: createGuildResponse.id, - // AgreementId: agreement.id - // }) - // const guildResponse = await guild.get(createGuildResponse.id) - // const agreementRoles = await Promise.all( - // guildResponse.roles.map(async role => { - // const agreementRole = await orm.models.AgreementRole.create({ - // guildRoleId: role.id, - // name: role.name, - // AgreementId: agreement.id, - // AgreementGuildId: agreementGuild.id, - // isDefaultRole: true - // }) - // return agreementRole - // }) - // ) - // const adminRole = await this.createAgreementGuildRole({ - // name: 'Admin', - // agreement, - // agreementGuild, - // permissions: [ - // 'clubs.admin.editProfile', - // 'clubs.admin.manageMembershipSettings', - // 'clubs.admin.manageRoles', - // 'clubs.apps.manageApps', - // 'clubs.apps.viewApps' - // ], - // isTokenBasedRole: true, - // isTokenTransferrable: false, - // members: adminAddresses, - // senderWalletAddress: wallet.address, - // isAdminRole: true - // }) - // if (adminRole) { - // agreementRoles.push(adminRole) - // } - // return { - // agreementGuild, - // agreementRoles - // } - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async deleteAgreementGuild(data: { - // agreementId: string - // }): Promise { - // const { agreementId } = data - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild, - // include: [ - // { - // model: orm.models.AgreementRole, - // include: [ - // { - // model: orm.models.RolePermission - // } - // ] - // } - // ] - // } - // ] - // }) - // if (!agreement || !agreement.AgreementGuild) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // const { wallet } = await services.ethers.getProvider({ - // chainId: agreement.chainId - // }) - // const sign = (signableMessage: string | Bytes) => - // wallet.signMessage(signableMessage) - // try { - // await guild.delete( - // agreement.AgreementGuild.guildId, - // wallet.address, - // sign, - // true - // ) - // const promises: Promise[] = [] - // const t = await orm.sequelize.transaction() - // promises.push( - // orm.models.AgreementRole.destroy({ - // where: { - // id: agreement.AgreementGuild.AgreementRoles?.map(role => role.id) - // }, - // transaction: t - // }) - // ) - // promises.push( - // orm.models.AgreementGuild.destroy({ - // where: { - // id: agreement.AgreementGuild.id - // }, - // transaction: t - // }) - // ) - // await Promise.all(promises) - // await t.commit() - // return - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async getAgreementGuild(data: { - // agreementId: string - // }): Promise { - // try { - // const agreementGuild = await orm.models.AgreementGuild.findOne({ - // where: { - // AgreementId: data.agreementId - // } - // }) - // if (!agreementGuild) { - // return null - // } - // const guildResponse = await guild.get(agreementGuild.guildId) - // return guildResponse - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async createAgreementGuildRole(data: { - // name: string - // agreement: Agreement - // agreementGuild: AgreementGuild - // permissions?: string[] - // isTokenBasedRole: boolean - // isTokenTransferrable?: boolean - // members: string[] - // senderWalletAddress: string - // isAdminRole?: boolean - // }): Promise { - // const { - // name, - // agreement, - // agreementGuild, - // permissions, - // isTokenBasedRole, - // isTokenTransferrable, - // members, - // senderWalletAddress, - // isAdminRole - // } = data - // const { wallet } = await services.ethers.getProvider({ - // chainId: agreement.chainId - // }) - // const sign = (signableMessage: string | Bytes) => - // wallet.signMessage(signableMessage) - // try { - // if (isTokenBasedRole) { - // const baseContract = Mycontract__factory.connect( - // agreement.address, - // wallet - // ) - // const admins = await baseContract.getRoles(config.ADMIN_ROLE) - // const roleContractData = { - // chainId: agreement.chainId, - // shouldMintTokens: true, - // metadata: { - // meem_metadata_type: 'Meem_AgreementRoleContract', - // meem_metadata_version: 'MeemClubRole_Contract_20220718', - // name: `${agreement.name ?? ''} - ${name}`, - // description: name, - // image: '', - // associations: [ - // { - // meem_contract_type: 'meem-club', - // address: agreement.address - // } - // ], - // external_url: '' - // }, - // name: `${agreement.name ?? ''} - ${name}`, - // admins, - // members, - // minters: admins, - // maxSupply: '0', - // // TODO: What do we want mintPermissions to be? - // mintPermissions: agreement.mintPermissions, - // splits: [], - // isTransferLocked: !isTokenTransferrable, - // tokenMetadata: { - // meem_metadata_version: 'MeemClubRole_Token_20220718', - // description: name, - // name: `${agreement.name ?? ''} - ${name}`, - // // TODO: Token image? - // image: '', - // associations: [], - // external_url: '' - // } - // } - // // log.debug(JSON.stringify(data)) - // log.debug(roleContractData) - // if (config.DISABLE_ASYNC_MINTING) { - // try { - // await services.agreement.createAgreement({ - // ...roleContractData, - // senderWalletAddress, - // agreementRoleData: { - // name, - // agreement, - // agreementGuild, - // permissions, - // isAdminRole - // } - // }) - // } catch (e) { - // log.crit(e) - // sockets?.emitError( - // config.errors.CONTRACT_CREATION_FAILED, - // senderWalletAddress - // ) - // } - // } else { - // const lambda = new AWS.Lambda({ - // accessKeyId: config.APP_AWS_ACCESS_KEY_ID, - // secretAccessKey: config.APP_AWS_SECRET_ACCESS_KEY, - // region: 'us-east-1' - // }) - // await lambda - // .invoke({ - // InvocationType: 'Event', - // FunctionName: config.LAMBDA_CREATE_CONTRACT_FUNCTION, - // Payload: JSON.stringify({ - // ...roleContractData, - // senderWalletAddress - // }) - // }) - // .promise() - // } - // } else { - // const guildChain = this.getGuildChain(agreement.chainId) - // const createGuildRoleResponse = await guildRole.create( - // wallet.address, - // sign, - // { - // guildId: agreementGuild.guildId, - // name, - // logic: 'AND', - // requirements: [ - // { - // type: 'ALLOWLIST', - // data: { - // addresses: members - // } - // }, - // { - // type: 'ERC721', - // chain: guildChain, - // address: agreement.address, - // data: { - // minAmount: 1 - // } - // } - // ] - // } - // ) - // const agreementRole = await orm.models.AgreementRole.create({ - // guildRoleId: createGuildRoleResponse.id, - // name, - // AgreementId: agreement.id, - // AgreementGuildId: agreementGuild.id - // }) - // if (!_.isUndefined(permissions) && _.isArray(permissions)) { - // const promises: Promise[] = [] - // const t = await orm.sequelize.transaction() - // const roleIdsToAdd = - // permissions.filter(pid => { - // const existingPermission = agreementRole.RolePermissions?.find( - // rp => rp.id === pid - // ) - // return !existingPermission - // }) ?? [] - // if (roleIdsToAdd.length > 0) { - // const agreementRolePermissionsData: { - // AgreementRoleId: string - // RolePermissionId: string - // }[] = roleIdsToAdd.map(rid => { - // return { - // AgreementRoleId: agreementRole.id, - // RolePermissionId: rid - // } - // }) - // promises.push( - // orm.models.AgreementRolePermission.bulkCreate( - // agreementRolePermissionsData, - // { - // transaction: t - // } - // ) - // ) - // } - // try { - // await Promise.all(promises) - // await t.commit() - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // } - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async updateAgreementGuildRole(data: { - // name?: string - // agreementId: string - // guildRoleId: number - // members?: string[] - // guildRoleData?: { - // rolePlatforms?: { - // guildPlatform: { - // platformName: string - // platformGuildId: string - // isNew: boolean - // } - // platformRoleData?: { - // [key: string]: string - // } - // }[] - // } - // senderWalletAddress: string - // }): Promise { - // const { - // name, - // agreementId, - // guildRoleId, - // members, - // guildRoleData, - // senderWalletAddress - // } = data - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild, - // include: [ - // { - // model: orm.models.AgreementRole - // } - // ] - // } - // ] - // }) - // const agreementRole = agreement?.AgreementGuild?.AgreementRoles?.find( - // r => r.guildRoleId === guildRoleId - // ) - // if (!agreement || !agreementRole) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // if ( - // _.isUndefined(name) && - // _.isUndefined(members) && - // _.isUndefined(guildRoleData) - // ) { - // return agreementRole - // } - // const { wallet } = await services.ethers.getProvider({ - // chainId: agreement.chainId - // }) - // const sign = (signableMessage: string | Bytes) => - // wallet.signMessage(signableMessage) - // try { - // const existingGuildRole = await guildRole.get(guildRoleId) - // const requirements = existingGuildRole.requirements - // const allowListRoleIndex = requirements.findIndex( - // r => r.type === 'ALLOWLIST' - // ) - // if (allowListRoleIndex > -1 && members) { - // requirements[allowListRoleIndex] = { - // type: 'ALLOWLIST', - // data: { - // addresses: members - // } - // } - // } - // if ((allowListRoleIndex > -1 && members) || name || guildRoleData) { - // const rolePlatforms: - // | { - // guildPlatform: { - // platformName: string - // platformGuildId: string - // isNew: boolean - // } - // platformRoleData?: { - // [key: string]: string - // } - // }[] - // | undefined = guildRoleData?.rolePlatforms - // ? guildRoleData.rolePlatforms - // : existingGuildRole.rolePlatforms?.map(rp => { - // return { - // guildPlatform: { - // platformGuildId: rp.guildPlatform.platformGuildId, - // platformName: rp.guildPlatform.platformName, - // isNew: false - // }, - // platformRoleData: rp.platformRoleData - // } - // }) - // await guildRole.update(guildRoleId, wallet.address, sign, { - // name: name ?? existingGuildRole.name, - // logic: existingGuildRole.logic, - // rolePlatforms, - // requirements - // }) - // } - // if (name) { - // await agreementRole.update({ - // name - // }) - // } - // if (members && agreementRole.tokenAddress) { - // const roleAgreement = await orm.models.Agreement.findOne({ - // where: { - // address: agreementRole.tokenAddress - // } - // }) - // // TODO: Allow other contracts besides Meem - // if (roleAgreement) { - // const memberMeems = await orm.models.AgreementToken.findAll({ - // where: { - // AgreementId: roleAgreement.id - // }, - // include: [ - // { - // model: orm.models.Wallet, - // as: 'Owner' - // } - // ] - // }) - // const removeMemberMeems: Meem[] = [] - // memberMeems.forEach(meem => { - // if (meem.Owner !== null) { - // if ( - // members.findIndex( - // m => m.toLowerCase() === meem.Owner.address.toLowerCase() - // ) < 0 - // ) { - // removeMemberMeems.push(meem) - // } - // } - // }) - // if (removeMemberMeems.length > 0) { - // // const roleContract = Mycontract__factory.connect( - // // roleAgreement.address, - // // wallet - // // ) - // log.debug( - // 'BURN MEMBER TOKENS', - // removeMemberMeems.map(m => m.id) - // ) - // // for (let i = 0; i < removeMemberMeems.length; i += 1) { - // // await roleContract.burn(removeMemberMeems[i].tokenId) - // // } - // } - // const membersToAdd: string[] = members.filter((m: string) => { - // const existingMemberIndex = memberMeems.findIndex( - // meem => meem.Owner?.address.toLowerCase() === m.toLowerCase() - // ) - // return existingMemberIndex < 0 - // }) - // log.debug('ADD MEMBERS', membersToAdd) - // // TODO: Do we need this to be async? - // // Need to get token metadata - // if (membersToAdd.length > 0) { - // const roleTokenMetadata = { - // meem_metadata_version: 'MeemClubRole_Token_20220718', - // name: `${agreement.name ?? ''} - ${name ?? agreementRole.name}`, - // description: name ?? agreementRole.name, - // image: '', - // associations: [ - // { - // meem_contract_type: 'meem-club', - // address: agreement.address - // } - // ], - // external_url: '' - // } - // const tokens = membersToAdd.map(a => { - // return { - // to: a, - // metadata: roleTokenMetadata - // } - // }) - // if (config.DISABLE_ASYNC_MINTING) { - // try { - // await services.meem.bulkMint({ - // tokens, - // mintedBy: senderWalletAddress, - // agreementId: agreement.id - // }) - // } catch (e) { - // log.crit(e) - // } - // } else { - // const lambda = new AWS.Lambda({ - // accessKeyId: config.APP_AWS_ACCESS_KEY_ID, - // secretAccessKey: config.APP_AWS_SECRET_ACCESS_KEY, - // region: 'us-east-1' - // }) - // await lambda - // .invoke({ - // InvocationType: 'Event', - // FunctionName: config.LAMBDA_AGREEMENT_BULK_MINT_FUNCTION, - // Payload: JSON.stringify({ - // tokens, - // mintedBy: senderWalletAddress, - // agreementId: agreement.id - // }) - // }) - // .promise() - // } - // } - // } - // } - // return agreementRole - // } catch (e) { - // // TODO: Re-create guild role if no longer exists? - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async deleteAgreementGuildRole(data: { - // agreementId: string - // guildRoleId: number - // }): Promise { - // const { agreementId, guildRoleId } = data - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: agreementId - // }, - // include: [ - // { - // model: orm.models.AgreementGuild, - // include: [ - // { - // model: orm.models.AgreementRole - // } - // ] - // } - // ] - // }) - // const agreementRole = agreement?.AgreementGuild?.AgreementRoles?.find( - // r => r.guildRoleId === guildRoleId - // ) - // if (!agreement || !agreementRole) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // const { wallet } = await services.ethers.getProvider({ - // chainId: agreement.chainId - // }) - // const sign = (signableMessage: string | Bytes) => - // wallet.signMessage(signableMessage) - // try { - // await guildRole.delete(guildRoleId, wallet.address, sign) - // return - // } catch (e) { - // log.crit(e) - // throw new Error('SERVER_ERROR') - // } - // } - // public static async getUserGuilds(data: { - // walletAddress: string - // }): Promise { - // const guildMemberships = - // (await user.getMemberships(data.walletAddress)) ?? [] - // const guilds = await Promise.all( - // guildMemberships?.map(async gm => - // orm.models.Guild.findOne({ - // where: { - // guildId: gm.guildId - // } - // }) - // ) - // ) - // return guilds ?? [] - // } - // public static async getAgreementGuilds(data: { - // agreementId: string - // }): Promise { - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: data.agreementId - // } - // }) - // if (!agreement) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // const guilds = await orm.models.Guild.findAll({ - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // id: data.agreementId - // } - // } - // ] - // }) - // const guildsData = await Promise.all(guilds.map(g => guild.get(g.guildId))) - // return guildsData - // } - // public static async getAgreementGuilds(data: { - // agreementId: string - // }): Promise { - // const agreement = await orm.models.Agreement.findOne({ - // where: { - // id: data.agreementId - // } - // }) - // if (!agreement) { - // throw new Error('AGREEMENT_NOT_FOUND') - // } - // const guilds = await orm.models.Guild.findAll({ - // include: [ - // { - // model: orm.models.Agreement, - // where: { - // id: data.agreementId - // } - // } - // ] - // }) - // const guildsData = await Promise.all(guilds.map(g => guild.get(g.guildId))) - // return guildsData - // } -} diff --git a/src/services/Ipfs.ts b/src/services/Ipfs.ts deleted file mode 100644 index 0cfd5867..00000000 --- a/src/services/Ipfs.ts +++ /dev/null @@ -1,13 +0,0 @@ -import request from 'superagent' - -// https://www.reddit.com/r/ipfs/comments/lvwn4o/ipfs_http_gateways_ranked_by_performance/ - -export default class IpfsService { - public static async getIPFSFile(filename: string) { - const ipfsId = filename.replace('ipfs://', '') - const url = `${config.IPFS_CONTENT_GATEWAY_URL}/ipfs/${ipfsId}` - const { body, type } = await request.get(url) - - return { body, type } - } -} diff --git a/src/services/Lit.ts b/src/services/Lit.ts deleted file mode 100644 index 54d41613..00000000 --- a/src/services/Lit.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { ethers } from 'ethers' -import { Pkpnft__factory } from '../types/PKPNFT' - -export default class LitService { - public static async mintPKP() { - const { provider, wallet } = await services.ethers.getProvider({ - chainId: 80001 - }) - - const pkpNFTContract = Pkpnft__factory.connect( - config.PKP_CONTRACT_ADDRESS, - wallet - ) - - const tx = await pkpNFTContract.mintNext(2, { - value: ethers.utils.parseEther(config.PKP_MINT_COST) - }) - - log.debug(`Minting PKP w/ tx: ${tx.hash}`) - - await tx.wait() - - const receipt = await provider.core.getTransactionReceipt(tx.hash) - - const transferLog = receipt?.logs.find( - l => - l.topics[0] === - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' - ) - - const tokenId = transferLog ? transferLog.topics[3] : null - - log.debug({ tx, tokenId }) - if (!tokenId) { - throw new Error('PKP_MINT_FAILED') - } - - const address = await pkpNFTContract.getEthAddress(tokenId) - - return { tx, tokenId, address } - } - - public static async getEthAddress(tokenId: string) { - const { wallet } = await services.ethers.getProvider({ - chainId: 80001 - }) - - const pkpNFTContract = Pkpnft__factory.connect( - config.PKP_CONTRACT_ADDRESS, - wallet - ) - - const address = await pkpNFTContract.getEthAddress(tokenId) - - return address - } -} diff --git a/src/services/Meem.ts b/src/services/Meem.ts deleted file mode 100644 index df77c13d..00000000 --- a/src/services/Meem.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { ethers as Ethers } from 'ethers' -import request from 'superagent' -import ERC721ABI from '../abis/ERC721.json' -import meemABI from '../abis/Meem.json' -import { ERC721 } from '../types/ERC721' -import { Mycontract } from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' -export default class MeemService { - /** Get generic ERC721 contract instance */ - public static async erc721Contract(options: { - networkName?: MeemAPI.NetworkName - address: string - }) { - const ethers = services.ethers.getInstance() - const { networkName, address } = options - const { wallet } = await services.ethers.getProvider({ - chainId: MeemAPI.networkNameToChain( - networkName ?? MeemAPI.NetworkName.Mainnet - ) - }) - - const contract = new ethers.Contract(address, ERC721ABI, wallet) as ERC721 - - return contract - } - - public static async getErc721Metadata(uri: string) { - let metadata: MeemAPI.IERC721Metadata - if (uri.length === 0 || uri === 'ipfs://example') { - return {} - } - if (/^data:application\/json/.test(uri)) { - const json = Buffer.from(uri.substring(29), 'base64').toString() - metadata = JSON.parse(json) - } else if (/^{/.test(uri)) { - metadata = JSON.parse(uri) - } else if (/^ipfs/.test(uri)) { - const result = await services.ipfs.getIPFSFile(uri) - if (result.type !== 'application/json') { - throw new Error('INVALID_METADATA') - } - metadata = result.body - } else { - const result = await request.get(uri) - if (result.type === 'application/json') { - metadata = result.body - } else if (result.type === 'text/plain') { - metadata = JSON.parse(result.text) - } else { - throw new Error('INVALID_METADATA') - } - } - - return metadata - } - - public static async getImageFromMetadata(metadata: MeemAPI.IERC721Metadata) { - if (!metadata.image) { - throw new Error('INVALID_METADATA') - } - - let image - - if (/^ipfs/.test(metadata.image)) { - const result = await services.ipfs.getIPFSFile(metadata.image) - if (!/image/.test(result.type)) { - throw new Error('INVALID_IMAGE_TYPE') - } - image = Buffer.from(result.body) - } else if (/^data:image/.test(metadata.image)) { - const dataIndex = metadata.image.indexOf('base64,') - image = Buffer.from(metadata.image.substring(dataIndex + 7), 'base64') - } else { - const { body } = await request.get(metadata.image) - image = Buffer.from(body) - } - - return image - } - - /** Get a Meem contract instance */ - public static async getAgreement(options: { - address: string - chainId: number - walletPrivateKey?: string - }) { - const { chainId, address } = options - - const ethers = services.ethers.getInstance() - - if (config.TESTING) { - // @ts-ignore - const c = (await ethers.getContractAt(meemABI, address)) - // @ts-ignore - .connect(global.signer) - // const c = await ethers.getContractAt(meemABI, address) - return c as Mycontract - } - - const { wallet } = await services.ethers.getProvider({ - chainId - }) - - const agreement = new ethers.Contract( - address, - meemABI, - wallet - ) as unknown as Mycontract - - return agreement - } - - public static meemInterface() { - const ethers = services.ethers.getInstance() - const inter = new ethers.utils.Interface(meemABI) - return inter - } - - public static async getContractInfo(options: { - contractAddress: string - chainId: number - tokenId: Ethers.BigNumberish - networkName: MeemAPI.NetworkName - }) { - const { contractAddress, tokenId, networkName, chainId } = options - const isMeemToken = - contractAddress.toLowerCase() === config.MEEM_PROXY_ADDRESS.toLowerCase() - - const contract = await this.erc721Contract({ - networkName, - address: contractAddress - }) - - const { - tokenURI: parentTokenURI, - tokenMetadata: parentTokenMetadata, - contractURI: parentContractURI, - contractMetadata: parentContractMetadata - } = await this.getMetadata({ - contract, - tokenId - }) - - // Fetch root data unless this isn't a Meem in which case root is the parent - const rootTokenAddress = contractAddress - const rootTokenId = tokenId - let rootTokenMetadata = parentTokenMetadata - let rootTokenURI = parentTokenURI - let rootContractURI = parentContractURI - let rootContractMetadata = parentContractMetadata - - if (isMeemToken) { - const agreement = await this.getAgreement({ - address: contractAddress, - chainId - }) - // const meem = await agreement.getMeem(tokenId) - // rootTokenAddress = meem.root - // rootTokenId = meem.rootTokenId - - const meemInfo = await this.getMetadata({ - contract: agreement, - tokenId - }) - - rootTokenMetadata = meemInfo.tokenMetadata - rootTokenURI = meemInfo.tokenURI - rootContractMetadata = meemInfo.contractMetadata - rootContractURI = meemInfo.contractURI - } - - return { - parentTokenAddress: contractAddress, - parentTokenId: tokenId, - parentTokenURI, - parentTokenMetadata, - parentContractURI, - parentContractMetadata, - rootTokenAddress, - rootTokenId, - rootTokenURI, - rootTokenMetadata, - rootContractURI, - rootContractMetadata - } - } - - public static async getMetadata(options: { - contract: ERC721 | Mycontract - tokenId: Ethers.BigNumberish - }) { - const { contract, tokenId } = options - const tokenURI = await contract.tokenURI(tokenId) - const tokenMetadata = await this.getErc721Metadata(tokenURI) - let contractURI: string | undefined - let contractMetadata: MeemAPI.IERC721Metadata | undefined - - try { - contractURI = await contract.contractURI() - } catch (e) { - log.warn(e) - } - if (contractURI) { - try { - contractMetadata = await this.getErc721Metadata(contractURI) - } catch (e) { - log.warn(e) - } - } - - return { - tokenURI, - tokenMetadata, - contractURI, - contractMetadata - } - } - - public static parseMeemData(data: string): Record { - let parsedData: Record | undefined - - try { - if (/^data:application\/json/.test(data)) { - const json = Buffer.from(data.substring(29), 'base64').toString() - parsedData = JSON.parse(json) - } - } catch (e) { - log.trace(e) - } - - try { - if (!parsedData && data !== '') { - parsedData = JSON.parse(data) - } - } catch (e) { - log.trace(e) - } - - return parsedData ?? {} - } -} diff --git a/src/services/MeemId.ts b/src/services/MeemId.ts index 62ae3ea3..1bbce5b7 100644 --- a/src/services/MeemId.ts +++ b/src/services/MeemId.ts @@ -76,8 +76,12 @@ export default class MeemIdentityService { /** Wallet signature */ signature?: string + + /** Optional invite code */ + inviteCode?: string }) { - const { attachToUser, accessToken, message, signature } = options + const { attachToUser, accessToken, message, signature, inviteCode } = + options let wallet: Wallet | undefined | null let user: User | undefined | null = attachToUser @@ -211,19 +215,14 @@ export default class MeemIdentityService { } if (!wallet) { - const { tokenId, address: pkpAddress } = await services.lit.mintPKP() - wallet = await orm.models.Wallet.create({ - address: pkpAddress, - UserId: user.id, - pkpTokenId: tokenId - }) - - user.DefaultWalletId = wallet.id - await user.save() + throw new Error('MISSING_WALLET') } - if (wallet.pkpTokenId === null && wallet.ensFetchedAt === null) { - await this.updateENS(wallet) + if (inviteCode) { + await services.agreement.acceptInvite({ + wallet, + code: inviteCode + }) } return { @@ -279,6 +278,15 @@ export default class MeemIdentityService { } jwtOptions.expiresIn = exp } + log.debug( + 'Sign JWT', + { + ...data, + walletAddress + }, + config.JWT_RSA_PRIVATE_KEY, + jwtOptions + ) const token = jsonwebtoken.sign( { ...data, @@ -458,7 +466,6 @@ export default class MeemIdentityService { wallet: Wallet profilePicBase64?: string displayName?: string - isDefaultWallet?: boolean }): Promise { // TODO: Add ability to add another wallet const { wallet, profilePicBase64, displayName } = data @@ -517,6 +524,9 @@ export default class MeemIdentityService { DefaultWalletId: wallet.id }) + wallet.UserId = user.id + await wallet.save() + const updatedUser = await orm.models.User.findOne({ include: [ { diff --git a/src/services/Puppeteer.ts b/src/services/Puppeteer.ts deleted file mode 100644 index a2b471f1..00000000 --- a/src/services/Puppeteer.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type Puppeteer from 'puppeteer-extra' - -export default class PuppeteerService { - public static shouldInitialize = true - - public puppeteer!: typeof Puppeteer - - public constructor() { - if (!config.ENABLE_PUPPETEER) { - log.debug('Puppeteer is disabled') - return - } - // eslint-disable-next-line - this.puppeteer = require('puppeteer-extra') - // eslint-disable-next-line - const StealthPlugin = require('puppeteer-extra-plugin-stealth') - this.puppeteer.use(StealthPlugin()) - // eslint-disable-next-line - const AdblockerPlugin = require('puppeteer-extra-plugin-adblocker') - this.puppeteer.use(AdblockerPlugin({ blockTrackers: true })) - } - - public getInstance() { - return this.puppeteer - } -} diff --git a/src/services/Queue.ts b/src/services/Queue.ts deleted file mode 100644 index 8f9c9aba..00000000 --- a/src/services/Queue.ts +++ /dev/null @@ -1,647 +0,0 @@ -import { getCuts, IFacetVersion } from '@meemproject/meem-contracts' -// eslint-disable-next-line import/no-extraneous-dependencies -import AWS from 'aws-sdk' -import { ethers } from 'ethers' -import { encodeSingle, TransactionType } from 'ethers-multisend' -import type { CallContractTransactionInput } from 'ethers-multisend' -import meemABI from '../abis/Meem.json' -import { InitParamsStruct } from '../types/Meem' -import { MeemAPI } from '../types/meem.generated' - -export interface IDeployTransactionInput { - args: any[] - bytecode: string -} - -export interface IDiamondCutTransactionInput { - bundleABI: Record[] - fromVersion: IFacetVersion[] - toVersion: IFacetVersion[] - contractInitParams: InitParamsStruct - senderWalletAddress: string - metadata: MeemAPI.IMeemMetadataLike - contractTxId?: string - contractAddress?: string - parentContractTxtId?: string -} - -export interface ICallContractInput - extends Partial { - id: string - contractAddress?: string - contractTxId?: string - functionSignature: string - inputValues: Record -} - -export interface ICreateTablelandTableInput extends IDeployTransactionInput { - fromVersion: IFacetVersion[] - toVersion: IFacetVersion[] - contractTxId?: string - contractAddress?: string - tableName: string - agreementExtensionId: string - functionCall: string - columns: { - [columnName: string]: MeemAPI.StorageDataType - } -} - -export interface IEvent { - eventName: MeemAPI.QueueEvent - id: string - chainId: number - agreementId?: string - transactionInput: - | ICallContractInput - | IDeployTransactionInput - | IDiamondCutTransactionInput - | ICreateTablelandTableInput - customABI?: Record[] -} - -export default class QueueService { - public static async handleEvent(options: { event: IEvent }) { - const { event } = options - const { eventName, id, chainId, transactionInput, customABI } = event - try { - log.debug('Queue.handleEvent', { event }) - - const transaction = await orm.models.Transaction.create({ - id, - transactionInput, - transactionType: eventName, - customABI, - chainId - }) - try { - const { recommendedGwei } = await services.web3.getGasEstimate({ - chainId - }) - - switch (eventName) { - case MeemAPI.QueueEvent.CreateTablelandTable: { - if (!customABI) { - log.crit('Missing ABI for DeployContract task') - throw new Error('MISSING_PARAMETERS') - } - - const { wallet } = await services.ethers.getProvider({ chainId }) - - const { - args, - bytecode, - fromVersion, - toVersion, - functionCall, - tableName, - columns, - agreementExtensionId - } = transactionInput as ICreateTablelandTableInput - - const t = await orm.sequelize.transaction() - - const agreementExtension = - await orm.models.AgreementExtension.findOne({ - where: { - id: agreementExtensionId - }, - transaction: t - }) - - try { - if (!agreementExtension) { - log.crit( - `Agreement extension not found for id: ${agreementExtensionId}` - ) - throw new Error('AGREEMENT_EXTENSION_NOT_FOUND') - } - - // Deploy proxy - const proxyContractFactory = new ethers.ContractFactory( - customABI, - { - object: bytecode - }, - wallet - ) - - const { nonce: deployNonce } = - await services.ethers.aquireLockAndNonce(chainId) - - const deployTx = await proxyContractFactory.deploy(...args, { - nonce: deployNonce, - gasPrice: services.web3.gweiToWei(recommendedGwei), - gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT) - }) - - await services.ethers.releaseLockAndNonce({ - chainId, - nonce: deployNonce - }) - - // Init proxy - const { nonce: cutNonce } = - await services.ethers.aquireLockAndNonce(chainId) - - const cuts = getCuts({ - proxyContractAddress: deployTx.address, - fromVersion, - toVersion - }) - - const facetCuts = cuts.map(c => ({ - target: c.facetAddress, - action: c.action, - selectors: c.functionSelectors - })) - - const cutTx = await deployTx.diamondCut( - facetCuts, - deployTx.address, - functionCall, - { - nonce: cutNonce, - gasPrice: services.web3.gweiToWei(recommendedGwei), - gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT) - } - ) - - log.debug(`Diamond cut w/ tx: ${cutTx.hash}`) - - await cutTx.wait() - - await services.ethers.releaseLockAndNonce({ - chainId, - nonce: cutNonce - }) - - const result = await services.storage.createTable({ - chainId, - schema: columns, - controllerAddress: deployTx.address - }) - - transaction.status = MeemAPI.TransactionStatus.Success - transaction.hash = result.txnHash - - const transactions = agreementExtension.metadata?.transactions - if (Array.isArray(agreementExtension.metadata?.transactions)) { - const idx = transactions?.findIndex( - tx => tx.TransactionId === transaction.id - ) - if (transactions && typeof idx !== 'undefined' && idx > -1) { - transactions[idx] = { - ...transactions[idx], - status: MeemAPI.TransactionStatus.Success - } - } - } - - agreementExtension.metadata = { - ...agreementExtension.metadata, - transactions, - storage: { - ...agreementExtension.metadata?.storage, - tableland: { - ...agreementExtension.metadata?.storage?.tableland, - [tableName]: { - tableId: result.tableId?.toHexString(), - tablelandTableName: result.name - } - } - } - } as MeemAPI.IAgreementExtensionMetadata - - let isInitialized = true - - if (Array.isArray(agreementExtension.metadata.transactions)) { - agreementExtension.metadata.transactions.forEach(tx => { - if (tx.status !== MeemAPI.TransactionStatus.Success) { - isInitialized = false - } - }) - } - - agreementExtension.isInitialized = isInitialized - agreementExtension.changed('metadata', true) - - await transaction.save({ transaction: t }) - await agreementExtension.save({ transaction: t }) - - await t.commit() - } catch (e) { - log.crit(e) - if (agreementExtension) { - const transactions = agreementExtension.metadata?.transactions - if (Array.isArray(agreementExtension.metadata?.transactions)) { - const idx = transactions?.findIndex( - tx => tx.TransactionId === transaction.id - ) - if (transactions && typeof idx !== 'undefined' && idx > -1) { - transactions[idx] = { - ...transactions[idx], - status: MeemAPI.TransactionStatus.Failure - } - } - } - - agreementExtension.metadata = { - ...agreementExtension.metadata, - transactions - } as MeemAPI.IAgreementExtensionMetadata - agreementExtension.changed('metadata', true) - } - - transaction.status = MeemAPI.TransactionStatus.Failure - await transaction.save() - } - - break - } - - case MeemAPI.QueueEvent.DeploySafe: - case MeemAPI.QueueEvent.CallContract: { - const { nonce } = await services.ethers.aquireLockAndNonce(chainId) - const { contractTxId, functionSignature } = - transactionInput as ICallContractInput - let { contractAddress, inputValues } = - transactionInput as ICallContractInput - - const { provider, wallet } = await services.ethers.getProvider({ - chainId - }) - - if (!contractAddress && contractTxId) { - const contractTransaction = await orm.models.Transaction.findOne({ - where: { - id: contractTxId - } - }) - - if (!contractTransaction) { - log.crit('Contract transaction not found') - throw new Error('TRANSACTION_NOT_FOUND') - } - - const result = await provider.core.getTransactionReceipt( - contractTransaction.hash - ) - contractAddress = result?.contractAddress - } - - if (!contractAddress) { - throw new Error('CONTRACT_ADDRESS_NOT_FOUND') - } - - // Special check for admin contract address transaction - if ( - functionSignature.includes('setAdminContract') && - inputValues.newAdminContractTxId - ) { - const adminContractTransaction = - await orm.models.Transaction.findOne({ - where: { - id: inputValues.newAdminContractTxId - } - }) - - if (!adminContractTransaction) { - log.crit('Admin contract transaction not found') - throw new Error('TRANSACTION_NOT_FOUND') - } - - const result = await provider.core.getTransactionReceipt( - adminContractTransaction.hash - ) - - inputValues = { - newAdminContract: result?.contractAddress - } - } - - // Encode and send the transaction - log.debug({ - id, - value: '0', - type: TransactionType.callContract, - to: contractAddress, - functionSignature, - inputValues - }) - const encoded = encodeSingle({ - id, - abi: customABI - ? JSON.stringify(customABI) - : JSON.stringify(meemABI), - value: '0', - type: TransactionType.callContract, - to: contractAddress, - functionSignature, - inputValues - }) - - const signedTx = await wallet.signTransaction({ - ...encoded, - gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT), - gasPrice: services.web3.gweiToWei(recommendedGwei), - nonce, - chainId - }) - - const tx = await provider.transact.sendTransaction(signedTx) - transaction.hash = tx.hash - - log.debug(`Running ${functionSignature} w/ hash: ${tx.hash}`) - - await transaction.save() - - try { - // Update the transaction status in the db - await tx.wait() - transaction.status = MeemAPI.TransactionStatus.Success - await transaction.save() - } catch (e) { - log.warn(e) - transaction.status = MeemAPI.TransactionStatus.Failure - await transaction.save() - } - - if (eventName === MeemAPI.QueueEvent.DeploySafe) { - const receipt = await provider.core.getTransactionReceipt(tx.hash) - - if (receipt) { - const { agreementId } = event - const agreement = await orm.models.Agreement.findOne({ - where: { - id: agreementId - } - }) - - if (!agreement) { - log.crit( - `Unable to update safe address. Agreement not found: ${agreementId}` - ) - throw new Error('AGREEMENT_NOT_FOUND') - } - - // Gnosis safe contract creation topic - const topic = - '0x141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a8' - - // Find the newly created Safe contract address in the transaction receipt - for (let i = 0; i < receipt.logs.length; i += 1) { - const receiptLog = receipt.logs[i] - const foundTopic = receiptLog.topics.find(t => t === topic) - if (foundTopic) { - log.debug( - `Setting safe address: ${receiptLog.address} for agreement: ${agreement.id}` - ) - agreement.gnosisSafeAddress = receiptLog.address - await agreement?.save() - break - } - } - } - } - - break - } - - case MeemAPI.QueueEvent.DeployContract: { - if (!customABI) { - log.crit('Missing ABI for DeployContract task') - throw new Error('MISSING_PARAMETERS') - } - - const { provider, wallet } = await services.ethers.getProvider({ - chainId - }) - - const { args, bytecode } = - transactionInput as IDeployTransactionInput - - const proxyContractFactory = new ethers.ContractFactory( - customABI, - { - object: bytecode - }, - wallet - ) - - const { nonce } = await services.ethers.aquireLockAndNonce(chainId) - - const unsignedTx = proxyContractFactory.getDeployTransaction( - ...args, - { - gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT), - gasPrice: services.web3.gweiToWei(recommendedGwei), - nonce - } - ) - - unsignedTx.chainId = chainId - - const signedTx = await wallet.signTransaction(unsignedTx) - - const tx = await provider.transact.sendTransaction(signedTx) - - transaction.hash = tx.hash - await transaction.save() - - log.debug(`Deploying contract w/ hash: ${tx.hash}`) - - try { - // Update the transaction status in the db - await tx.wait() - transaction.status = MeemAPI.TransactionStatus.Success - await transaction.save() - } catch (e) { - log.warn(e) - transaction.status = MeemAPI.TransactionStatus.Failure - await transaction.save() - } - - break - } - - case MeemAPI.QueueEvent.DiamondCut: { - if (!customABI) { - log.crit('Missing ABI for DeployContract task') - throw new Error('MISSING_PARAMETERS') - } - - const { provider, wallet } = await services.ethers.getProvider({ - chainId - }) - - const { - bundleABI, - contractTxId, - fromVersion, - toVersion, - metadata, - parentContractTxtId, - contractInitParams - } = transactionInput as IDiamondCutTransactionInput - - let { contractAddress } = - transactionInput as IDiamondCutTransactionInput - - if (!contractAddress) { - const contractTransaction = await orm.models.Transaction.findOne({ - where: { - id: contractTxId - } - }) - - if (!contractTransaction) { - log.crit('Contract transaction not found') - throw new Error('TRANSACTION_NOT_FOUND') - } - - const result = await provider.core.getTransactionReceipt( - contractTransaction.hash - ) - contractAddress = result?.contractAddress - } - - if (!contractAddress) { - throw new Error('CONTRACT_ADDRESS_NOT_FOUND') - } - - let parentContractAddress: string | undefined - - if (parentContractTxtId) { - const parentContractTransaction = - await orm.models.Transaction.findOne({ - where: { - id: parentContractTxtId - } - }) - - if (!parentContractTransaction) { - log.crit('Contract transaction not found') - throw new Error('TRANSACTION_NOT_FOUND') - } - - const result = await provider.core.getTransactionReceipt( - parentContractTransaction.hash - ) - parentContractAddress = result?.contractAddress - } - - if (metadata && contractInitParams.contractURI === '') { - if (parentContractAddress) { - metadata.meem_agreement_address = parentContractAddress - } - - const result = await services.web3.saveToPinata({ - json: { - ...metadata - } - }) - - contractInitParams.contractURI = `ipfs://${result.IpfsHash}` - } - - const iFace = new ethers.utils.Interface(bundleABI) - const functionCall = iFace.encodeFunctionData('initialize', [ - contractInitParams - ]) - - const proxyContract = new ethers.Contract( - contractAddress, - customABI, - wallet - ) - - const { nonce } = await services.ethers.aquireLockAndNonce(chainId) - - const cuts = getCuts({ - proxyContractAddress: proxyContract.address, - fromVersion, - toVersion - }) - - const facetCuts = cuts.map(c => ({ - target: c.facetAddress, - action: c.action, - selectors: c.functionSelectors - })) - - const tx = await proxyContract.diamondCut( - facetCuts, - contractAddress, - functionCall, - { - nonce, - gasPrice: services.web3.gweiToWei(recommendedGwei), - gasLimit: ethers.BigNumber.from(config.MINT_GAS_LIMIT) - } - ) - - transaction.hash = tx.hash - await transaction.save() - - log.debug(`DiamondCut contract w/ hash: ${tx.hash}`) - - try { - // Update the transaction status in the db - await tx.wait() - transaction.status = MeemAPI.TransactionStatus.Success - await transaction.save() - } catch (e) { - log.warn(e) - transaction.status = MeemAPI.TransactionStatus.Failure - await transaction.save() - } - - break - } - - default: - log.warn(`No event handlers for ${event.eventName}`) - break - } - log.debug('Finished processing event') - await services.ethers.releaseLock(chainId) - } catch (e) { - log.crit(e) - await services.ethers.releaseLock(chainId) - transaction.status = MeemAPI.TransactionStatus.Failure - await transaction.save() - } - } catch (e) { - log.crit(e) - await services.ethers.releaseLock(chainId) - } - } - - public static sendMessage(message: AWS.SQS.SendMessageBatchRequestEntry) { - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve, reject) => { - const sqs = new AWS.SQS({ - region: 'us-east-1', - apiVersion: '2012-11-05', - accessKeyId: config.APP_AWS_ACCESS_KEY_ID, - secretAccessKey: config.APP_AWS_SECRET_ACCESS_KEY - }) - - sqs.sendMessageBatch( - { - QueueUrl: config.SQS_QUEUE_URL, - Entries: [message] - }, - (err, response) => { - if (err) { - log.warn(err) - reject(err) - return - } - resolve(response) - } - ) - }) - } -} diff --git a/src/services/Scraper.ts b/src/services/Scraper.ts deleted file mode 100644 index 19b7f89e..00000000 --- a/src/services/Scraper.ts +++ /dev/null @@ -1,29 +0,0 @@ -export default class ScraperService { - public static async screenshotUrl(url: string): Promise { - const puppeteer = services.puppeteer.getInstance() - const browser = await puppeteer.launch({ - // headless: true, // debug only - args: ['--no-sandbox'] - }) - - const page = await browser.newPage() - - page.setViewport({ - width: 1024, - height: 768 - }) - - await page.goto(url, { - waitUntil: ['load', 'networkidle0', 'domcontentloaded'] - }) - - const buffer = await page.screenshot({ - fullPage: true, - type: 'jpeg' - }) - - await browser.close() - - return buffer - } -} diff --git a/src/services/Storage.ts b/src/services/Storage.ts deleted file mode 100644 index c33b2e23..00000000 --- a/src/services/Storage.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { connect } from '@tableland/sdk' -import type { Connection, NetworkName } from '@tableland/sdk' -import { ethers } from 'ethers' -import { MeemAPI } from '../types/meem.generated' - -export default class StorageService { - public static shouldInitialize = true - - private tablelands: { - [chainId: number]: Connection - } = {} - - public async createTable(options: { - chainId: number - schema: { - [column: string]: MeemAPI.StorageDataType - } - controllerAddress: string - }) { - const { chainId, schema, controllerAddress } = options - - const tableland = await this.getInstance({ - chainId - }) - - let createSchema = - 'id INTEGER PRIMARY KEY, updatedAt INTEGER, createdAt INTEGER' - - Object.keys(schema).forEach(columnName => { - createSchema += `, ${columnName} ${schema[columnName]}` - }) - - const receipt = await tableland.create(createSchema, {}) - - log.debug(receipt) - - if (receipt.name) { - try { - await tableland.setController(controllerAddress, receipt.name, { - rpcRelay: false - }) - } catch (e) { - log.warn( - `Error setting controller for tableland table: ${receipt.name} to controller contract: ${controllerAddress}` - ) - log.warn(e) - } - } - - /** - * Receipt - * { - * tableId: { - * type: "BigNumber", - * hex: "0x040a" - * }, - * prefix: "", - * chainId: 5, - * txnHash: "0x62249c1dc89d2f4c54979f63829576cf9204fd1d107638ccd58f7686c897843b", - * blockNumber: 8081735, - * name: "_5_1034" - * } - */ - - return receipt - } - - private async getInstance(options: { - chainId: number - network?: NetworkName - }) { - const { chainId, network } = options - if (!this.tablelands[chainId]) { - const { ethersProvider } = await services.ethers.getProvider({ chainId }) - const wallet = new ethers.Wallet(config.WALLET_PRIVATE_KEY) - const signer = wallet.connect(ethersProvider) - - const connection = await connect({ - signer, - network: network ?? 'testnet', - chain: this.chainIdToTablelandChainName(chainId) - }) - this.tablelands[chainId] = connection - } - - return this.tablelands[chainId] - } - - // TODO: Pull in this function from @meemproject/utils - private chainIdToTablelandChainName(chainId: number) { - switch (chainId) { - case 1: - return 'ethereum' - break - - case 10: - return 'optimism' - break - - case 137: - return 'polygon' - break - - case 42161: - return 'arbitrum' - break - - case 5: - return 'ethereum-goerli' - break - - case 420: - return 'optimism-goerli' - break - - case 421613: - return 'arbitrum-goerli' - break - - case 80001: - return 'polygon-mumbai' - break - - // case 1: - // return 'optimism-goerli-staging' - // break - - // case 1: - // return 'local-tableland' - // break - - // case 1: - // return 'custom' - // break - - default: - throw new Error('CHAIN_NOT_SUPPORTED') - } - } -} diff --git a/src/services/Web3.ts b/src/services/Web3.ts index 993fa3f4..f05c1f0b 100644 --- a/src/services/Web3.ts +++ b/src/services/Web3.ts @@ -1,6 +1,5 @@ import { Readable } from 'stream' import Pinata, { PinataPinResponse } from '@pinata/sdk' -// import BigNumber from 'bignumber.js' import type { ethers as Ethers } from 'ethers' import request from 'superagent' import { MeemAPI } from '../types/meem.generated' @@ -155,17 +154,6 @@ export default class Web3 { public static toBigNumber(val: Ethers.BigNumberish): Ethers.BigNumber { const ethers = services.ethers.getInstance() const bn = ethers.BigNumber.from(val.toString()) - // let bigStr = bn.toString() - // let isNegative = false - // if (/^-/.test(bigStr)) { - // bigStr = bigStr.substr(1) - // isNegative = true - // } - // const ebn = ethers.BigNumber.from( - // `${isNegative ? '-' : ''}0x${bn.toHexString()}` - // ) - - // return ebn return bn } @@ -174,116 +162,6 @@ export default class Web3 { return pinata } - // public static async saveMeemMetadata(data: { - // imageBase64?: string - // image?: Buffer - // metadata: MeemAPI.IMeemMetadataLike | MeemAPI.ICreateMeemMetadata - // }): Promise<{ metadata: MeemAPI.IMeemMetadataLike; tokenURI: string }> { - // if (config.TESTING) { - // const imageURI = services.testing.getIpfsUrl() - // return { - // metadata: services.testing.getMeemMetadata({ - // image: imageURI, - // image_original: imageURI - // }), - // tokenURI: services.testing.getIpfsUrl() - // } - // } - - // this.validateCreateMeemMetadata(data.metadata) - - // const imgData = data.imageBase64 ?? data.image?.toString('base64') - - // if (!imgData) { - // throw new Error('INVALID_IMAGE_TYPE') - // } - - // const meemMetadata = data.metadata as MeemAPI.IMeemMetadataLike - - // const meemId = data.metadata.meem_id ?? uuidv4() - // const isValid = validateUUID(meemId) - - // if (!isValid) { - // throw new Error('INVALID_METADATA') - // } - - // // const buffStream = new stream.PassThrough() - // // buffStream.end(Buffer.from(imgData, 'base64')) - // const buff = Buffer.from(imgData, 'base64') - // const stream = Readable.from(buff) - // // @ts-ignore - // stream.path = `${meemId}/image.png` - - // const imageResponse = await this.saveToPinata({ - // // file: Readable.from(Buffer.from(imgData, 'base64')) - // // file: buffStream - // file: stream - // }) - - // const image = `ipfs://${imageResponse.IpfsHash}` - - // const externalUrl = - // meemMetadata.external_url ?? `${config.MEEM_DOMAIN}/meems/${meemId}` - - // const storedMetadata: MeemAPI.IMeemMetadataLike = { - // ...data.metadata, - // external_url: externalUrl, - // meem_id: meemId, - // image, - // image_original: - // meemMetadata.image && meemMetadata.image !== '' - // ? meemMetadata.image - // : image - // } - - // const metadataResponse = await this.saveToPinata({ - // json: storedMetadata - // }) - - // // return { - // // metadata: storedMetadata, - // // tokenURI: metadataPath - // // } - // return { - // metadata: storedMetadata, - // tokenURI: `ipfs://${metadataResponse.IpfsHash}` - // } - // } - - // public static validateCreateMeemMetadata(metadata: Record) { - // if (!metadata.name || !metadata.description) { - // throw new Error('INVALID_METADATA') - // } - // } - - public static async syncPins() { - const meems = await orm.models.AgreementToken.findAll({ limit: 5 }) - const pinata = this.getPinataInstance() - - for (let i = 0; i < meems.length; i += 1) { - const meem = meems[i] - const matches = meem.tokenURI.match(/ipfs:\/\/([^/]*)/) - if (matches && matches[1]) { - const ipfsHash = matches[1] - log.debug(`Pinning metadata w/ hash: ${ipfsHash}`) - // eslint-disable-next-line no-await-in-loop - await pinata.pinByHash(ipfsHash) - } else { - log.debug(`Skipping ${meem.tokenURI}`) - } - - const imgMatches = meem.metadata.image.match(/ipfs:\/\/([^/]*)/) - if (imgMatches && imgMatches[1]) { - const ipfsHash = imgMatches[1] - log.debug(`Pinning image w/ hash: ${ipfsHash}`) - // eslint-disable-next-line no-await-in-loop - await pinata.pinByHash(ipfsHash) - } else { - log.debug(`Skipping ${meem.metadata.image}`) - } - } - } - public static async saveToPinata(options: { json?: Record file?: Readable diff --git a/src/tests/BaseTest.ts b/src/tests/BaseTest.ts index 4f4807c6..3a2b43a7 100644 --- a/src/tests/BaseTest.ts +++ b/src/tests/BaseTest.ts @@ -1,8 +1,11 @@ import { Server } from 'http' +import faker from 'faker' import { Suite } from 'mocha' import supertest, { SuperTest, Test, Response } from 'supertest' import start from '../core/start' +import User from '../models/User' import { MeemAPI } from '../types/meem.generated' +import { wallets, type IMocks } from './mocks' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' @@ -11,6 +14,11 @@ export default class BaseTest { protected request!: SuperTest + protected mocks: IMocks = { + users: [], + agreements: [] + } + public constructor(mocha: Suite) { if (!mocha) { throw new Error('Test suite is not passing mocha to base constructor') @@ -30,20 +38,64 @@ export default class BaseTest { const { server } = await start() this.server = server as Server this.request = supertest(this.server) + await orm.runSync() await this.setupMocks() } protected async setupMocks() { - // const promises = wallets.map(w => { - // return services.meemId.createOrUpdateMeemId({ - // address: w.address, - // signature: '', - // twitterAccessToken: '', - // twitterAccessSecret: '' - // }) - // }) - // await Promise.all(promises) + for (let i = 0; i < wallets.length; i++) { + const w = wallets[i] + const wallet = await orm.models.Wallet.create({ + address: w.address + }) + const user = await services.meemId.createOrUpdateUser({ + wallet + }) + + this.mocks.users.push(user) + } + } + + protected async getAgreement() { + const wallet = this.mocks.users[0].DefaultWallet + + const result = await services.agreement.createAgreementWithoutContract({ + body: { + name: faker.lorem.words(), + metadata: {}, + shouldCreateAdminRole: true + }, + owner: wallet + }) + + await Promise.all([ + services.agreement.bulkMint({ + agreementId: result.agreement.id, + mintedBy: wallet.address, + tokens: [ + { + to: wallet.address, + metadata: {} + } + ] + }), + result.adminAgreement + ? services.agreement.bulkMint({ + agreementId: result.agreement.id, + agreementRoleId: result.adminAgreement.id, + mintedBy: wallet.address, + tokens: [ + { + to: wallet.address, + metadata: {} + } + ] + }) + : Promise.resolve(null) + ]) + + return result } protected async after() {} @@ -63,14 +115,27 @@ export default class BaseTest { // eslint-disable-next-line @typescript-eslint/ban-types data?: string | object expect?: number + user?: User + headers?: Record }): Promise { - const { path, method, data, query, expect } = options + const { path, method, data, query, expect, user, headers } = options let req = this.getRequest(method)(path) if (query) { req = req.query(query) } + if (headers) { + Object.keys(headers).forEach(key => req.set(key, headers[key])) + } + + if (user) { + const jwt = services.meemId.generateJWT({ + walletAddress: user.DefaultWallet.address + }) + req = req.set('Authorization', `JWT ${jwt}`) + } + if (data) { req = req.send(data) } diff --git a/src/tests/api/ContractInit.test.ts b/src/tests/api/ContractInit.test.ts deleted file mode 100644 index 76c2597c..00000000 --- a/src/tests/api/ContractInit.test.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { assert } from 'chai' -import BaseTest from '../BaseTest' - -class ContractInitTests extends BaseTest { - protected async setup() { - it.skip('Can prepare init values for removing admins', () => - this.prepareInit()) - } - - private async prepareInit() { - const apiWallet = '0xde19C037a85A609ec33Fc747bE9Db8809175C3a5' - const metadata = { - meem_contract_type: 'meem-club', - meem_metadata_version: 'MeemClub_Contract_20220718', - name: 'asdf', - description: 'asdf', - image: '', - associations: [], - external_url: `https://clubs.link/`, - application_instructions: [] - } - - const agreement = await orm.models.Agreement.create({ - address: '0xEFDa83b22E408A27182CFb7a44296DE313Fbc49b', - mintPermissions: [], - slug: 'test', - symbol: 'TEST', - name: 'test', - chainId: 5, - metadata - }) - - const wallets = await orm.models.Wallet.bulkCreate([ - { - address: '0x0000000000000000000000000000000000000001' - }, - { - address: '0x0000000000000000000000000000000000000002' - }, - { - address: '0x0000000000000000000000000000000000000003' - }, - { - address: '0x0000000000000000000000000000000000000004' - } - ]) - - await orm.models.AgreementWallet.bulkCreate([ - { - role: config.ADMIN_ROLE, - AgreementId: agreement.id, - WalletId: wallets[0].id - } - ]) - - let result = await services.agreement.prepareInitValues({ - admins: ['0x0000000000000000000000000000000000000001'], - minters: [], - chainId: 5, - senderWalletAddress: '0xa44296DE313Fbc49bEFDa83b22E408A27182CFb7', - agreementOrRole: agreement - }) - - const apiAdmin = result.contractInitParams.roles.find( - r => r.role === config.ADMIN_ROLE && r.user === apiWallet && r.hasRole - ) - const apiUpgrader = result.contractInitParams.roles.find( - r => r.role === config.UPGRADER_ROLE && r.user === apiWallet && r.hasRole - ) - const apiMinter = result.contractInitParams.roles.find( - r => r.role === config.MINTER_ROLE && r.user === apiWallet && r.hasRole - ) - - assert.isOk(apiAdmin) - assert.isOk(apiUpgrader) - assert.isOk(apiMinter) - - result = await services.agreement.prepareInitValues({ - admins: [ - '0x0000000000000000000000000000000000000001', - '0x0000000000000000000000000000000000000002' - ], - minters: [], - chainId: 5, - senderWalletAddress: '0xa44296DE313Fbc49bEFDa83b22E408A27182CFb7', - agreementOrRole: agreement - }) - - const user2Admin = result.contractInitParams.roles.find( - r => - r.role === config.ADMIN_ROLE && - r.user === '0x0000000000000000000000000000000000000002' && - r.hasRole - ) - - assert.isOk(user2Admin) - - assert.equal( - result.cleanAdmins[1].user, - '0x0000000000000000000000000000000000000002' - ) - - assert.isTrue(result.cleanAdmins[1].hasRole) - - result = await services.agreement.prepareInitValues({ - admins: ['0x0000000000000000000000000000000000000002'], - minters: [], - chainId: 5, - senderWalletAddress: '0xa44296DE313Fbc49bEFDa83b22E408A27182CFb7', - agreementOrRole: agreement - }) - - const user1Admin = result.contractInitParams.roles.find( - r => - r.role === config.ADMIN_ROLE && - r.user === '0x0000000000000000000000000000000000000001' && - !r.hasRole - ) - - assert.isOk(user1Admin) - } -} - -describe('ContractInitTests', function tests() { - new ContractInitTests(this) -}) diff --git a/src/tests/api/Invites.test.ts b/src/tests/api/Invites.test.ts new file mode 100644 index 00000000..49738061 --- /dev/null +++ b/src/tests/api/Invites.test.ts @@ -0,0 +1,89 @@ +import { assert } from 'chai' +import { MeemAPI } from '../../types/meem.generated' +import BaseTest from '../BaseTest' + +class ConfigTests extends BaseTest { + protected async setup() { + it('Can not invite a user if not logged in', () => + this.inviteUserNotLoggedIn()) + it.skip('Can invite a user and accept invite', () => this.inviteUser()) + } + + private async inviteUserNotLoggedIn() { + const { agreement } = await this.getAgreement() + + await this.makeRequest({ + path: MeemAPI.v1.SendAgreementInvites.path({ + agreementId: agreement.id + }), + method: MeemAPI.v1.SendAgreementInvites.method, + expect: 403 + }) + } + + private async inviteUser() { + const { agreement } = await this.getAgreement() + + const user0 = this.mocks.users[0] + const user1 = this.mocks.users[1] + + const { body } = await this.makeRequest({ + path: MeemAPI.v1.SendAgreementInvites.path({ + agreementId: agreement.id + }), + data: { + to: ['test@example.com'] + }, + method: MeemAPI.v1.SendAgreementInvites.method, + expect: 200, + user: user0 + }) + + assert.equal(body.status, 'success') + + const invite = await orm.models.Invite.findOne({ + order: [['createdAt', 'DESC']] + }) + + assert.equal(invite?.AgreementId, agreement.id) + + const { body: body2 } = await this.makeRequest({ + path: MeemAPI.v1.AcceptAgreementInvite.path(), + data: { + code: invite?.code + }, + method: MeemAPI.v1.AcceptAgreementInvite.method, + expect: 200, + user: user1 + }) + + assert.isOk(body2.agreementId) + assert.isOk(body2.agreementTokenId) + assert.isOk(body2.name) + assert.isOk(body2.slug) + assert.isOk(body2.agreementRoleId) + assert.isOk(body2.agreementRoleTokenId) + + const agreementToken = await orm.models.AgreementToken.findOne({ + where: { + id: body2.agreementTokenId, + OwnerId: user1.DefaultWalletId + } + }) + + assert.isOk(agreementToken) + + const agreementRoleToken = await orm.models.AgreementRoleToken.findOne({ + where: { + id: body2.agreementRoleTokenId, + OwnerId: user1.DefaultWalletId + } + }) + + assert.isOk(agreementRoleToken) + } +} + +describe('ConfigTests', function tests() { + new ConfigTests(this) +}) diff --git a/src/tests/api/MintTweets.test.ts.OLD b/src/tests/api/MintTweets.test.ts.OLD deleted file mode 100644 index 7811cabd..00000000 --- a/src/tests/api/MintTweets.test.ts.OLD +++ /dev/null @@ -1,384 +0,0 @@ -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import chai, { assert } from 'chai' -import chaiAsPromised from 'chai-as-promised' -import faker from 'faker' -import { ethers } from 'hardhat' -import { v4 as uuidv4 } from 'uuid' -import { deployMeemDiamond } from '../../../tasks' -import { MeemAPI } from '../../types/meem.generated' -import BaseTest from '../BaseTest' - -chai.use(chaiAsPromised) - -class MintTweetsTests extends BaseTest { - private signers!: SignerWithAddress[] - - private contractAddress!: string - - protected async beforeEach() { - this.signers = await ethers.getSigners() - this.setSigner(this.signers[0]) - const { DiamondProxy: contractAddress } = await deployMeemDiamond({ - ethers - }) - this.contractAddress = contractAddress - config.MEEM_PROXY_ADDRESS = contractAddress - config.TWITTER_WALLET_PRIVATE_KEY = config.HARDHAT_MEEM_CONTRACT_WALLET - } - - protected async setup() { - // it('Can mint a Tweet', () => this.mintTweet()) - // it('Can not mint a Tweet as non-minter', () => this.nonMinterTweet()) - // // TODO: Why does this test fail on CI but pass locally? - // // it('Can mint remix tweet', () => this.mintAndRemixTweet()) - // it('Can claim a Tweet', () => this.claimTweet()) - // it('Can claim a Wrapped Meem', () => this.claimWrappedMeem()) - // it('Can not claim a Tweet as non-owner', () => this.claimTweetNonOwner()) - } - - private async mintTweet() { - const meemContract = await services.meem.getAgreement() - - await services.meem.createMeemProject({ - name: 'Twitter project', - description: 'blah blah', - minterAddresses: [this.signers[0].address] - }) - - config.TWITTER_PROJECT_TOKEN_ID = '100000' - - const project = await meemContract.getMeem(config.TWITTER_PROJECT_TOKEN_ID) - assert.equal(project.meemType, MeemAPI.MeemType.Original) - - await services.twitter.mintTweet({ - tweetData: { - id: uuidv4(), - text: faker.lorem.words() - }, - twitterUser: { - id: uuidv4(), - name: faker.name.firstName(), - username: faker.lorem.word() - } - }) - - const meem = await meemContract.connect(this.signers[0]).getMeem(100001) - assert.equal(meem.meemType, MeemAPI.MeemType.Remix) - assert.equal(meem.parent, this.contractAddress) - assert.equal(meem.parentTokenId.toNumber(), 100000) - assert.equal(meem.root, this.contractAddress) - assert.equal(meem.rootTokenId.toNumber(), 100000) - assert.equal(meem.generation.toNumber(), 1) - assert.notEqual(meem.properties.splits[0].lockedBy, MeemAPI.zeroAddress) - assert.equal(meem.properties.splits[0].amount.toNumber(), 100) - assert.equal(meem.properties.splits[0].toAddress, config.DAO_WALLET) - } - - private async nonMinterTweet() { - await services.meem.createMeemProject({ - name: 'Twitter project', - description: 'blah blah', - minterAddresses: [this.signers[0].address] - }) - - config.TWITTER_PROJECT_TOKEN_ID = '100000' - - this.setSigner(this.signers[1]) - - await assert.isRejected( - services.twitter.mintTweet({ - tweetData: { - id: uuidv4(), - text: faker.lorem.words() - }, - twitterUser: { - id: uuidv4(), - name: faker.name.firstName(), - username: faker.lorem.word() - } - }) - ) - } - - private async claimTweet() { - const meemContract = await services.meem.getAgreement() - - await services.meem.createMeemProject({ - name: 'Twitter project', - description: 'blah blah', - minterAddresses: [this.signers[0].address] - }) - - config.TWITTER_PROJECT_TOKEN_ID = '100000' - - const project = await meemContract.getMeem(config.TWITTER_PROJECT_TOKEN_ID) - assert.equal(project.meemType, MeemAPI.MeemType.Original) - - const twitterUserId = uuidv4() - - await services.twitter.mintTweet({ - tweetData: { - id: twitterUserId, - text: faker.lorem.words() - }, - twitterUser: { - id: twitterUserId, - name: faker.name.firstName(), - username: faker.lorem.word() - } - }) - - const meem = await meemContract.connect(this.signers[0]).getMeem(100001) - assert.equal(meem.owner, config.MEEM_PROXY_ADDRESS) - assert.equal(meem.meemType, MeemAPI.MeemType.Remix) - assert.equal(meem.parent, this.contractAddress) - assert.equal(meem.parentTokenId.toNumber(), 100000) - assert.equal(meem.generation.toNumber(), 1) - assert.notEqual(meem.properties.splits[0].lockedBy, MeemAPI.zeroAddress) - assert.equal(meem.properties.splits[0].amount.toNumber(), 100) - assert.equal(meem.properties.splits[0].toAddress, config.DAO_WALLET) - - const meemIdentificationId = uuidv4() - const meemIdentification = await orm.models.MeemIdentification.create({ - id: meemIdentificationId - }) - - const wallet = await orm.models.Wallet.create({ - address: this.signers[1].address, - isDefault: true, - meemIdentification - }) - - const twitter = await orm.models.Twitter.create({ - twitterId: twitterUserId, - isDefault: true, - meemIdentification - }) - - meemIdentification.Wallets = [wallet] - meemIdentification.Twitters = [twitter] - - await services.meem.claimMeem('100001', meemIdentification) - - const claimedMeem = await meemContract - .connect(this.signers[0]) - .getMeem(100001) - assert.equal(claimedMeem.owner, this.signers[1].address) - } - - private async claimWrappedMeem() { - const meemContract = await services.meem.getAgreement() - - await services.meem.mintWrappedMeem({ - tokenAddress: '0x6444070d9b4776a2363d1bac287571db11d692eb', - tokenId: 80, - chain: 1, - accountAddress: config.MEEM_PROXY_ADDRESS, - properties: { - totalCopies: '-1', - totalCopiesLockedBy: MeemAPI.zeroAddress, - totalRemixes: '-1', - totalRemixesLockedBy: MeemAPI.zeroAddress, - copyPermissions: [ - { - permission: 1, - addresses: [], - numTokens: '0', - lockedBy: MeemAPI.zeroAddress, - costWei: '0' - } - ], - splits: [ - { - toAddress: '0x40c6BeE45d94063c5B05144489cd8A9879899592', - amount: 1000, - lockedBy: MeemAPI.zeroAddress - } - ] - }, - childProperties: { - totalCopies: '-1', - totalCopiesLockedBy: MeemAPI.zeroAddress, - totalRemixes: '-1', - totalRemixesLockedBy: MeemAPI.zeroAddress, - copyPermissions: [ - { - permission: 1, - addresses: [], - numTokens: '0', - lockedBy: MeemAPI.zeroAddress, - costWei: '0' - } - ], - splits: [ - { - toAddress: '0x40c6BeE45d94063c5B05144489cd8A9879899592', - amount: 1000, - lockedBy: MeemAPI.zeroAddress - } - ] - } - }) - - const meem = await meemContract.connect(this.signers[0]).getMeem(100000) - - assert.equal(meem.owner, config.MEEM_PROXY_ADDRESS) - assert.equal(meem.meemType, MeemAPI.MeemType.Wrapped) - assert.equal(meem.generation.toNumber(), 0) - - const meemIdentificationId = uuidv4() - const meemIdentification = await orm.models.MeemIdentification.create({ - id: meemIdentificationId - }) - - const wallet = await orm.models.Wallet.create({ - address: '0xE7EDF0FeAebaF19Ad799eA9246E7bd8a38002d89', - isDefault: true, - meemIdentification - }) - - const twitter = await orm.models.Twitter.create({ - twitterId: uuidv4(), - isDefault: true, - meemIdentification - }) - - meemIdentification.Wallets = [wallet] - meemIdentification.Twitters = [twitter] - - await services.meem.claimMeem('100000', meemIdentification) - - const claimedMeem = await meemContract - .connect(this.signers[0]) - .getMeem(100000) - assert.equal( - claimedMeem.owner, - '0xE7EDF0FeAebaF19Ad799eA9246E7bd8a38002d89' - ) - } - - private async claimTweetNonOwner() { - const meemContract = await services.meem.getAgreement() - - await services.meem.createMeemProject({ - name: 'Twitter project', - description: 'blah blah', - minterAddresses: [this.signers[0].address] - }) - - config.TWITTER_PROJECT_TOKEN_ID = '100000' - - const project = await meemContract.getMeem(config.TWITTER_PROJECT_TOKEN_ID) - assert.equal(project.meemType, MeemAPI.MeemType.Original) - - const twitterUserId = uuidv4() - const nonOwnerTwitterUserId = uuidv4() - - await services.twitter.mintTweet({ - tweetData: { - id: twitterUserId, - text: faker.lorem.words() - }, - twitterUser: { - id: twitterUserId, - name: faker.name.firstName(), - username: faker.lorem.word() - } - }) - - const meemIdentificationId = uuidv4() - const meemIdentification = await orm.models.MeemIdentification.create({ - id: meemIdentificationId - }) - - const wallet = await orm.models.Wallet.create({ - address: this.signers[1].address, - isDefault: true, - meemIdentification - }) - - const twitter = await orm.models.Twitter.create({ - twitterId: nonOwnerTwitterUserId, - isDefault: true, - meemIdentification - }) - - meemIdentification.Wallets = [wallet] - meemIdentification.Twitters = [twitter] - - await assert.isRejected( - services.meem.claimMeem('100001', meemIdentification) - ) - } - - private async mintAndRemixTweet() { - const meemContract = await services.meem.getAgreement() - - await services.meem.createMeemProject({ - name: 'Twitter project', - description: 'blah blah', - minterAddresses: [this.signers[0].address] - }) - - const twitterUserId = uuidv4() - - config.TWITTER_PROJECT_TOKEN_ID = '100000' - - await services.twitter.mintTweet({ - tweetData: { - id: uuidv4(), - text: faker.lorem.words() - }, - twitterUser: { - id: uuidv4(), - name: faker.name.firstName(), - username: faker.lorem.word() - }, - remix: { - meemId: { - wallets: [this.signers[1].address], - twitters: [twitterUserId], - defaultWallet: this.signers[1].address, - defaultTwitter: twitterUserId, - hasOnboarded: true, - meemPass: { - twitter: { - hasApplied: true, - isWhitelisted: true, - tweetsPerDayQuota: 99 - }, - isAdmin: false - } - }, - tweetData: { - id: uuidv4(), - text: faker.lorem.words() - }, - twitterUser: { - id: uuidv4(), - name: faker.name.firstName(), - username: faker.lorem.word() - } - } - }) - - const meem = await meemContract.connect(this.signers[0]).getMeem(100001) - assert.equal(meem.owner, config.MEEM_PROXY_ADDRESS) - assert.equal(meem.meemType, MeemAPI.MeemType.Remix) - assert.equal(meem.parent, this.contractAddress) - assert.equal(meem.parentTokenId.toNumber(), 100000) - assert.equal(meem.generation.toNumber(), 1) - const remixMeem = await meemContract - .connect(this.signers[0]) - .getMeem(100002) - assert.equal(remixMeem.owner, this.signers[1].address) - assert.equal(remixMeem.meemType, MeemAPI.MeemType.Remix) - assert.equal(remixMeem.parent, this.contractAddress) - assert.equal(remixMeem.parentTokenId.toNumber(), 100001) - assert.equal(remixMeem.generation.toNumber(), 2) - } -} - -describe('MintTweetsTests', function tests() { - new MintTweetsTests(this) -}) diff --git a/src/tests/mocks.ts b/src/tests/mocks.ts index 03774e88..54d16f26 100644 --- a/src/tests/mocks.ts +++ b/src/tests/mocks.ts @@ -1,3 +1,11 @@ +import Agreement from '../models/Agreement' +import User from '../models/User' + +export interface IMocks { + users: User[] + agreements: Agreement[] +} + export const wallets = [ { address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', diff --git a/src/types/meem.generated.ts b/src/types/meem.generated.ts index 2151ae27..076508ee 100644 --- a/src/types/meem.generated.ts +++ b/src/types/meem.generated.ts @@ -247,8 +247,8 @@ export interface IMeemSplit { lockedBy: string } export interface IMeemMetadataLike { - meem_metadata_type: string - meem_metadata_version: string + meem_metadata_type?: string + meem_metadata_version?: string [key: string]: any } @@ -901,6 +901,40 @@ export interface IWebhookBody { export namespace v1 { +export namespace AcceptAgreementInvite { + export interface IPathParams {} + + export const path = () => `/api/1.0/acceptInvite` + + export const method = HttpMethod.Post + + export interface IQueryParams {} + + export interface IRequestBody { + code: string + } + + export interface IResponseBody extends IApiResponseBody { + name: string + agreementId: string + slug: string + agreementTokenId: string + agreementRoleId?: string + agreementRoleTokenId?: string + } + + export interface IDefinition { + pathParams: IPathParams + queryParams: IQueryParams + requestBody: IRequestBody + responseBody: IResponseBody + } + + export type Response = IResponseBody | IError +} + + + /** Bulk mint agreement role tokens */ export namespace BulkBurnAgreementRoleTokens { export interface IPathParams { @@ -1339,48 +1373,6 @@ export namespace CreateAgreementRole { -/** Create an agreement safe */ -export namespace CreateAgreementSafe { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/safe` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Addresses of the safe owners */ - safeOwners: string[] - - /** Chain id of the safe */ - chainId?: number - - /** The number of signatures required */ - threshold?: number - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - /** Delete an agreement role contract */ export namespace DeleteAgreementRole { export interface IPathParams { @@ -1667,28 +1659,27 @@ export namespace ReInitializeAgreementRole { -/** Set the agreement admin role */ -export namespace SetAgreementAdminRole { +/** Allows invitation via email and/or wallet addresses. In the case of wallet address, this will function the same as bulkMint */ +export namespace SendAgreementInvites { export interface IPathParams { /** The id of the agreement */ agreementId: string } export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/setAdminRole` + `/api/1.0/agreements/${options.agreementId}/invite` - export const method = HttpMethod.Patch + export const method = HttpMethod.Post export interface IQueryParams {} export interface IRequestBody { - /** The id of the agreement role to set as admin role */ - adminAgreementRoleId: string + /** Array of email and/or wallet addresses */ + to: string[] } export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string + status: 'success' } export interface IDefinition { @@ -1697,8 +1688,9 @@ export namespace SetAgreementAdminRole { requestBody: IRequestBody responseBody: IResponseBody } -} + export type Response = IResponseBody | IError +} @@ -1841,81 +1833,6 @@ export namespace UpdateAgreementExtension { -/** Upgrade an agreement contract */ -export namespace UpgradeAgreement { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - -/** Upgrade an agreement role contract */ -export namespace UpgradeAgreementRole { - export interface IPathParams { - /** The id of the agreement */ - agreementId: string - /** The id of the agreement role */ - agreementRoleId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/roles/${options.agreementRoleId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - export namespace AuthenticateWithDiscord { export interface IPathParams {} @@ -2303,90 +2220,6 @@ export namespace GetNonce { -export namespace GetJoinGuildMessage { - export interface IPathParams { - /** The Agreement id */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/getJoinGuildMessage` - - export const method = HttpMethod.Get - - export interface IQueryParams {} - - export interface IRequestBody {} - - export interface IResponseBody extends IApiResponseBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - -export namespace JoinGuild { - export interface IPathParams { - /** The Agreement id */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/joinGuild` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - sig: string - mintToken?: boolean - } - - export interface IResponseBody extends IApiResponseBody { - status: 'success' - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - /** Log in a user. */ export namespace Login { export interface IPathParams {} @@ -2627,44 +2460,6 @@ export namespace UpdateUserIdentity { -/** Save some data to IPFS */ -export namespace SaveToIPFS { - export interface IPathParams {} - - export const path = () => `/api/1.0/ipfs` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** The data to save. Only one of "data" or "json" should be sent */ - data?: string - - /** The JSON to save. Only one of "data" or "json" should be sent */ - json?: Record - } - - export interface IResponseBody extends IApiResponseBody { - /** The IPFS hash for the saved data */ - ipfsHash: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -// TODO: How to specify json in OpenAPI definition - - - - /** Redirect the user to this endpoint to authenticate w/ slack */ export namespace AuthenticateWithSlack { export interface IPathParams {} diff --git a/src/types/meem.public.generated.ts b/src/types/meem.public.generated.ts index c08b0cf4..c017e88e 100644 --- a/src/types/meem.public.generated.ts +++ b/src/types/meem.public.generated.ts @@ -247,8 +247,8 @@ export interface IMeemSplit { lockedBy: string } export interface IMeemMetadataLike { - meem_metadata_type: string - meem_metadata_version: string + meem_metadata_type?: string + meem_metadata_version?: string [key: string]: any } @@ -899,6 +899,40 @@ export interface IWebhookBody { export namespace v1 { +export namespace AcceptAgreementInvite { + export interface IPathParams {} + + export const path = () => `/api/1.0/acceptInvite` + + export const method = HttpMethod.Post + + export interface IQueryParams {} + + export interface IRequestBody { + code: string + } + + export interface IResponseBody extends IApiResponseBody { + name: string + agreementId: string + slug: string + agreementTokenId: string + agreementRoleId?: string + agreementRoleTokenId?: string + } + + export interface IDefinition { + pathParams: IPathParams + queryParams: IQueryParams + requestBody: IRequestBody + responseBody: IResponseBody + } + + export type Response = IResponseBody | IError +} + + + /** Bulk mint agreement role tokens */ export namespace BulkBurnAgreementRoleTokens { export interface IPathParams { @@ -1337,48 +1371,6 @@ export namespace CreateAgreementRole { -/** Create an agreement safe */ -export namespace CreateAgreementSafe { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/safe` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Addresses of the safe owners */ - safeOwners: string[] - - /** Chain id of the safe */ - chainId?: number - - /** The number of signatures required */ - threshold?: number - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - /** Delete an agreement role contract */ export namespace DeleteAgreementRole { export interface IPathParams { @@ -1665,28 +1657,27 @@ export namespace ReInitializeAgreementRole { -/** Set the agreement admin role */ -export namespace SetAgreementAdminRole { +/** Allows invitation via email and/or wallet addresses. In the case of wallet address, this will function the same as bulkMint */ +export namespace SendAgreementInvites { export interface IPathParams { /** The id of the agreement */ agreementId: string } export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/setAdminRole` + `/api/1.0/agreements/${options.agreementId}/invite` - export const method = HttpMethod.Patch + export const method = HttpMethod.Post export interface IQueryParams {} export interface IRequestBody { - /** The id of the agreement role to set as admin role */ - adminAgreementRoleId: string + /** Array of email and/or wallet addresses */ + to: string[] } export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string + status: 'success' } export interface IDefinition { @@ -1695,8 +1686,9 @@ export namespace SetAgreementAdminRole { requestBody: IRequestBody responseBody: IResponseBody } -} + export type Response = IResponseBody | IError +} @@ -1839,81 +1831,6 @@ export namespace UpdateAgreementExtension { -/** Upgrade an agreement contract */ -export namespace UpgradeAgreement { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - -/** Upgrade an agreement role contract */ -export namespace UpgradeAgreementRole { - export interface IPathParams { - /** The id of the agreement */ - agreementId: string - /** The id of the agreement role */ - agreementRoleId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/roles/${options.agreementRoleId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - - export namespace AuthenticateWithDiscord { export interface IPathParams {} @@ -2301,90 +2218,6 @@ export namespace GetNonce { -export namespace GetJoinGuildMessage { - export interface IPathParams { - /** The Agreement id */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/getJoinGuildMessage` - - export const method = HttpMethod.Get - - export interface IQueryParams {} - - export interface IRequestBody {} - - export interface IResponseBody extends IApiResponseBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - -export namespace JoinGuild { - export interface IPathParams { - /** The Agreement id */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/joinGuild` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - sig: string - mintToken?: boolean - } - - export interface IResponseBody extends IApiResponseBody { - status: 'success' - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - - - /** Log in a user. */ export namespace Login { export interface IPathParams {} @@ -2625,44 +2458,6 @@ export namespace UpdateUserIdentity { -/** Save some data to IPFS */ -export namespace SaveToIPFS { - export interface IPathParams {} - - export const path = () => `/api/1.0/ipfs` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** The data to save. Only one of "data" or "json" should be sent */ - data?: string - - /** The JSON to save. Only one of "data" or "json" should be sent */ - json?: Record - } - - export interface IResponseBody extends IApiResponseBody { - /** The IPFS hash for the saved data */ - ipfsHash: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -// TODO: How to specify json in OpenAPI definition - - - - /** Redirect the user to this endpoint to authenticate w/ slack */ export namespace AuthenticateWithSlack { export interface IPathParams {} diff --git a/src/types/models.ts b/src/types/models.ts index a682e653..32786b1b 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -22,6 +22,7 @@ import ContractInstance from '../models/ContractInstance' import Discord from '../models/Discord' import Extension from '../models/Extension' import IdentityProvider from '../models/IdentityProvider' +import Invite from '../models/Invite' import Message from '../models/Message' import Rule from '../models/Rule' import Slack from '../models/Slack' @@ -57,6 +58,7 @@ export interface IModels { Discord: typeof Discord Extension: typeof Extension IdentityProvider: typeof IdentityProvider + Invite: typeof Invite Message: typeof Message UserIdentity: typeof UserIdentity Transaction: typeof Transaction diff --git a/src/types/services.d.ts b/src/types/services.d.ts index 7d5960d1..1a7913a5 100644 --- a/src/types/services.d.ts +++ b/src/types/services.d.ts @@ -2,27 +2,18 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import Agreement from '../services/Agreement' import Analytics from '../services/Analytics' +import Aws from '../services/Aws' import Child from '../services/Child' -import ContractEvents from '../services/ContractEvents' import Data from '../services/Data' import Db from '../services/Db' import Discord from '../services/Discord' import Ethers from '../services/Ethers' -import Git from '../services/Git' -import Guild from '../services/Guild' -import Ipfs from '../services/Ipfs' import Lint from '../services/Lint' -import Lit from '../services/Lit' -import Meem from '../services/Meem' import MeemHelpDesk from '../services/MeemHelpdesk' import MeemId from '../services/MeemId' import Openai from '../services/Openai' -import Puppeteer from '../services/Puppeteer' -import Queue from '../services/Queue' import Rule from '../services/Rule' -import Scraper from '../services/Scraper' import Slack from '../services/Slack' -import Storage from '../services/Storage' import Testing from '../services/Testing' import Twitter from '../services/Twitter' import Types from '../services/Types' @@ -32,28 +23,18 @@ declare global { namespace services { let analytics: typeof Analytics let agreement: typeof Agreement - let agreementRole: typeof AgreementRole + let aws: typeof Aws let child: typeof Child - let contractEvents: typeof ContractEvents let data: typeof Data let db: typeof Db let discord: Discord let ethers: Ethers - let guild: typeof Guild - let git: typeof Git - let ipfs: typeof Ipfs let lint: typeof Lint - let lit: typeof Lit - let meem: typeof Meem let meemHelpdesk: typeof MeemHelpDesk let meemId: typeof MeemId let openai: typeof Openai - let puppeteer: Puppeteer - let queue: typeof Queue let rule: typeof Rule - let scraper: typeof Scraper let slack: typeof Slack - let storage: Storage let testing: Testing let twitter: typeof Twitter let types: typeof Types diff --git a/src/types/shared/api/agreements/acceptInvite.shared.ts b/src/types/shared/api/agreements/acceptInvite.shared.ts new file mode 100644 index 00000000..97f794dc --- /dev/null +++ b/src/types/shared/api/agreements/acceptInvite.shared.ts @@ -0,0 +1,34 @@ +import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' +import { IMeemMetadataLike } from '../../meem.shared' + +export namespace AcceptAgreementInvite { + export interface IPathParams {} + + export const path = () => `/api/1.0/acceptInvite` + + export const method = HttpMethod.Post + + export interface IQueryParams {} + + export interface IRequestBody { + code: string + } + + export interface IResponseBody extends IApiResponseBody { + name: string + agreementId: string + slug: string + agreementTokenId: string + agreementRoleId?: string + agreementRoleTokenId?: string + } + + export interface IDefinition { + pathParams: IPathParams + queryParams: IQueryParams + requestBody: IRequestBody + responseBody: IResponseBody + } + + export type Response = IResponseBody | IError +} diff --git a/src/types/shared/api/agreements/createAgreementSafe.shared.ts b/src/types/shared/api/agreements/createAgreementSafe.shared.ts deleted file mode 100644 index 075a00c1..00000000 --- a/src/types/shared/api/agreements/createAgreementSafe.shared.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -/** Create an agreement safe */ -export namespace CreateAgreementSafe { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/safe` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Addresses of the safe owners */ - safeOwners: string[] - - /** Chain id of the safe */ - chainId?: number - - /** The number of signatures required */ - threshold?: number - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -/** === OpenAPI Definition === */ - -/** - * @api [post] /agreements/{agreementId}/safe - * security: - * - jwtAuth: [] - * summary: "Create an agreement safe" - * parameters: - * - (path) agreementId* {string} The id of the agreement - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/CreateAgreementSafeRequestBody' - * responses: - * "200": - * description: "Returns 'success' if safe is successfully created." - * content: - * application/json: - * schema: - * type: object - * properties: - * txId: - * type: string - * description: The transaction id - **/ - -/** - * @schema CreateAgreementSafeRequestBody - * required: - * - safeOwners - * - chainId - * properties: - * safeOwners: - * description: Addresses of the safe owners - * type: array - * items: - * type: string - * chainId: - * description: Chain id of the safe - * type: integer - * example: 421613 - * threshold: - * description: The number of signatures required - * type: integer - * example: 2 - */ diff --git a/src/types/shared/api/guild/joinGuild.shared.ts b/src/types/shared/api/agreements/sendInvites.shared.ts similarity index 60% rename from src/types/shared/api/guild/joinGuild.shared.ts rename to src/types/shared/api/agreements/sendInvites.shared.ts index 525592a0..3e972b50 100644 --- a/src/types/shared/api/guild/joinGuild.shared.ts +++ b/src/types/shared/api/agreements/sendInvites.shared.ts @@ -1,31 +1,23 @@ import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' +import { IMeemMetadataLike } from '../../meem.shared' -export namespace JoinGuild { +/** Allows invitation via email and/or wallet addresses. In the case of wallet address, this will function the same as bulkMint */ +export namespace SendAgreementInvites { export interface IPathParams { - /** The Agreement id */ + /** The id of the agreement */ agreementId: string } export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/joinGuild` + `/api/1.0/agreements/${options.agreementId}/invite` export const method = HttpMethod.Post export interface IQueryParams {} export interface IRequestBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - sig: string - mintToken?: boolean + /** Array of email and/or wallet addresses */ + to: string[] } export interface IResponseBody extends IApiResponseBody { diff --git a/src/types/shared/api/agreements/setAgreementAdminRole.shared.ts b/src/types/shared/api/agreements/setAgreementAdminRole.shared.ts deleted file mode 100644 index f2fca931..00000000 --- a/src/types/shared/api/agreements/setAgreementAdminRole.shared.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -/** Set the agreement admin role */ -export namespace SetAgreementAdminRole { - export interface IPathParams { - /** The id of the agreement */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/setAdminRole` - - export const method = HttpMethod.Patch - - export interface IQueryParams {} - - export interface IRequestBody { - /** The id of the agreement role to set as admin role */ - adminAgreementRoleId: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } -} - -/** === OpenAPI Definition === */ - -/** - * @api [patch] /agreements/{agreementId}/setAdminRole - * security: - * - jwtAuth: [] - * summary: "Set the agreement admin role" - * parameters: - * - (path) agreementId* {string} The id of the agreement - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SetAgreemetAdminRoleRequestBody' - * responses: - * "200": - * description: "Returns 'success' if admin role was successfully set." - * content: - * application/json: - * schema: - * type: object - * properties: - * txId: - * type: string - * description: The transaction id - **/ - -/** - * @schema SetAgreemetAdminRoleRequestBody - * required: - * - address - * properties: - - * adminAgreementRoleId: - * description: The id of the agreement role to set as admin role - * type: string - */ diff --git a/src/types/shared/api/agreements/upgradeAgreement.shared.ts b/src/types/shared/api/agreements/upgradeAgreement.shared.ts deleted file mode 100644 index 539e5e3f..00000000 --- a/src/types/shared/api/agreements/upgradeAgreement.shared.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -/** Upgrade an agreement contract */ -export namespace UpgradeAgreement { - export interface IPathParams { - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -/** === OpenAPI Definition === */ - -/** - * @api [post] /agreements/{agreementId}/upgrade - * security: - * - jwtAuth: [] - * summary: "Upgrade an agreement contract." - * parameters: - * - (path) agreementId* {string} The ID of the agreement to upgrade - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/UpgradeAgreementRequestBody' - * responses: - * "200": - * description: "Returns 'success' if upgrade agreement transaction is executed." - * content: - * application/json: - * schema: - * type: object - * properties: - * txId: - * type: string - * description: The transaction id - **/ - -/** - * @schema UpgradeAgreementRequestBody - * properties: - * bundleId: - * description: Specify the bundle id to upgrade to. Defaults to latest Agreements bundle - * type: string - */ diff --git a/src/types/shared/api/agreements/upgradeAgreementRole.shared.ts b/src/types/shared/api/agreements/upgradeAgreementRole.shared.ts deleted file mode 100644 index 493201b8..00000000 --- a/src/types/shared/api/agreements/upgradeAgreementRole.shared.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -/** Upgrade an agreement role contract */ -export namespace UpgradeAgreementRole { - export interface IPathParams { - /** The id of the agreement */ - agreementId: string - /** The id of the agreement role */ - agreementRoleId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/roles/${options.agreementRoleId}/upgrade` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Specify the bundle id to upgrade to. Defaults to latest Agreements bundle */ - bundleId?: string - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id */ - txId: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -/** === OpenAPI Definition === */ - -/** - * @api [post] /agreements/{agreementId}/upgrade - * security: - * - jwtAuth: [] - * summary: "Upgrade an agreement contract." - * parameters: - * - (path) agreementId* {string} The id of the agreement - * - (path) agreementRoleId* {string} The id of the agreement role - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/UpgradeAgreementRoleRequestBody' - * responses: - * "200": - * description: "Returns 'success' if upgrade agreement transaction is executed." - * content: - * application/json: - * schema: - * type: object - * properties: - * txId: - * type: string - * description: The transaction id - **/ - -/** - * @schema UpgradeAgreementRoleRequestBody - * properties: - * bundleId: - * description: Specify the bundle id to upgrade to. Defaults to latest Agreements bundle - * type: string - */ diff --git a/src/types/shared/api/createAgreement.shared.ts.OLD b/src/types/shared/api/createAgreement.shared.ts.OLD deleted file mode 100644 index 72da8413..00000000 --- a/src/types/shared/api/createAgreement.shared.ts.OLD +++ /dev/null @@ -1,77 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../api.shared' -import { IMeemMetadataLike, IMeemPermission, IMeemSplit } from '../meem.shared' - -/** Create Meem Image */ -export namespace CreateAgreement { - export interface IPathParams {} - - export const path = () => `/api/1.0/agreements` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** Contract metadata */ - metadata: IMeemMetadataLike - - /** The chain id */ - chainId: number - - /** The symbol for the token. If omitted, will use a slug of the name */ - symbol?: string - - /** The name of the token */ - name: string - - /** Contract admins */ - admins?: string[] - - /** Special minter permissions */ - minters?: string[] - - /** The max number of tokens */ - maxSupply: string - - /** Whether the max supply is locked */ - isMaxSupplyLocked?: boolean - - /** Minting permissions */ - mintPermissions?: Omit[] - - /** Splits for minting / transfers */ - splits?: IMeemSplit[] - - /** Whether tokens can be transferred */ - isTransferLocked?: boolean - - /** If true, will mint a token to the admin wallet addresses and any addresses in the members parameter */ - shouldMintTokens?: boolean - - /** Members to mint tokens to */ - members?: string[] - - /** Token metadata */ - tokenMetadata?: IMeemMetadataLike - } - - export interface IResponseBody extends IApiResponseBody { - /** The Transaction id for deploying the contract. Transaction #1 */ - deployContractTxId: string - - /** The Transaction id for initializing the contract. Transaction #2 */ - cutTxId: string - - /** The Transaction id for minting tokens. Transaction #3 */ - mintTxId?: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} diff --git a/src/types/shared/api/guild/getJoinGuildMessage.shared.ts b/src/types/shared/api/guild/getJoinGuildMessage.shared.ts deleted file mode 100644 index a0173fff..00000000 --- a/src/types/shared/api/guild/getJoinGuildMessage.shared.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -export namespace GetJoinGuildMessage { - export interface IPathParams { - /** The Agreement id */ - agreementId: string - } - - export const path = (options: IPathParams) => - `/api/1.0/agreements/${options.agreementId}/getJoinGuildMessage` - - export const method = HttpMethod.Get - - export interface IQueryParams {} - - export interface IRequestBody {} - - export interface IResponseBody extends IApiResponseBody { - message: string - params: { - chainId?: string - msg: string - method: number - addr: string - nonce: string - hash?: string - ts: string - } - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} diff --git a/src/types/shared/api/storage/saveToIPFS.shared.ts b/src/types/shared/api/storage/saveToIPFS.shared.ts deleted file mode 100644 index 3efb2921..00000000 --- a/src/types/shared/api/storage/saveToIPFS.shared.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { IError, HttpMethod, IApiResponseBody } from '../../api.shared' - -/** Save some data to IPFS */ -export namespace SaveToIPFS { - export interface IPathParams {} - - export const path = () => `/api/1.0/ipfs` - - export const method = HttpMethod.Post - - export interface IQueryParams {} - - export interface IRequestBody { - /** The data to save. Only one of "data" or "json" should be sent */ - data?: string - - /** The JSON to save. Only one of "data" or "json" should be sent */ - json?: Record - } - - export interface IResponseBody extends IApiResponseBody { - /** The IPFS hash for the saved data */ - ipfsHash: string - } - - export interface IDefinition { - pathParams: IPathParams - queryParams: IQueryParams - requestBody: IRequestBody - responseBody: IResponseBody - } - - export type Response = IResponseBody | IError -} - -// TODO: How to specify json in OpenAPI definition - -/** === OpenAPI Definition === */ - -/** - * @api [post] /ipfs - * summary: Save data to IPFS - * description: Save data to IPFS - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SaveToIPFSRequestBody' - * responses: - * "200": - * description: "Returns the IPFS hash" - * content: - * application/json: - * schema: - * type: object - * properties: - * ipfsHash: - * description: The IPFS hash - * type: string - **/ - -/** - * @schema SaveToIPFSRequestBody - * properties: - * data: - * description: The data to save to IPFS - * type: string - */ diff --git a/src/types/shared/meem.shared.ts b/src/types/shared/meem.shared.ts index e82ecfa8..15a2b367 100644 --- a/src/types/shared/meem.shared.ts +++ b/src/types/shared/meem.shared.ts @@ -192,8 +192,8 @@ export interface IMeemSplit { lockedBy: string } export interface IMeemMetadataLike { - meem_metadata_type: string - meem_metadata_version: string + meem_metadata_type?: string + meem_metadata_version?: string [key: string]: any } diff --git a/yarn.lock b/yarn.lock index 347cc86e..ad406bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -431,13 +431,6 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.0.tgz#df72a392f1a63a57f87210515695a31a245845ad" - integrity sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA== - dependencies: - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" @@ -460,32 +453,6 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.0.tgz#a885cfc7650a64385e7b03ac86fe9c2d4a9c2c63" - integrity sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - "@ethersproject/providers@5.7.1": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" @@ -641,17 +608,6 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/wordlists" "^5.7.0" -"@ethersproject/web@5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.0.tgz#40850c05260edad8b54827923bbad23d96aac0bc" - integrity sha512-ApHcbbj+muRASVDSCl/tgxaH2LBkRMEYfLOLVa0COipx0+nlu0QKet7U2lEg0vdkh8XRSLf2nd1f1Uk9SrVSGA== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" @@ -679,15 +635,6 @@ resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz" integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== -"@guildxyz/sdk@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@guildxyz/sdk/-/sdk-1.1.1.tgz#1ff8d3ff12e5003d9286e49b5a66de3bc5b10166" - integrity sha512-zyNCdxmKJgKfSsgtSRMdLAfLdXKkbOA1UXXXkA6PLJoiso4fzKtQUCnLyOka8urTBcvueCapSXVeLWNN6KmiRg== - dependencies: - axios "^0.26.1" - ethers "^5.5.4" - fast-json-stable-stringify "^2.1.0" - "@humanwhocodes/config-array@^0.11.8": version "0.11.8" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" @@ -2662,7 +2609,7 @@ aws-lambda@^1.0.7: js-yaml "^3.14.1" watchpack "^2.0.0-beta.10" -aws-sdk@^2.1195.0, aws-sdk@^2.1225.0, aws-sdk@^2.814.0: +aws-sdk@^2.1195.0, aws-sdk@^2.814.0: version "2.1225.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1225.0.tgz#5747cd1842f461300fb1b8d034c7ef1ae14185a1" integrity sha512-JYYYVpr4EktsohOrO8+KfhmHGt2x2zi20Ypkrtllhrh6fhtosduqpH5cQF7wYX/zEvjqduv0dHYd3sXCROHP8A== @@ -2678,6 +2625,22 @@ aws-sdk@^2.1195.0, aws-sdk@^2.1225.0, aws-sdk@^2.814.0: uuid "8.0.0" xml2js "0.4.19" +aws-sdk@^2.1378.0: + version "2.1378.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1378.0.tgz#a6ba9785bdc2677864b77ff757e9dbca0e65e7d3" + integrity sha512-9ZY11zkc3nMSejrrj08NdL+7hgiY7GZE3Sk7eVhH4VAJeoNqAMAyxc61Sg9yi83Y1i5rRWIcIgX9CYwenokyWQ== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.16.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + util "^0.12.4" + uuid "8.0.0" + xml2js "0.5.0" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" @@ -3486,32 +3449,16 @@ color-name@1.1.3: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" - integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -color@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" - integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - colors@^1.1.2: version "1.4.0" resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz" @@ -4127,11 +4074,6 @@ detect-libc@^1.0.3: resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-libc@^2.0.0, detect-libc@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" - integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== - devtools-protocol@0.0.1036444: version "0.0.1036444" resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1036444.tgz#a570d3cdde61527c82f9b03919847b8ac7b1c2b9" @@ -4966,42 +4908,6 @@ ethers-multisend@^2.4.0: "@ethersproject/solidity" "^5.0.0" "@ethersproject/units" "^5.0.0" -ethers@^5.5.4: - version "5.7.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.0.tgz#0055da174b9e076b242b8282638bc94e04b39835" - integrity sha512-5Xhzp2ZQRi0Em+0OkOcRHxPzCfoBfgtOQA+RUylSkuHbhTEaQklnYi2hsWbRgs3ztJsXVXd9VKBcO1ScWL8YfA== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.0" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.0" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.0" - "@ethersproject/wordlists" "5.7.0" - ethers@^5.6.4, ethers@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33" @@ -5138,11 +5044,6 @@ exit-on-epipe@~1.0.1: resolved "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz" integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== -expand-template@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" - integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== - express@^4.18.1: version "4.18.1" resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" @@ -5269,7 +5170,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5819,11 +5720,6 @@ git-log-parser@^1.2.0: through2 "~2.0.0" traverse "~0.6.6" -github-from-package@0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" - integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -6366,11 +6262,6 @@ is-arrayish@^0.2.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" @@ -7824,7 +7715,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -7904,7 +7795,7 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" -mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: +mkdirp-classic@^0.5.2: version "0.5.3" resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== @@ -8079,11 +7970,6 @@ nanoid@3.3.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== -napi-build-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" - integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== - native-promise-only@^0.8.1: version "0.8.1" resolved "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz" @@ -8151,13 +8037,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-abi@^3.3.0: - version "3.25.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.25.0.tgz#ca57dd23ae67679ce152b6c45cae2c57ed04faff" - integrity sha512-p+0xx5ruIQ+8X57CRIMxbTZRT7tU0Tjn2C/aAK68AEMrbGsCo6IjnDdPNhEyyjWCT4bRtzomXchYd3sSgk3BJQ== - dependencies: - semver "^7.3.5" - node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" @@ -8173,11 +8052,6 @@ node-addon-api@^4.2.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== -node-addon-api@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.0.0.tgz#7d7e6f9ef89043befdb20c1989c905ebde18c501" - integrity sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA== - node-dir@^0.1.17: version "0.1.17" resolved "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz" @@ -9100,24 +8974,6 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -prebuild-install@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" - integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== - dependencies: - detect-libc "^2.0.0" - expand-template "^2.0.3" - github-from-package "0.0.0" - minimist "^1.2.3" - mkdirp-classic "^0.5.3" - napi-build-utils "^1.0.1" - node-abi "^3.3.0" - pump "^3.0.0" - rc "^1.2.7" - simple-get "^4.0.0" - tar-fs "^2.0.0" - tunnel-agent "^0.6.0" - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" @@ -9440,7 +9296,7 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.7, rc@^1.2.8: +rc@^1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -10103,20 +9959,6 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -sharp@^0.31.0: - version "0.31.0" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.31.0.tgz#ce9b5202a5667486721cf07fd5b52360b1c2275a" - integrity sha512-ft96f8WzGxavg0rkLpMw90MTPMUZDyf0tHjPPh8Ob59xt6KzX8EqtotcqZGUm7kwqpX2pmYiyYX2LL0IZ/FDEw== - dependencies: - color "^4.2.3" - detect-libc "^2.0.1" - node-addon-api "^5.0.0" - prebuild-install "^7.1.1" - semver "^7.3.7" - simple-get "^4.0.1" - tar-fs "^2.1.1" - tunnel-agent "^0.6.0" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" @@ -10184,20 +10026,6 @@ signale@^1.2.1: figures "^2.0.0" pkg-conf "^2.1.0" -simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - -simple-get@^4.0.0, simple-get@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" - integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== - dependencies: - decompress-response "^6.0.0" - once "^1.3.1" - simple-concat "^1.0.0" - simple-git@^3.7.0: version "3.14.1" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.14.1.tgz#68018a5f168f8a568862e30b692004b37c3b5ced" @@ -10207,13 +10035,6 @@ simple-git@^3.7.0: "@kwsites/promise-deferred" "^1.1.1" debug "^4.3.4" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - siwe@^2.0.5: version "2.1.3" resolved "https://registry.yarnpkg.com/siwe/-/siwe-2.1.3.tgz#3048f6d0c1534d4edfb074efddc3f41939472421" @@ -10773,7 +10594,7 @@ table-layout@^1.0.2: typical "^5.2.0" wordwrapjs "^4.0.0" -tar-fs@2.1.1, tar-fs@^2.0.0, tar-fs@^2.1.1: +tar-fs@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz" integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== @@ -11716,6 +11537,19 @@ xml2js@0.4.19: sax ">=0.6.0" xmlbuilder "~9.0.1" +xml2js@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + xmlbuilder@~9.0.1: version "9.0.7" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz"