├── .aliases ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── general-todos.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ARM.yml │ ├── feature.yml │ └── prod.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .solhint.json ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ ├── 0_config.spec.js │ ├── 1_window_web_page.spec.js │ ├── 2_node_profile_creation.spec.js │ ├── 3_channel_setup.spec.js │ ├── 4_deposit_Withdraw.spec.js │ ├── 5_transfer.spec.js │ ├── http-request.js │ └── utils.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── lerna.json ├── modules ├── auth │ ├── ops │ │ ├── Dockerfile │ │ ├── entry.sh │ │ ├── package.json │ │ └── webpack.config.js │ ├── package.json │ ├── src │ │ ├── auth │ │ │ └── messaging-auth-service.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── schemas.ts │ └── tsconfig.json ├── browser-node │ ├── .nycrc.json │ ├── ops │ │ └── webpack.config.ts │ ├── package.json │ ├── src │ │ ├── channelProvider.ts │ │ ├── constants.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ └── services │ │ │ ├── lock.ts │ │ │ ├── store.spec.ts │ │ │ └── store.ts │ └── tsconfig.json ├── contracts │ ├── .nycrc.json │ ├── .solhint.json │ ├── README.md │ ├── deploy │ │ └── deploy.ts │ ├── deployments │ │ ├── arbitrumtest │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── arbitrumtest4 │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── avalanche │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── avalanchefuji │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── bsc │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── bsctestnet │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── fantom │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── goerli │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── StableSwap.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ ├── 4270066cb79148326df731b732884fa6.json │ │ │ │ ├── 89c55d5a88f10637860a9ea31a1daad3.json │ │ │ │ └── e64b9cdf4f72778a3c3a9b0d6a298f3c.json │ │ ├── harmony │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── harmonytestnet │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── heco │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── hecotestnet │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── kovan │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ ├── 89c55d5a88f10637860a9ea31a1daad3.json │ │ │ │ └── e64b9cdf4f72778a3c3a9b0d6a298f3c.json │ │ ├── mainnet │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── matic │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── moonbasealpha │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ │ ├── mumbai │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ ├── 89c55d5a88f10637860a9ea31a1daad3.json │ │ │ │ └── e64b9cdf4f72778a3c3a9b0d6a298f3c.json │ │ ├── rinkeby │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ │ ├── 89c55d5a88f10637860a9ea31a1daad3.json │ │ │ │ └── e64b9cdf4f72778a3c3a9b0d6a298f3c.json │ │ └── xdai │ │ │ ├── .chainId │ │ │ ├── ChannelFactory.json │ │ │ ├── ChannelMastercopy.json │ │ │ ├── HashlockTransfer.json │ │ │ ├── TestToken.json │ │ │ ├── TransferRegistry.json │ │ │ ├── Withdraw.json │ │ │ └── solcInputs │ │ │ └── 89c55d5a88f10637860a9ea31a1daad3.json │ ├── hardhat.config.ts │ ├── ops │ │ ├── Dockerfile │ │ ├── entry.sh │ │ └── package.json │ ├── package.json │ ├── src.sol │ │ ├── CMCAdjudicator.sol │ │ ├── CMCAsset.sol │ │ ├── CMCCore.sol │ │ ├── CMCDeposit.sol │ │ ├── CMCWithdraw.sol │ │ ├── ChannelFactory.sol │ │ ├── ChannelMastercopy.sol │ │ ├── ReentrancyGuard.sol │ │ ├── TransferRegistry.sol │ │ ├── amm │ │ │ ├── StableSwap.sol │ │ │ ├── lib │ │ │ │ ├── helpers │ │ │ │ │ ├── AssetHelpers.sol │ │ │ │ │ ├── Authentication.sol │ │ │ │ │ ├── BalancerErrors.sol │ │ │ │ │ ├── BalancerHelpers.sol │ │ │ │ │ ├── IAuthentication.sol │ │ │ │ │ ├── InputHelpers.sol │ │ │ │ │ ├── SignaturesValidator.sol │ │ │ │ │ └── TemporarilyPausable.sol │ │ │ │ ├── math │ │ │ │ │ ├── FixedPoint.sol │ │ │ │ │ ├── LogExpMath.sol │ │ │ │ │ └── Math.sol │ │ │ │ └── openzeppelin │ │ │ │ │ ├── AccessControl.sol │ │ │ │ │ ├── Address.sol │ │ │ │ │ ├── Create2.sol │ │ │ │ │ ├── EIP712.sol │ │ │ │ │ ├── ERC20.sol │ │ │ │ │ ├── ERC20Burnable.sol │ │ │ │ │ ├── EnumerableMap.sol │ │ │ │ │ ├── EnumerableSet.sol │ │ │ │ │ ├── IERC20.sol │ │ │ │ │ ├── IERC20Permit.sol │ │ │ │ │ ├── ReentrancyGuard.sol │ │ │ │ │ ├── SafeCast.sol │ │ │ │ │ ├── SafeERC20.sol │ │ │ │ │ └── SafeMath.sol │ │ │ ├── pools │ │ │ │ ├── BalancerPoolToken.sol │ │ │ │ ├── BaseGeneralPool.sol │ │ │ │ ├── BaseMinimalSwapInfoPool.sol │ │ │ │ ├── BasePool.sol │ │ │ │ ├── BasePoolAuthorization.sol │ │ │ │ ├── factories │ │ │ │ │ ├── BasePoolFactory.sol │ │ │ │ │ └── FactoryWidePauseWindow.sol │ │ │ │ ├── stable │ │ │ │ │ ├── StableMath.sol │ │ │ │ │ ├── StablePool.sol │ │ │ │ │ ├── StablePoolFactory.sol │ │ │ │ │ └── StablePoolUserDataHelpers.sol │ │ │ │ └── weighted │ │ │ │ │ ├── WeightedMath.sol │ │ │ │ │ ├── WeightedPool.sol │ │ │ │ │ ├── WeightedPoolFactory.sol │ │ │ │ │ └── WeightedPoolUserDataHelpers.sol │ │ │ └── vault │ │ │ │ ├── AssetManagers.sol │ │ │ │ ├── AssetTransfersHandler.sol │ │ │ │ ├── Authorizer.sol │ │ │ │ ├── Fees.sol │ │ │ │ ├── FlashLoans.sol │ │ │ │ ├── PoolBalances.sol │ │ │ │ ├── PoolRegistry.sol │ │ │ │ ├── PoolTokens.sol │ │ │ │ ├── ProtocolFeesCollector.sol │ │ │ │ ├── Swaps.sol │ │ │ │ ├── UserBalance.sol │ │ │ │ ├── Vault.sol │ │ │ │ ├── VaultAuthorization.sol │ │ │ │ ├── balances │ │ │ │ ├── BalanceAllocation.sol │ │ │ │ ├── GeneralPoolsBalance.sol │ │ │ │ ├── MinimalSwapInfoPoolsBalance.sol │ │ │ │ └── TwoTokenPoolsBalance.sol │ │ │ │ └── interfaces │ │ │ │ ├── IAsset.sol │ │ │ │ ├── IAuthorizer.sol │ │ │ │ ├── IBasePool.sol │ │ │ │ ├── IFlashLoanRecipient.sol │ │ │ │ ├── IGeneralPool.sol │ │ │ │ ├── IMinimalSwapInfoPool.sol │ │ │ │ ├── IPoolSwapStructs.sol │ │ │ │ ├── ISignaturesValidator.sol │ │ │ │ ├── IVault.sol │ │ │ │ └── IWETH.sol │ │ ├── interfaces │ │ │ ├── Commitment.sol │ │ │ ├── ICMCAdjudicator.sol │ │ │ ├── ICMCAsset.sol │ │ │ ├── ICMCCore.sol │ │ │ ├── ICMCDeposit.sol │ │ │ ├── ICMCWithdraw.sol │ │ │ ├── IChannelFactory.sol │ │ │ ├── ITestChannel.sol │ │ │ ├── ITransferDefinition.sol │ │ │ ├── ITransferRegistry.sol │ │ │ ├── IVectorChannel.sol │ │ │ ├── Types.sol │ │ │ └── WithdrawHelper.sol │ │ ├── lib │ │ │ ├── LibAsset.sol │ │ │ ├── LibChannelCrypto.sol │ │ │ ├── LibERC20.sol │ │ │ ├── LibIterableMapping.sol │ │ │ ├── LibMath.sol │ │ │ └── LibUtils.sol │ │ ├── testing │ │ │ ├── FailingToken.sol │ │ │ ├── NonconformingToken.sol │ │ │ ├── ReentrantToken.sol │ │ │ ├── TestChannel.sol │ │ │ ├── TestChannelFactory.sol │ │ │ ├── TestLibIterableMapping.sol │ │ │ └── TestToken.sol │ │ └── transferDefinitions │ │ │ ├── HashlockTransfer.sol │ │ │ ├── TransferDefinition.sol │ │ │ └── Withdraw.sol │ ├── src.ts │ │ ├── artifacts.ts │ │ ├── commitments │ │ │ ├── index.ts │ │ │ ├── withdraw.spec.ts │ │ │ └── withdraw.ts │ │ ├── constants.ts │ │ ├── deployments.ts │ │ ├── index.ts │ │ ├── services │ │ │ ├── ethReader.spec.ts │ │ │ ├── ethReader.ts │ │ │ ├── ethService.spec.ts │ │ │ ├── ethService.ts │ │ │ └── index.ts │ │ ├── tasks │ │ │ ├── calcStableSwap.ts │ │ │ ├── changeTransferRegistryOwner.ts │ │ │ ├── createChannel.ts │ │ │ ├── displayAccounts.ts │ │ │ ├── drip.ts │ │ │ ├── index.ts │ │ │ ├── registerTransfer.spec.ts │ │ │ └── registerTransfer.ts │ │ ├── tests │ │ │ ├── amm │ │ │ │ └── StableSwap.spec.ts │ │ │ ├── channelFactory.spec.ts │ │ │ ├── channelMastercopy.spec.ts │ │ │ ├── cmcs │ │ │ │ ├── adjudicator.spec.ts │ │ │ │ ├── asset.spec.ts │ │ │ │ ├── core.spec.ts │ │ │ │ ├── deposit.spec.ts │ │ │ │ └── withdraw.spec.ts │ │ │ ├── deploy.spec.ts │ │ │ ├── integration │ │ │ │ ├── ethReader.spec.ts │ │ │ │ └── ethService.spec.ts │ │ │ ├── lib │ │ │ │ ├── asset.spec.ts │ │ │ │ ├── channelCrypto.spec.ts │ │ │ │ └── iterableMapping.spec.ts │ │ │ ├── transferDefinitions │ │ │ │ ├── hashlockTransfer.spec.ts │ │ │ │ └── withdraw.spec.ts │ │ │ └── transferRegistry.spec.ts │ │ └── utils.ts │ └── tsconfig.json ├── documentation │ ├── README.md │ ├── docs │ │ ├── assets │ │ │ ├── favicon.png │ │ │ └── logo.png │ │ ├── changelog.md │ │ ├── index.md │ │ ├── node │ │ │ ├── basics.md │ │ │ ├── configure.md │ │ │ ├── events.md │ │ │ └── transfers.md │ │ ├── quickStart │ │ │ ├── browserNode.md │ │ │ └── serverNode.md │ │ ├── reference │ │ │ ├── hostedNodes.md │ │ │ └── nodeAPI.md │ │ ├── router │ │ │ ├── basics.md │ │ │ ├── chains.md │ │ │ └── configure.md │ │ └── stylesheets │ │ │ └── extra.css │ └── mkdocs.yml ├── engine │ ├── .nycrc.json │ ├── README.md │ ├── package.json │ ├── src │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── isAlive.ts │ │ ├── listeners.ts │ │ ├── paramConverter.ts │ │ ├── testing │ │ │ ├── env.ts │ │ │ ├── happy.spec.ts │ │ │ ├── index.spec.ts │ │ │ ├── isAlive.spec.ts │ │ │ ├── listeners.spec.ts │ │ │ ├── paramConverter.spec.ts │ │ │ └── utils.spec.ts │ │ └── utils.ts │ └── tsconfig.json ├── iframe-app │ ├── README.md │ ├── amplify.yml │ ├── ops │ │ ├── Dockerfile │ │ └── package.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.tsx │ │ ├── ConnextManager.tsx │ │ ├── config.ts │ │ └── index.tsx │ └── tsconfig.json ├── protocol │ ├── .nycrc.json │ ├── README.md │ ├── package.json │ ├── src │ │ ├── errors.ts │ │ ├── sync.ts │ │ ├── testing │ │ │ ├── constants.ts │ │ │ ├── env.ts │ │ │ ├── global-hooks.ts │ │ │ ├── integration │ │ │ │ ├── create.spec.ts │ │ │ │ ├── deposit.spec.ts │ │ │ │ ├── happy.spec.ts │ │ │ │ ├── resolve.spec.ts │ │ │ │ └── setup.spec.ts │ │ │ ├── sync.spec.ts │ │ │ ├── update.spec.ts │ │ │ ├── utils.spec.ts │ │ │ ├── utils │ │ │ │ ├── channel.ts │ │ │ │ ├── funding.ts │ │ │ │ ├── index.ts │ │ │ │ └── transfer.ts │ │ │ ├── validate.spec.ts │ │ │ └── vector.spec.ts │ │ ├── update.ts │ │ ├── utils.ts │ │ ├── validate.ts │ │ └── vector.ts │ └── tsconfig.json ├── router │ ├── .nycrc.json │ ├── README.md │ ├── examples │ │ └── admin.http │ ├── migrations-legacy │ │ ├── 20201220171143-init │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ └── migrate.lock │ ├── ops │ │ ├── Dockerfile │ │ ├── entry.sh │ │ ├── package.json │ │ ├── test.sh │ │ └── webpack.config.js │ ├── package.json │ ├── prisma-postgres │ │ ├── migrations │ │ │ ├── 20210208141017_init │ │ │ │ └── migration.sql │ │ │ ├── 20210315014934_add_autorebalance │ │ │ │ └── migration.sql │ │ │ ├── 20210409193148_autorebalance_record_save_chain_i_ds_for_executed_txs │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ └── schema.prisma │ ├── prisma-sqlite │ │ ├── migrations │ │ │ ├── 20210208152136_init │ │ │ │ └── migration.sql │ │ │ ├── 20210315014920_add_autorebalance │ │ │ │ └── migration.sql │ │ │ ├── 20210409195115_autorebalance_record_save_chain_i_ds_for_executed_txs │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ └── schema.prisma │ ├── src │ │ ├── config.ts │ │ ├── errors.ts │ │ ├── forwarding.ts │ │ ├── index.ts │ │ ├── listener.ts │ │ ├── metrics.ts │ │ ├── router.ts │ │ ├── services │ │ │ ├── autoRebalance.ts │ │ │ ├── collateral.ts │ │ │ ├── config.ts │ │ │ ├── creationQueue.ts │ │ │ ├── fees.ts │ │ │ ├── globalMetrics.ts │ │ │ ├── messaging.ts │ │ │ ├── rebalanceQueue.ts │ │ │ ├── store.ts │ │ │ ├── swap.ts │ │ │ ├── transfer.ts │ │ │ └── utils.ts │ │ └── test │ │ │ ├── autoRebalance.spec.ts │ │ │ ├── collateral.spec.ts │ │ │ ├── forwarding.spec.ts │ │ │ ├── services │ │ │ ├── config.spec.ts │ │ │ ├── fees.spec.ts │ │ │ ├── messaging.spec.ts │ │ │ ├── store.spec.ts │ │ │ ├── swap.spec.ts │ │ │ └── transfer.spec.ts │ │ │ └── utils │ │ │ └── mocks.ts │ └── tsconfig.json ├── server-node │ ├── .nycrc.json │ ├── README.md │ ├── examples │ │ ├── 0-config.http │ │ ├── 1-setup.http │ │ ├── 2-deposit.http │ │ ├── 3-transfer.http │ │ ├── 4-event-subscriptions.http │ │ ├── 5-withdraw.http │ │ ├── 6-restore.http │ │ ├── 7-dispute.http │ │ ├── admin.http │ │ ├── cross-chain-flow.http │ │ └── eth-rpc.http │ ├── migrations-legacy │ │ ├── 20201026173854-init │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201030172744-dispute-flag │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201102150429-rm-mastercopy-address │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201111192514-chain-id-fixes │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201118004412-defund-array │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201215210233-add-transaction-nonce │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20201219012400-queued-update │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ ├── 20210128085513-add-created-at │ │ │ ├── README.md │ │ │ ├── schema.prisma │ │ │ └── steps.json │ │ └── migrate.lock │ ├── ops │ │ ├── Dockerfile │ │ ├── arm.Dockerfile │ │ ├── entry.sh │ │ ├── package.json │ │ ├── test.sh │ │ └── webpack.config.js │ ├── package.json │ ├── prisma-binaries-armv8 │ │ ├── introspection-engine │ │ ├── migration-engine │ │ ├── prisma-fmt │ │ └── query-engine │ ├── prisma-postgres │ │ ├── migrations │ │ │ ├── 20210208123402_init │ │ │ │ └── migration.sql │ │ │ ├── 20210212024650_add_transaction │ │ │ │ └── migration.sql │ │ │ ├── 20210216034007_remove_unique_onchain_id │ │ │ │ └── migration.sql │ │ │ ├── 20210223223007_remove_provider_url │ │ │ │ └── migration.sql │ │ │ ├── 20210225093205_update_config │ │ │ │ └── migration.sql │ │ │ ├── 20210401215828_add_disputes │ │ │ │ └── migration.sql │ │ │ ├── 20210518023805_add_tx_service_onchain_attempts │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ └── schema.prisma │ ├── prisma-sqlite │ │ ├── migrations │ │ │ ├── 20210208112649_init │ │ │ │ └── migration.sql │ │ │ ├── 20210212024705_add_transaction │ │ │ │ └── migration.sql │ │ │ ├── 20210216033910_remove_unique_onchain_id │ │ │ │ └── migration.sql │ │ │ ├── 20210223222849_remove_provider_url │ │ │ │ └── migration.sql │ │ │ ├── 20210225085644_update_config │ │ │ │ └── migration.sql │ │ │ ├── 20210401220107_add_disputes │ │ │ │ └── migration.sql │ │ │ ├── 20210518021355_add_tx_service_onchain_attempts │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ └── schema.prisma │ ├── src │ │ ├── config.ts │ │ ├── helpers │ │ │ ├── errors.ts │ │ │ └── nodes.ts │ │ ├── index.ts │ │ └── services │ │ │ ├── lock.ts │ │ │ ├── messaging.spec.ts │ │ │ ├── store.spec.ts │ │ │ ├── store.ts │ │ │ ├── withdrawal.spec.ts │ │ │ └── withdrawal.ts │ └── tsconfig.json ├── test-runner │ ├── README.md │ ├── ops │ │ ├── Dockerfile │ │ ├── entry.sh │ │ ├── package.json │ │ └── webpack.config.js │ ├── package.json │ ├── src │ │ ├── duet │ │ │ ├── config.test.ts │ │ │ ├── eventSetup.ts │ │ │ ├── happy.test.ts │ │ │ ├── index.ts │ │ │ └── restore.test.ts │ │ ├── load │ │ │ ├── helpers │ │ │ │ ├── agent.ts │ │ │ │ ├── config.ts │ │ │ │ ├── setupServer.ts │ │ │ │ └── test.ts │ │ │ ├── start-channel-bandwidth.ts │ │ │ ├── start-concurrency.ts │ │ │ └── start-cyclical.ts │ │ ├── messaging │ │ │ ├── auth.test.ts │ │ │ └── index.ts │ │ ├── node │ │ │ ├── config.test.ts │ │ │ └── index.ts │ │ ├── router │ │ │ ├── config.test.ts │ │ │ └── index.ts │ │ ├── trio │ │ │ ├── config.test.ts │ │ │ ├── eventSetup.ts │ │ │ ├── happy.test.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── channel.ts │ │ │ ├── env.ts │ │ │ ├── ethereum.ts │ │ │ ├── index.ts │ │ │ └── logger.ts │ └── tsconfig.json ├── test-ui │ ├── README.md │ ├── amplify.yml │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── config.ts │ │ ├── index.css │ │ ├── index.tsx │ │ └── serviceWorker.ts │ └── tsconfig.json ├── types │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── basic.ts │ │ ├── chain.ts │ │ ├── channel.ts │ │ ├── constants.ts │ │ ├── contracts.ts │ │ ├── crypto.ts │ │ ├── dispute.ts │ │ ├── engine.ts │ │ ├── error.ts │ │ ├── event.ts │ │ ├── externalValidation.ts │ │ ├── index.ts │ │ ├── lock.ts │ │ ├── messaging.ts │ │ ├── network.ts │ │ ├── node.ts │ │ ├── protocol.ts │ │ ├── rpc.ts │ │ ├── schemas │ │ │ ├── autoRebalance.ts │ │ │ ├── basic.ts │ │ │ ├── config.ts │ │ │ ├── engine.ts │ │ │ ├── index.ts │ │ │ ├── node.ts │ │ │ ├── protocol.ts │ │ │ └── router.ts │ │ ├── store.ts │ │ ├── transferDefinitions │ │ │ ├── hashlockTransfer.ts │ │ │ ├── index.ts │ │ │ ├── shared.ts │ │ │ └── withdraw.ts │ │ ├── utils.ts │ │ └── vectorProvider.ts │ └── tsconfig.json └── utils │ ├── .gitignore │ ├── .nycrc.json │ ├── README.md │ ├── package.json │ ├── src │ ├── bigNumbers.spec.ts │ ├── bigNumbers.ts │ ├── caip.ts │ ├── chainId.ts │ ├── chainInfo.ts │ ├── chains.json │ ├── channel.ts │ ├── channelSigner.spec.ts │ ├── channelSigner.ts │ ├── comparisons.ts │ ├── create2.ts │ ├── crypto.spec.ts │ ├── crypto.ts │ ├── currency.ts │ ├── delay.ts │ ├── env.ts │ ├── error.ts │ ├── eth.ts │ ├── fees.spec.ts │ ├── fees.ts │ ├── fs.ts │ ├── hexStrings.ts │ ├── identifiers.spec.ts │ ├── identifiers.ts │ ├── index.ts │ ├── json.spec.ts │ ├── json.ts │ ├── limitedCache.ts │ ├── lock.spec.ts │ ├── lock.ts │ ├── math.spec.ts │ ├── math.ts │ ├── merkle.spec.ts │ ├── merkle.ts │ ├── messaging.ts │ ├── rpc.ts │ ├── serverNode.ts │ ├── strings.ts │ ├── test │ │ ├── chain.ts │ │ ├── channel.ts │ │ ├── expect.ts │ │ ├── index.ts │ │ ├── logger.ts │ │ ├── message.ts │ │ ├── services │ │ │ ├── index.ts │ │ │ ├── messaging.ts │ │ │ └── store.ts │ │ ├── transfers.ts │ │ └── util.ts │ ├── testStore.ts │ ├── transfer.spec.ts │ ├── transfers.ts │ ├── validateUpdateSignatures.spec.ts │ └── validateUpdateSignatures.ts │ └── tsconfig.json ├── ops ├── build-report.sh ├── builder │ ├── Dockerfile │ ├── entry.sh │ └── test.sh ├── config │ ├── browser.default.json │ ├── messaging.default.json │ ├── node.default.json │ └── router.default.json ├── database │ ├── Dockerfile │ ├── backup-lifecycle.json │ ├── backup.sh │ ├── config.json │ ├── database.json │ ├── db.dockerfile │ ├── entry.sh │ ├── postgresql.conf │ └── run-backup.sh ├── db.sh ├── deploy-vector.sh ├── grafana │ ├── dashboards │ │ ├── Container-Stats.json │ │ ├── Host-Stats-Extended.json │ │ ├── Host-Stats.json │ │ ├── Router-Main-2.json │ │ └── Router-Main.json │ └── grafana │ │ ├── grafana.ini │ │ └── provisioning │ │ ├── dashboards │ │ └── dashboards.yaml │ │ └── datasources │ │ └── datasources.yaml ├── hardhat.sh ├── lint.sh ├── logs.sh ├── nats │ ├── Dockerfile │ └── entry.sh ├── npm-publish.sh ├── prometheus │ └── prometheus.yml ├── proxy │ ├── Dockerfile │ ├── entry.sh │ ├── http.cfg │ └── https.cfg ├── pull-images.sh ├── push-images.sh ├── replace.sh ├── save-secret.sh ├── search.sh ├── server-setup.sh ├── ssh-action │ ├── Dockerfile │ ├── action.yml │ └── entry.sh ├── start-chains.sh ├── start-duet.sh ├── start-iframe-app.sh ├── start-messaging.sh ├── start-node.sh ├── start-router.sh ├── start-test-ui.sh ├── start-trio.sh ├── stop.sh ├── test-integration.sh ├── test-load.sh ├── test-network.sh ├── test-unit.sh ├── upgrade-package.sh └── version-check.sh ├── package.json └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: "@typescript-eslint/parser", 3 | plugins: ["import"], 4 | extends: [ 5 | "plugin:@typescript-eslint/recommended", 6 | "prettier/@typescript-eslint", 7 | "plugin:import/errors", 8 | "plugin:import/warnings", 9 | "plugin:import/typescript", 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2018, 13 | sourceType: "module", 14 | }, 15 | rules: { 16 | "@typescript-eslint/no-empty-interface": ["off"], 17 | "@typescript-eslint/no-non-null-assertion": ["off"], 18 | "comma-dangle": ["warn", "always-multiline"], 19 | quotes: ["warn", "double", { allowTemplateLiterals: true, avoidEscape: true }], 20 | semi: ["error", "always"], 21 | "@typescript-eslint/no-explicit-any": ["off"], 22 | "import/order": [ 23 | 1, 24 | { 25 | groups: ["builtin", "external", "internal", "parent", "sibling", "index"], 26 | "newlines-between": "always", 27 | }, 28 | ], 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: Needs Triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Your Environment** 27 | 28 | * Client version used: 29 | * Node version used: 30 | * Chain used: 31 | * Browser Name and version: 32 | * Operating System and version (desktop or mobile): 33 | * Link to your project: 34 | 35 | **Additional context** 36 | Add any other context about the problem here. 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: Needs Triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-todos.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General Todos 3 | about: Issues 4 | title: '' 5 | labels: Needs Triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Expected Behavior 13 | 14 | 15 | ## Current Behavior 16 | 17 | 18 | ## Possible Solution 19 | 20 | 21 | 22 | ## Context 23 | 24 | 25 | 26 | 27 | * Client version used: 28 | * Node version used: 29 | * Chain used: 30 | * Browser Name and version: 31 | * Operating System and version (desktop or mobile): 32 | * Link to your project: 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## The Problem 2 | 3 | 4 | 5 | ## The Solution 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Config & sensitive data 2 | *.config.json 3 | modules/browser-node-test-ui/config-node.json 4 | .*.sqlite 5 | 6 | # Build Output 7 | **/*.0x 8 | **/.flags 9 | **/_build/** 10 | **/artifacts 11 | **/build 12 | **/dist 13 | **/node_modules 14 | **/tsconfig.tsbuildinfo 15 | *.docker-compose.yml 16 | docker-compose.yml 17 | modules/*/package-lock.json 18 | package-lock.json 19 | config-prod.json 20 | 21 | # Cache 22 | **/.bot-store 23 | **/.hardhat 24 | **/.cache 25 | **/.config 26 | **/.connext-store/** 27 | **/.git 28 | **/.jest.cache 29 | **/.local 30 | **/.node-gyp 31 | **/.npm 32 | **/.pyEnv 33 | **/.rpt2_cache 34 | **/.test-store 35 | **/.tmp 36 | **/cache 37 | **/*.backup 38 | 39 | # Data Storage 40 | **/.bot-store/ 41 | **/.chaindata 42 | **/.db-snapshots 43 | **/.db-snapshots-node/ 44 | **/.db-snapshots-router/ 45 | modules/server-node/connext-store.db 46 | modules/server-node/migrations/migrate.lock 47 | modules/contracts/typechain 48 | 49 | # Docs 50 | modules/client/docs 51 | modules/documentation/site 52 | 53 | # IDEs and editors 54 | **/*.launch 55 | **/*.sublime-workspace 56 | **/*.sw[opq] 57 | **/.c9/ 58 | **/.classpath 59 | **/.idea 60 | **/.project 61 | **/.settings/ 62 | **/.vscode 63 | 64 | # Logs 65 | **/*.*_backup 66 | **/*.log 67 | **/*.patch 68 | cypress/screenshots 69 | cypress/videos 70 | 71 | # OS 72 | **/.bash_history 73 | **/.DS_Store 74 | 75 | # Sensitive Data 76 | **/.env 77 | **/react-app-env.d.ts 78 | .secret 79 | **/generated 80 | 81 | # Tests 82 | modules/**/.nyc_output 83 | modules/**/coverage 84 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignored 2 | modules/documentation/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | trailingComma: "all", 4 | singleQuote: false, 5 | printWidth: 120, 6 | tabWidth: 2, 7 | overrides: [ 8 | { 9 | files: "*.sol", 10 | options: { 11 | printWidth: 80, 12 | tabWidth: 4, 13 | useTabs: false, 14 | singleQuote: false, 15 | bracketSpacing: false, 16 | explicitTypes: "always", 17 | }, 18 | }, 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:default", 3 | "rules": { 4 | "max-line-length": ["warn", 140] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Danniel Hugo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | add smoke test for ops/deploy-contracts.sh and/or ops/contracts.sh 2 | anything else? 3 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3333", 3 | "env": { 4 | "NETWORK": "http://localhost:8545", 5 | "MNEMONIC": "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", 6 | "PRIVATE_KEY": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3" 7 | } 8 | } -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/0_config.spec.js: -------------------------------------------------------------------------------- 1 | import my from "./utils"; 2 | const carolUrl = "http://localhost:8005"; // Node A 3 | const daveUrl = "http://localhost:8006"; // Node B 4 | 5 | const routerUrl = "http://localhost:8007"; 6 | 7 | context("GET Config", () => { 8 | describe("Request", () => { 9 | it("Get Request from Router", () => { 10 | my.getConfig(routerUrl); 11 | }); 12 | 13 | it("GET Request from Node A: Carol", () => { 14 | my.getConfig(carolUrl); 15 | }); 16 | 17 | it("GET Request from Node B: Dave", () => { 18 | my.getConfig(daveUrl); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /cypress/integration/1_window_web_page.spec.js: -------------------------------------------------------------------------------- 1 | context("Web Page Status", () => { 2 | beforeEach(() => { 3 | cy.visit("/"); 4 | }); 5 | 6 | it("Check status of web page", () => { 7 | cy.contains("Vector Browser Node"); 8 | }); 9 | 10 | it("cy.window() - get the global window object", () => { 11 | cy.window().should("have.property", "top"); 12 | }); 13 | 14 | it("cy.document() - get the document object", () => { 15 | cy.document() 16 | .should("have.property", "charset") 17 | .and("eq", "UTF-8"); 18 | }); 19 | 20 | it("cy.input() - get the if the field for Mnemonic is empty", () => { 21 | cy.get("input").should("have.length", 1); 22 | }); 23 | 24 | it("cy.random_mnemonic - click to create random mnemonic from generator", () => { 25 | cy.contains("Generate Random Mnemonic").click(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | 19 | module.exports = (on, config) => { 20 | // on('before:browser:launch', (browser, launchOptions) => { 21 | // // supply the absolute path to an unpacked extension's folder 22 | // // NOTE: extensions cannot be loaded in headless Chrome 23 | // launchOptions.extensions.push('./cypress/metamask_8.1.3_0') 24 | 25 | // return launchOptions 26 | // }) 27 | } -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["modules/*"], 3 | "version": "0.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /modules/auth/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY ops/package.json package.json 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY ops ops 24 | COPY dist dist 25 | 26 | RUN chmod +x ./ops/entry.sh 27 | 28 | # USER node 29 | 30 | ENTRYPOINT ["bash", "ops/entry.sh"] 31 | -------------------------------------------------------------------------------- /modules/auth/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auth", 3 | "description": "This is only used to install & pin versions for a few global packages in the prod-mode docker container", 4 | "dependencies": { 5 | "nodemon": "2.0.7", 6 | "pino-pretty": "4.6.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /modules/auth/ops/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | mode: "development", 5 | target: "node", 6 | 7 | context: path.join(__dirname, ".."), 8 | 9 | entry: path.join(__dirname, "../src/index.ts"), 10 | 11 | externals: { 12 | "pg-native": "commonjs2 pg-native", 13 | sqlite3: "commonjs2 sqlite3", 14 | }, 15 | 16 | node: { 17 | __filename: false, 18 | __dirname: false, 19 | }, 20 | 21 | resolve: { 22 | mainFields: ["main", "module"], 23 | extensions: [".js", ".ts", ".json"], 24 | symlinks: false, 25 | }, 26 | 27 | output: { 28 | path: path.join(__dirname, "../dist"), 29 | filename: "bundle.js", 30 | }, 31 | 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.js$/, 36 | exclude: /node_modules/, 37 | use: { 38 | loader: "babel-loader", 39 | options: { 40 | presets: ["@babel/env"], 41 | }, 42 | }, 43 | }, 44 | { 45 | test: /\.ts$/, 46 | exclude: /node_modules/, 47 | use: { 48 | loader: "ts-loader", 49 | options: { 50 | configFile: path.join(__dirname, "../tsconfig.json"), 51 | }, 52 | }, 53 | }, 54 | ], 55 | }, 56 | 57 | stats: { warnings: false }, 58 | }; 59 | -------------------------------------------------------------------------------- /modules/auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@connext/vector-auth", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "Arjun Bhuptani", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "scripts": { 10 | "build": "rm -rf dist && tsc", 11 | "build-bundle": "webpack --config ops/webpack.config.js", 12 | "test": "ts-mocha --check-leaks --exit --timeout 60000 'src/**/*.spec.ts'" 13 | }, 14 | "dependencies": { 15 | "@connext/vector-types": "0.2.5-beta.21", 16 | "@connext/vector-utils": "0.2.5-beta.21", 17 | "@sinclair/typebox": "0.12.7", 18 | "crypto": "1.0.1", 19 | "fastify": "3.13.0", 20 | "fastify-cors": "5.2.0", 21 | "nodemon": "2.0.7", 22 | "pino": "6.11.1" 23 | }, 24 | "devDependencies": { 25 | "@types/chai": "4.2.15", 26 | "@types/chai-as-promised": "7.1.3", 27 | "@types/chai-subset": "1.3.3", 28 | "@types/mocha": "8.2.1", 29 | "@types/pino": "6.3.6", 30 | "babel-loader": "8.1.0", 31 | "chai": "4.3.1", 32 | "chai-as-promised": "7.1.1", 33 | "copy-webpack-plugin": "6.2.1", 34 | "mocha": "8.3.0", 35 | "nodemon": "2.0.7", 36 | "pino-pretty": "4.6.0", 37 | "ts-loader": "8.0.7", 38 | "ts-mocha": "8.0.0", 39 | "ts-node": "9.1.1", 40 | "typescript": "4.2.4", 41 | "webpack": "4.44.2", 42 | "webpack-cli": "4.1.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /modules/auth/src/config.ts: -------------------------------------------------------------------------------- 1 | const publicKey = process.env.VECTOR_JWT_SIGNER_PUBLIC_KEY?.replace(/\\n/g, "\n"); 2 | if (!publicKey) { 3 | throw new Error(`VECTOR_JWT_SIGNER_PUBLIC_KEY is required`); 4 | } 5 | 6 | const privateKey = process.env.VECTOR_JWT_SIGNER_PRIVATE_KEY?.replace(/\\n/g, "\n"); 7 | if (!privateKey) { 8 | throw new Error(`VECTOR_JWT_SIGNER_PRIVATE_KEY is required`); 9 | } 10 | 11 | const natsServers = process.env.VECTOR_NATS_URL; 12 | if (!natsServers) { 13 | throw new Error(`VECTOR_NATS_URL is required`); 14 | } 15 | 16 | const adminToken = process.env.VECTOR_ADMIN_TOKEN; 17 | if (!adminToken) { 18 | throw new Error(`VECTOR_ADMIN_TOKEN is required`); 19 | } 20 | 21 | export const config = { 22 | messagingUrl: natsServers, 23 | privateKey, 24 | publicKey, 25 | adminToken, 26 | port: parseInt(process.env.VECTOR_PORT ?? "5040"), 27 | }; 28 | -------------------------------------------------------------------------------- /modules/auth/src/schemas.ts: -------------------------------------------------------------------------------- 1 | import { Static, Type } from "@sinclair/typebox"; 2 | 3 | // GET NONCE 4 | export const getNonceParamsSchema = Type.Object({ 5 | userIdentifier: Type.String({ 6 | example: "vector8AXWmo3dFpK1drnjeWPyi9KTy9Fy3SkCydWx8waQrxhnW4KPmR", 7 | description: "Public identifier", 8 | }), 9 | }); 10 | 11 | export type GetNonceRequestParams = Static; 12 | 13 | export const getNonceResponseSchema = { 14 | 200: Type.Object({ 15 | nonce: Type.String({ example: "abc" }), 16 | }), 17 | }; 18 | export type GetNonceResponseBody = Static; 19 | 20 | // POST AUTH 21 | export const postAuthBodySchema = Type.Object({ 22 | userIdentifier: Type.String({ 23 | example: "vector8AXWmo3dFpK1drnjeWPyi9KTy9Fy3SkCydWx8waQrxhnW4KPmR", 24 | description: "Public identifier", 25 | }), 26 | sig: Type.String({ 27 | description: "Signature of nonce using public identifier private key", 28 | }), 29 | adminToken: Type.Optional( 30 | Type.String({ 31 | example: "connext123", 32 | description: "Admin token to grant full permissions", 33 | }), 34 | ), 35 | }); 36 | 37 | export type PostAuthRequestBody = Static; 38 | 39 | export const postAuthResponseSchema = { 40 | 200: Type.Object({ 41 | token: Type.String({ example: "abc", description: "Token to be used for messaging auth" }), 42 | }), 43 | }; 44 | export type PostAuthResponseBody = Static; 45 | -------------------------------------------------------------------------------- /modules/auth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "declarationDir": "dist/", 6 | "incremental": true, 7 | "module": "commonjs", 8 | "noUnusedLocals": false, 9 | "outDir": "dist", 10 | "strict": true, 11 | "target": "es6", 12 | }, 13 | "exclude": ["dist", "node_modules", "src/testing"], 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/browser-node/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src/**"], 5 | "exclude": ["src/**/*.spec.ts"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/browser-node/ops/webpack.config.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | 3 | import * as webpack from "webpack"; 4 | 5 | const config: webpack.Configuration = { 6 | entry: "./src/index.ts", 7 | module: { 8 | rules: [ 9 | { 10 | test: /\.tsx?$/, 11 | use: "ts-loader", 12 | exclude: /node_modules/, 13 | }, 14 | ], 15 | }, 16 | resolve: { 17 | extensions: [".tsx", ".ts", ".js"], 18 | }, 19 | output: { 20 | filename: "bundle.js", 21 | path: path.resolve(__dirname, "dist"), 22 | }, 23 | }; 24 | 25 | export default config; 26 | -------------------------------------------------------------------------------- /modules/browser-node/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { HashZero } from "@ethersproject/constants"; 2 | 3 | export const EIP712Domain = { 4 | name: "Vector", 5 | version: "1", 6 | salt: HashZero, 7 | }; 8 | 9 | export const EIP712Types = { 10 | Greeting: [ 11 | { 12 | name: "contents", 13 | type: "string", 14 | }, 15 | ], 16 | }; 17 | 18 | export const EIP712Value = { 19 | contents: "Welcome to Connext. Please confirm signature to sign in!", 20 | }; 21 | 22 | export const NonEIP712Message = "Connext Login v1.0"; 23 | -------------------------------------------------------------------------------- /modules/browser-node/src/services/store.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getTestLoggers, 3 | mkPublicIdentifier, 4 | testStore, 5 | } from "@connext/vector-utils"; 6 | import indexedDB from "fake-indexeddb"; 7 | import IDBKeyRange from "fake-indexeddb/lib/FDBKeyRange"; 8 | 9 | import { BrowserStore } from "./store"; 10 | 11 | const name = "BrowserStore"; 12 | const { log } = getTestLoggers(name); 13 | const pubId = mkPublicIdentifier(); 14 | 15 | testStore(name, () => new BrowserStore(pubId, log, indexedDB, IDBKeyRange), true) 16 | -------------------------------------------------------------------------------- /modules/browser-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "declarationDir": "dist/", 6 | "incremental": true, 7 | "module": "commonjs", 8 | "outDir": "dist", 9 | "strict": true, 10 | "target": "es6" 11 | }, 12 | "exclude": ["dist", "node_modules"], 13 | "include": ["src/**/*.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /modules/contracts/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src.ts/**"], 5 | "exclude": ["src.ts/tests/**"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/contracts/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:default" 3 | } 4 | -------------------------------------------------------------------------------- /modules/contracts/deployments/arbitrumtest/.chainId: -------------------------------------------------------------------------------- 1 | 79377087078960 -------------------------------------------------------------------------------- /modules/contracts/deployments/arbitrumtest4/.chainId: -------------------------------------------------------------------------------- 1 | 212984383488152 -------------------------------------------------------------------------------- /modules/contracts/deployments/avalanche/.chainId: -------------------------------------------------------------------------------- 1 | 43114 -------------------------------------------------------------------------------- /modules/contracts/deployments/avalanchefuji/.chainId: -------------------------------------------------------------------------------- 1 | 43113 -------------------------------------------------------------------------------- /modules/contracts/deployments/bsc/.chainId: -------------------------------------------------------------------------------- 1 | 56 -------------------------------------------------------------------------------- /modules/contracts/deployments/bsctestnet/.chainId: -------------------------------------------------------------------------------- 1 | 97 -------------------------------------------------------------------------------- /modules/contracts/deployments/fantom/.chainId: -------------------------------------------------------------------------------- 1 | 250 -------------------------------------------------------------------------------- /modules/contracts/deployments/goerli/.chainId: -------------------------------------------------------------------------------- 1 | 5 -------------------------------------------------------------------------------- /modules/contracts/deployments/harmony/.chainId: -------------------------------------------------------------------------------- 1 | 1666600000 2 | -------------------------------------------------------------------------------- /modules/contracts/deployments/harmonytestnet/.chainId: -------------------------------------------------------------------------------- 1 | 1666700000 2 | -------------------------------------------------------------------------------- /modules/contracts/deployments/heco/.chainId: -------------------------------------------------------------------------------- 1 | 128 -------------------------------------------------------------------------------- /modules/contracts/deployments/hecotestnet/.chainId: -------------------------------------------------------------------------------- 1 | 256 -------------------------------------------------------------------------------- /modules/contracts/deployments/kovan/.chainId: -------------------------------------------------------------------------------- 1 | 42 -------------------------------------------------------------------------------- /modules/contracts/deployments/mainnet/.chainId: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /modules/contracts/deployments/matic/.chainId: -------------------------------------------------------------------------------- 1 | 137 -------------------------------------------------------------------------------- /modules/contracts/deployments/moonbasealpha/.chainId: -------------------------------------------------------------------------------- 1 | 1287 -------------------------------------------------------------------------------- /modules/contracts/deployments/mumbai/.chainId: -------------------------------------------------------------------------------- 1 | 80001 -------------------------------------------------------------------------------- /modules/contracts/deployments/rinkeby/.chainId: -------------------------------------------------------------------------------- 1 | 4 -------------------------------------------------------------------------------- /modules/contracts/deployments/xdai/.chainId: -------------------------------------------------------------------------------- 1 | 100 -------------------------------------------------------------------------------- /modules/contracts/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY package.json ./ 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY tsconfig.json tsconfig.json 24 | COPY hardhat.config.ts hardhat.config.ts 25 | COPY ops/entry.sh /entry.sh 26 | COPY deploy deploy 27 | COPY src.sol src.sol 28 | COPY src.ts src.ts 29 | COPY artifacts artifacts 30 | COPY dist dist 31 | 32 | RUN find dist -type f -name "*.ts" -exec rm {} \; &&\ 33 | find dist -type f -name "*.map" -exec rm {} \; &&\ 34 | chmod +x /*.sh 35 | 36 | # USER node 37 | 38 | ENTRYPOINT ["bash", "/entry.sh"] 39 | -------------------------------------------------------------------------------- /modules/contracts/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ethprovider", 3 | "description": "This is only used to install a few packages into the ethprovider docker container", 4 | "dependencies": { 5 | "ethers": "5.2.0", 6 | "hardhat": "2.2.0", 7 | "pino-pretty": "4.6.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/ChannelMastercopy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "./interfaces/IVectorChannel.sol"; 6 | import "./CMCCore.sol"; 7 | import "./CMCAsset.sol"; 8 | import "./CMCDeposit.sol"; 9 | import "./CMCWithdraw.sol"; 10 | import "./CMCAdjudicator.sol"; 11 | 12 | /// @title ChannelMastercopy 13 | /// @author Connext 14 | /// @notice Contains the logic used by all Vector multisigs. A proxy to this 15 | /// contract is deployed per-channel using the ChannelFactory.sol. 16 | /// Supports channel adjudication logic, deposit logic, and arbitrary 17 | /// calls when a commitment is double-signed. 18 | contract ChannelMastercopy is 19 | CMCCore, 20 | CMCAsset, 21 | CMCDeposit, 22 | CMCWithdraw, 23 | CMCAdjudicator, 24 | IVectorChannel 25 | { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/ReentrancyGuard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /// @title CMCWithdraw 6 | /// @author Connext 7 | /// @notice A "mutex" reentrancy guard, heavily influenced by OpenZeppelin. 8 | 9 | contract ReentrancyGuard { 10 | uint256 private constant OPEN = 1; 11 | uint256 private constant LOCKED = 2; 12 | 13 | uint256 public lock; 14 | 15 | function setup() internal { 16 | lock = OPEN; 17 | } 18 | 19 | modifier nonReentrant() { 20 | require(lock == OPEN, "ReentrancyGuard: REENTRANT_CALL"); 21 | lock = LOCKED; 22 | _; 23 | lock = OPEN; 24 | } 25 | 26 | modifier nonReentrantView() { 27 | require(lock == OPEN, "ReentrancyGuard: REENTRANT_CALL"); 28 | _; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/lib/helpers/IAuthentication.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU General Public License for more details. 11 | 12 | // You should have received a copy of the GNU General Public License 13 | // along with this program. If not, see . 14 | 15 | pragma solidity ^0.7.0; 16 | 17 | interface IAuthentication { 18 | /** 19 | * @dev Returns the action identifier associated with the external function described by `selector`. 20 | */ 21 | function getActionId(bytes4 selector) external view returns (bytes32); 22 | } 23 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/lib/openzeppelin/ERC20Burnable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.0; 4 | 5 | import "./ERC20.sol"; 6 | 7 | /** 8 | * @dev Extension of {ERC20} that allows token holders to destroy both their own 9 | * tokens and those that they have an allowance for, in a way that can be 10 | * recognized off-chain (via event analysis). 11 | */ 12 | abstract contract ERC20Burnable is ERC20 { 13 | using SafeMath for uint256; 14 | 15 | /** 16 | * @dev Destroys `amount` tokens from the caller. 17 | * 18 | * See {ERC20-_burn}. 19 | */ 20 | function burn(uint256 amount) public virtual { 21 | _burn(msg.sender, amount); 22 | } 23 | 24 | /** 25 | * @dev Destroys `amount` tokens from `account`, deducting from the caller's 26 | * allowance. 27 | * 28 | * See {ERC20-_burn} and {ERC20-allowance}. 29 | * 30 | * Requirements: 31 | * 32 | * - the caller must have allowance for ``accounts``'s tokens of at least 33 | * `amount`. 34 | */ 35 | function burnFrom(address account, uint256 amount) public virtual { 36 | uint256 decreasedAllowance = allowance(account, msg.sender).sub(amount, Errors.ERC20_BURN_EXCEEDS_ALLOWANCE); 37 | 38 | _approve(account, msg.sender, decreasedAllowance); 39 | _burn(account, amount); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/lib/openzeppelin/SafeCast.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.0; 4 | 5 | import "../helpers/BalancerErrors.sol"; 6 | 7 | /** 8 | * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow 9 | * checks. 10 | * 11 | * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can 12 | * easily result in undesired exploitation or bugs, since developers usually 13 | * assume that overflows raise errors. `SafeCast` restores this intuition by 14 | * reverting the transaction when such an operation overflows. 15 | * 16 | * Using this library instead of the unchecked operations eliminates an entire 17 | * class of bugs, so it's recommended to use it always. 18 | * 19 | * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing 20 | * all math on `uint256` and `int256` and then downcasting. 21 | */ 22 | library SafeCast { 23 | /** 24 | * @dev Converts an unsigned uint256 into a signed int256. 25 | * 26 | * Requirements: 27 | * 28 | * - input must be less than or equal to maxInt256. 29 | */ 30 | function toInt256(uint256 value) internal pure returns (int256) { 31 | _require(value < 2**255, Errors.SAFE_CAST_VALUE_CANT_FIT_INT256); 32 | return int256(value); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/vault/interfaces/IAsset.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU General Public License for more details. 11 | 12 | // You should have received a copy of the GNU General Public License 13 | // along with this program. If not, see . 14 | 15 | pragma solidity ^0.7.0; 16 | 17 | /** 18 | * @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero 19 | * address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like 20 | * types. 21 | * 22 | * This concept is unrelated to a Pool's Asset Managers. 23 | */ 24 | interface IAsset { 25 | // solhint-disable-previous-line no-empty-blocks 26 | } 27 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/vault/interfaces/IAuthorizer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU General Public License for more details. 11 | 12 | // You should have received a copy of the GNU General Public License 13 | // along with this program. If not, see . 14 | 15 | pragma solidity ^0.7.0; 16 | 17 | interface IAuthorizer { 18 | /** 19 | * @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`. 20 | */ 21 | function canPerform( 22 | bytes32 actionId, 23 | address account, 24 | address where 25 | ) external view returns (bool); 26 | } 27 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/vault/interfaces/ISignaturesValidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU General Public License for more details. 11 | 12 | // You should have received a copy of the GNU General Public License 13 | // along with this program. If not, see . 14 | 15 | pragma solidity ^0.7.0; 16 | 17 | /** 18 | * @dev Interface for the SignatureValidator helper, used to support meta-transactions. 19 | */ 20 | interface ISignaturesValidator { 21 | /** 22 | * @dev Returns the EIP712 domain separator. 23 | */ 24 | function getDomainSeparator() external view returns (bytes32); 25 | 26 | /** 27 | * @dev Returns the next nonce used by an address to sign messages. 28 | */ 29 | function getNextNonce(address user) external view returns (uint256); 30 | } 31 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/amm/vault/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | // This program is free software: you can redistribute it and/or modify 3 | // it under the terms of the GNU General Public License as published by 4 | // the Free Software Foundation, either version 3 of the License, or 5 | // (at your option) any later version. 6 | 7 | // This program is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | // GNU General Public License for more details. 11 | 12 | // You should have received a copy of the GNU General Public License 13 | // along with this program. If not, see . 14 | 15 | pragma solidity ^0.7.0; 16 | 17 | import "../../lib/openzeppelin/IERC20.sol"; 18 | 19 | /** 20 | * @dev Interface for the WETH token contract used internally for wrapping and unwrapping, to support 21 | * sending and receiving ETH in joins, swaps, and internal balance deposits and withdrawals. 22 | */ 23 | interface IWETH is IERC20 { 24 | function deposit() external payable; 25 | 26 | function withdraw(uint256 amount) external; 27 | } 28 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/Commitment.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | enum CommitmentType {ChannelState, WithdrawData} 6 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ICMCAsset.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface ICMCAsset { 6 | function getTotalTransferred(address assetId) 7 | external 8 | view 9 | returns (uint256); 10 | 11 | function getExitableAmount(address assetId, address owner) 12 | external 13 | view 14 | returns (uint256); 15 | 16 | function exit( 17 | address assetId, 18 | address owner, 19 | address payable recipient 20 | ) external; 21 | } 22 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ICMCCore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface ICMCCore { 6 | function setup(address _alice, address _bob) external; 7 | 8 | function getAlice() external view returns (address); 9 | 10 | function getBob() external view returns (address); 11 | } 12 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ICMCDeposit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface ICMCDeposit { 6 | event AliceDeposited(address assetId, uint256 amount); 7 | 8 | function getTotalDepositsAlice(address assetId) 9 | external 10 | view 11 | returns (uint256); 12 | 13 | function getTotalDepositsBob(address assetId) 14 | external 15 | view 16 | returns (uint256); 17 | 18 | function depositAlice(address assetId, uint256 amount) external payable; 19 | } 20 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ICMCWithdraw.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | struct WithdrawData { 6 | address channelAddress; 7 | address assetId; 8 | address payable recipient; 9 | uint256 amount; 10 | uint256 nonce; 11 | address callTo; 12 | bytes callData; 13 | } 14 | 15 | interface ICMCWithdraw { 16 | function getWithdrawalTransactionRecord(WithdrawData calldata wd) 17 | external 18 | view 19 | returns (bool); 20 | 21 | function withdraw( 22 | WithdrawData calldata wd, 23 | bytes calldata aliceSignature, 24 | bytes calldata bobSignature 25 | ) external; 26 | } 27 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/IChannelFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | interface IChannelFactory { 6 | event ChannelCreation(address channel); 7 | 8 | function getMastercopy() external view returns (address); 9 | 10 | function getChainId() external view returns (uint256); 11 | 12 | function getStoredChainId() external view returns (uint256); 13 | 14 | function getProxyCreationCode() external view returns (bytes memory); 15 | 16 | function getChannelAddress(address alice, address bob) 17 | external 18 | view 19 | returns (address); 20 | 21 | function createChannel(address alice, address bob) 22 | external 23 | returns (address); 24 | 25 | function createChannelAndDepositAlice( 26 | address alice, 27 | address bob, 28 | address assetId, 29 | uint256 amount 30 | ) external payable returns (address); 31 | } 32 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ITestChannel.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "./IVectorChannel.sol"; 6 | import "./Types.sol"; 7 | 8 | interface ITestChannel is IVectorChannel { 9 | function testMakeExitable( 10 | address assetId, 11 | address payable recipient, 12 | uint256 maxAmount 13 | ) external; 14 | 15 | function testMakeBalanceExitable( 16 | address assetId, 17 | Balance memory balance 18 | ) external; 19 | } 20 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/ITransferRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental "ABIEncoderV2"; 4 | 5 | struct RegisteredTransfer { 6 | string name; 7 | address definition; 8 | string stateEncoding; 9 | string resolverEncoding; 10 | bytes encodedCancel; 11 | } 12 | 13 | interface ITransferRegistry { 14 | event TransferAdded(RegisteredTransfer transfer); 15 | 16 | event TransferRemoved(RegisteredTransfer transfer); 17 | 18 | // Should add a transfer definition to the registry 19 | // onlyOwner 20 | function addTransferDefinition(RegisteredTransfer memory transfer) external; 21 | 22 | // Should remove a transfer definition to the registry 23 | // onlyOwner 24 | function removeTransferDefinition(string memory name) external; 25 | 26 | // Should return all transfer defintions in registry 27 | function getTransferDefinitions() 28 | external 29 | view 30 | returns (RegisteredTransfer[] memory); 31 | } 32 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/IVectorChannel.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "./ICMCCore.sol"; 6 | import "./ICMCAsset.sol"; 7 | import "./ICMCDeposit.sol"; 8 | import "./ICMCWithdraw.sol"; 9 | import "./ICMCAdjudicator.sol"; 10 | 11 | interface IVectorChannel is 12 | ICMCCore, 13 | ICMCAsset, 14 | ICMCDeposit, 15 | ICMCWithdraw, 16 | ICMCAdjudicator 17 | {} 18 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/Types.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | struct Balance { 6 | uint256[2] amount; // [alice, bob] in channel, [initiator, responder] in transfer 7 | address payable[2] to; // [alice, bob] in channel, [initiator, responder] in transfer 8 | } 9 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/interfaces/WithdrawHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "./ICMCWithdraw.sol"; 6 | 7 | interface WithdrawHelper { 8 | function execute(WithdrawData calldata wd, uint256 actualAmount) external; 9 | } 10 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/lib/LibMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /// @title LibMath 6 | /// @author Connext 7 | /// @notice This library allows functions that would otherwise overflow and 8 | /// revert if SafeMath was used to instead return the UINT_MAX. In the 9 | /// adjudicator, this is used to ensure you can get the majority of 10 | /// funds out in the event your balance > UINT_MAX and there is an 11 | /// onchain dispute. 12 | library LibMath { 13 | /// @dev Returns the maximum uint256 for an addition that would overflow 14 | /// (saturation arithmetic) 15 | function satAdd(uint256 x, uint256 y) internal pure returns (uint256) { 16 | uint256 sum = x + y; 17 | return sum >= x ? sum : type(uint256).max; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/lib/LibUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | /// @title LibUtils 6 | /// @author Connext 7 | /// @notice Contains a helper to revert if a call was not successfully 8 | /// made 9 | library LibUtils { 10 | // If success is false, reverts and passes on the revert string. 11 | function revertIfCallFailed(bool success, bytes memory returnData) 12 | internal 13 | pure 14 | { 15 | if (!success) { 16 | assembly { 17 | revert(add(returnData, 0x20), mload(returnData)) 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/testing/ReentrantToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.7.1; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | import "../interfaces/IVectorChannel.sol"; 6 | 7 | contract ReentrantToken is ERC20 { 8 | address private immutable channel; 9 | 10 | constructor(address _channel) ERC20("Reentrant Token", "BADBOI") { 11 | channel = _channel; 12 | } 13 | 14 | function mint(address account, uint256 amount) external { 15 | _mint(account, amount); 16 | } 17 | 18 | // Designed to be called alongside CMCDeposit.depositAlice 19 | function transferFrom( 20 | address sender, 21 | address recipient, 22 | uint256 amount 23 | ) public override returns (bool) { 24 | IVectorChannel(channel).depositAlice(address(this), amount); 25 | return super.transferFrom(sender, recipient, amount); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/testing/TestChannel.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental "ABIEncoderV2"; 4 | 5 | import "../ChannelMastercopy.sol"; 6 | import "../interfaces/ITestChannel.sol"; 7 | 8 | /// @title TestChannel 9 | /// @author Layne Haber 10 | /// @notice This contract will help test the `ChannelMastercopy` contract and 11 | /// the associated bits of functionality. This contract should *only* 12 | /// contain aliases to internal functions that should be unit-tested, 13 | /// like the `makeExitable` call on `CMCAsset.sol`. Using this 14 | /// contract will help reduce the amount of boilerplate needed to test 15 | /// component functionality. For example, `CMCAsset.sol` is only 16 | /// able to be tested via the adjudicator in many practical cases. 17 | /// Creating a helper function allows for easier testing of only 18 | /// that functionality. 19 | 20 | contract TestChannel is ChannelMastercopy, ITestChannel { 21 | function testMakeExitable( 22 | address assetId, 23 | address payable recipient, 24 | uint256 maxAmount 25 | ) public override { 26 | makeExitable(assetId, recipient, maxAmount); 27 | } 28 | 29 | function testMakeBalanceExitable( 30 | address assetId, 31 | Balance memory balance 32 | ) public override { 33 | makeBalanceExitable(assetId, balance); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/testing/TestChannelFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "../interfaces/IVectorChannel.sol"; 6 | import "../ChannelFactory.sol"; 7 | 8 | /// @title TestChannelFactory 9 | /// @author Layne Haber 10 | /// @notice This factory is used for testing *ONLY* and allows you to 11 | /// deploy contracts without setting them up (to run the CMCCore 12 | /// setup tests) 13 | contract TestChannelFactory is ChannelFactory { 14 | constructor(address _mastercopy, uint256 _chainId) 15 | ChannelFactory(_mastercopy, _chainId) 16 | {} 17 | 18 | function deployChannelProxyWithoutSetup(address alice, address bob) 19 | public 20 | returns (address) 21 | { 22 | return deployChannelProxy(alice, bob); 23 | } 24 | 25 | function createChannelWithoutSetup(address alice, address bob) 26 | public 27 | returns (address channel) 28 | { 29 | channel = deployChannelProxy(alice, bob); 30 | emit ChannelCreation(channel); 31 | return channel; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/testing/TestToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.1; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | /* This token is ONLY useful for testing 8 | * Anybody can mint as many tokens as they like 9 | * Anybody can burn anyone else's tokens 10 | */ 11 | contract TestToken is ERC20 { 12 | constructor() ERC20("Test Token", "TEST") { 13 | _mint(msg.sender, 1000000 ether); 14 | } 15 | 16 | function mint(address account, uint256 amount) external { 17 | _mint(account, amount); 18 | } 19 | 20 | function burn(address account, uint256 amount) external { 21 | _burn(account, amount); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /modules/contracts/src.sol/transferDefinitions/TransferDefinition.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.7.1; 3 | pragma experimental ABIEncoderV2; 4 | 5 | import "../interfaces/ITransferDefinition.sol"; 6 | import "../interfaces/ITransferRegistry.sol"; 7 | 8 | /// @title TransferDefinition 9 | /// @author Connext 10 | /// @notice This contract helps reduce boilerplate needed when creating 11 | /// new transfer definitions by providing an implementation of 12 | /// the required getter 13 | 14 | abstract contract TransferDefinition is ITransferDefinition { 15 | function getRegistryInformation() 16 | external 17 | view 18 | override 19 | returns (RegisteredTransfer memory) 20 | { 21 | return 22 | RegisteredTransfer({ 23 | name: this.Name(), 24 | stateEncoding: this.StateEncoding(), 25 | resolverEncoding: this.ResolverEncoding(), 26 | definition: address(this), 27 | encodedCancel: this.EncodedCancel() 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/commitments/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./withdraw"; 2 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/constants.ts: -------------------------------------------------------------------------------- 1 | import { HDNode } from "@ethersproject/hdnode"; 2 | import { Wallet } from "@ethersproject/wallet"; 3 | import { JsonRpcProvider } from "@ethersproject/providers"; 4 | import { network, ethers }from "hardhat"; 5 | import pino from "pino"; 6 | 7 | // Get defaults from env 8 | const chainProviders = JSON.parse(process.env.CHAIN_PROVIDERS ?? "{}"); 9 | const chainId = Object.keys(chainProviders)[0]; 10 | const url = Object.values(chainProviders)[0]; 11 | const mnemonic = process.env.SUGAR_DADDY ?? "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat"; 12 | 13 | export const defaultLogLevel = process.env.LOG_LEVEL || "info"; 14 | export const logger = pino({ level: defaultLogLevel }); 15 | 16 | export const networkName = network.name; 17 | 18 | export const provider = url 19 | ? new JsonRpcProvider(url as string, parseInt(chainId)) 20 | : ethers.provider as JsonRpcProvider; 21 | 22 | const hdNode = HDNode.fromMnemonic(mnemonic).derivePath("m/44'/60'/0'/0"); 23 | 24 | export const wallets: Wallet[] = Array(20) 25 | .fill(0) 26 | .map((_, idx) => { 27 | const wallet = new Wallet(hdNode.derivePath(idx.toString()).privateKey, provider); 28 | return wallet; 29 | }); 30 | 31 | export const chainIdReq = provider.getNetwork().then(net => net.chainId); 32 | export const alice = wallets[0]; 33 | export const bob = wallets[1]; 34 | export const rando = wallets[2]; 35 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./artifacts"; 2 | export * from "./commitments"; 3 | export * from "./deployments"; 4 | export * from "./services"; 5 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/calcStableSwap.ts: -------------------------------------------------------------------------------- 1 | // import { Contract } from "@ethersproject/contracts"; 2 | // import { task } from "hardhat/config"; 3 | // import pino from "pino"; 4 | 5 | // import { StableMath } from "../../typechain"; 6 | 7 | // export default task("calc-stable-swap", "Calculates a stable swap given reserves") 8 | // .addParam("stableMath", "The address of the StableMath contract") 9 | // .addParam("amplificationParameter", "") 10 | // .addParam("balanceIn", "Balance In") 11 | // .addParam("balanceOut", "Balance Out") 12 | // .addOptionalParam("logLevel", "One of 'debug', 'info', 'warn', 'error', 'silent' (default: info)") 13 | // .setAction( 14 | // async (args, hre): Promise => { 15 | // const { stableMath, amplificationParameter, balanceIn, balanceOut, logLevel } = args; 16 | // const log = pino({ level: logLevel || "info" }); 17 | // log.info(`Calculating swap for alice=${balanceIn} and bob=${balanceOut}`); 18 | // const _stableMath = (await hre.ethers.getContractAt("StableMath", stableMath)) as StableMath; 19 | // const tokensOut = await _stableMath._calcOutGivenIn(); 20 | // }, 21 | // ); 22 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/changeTransferRegistryOwner.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import pino from "pino"; 3 | 4 | export default task("change-transfer-registry-owner", "Change transfer registry owner") 5 | .addParam("newOwner", "Address of the new owner") 6 | .addParam("signerAddress", "The address that will sign the registration tx") 7 | .addOptionalParam("logLevel", "One of 'debug', 'info', 'warn', 'error', 'silent' (default: info)") 8 | .setAction( 9 | async (args, hre): Promise => { 10 | const { newOwner, logLevel, signerAddress } = args; 11 | const log = pino({ level: logLevel || "info" }); 12 | 13 | log.info(`Preparing to add ${newOwner} to as owner of transfer registry (Sender=${signerAddress})`); 14 | const registry = await (hre.ethers as any).getContract("TransferRegistry", signerAddress); 15 | const currentOwner = await registry.owner(); 16 | log.info(`Current owner: ${currentOwner}`); 17 | 18 | const tx = await registry.transferOwnership(newOwner); 19 | log.info({ hash: tx.hash }, "transferOwnership tx broadcast"); 20 | 21 | await tx.wait(); 22 | log.info(`transferOwnership tx mined!`); 23 | 24 | const _newOwner = await registry.owner(); 25 | log.info(`New owner: ${_newOwner}`); 26 | }, 27 | ); 28 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/createChannel.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from "@ethersproject/contracts"; 2 | import { task } from "hardhat/config"; 3 | import pino from "pino"; 4 | 5 | export default task("create-channel", "Creates a new channel") 6 | .addParam("aliceAddress", "The address of both the alice role AND the signer") 7 | .addParam("bobAddress", "The address of the channel's bob role") 8 | .addOptionalParam("logLevel", "One of 'debug', 'info', 'warn', 'error', 'silent' (default: info)") 9 | .addParam("testMode", "If provided then create a TestChannel else create a VectorChannel") 10 | .setAction(async (args, hre): Promise => { 11 | const { aliceAddress, bobAddress, logLevel, testMode } = args; 12 | const log = pino({ level: logLevel || "info" }); 13 | log.info(`Preparing to create a channel for alice=${aliceAddress} and bob=${bobAddress}`); 14 | const channelFactory = await (hre.ethers as any).getContract(testMode ? "TestChannelFactory" : "ChannelFactory", aliceAddress); 15 | const channelAddress = await channelFactory.getChannelAddress(aliceAddress, bobAddress); 16 | const channelCode = await hre.ethers.provider.getCode(channelAddress); 17 | if (channelCode === "0x" || channelCode === "0x00") { 18 | await (await channelFactory.createChannel(aliceAddress, bobAddress)).wait(); 19 | log.info(`Successfully created a channel at ${channelAddress}`); 20 | } else { 21 | log.info(`Channel already exists at ${channelAddress}`); 22 | } 23 | return (hre.ethers as any).getContractAt( 24 | testMode ? "TestChannel" : "IVectorChannel", 25 | channelAddress, 26 | aliceAddress, 27 | ); 28 | }); 29 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/displayAccounts.ts: -------------------------------------------------------------------------------- 1 | import { HDNode } from "@ethersproject/hdnode"; 2 | import { Wallet } from "@ethersproject/wallet"; 3 | import { task } from "hardhat/config"; 4 | import pino from "pino"; 5 | 6 | export default task("display-accounts", "Displays first 3 accounts and their recommended gifts") 7 | .addParam("mnemonic", "The mnemonic to display accounts for") 8 | .addOptionalParam("logLevel", "One of 'debug', 'info', 'warn', 'error', 'silent' (default: info)") 9 | .setAction(async (args): Promise => { 10 | const { mnemonic, logLevel } = args; 11 | const log = pino({ level: logLevel || "info" }); 12 | const hdNode = HDNode.fromMnemonic(mnemonic).derivePath("m/44'/60'/0'/0"); 13 | const wallets: Wallet[] = Array(20) 14 | .fill(0) 15 | .map((_, idx) => { 16 | const wallet = new Wallet(hdNode.derivePath(idx.toString()).privateKey); 17 | return wallet; 18 | }); 19 | log.info( 20 | { wallets: wallets.map(w => w.address), privateKeys: wallets.map(w => w.privateKey) }, 21 | "All contract testing accounts", 22 | ); 23 | log.info({ alice: wallets[0].address, recommended: "1 ETH" }, "Alice"); 24 | log.info({ bob: wallets[1].address, recommended: "0.5 ETH" }, "Bob"); 25 | log.info({ rando: wallets[2].address, recommended: "0.1 ETH" }, "Rando"); 26 | }); 27 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/drip.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config"; 2 | import pino from "pino"; 3 | 4 | export default task("drip", "Mints tokens to given address") 5 | .addParam("address", "The address to drip funds to") 6 | .addOptionalParam("signerAddress", "The address that will sign the registration tx") 7 | .addOptionalParam("amount", "The amount to mint in wei (default: 10 tokens)") 8 | .addOptionalParam("logLevel", "One of 'debug', 'info', 'warn', 'error', 'silent' (default: info)") 9 | .setAction( 10 | async (args, hre): Promise => { 11 | const { address, logLevel, amount, signerAddress } = args; 12 | const toDrip = amount ?? (hre.ethers as any).utils.parseEther("10"); 13 | const log = pino({ level: logLevel ?? "info" }); 14 | log.info(`Preparing to drip ${(hre.ethers as any).utils.formatEther(toDrip)} tokens to addr=${address}`); 15 | const token = await (hre.ethers as any).getContract("TestToken", signerAddress ?? address); 16 | const mint = await token.mint(address, toDrip); 17 | log.info(`Transaction: ${mint.hash}`); 18 | await mint.wait(); 19 | log.info(`Successfully minted tokens`); 20 | }, 21 | ); 22 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/index.ts: -------------------------------------------------------------------------------- 1 | import "./createChannel"; 2 | import "./displayAccounts"; 3 | import "./drip"; 4 | import "./registerTransfer"; 5 | import "./changeTransferRegistryOwner"; 6 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tasks/registerTransfer.spec.ts: -------------------------------------------------------------------------------- 1 | import { TransferNames } from "@connext/vector-types"; 2 | import { expect } from "@connext/vector-utils"; 3 | import { Contract } from "@ethersproject/contracts"; 4 | import { deployments } from "hardhat"; 5 | 6 | import { alice } from "../constants"; 7 | import { getContract, registerTransfer } from "../utils"; 8 | 9 | describe("registerTransfer", function() { 10 | this.timeout(120_000); 11 | let registry: Contract; 12 | 13 | beforeEach(async () => { 14 | await deployments.fixture(); // Start w fresh deployments 15 | registry = await getContract("TransferRegistry", alice); 16 | }); 17 | 18 | it("should registry a new transfer", async () => { 19 | expect(registry.address).to.be.a("string"); 20 | await expect(registerTransfer(TransferNames.HashlockTransfer, alice.address)).to.be.fulfilled; 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tests/deploy.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@connext/vector-utils"; 2 | import { deployments } from "hardhat"; 3 | 4 | describe("deploy", function() { 5 | this.timeout(360_000); 6 | it("should run without error", async () => { 7 | await expect(deployments.fixture()).to.be.fulfilled; 8 | }); 9 | }); 10 | 11 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tests/lib/asset.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | 3 | // NOTE: this is tested via the tests of asset, probably does not need to 4 | // be tested separately 5 | describe("LibAsset.sol", function() { 6 | this.timeout(120_000); 7 | describe("isEther", () => { 8 | it.skip("should return true IFF asset is address(0)", async () => {}); 9 | }); 10 | 11 | describe("getOwnBalance", () => { 12 | it.skip("should return correct ETH balance", async () => {}); 13 | it.skip("should return correct ERC20 balance", async () => {}); 14 | }); 15 | 16 | describe("transfer", () => { 17 | it.skip("should transfer ETH", async () => {}); 18 | it.skip("should transfer ERC20", async () => {}); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/tests/lib/channelCrypto.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | 3 | // NOTE: all of these are internal functions, that are implicitly tested 4 | // throughout the code (every signature verification). Probably *dont* need 5 | // to test specifically 6 | describe("LibChannelCrypto.sol", function() { 7 | this.timeout(120_000); 8 | describe("verifyChannelMessage", () => { 9 | it.skip("should work", async () => {}); 10 | }); 11 | 12 | describe("toChannelSignedMessage", () => { 13 | it.skip("should work", async () => {}); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /modules/contracts/src.ts/utils.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from "@ethersproject/contracts"; 2 | import { ethers, run } from "hardhat"; 3 | 4 | import { alice, bob, defaultLogLevel, provider } from "./constants"; 5 | 6 | export const getContract = (ethers as any).getContract; 7 | 8 | //////////////////////////////////////// 9 | // Wrap tasks in a format that's easier to use internally 10 | 11 | export const registerTransfer = ( 12 | transferName: string, 13 | signerAddress: string = alice.address, 14 | logLevel = defaultLogLevel, 15 | ): Promise => 16 | run("register-transfer", { transferName, signerAddress, logLevel }); 17 | 18 | export const createChannel = ( 19 | aliceAddress: string = alice.address, 20 | bobAddress: string = bob.address, 21 | logLevel = defaultLogLevel, 22 | testMode = "yarp", 23 | ): Promise => 24 | run("create-channel", { aliceAddress, bobAddress, logLevel, testMode }); 25 | 26 | //////////////////////////////////////// 27 | // Other Utils 28 | 29 | export const advanceBlocktime = async (seconds: number): Promise => { 30 | const { timestamp: currTime } = await provider.getBlock("latest"); 31 | await provider.send("evm_increaseTime", [seconds]); 32 | await provider.send("evm_mine", []); 33 | const { timestamp: finalTime } = await provider.getBlock("latest"); 34 | const desired = currTime + seconds; 35 | if (finalTime < desired) { 36 | const diff = finalTime - desired; 37 | await provider.send("evm_increaseTime", [diff]); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /modules/contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "emitDecoratorMetadata": true, 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "lib": ["es2017", "dom", "esnext.asynciterable", "ES2019"], 12 | "module": "commonjs", 13 | "moduleResolution": "node", 14 | "noImplicitAny": true, 15 | "noImplicitReturns": true, 16 | "noLib": false, 17 | "noUnusedLocals": false, 18 | "noUnusedParameters": false, 19 | "outDir": "dist", 20 | "removeComments": true, 21 | "resolveJsonModule": true, 22 | "skipLibCheck": true, 23 | "sourceMap": true, 24 | "strict": true, 25 | "target": "es2017", 26 | "typeRoots": ["../../node_modules/@types"] 27 | }, 28 | "exclude": ["dist", "node_modules"], 29 | "include": ["hardhat.config.ts", "src.ts/**/*.ts", "deploy/*.ts"] 30 | } 31 | -------------------------------------------------------------------------------- /modules/documentation/README.md: -------------------------------------------------------------------------------- 1 | # Vector Docs 2 | 3 | Documentation for vector uses [MkDocs](https://www.mkdocs.org/) hosted using Github Pages. 4 | 5 | **Do not change the file structure of this module** -- it is tightly coupled with the mkdocs theme. 6 | 7 | ## Running Locally 8 | 9 | To run the docs locally, first [install mkdocs-material](https://squidfunk.github.io/mkdocs-material/getting-started/#installation), then run: 10 | 11 | ``` 12 | mkdocs serve 13 | ``` 14 | 15 | MkDocs will build and serve a preview site at `http://127.0.0.1:8000/`. Editing the docs will autoreload the preview site. 16 | 17 | To build the docs, run: 18 | 19 | ``` 20 | mkdocs build 21 | ``` 22 | 23 | ## Publishing Changes 24 | 25 | Changes are published to https://connext.github.io/vector/. 26 | 27 | Hypothetically, changes should be automatically published when you push to master. I may not have set up github actions to do this correctly, however. If that doesn't work, you can publish by doing: 28 | 29 | `mkdocs gh-deploy --force` 30 | 31 | in the documentation module. 32 | -------------------------------------------------------------------------------- /modules/documentation/docs/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/documentation/docs/assets/favicon.png -------------------------------------------------------------------------------- /modules/documentation/docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/documentation/docs/assets/logo.png -------------------------------------------------------------------------------- /modules/documentation/docs/reference/hostedNodes.md: -------------------------------------------------------------------------------- 1 | # List of Hosted Routing Nodes 2 | 3 | ## Testnet 4 | 5 | Public Identifier: `vector7tbbTxQp8ppEQUgPsbGiTrVdapLdU5dH7zTbVuXRf1M4CEBU9Q` 6 | Messaging: `https://messaging.connext.network` 7 | 8 | Chains Supported: 9 | 10 | * Rinkeby 11 | * Kovan 12 | * Arbitrum 13 | * Matic 14 | -------------------------------------------------------------------------------- /modules/documentation/docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | /* prettier-ignore 2 | :root { 3 | --md-footer-fg-color: hsla(217, 100%, 20%, 0.87); 4 | } */ 5 | -------------------------------------------------------------------------------- /modules/documentation/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Connext Documentation 2 | 3 | repo_name: connext/vector 4 | repo_url: https://github.com/connext/vector 5 | 6 | theme: 7 | name: material 8 | 9 | logo: assets/logo.png 10 | favicon: assets/favicon.png 11 | 12 | font: 13 | text: Proxima Nova 14 | palette: 15 | primary: "#002868" 16 | accent: "#FCA311" 17 | 18 | features: 19 | - navigation.tabs 20 | 21 | markdown_extensions: 22 | - admonition 23 | - pymdownx.superfences 24 | - pymdownx.tabbed 25 | - pymdownx.highlight 26 | - toc: 27 | toc_depth: 3 28 | permalink: true 29 | 30 | extra: 31 | social: 32 | - icon: fontawesome/brands/github 33 | link: https://github.com/connext 34 | - icon: fontawesome/brands/twitter 35 | link: https://twitter.com/ConnextNetwork 36 | - icon: fontawesome/brands/medium 37 | link: https://medium.com/connext 38 | - icon: fontawesome/brands/discord 39 | link: https://discord.gg/FTxQc8C 40 | 41 | nav: 42 | - Intro: 43 | - index.md 44 | - Quick Start: 45 | - quickStart/serverNode.md 46 | - quickStart/browserNode.md 47 | - Node Guides: 48 | - node/basics.md 49 | - node/configure.md 50 | # - node/depositAndWithdraw.md 51 | - node/transfers.md 52 | - node/events.md 53 | - Router Guides: 54 | - router/basics.md 55 | - router/configure.md 56 | - router/chains.md 57 | # - router/managingCollateral.md 58 | - Reference: 59 | - reference/nodeAPI.md 60 | - reference/hostedNodes.md 61 | - Changelog: 62 | - changelog.md 63 | -------------------------------------------------------------------------------- /modules/engine/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src/**"], 5 | "exclude": ["src/testing/**"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/engine/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@connext/vector-engine", 3 | "version": "0.2.5-beta.21", 4 | "description": "", 5 | "author": "Arjun Bhuptani", 6 | "license": "MIT", 7 | "main": "dist/src/index.js", 8 | "types": "dist/src/index.d.ts", 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "scripts": { 13 | "build": "rm -rf dist && tsc", 14 | "test": "nyc ts-mocha --check-leaks --exit --timeout 60000 'src/**/*.spec.ts'" 15 | }, 16 | "dependencies": { 17 | "@connext/vector-contracts": "0.2.5-beta.21", 18 | "@connext/vector-protocol": "0.2.5-beta.21", 19 | "@connext/vector-types": "0.2.5-beta.21", 20 | "@connext/vector-utils": "0.2.5-beta.21", 21 | "@ethersproject/address": "5.2.0", 22 | "@ethersproject/bignumber": "5.2.0", 23 | "@ethersproject/bytes": "5.2.0", 24 | "@ethersproject/constants": "5.2.0", 25 | "@ethersproject/random": "5.2.0", 26 | "@ethersproject/wallet": "5.2.0", 27 | "@sinclair/typebox": "0.12.7", 28 | "ajv": "6.12.6", 29 | "evt": "1.9.12", 30 | "pino": "6.11.1", 31 | "pino-pretty": "4.6.0" 32 | }, 33 | "devDependencies": { 34 | "@types/chai": "4.2.15", 35 | "@types/chai-as-promised": "7.1.3", 36 | "@types/chai-subset": "1.3.3", 37 | "@types/mocha": "8.2.1", 38 | "@types/pino": "6.3.6", 39 | "chai": "4.3.1", 40 | "chai-as-promised": "7.1.1", 41 | "mocha": "8.3.0", 42 | "nyc": "15.1.0", 43 | "sinon": "10.0.0", 44 | "ts-mocha": "8.0.0", 45 | "typescript": "4.2.4" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /modules/engine/src/testing/env.ts: -------------------------------------------------------------------------------- 1 | import { ChainProviders } from "@connext/vector-types"; 2 | import { Wallet } from "@ethersproject/wallet"; 3 | import pino from "pino"; 4 | 5 | type EngineTestEnv = { 6 | chainProviders: ChainProviders; 7 | chainAddresses: any; 8 | sugarDaddy: Wallet; 9 | logLevel?: pino.Level; 10 | }; 11 | 12 | export const env: EngineTestEnv = { 13 | chainAddresses: JSON.parse(process.env.CHAIN_ADDRESSES ?? "{}"), 14 | chainProviders: JSON.parse(process.env.CHAIN_PROVIDERS ?? '{"1337":"http://localhost:8545"}'), 15 | logLevel: (process.env.LOG_LEVEL || "silent") as pino.Level, 16 | sugarDaddy: Wallet.fromMnemonic( 17 | process.env.SUGAR_DADDY || "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", 18 | ), 19 | }; 20 | -------------------------------------------------------------------------------- /modules/engine/src/testing/happy.spec.ts: -------------------------------------------------------------------------------- 1 | describe.skip("Engine integration tests", () => { 2 | // Test should validate: 3 | // - store calls when channel is updated 4 | // - event emission is done properly 5 | // - update on latest channel corresponds to input params 6 | it("should be able to setup, deposit, transfer, and withdraw from channel", async () => {}); 7 | }); 8 | -------------------------------------------------------------------------------- /modules/engine/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "declarationDir": "dist/", 6 | "incremental": true, 7 | "module": "commonjs", 8 | "noUnusedLocals": false, 9 | "outDir": "dist", 10 | "strict": true, 11 | "target": "es6" 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/iframe-app/amplify.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | applications: 3 | - frontend: 4 | phases: 5 | preBuild: 6 | commands: 7 | - npm install 8 | build: 9 | commands: 10 | - npm run build-prod 11 | artifacts: 12 | baseDirectory: build 13 | files: 14 | - "**/*" 15 | cache: 16 | paths: 17 | - node_modules/**/* 18 | appRoot: modules/iframe-app 19 | -------------------------------------------------------------------------------- /modules/iframe-app/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY ops/package.json package.json 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY build build 24 | 25 | EXPOSE 5000 26 | 27 | # USER node 28 | 29 | ENTRYPOINT ["serve", "build"] 30 | -------------------------------------------------------------------------------- /modules/iframe-app/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iframe-app", 3 | "description": "This is only used to install & pin versions for a few global packages in the prod-mode docker container", 4 | "dependencies": { 5 | "serve": "11.3.2" 6 | } 7 | } 8 | 9 | 10 | -------------------------------------------------------------------------------- /modules/iframe-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/iframe-app/public/favicon.ico -------------------------------------------------------------------------------- /modules/iframe-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /modules/iframe-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /modules/iframe-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import ConnextManager from "./ConnextManager"; 4 | 5 | // eslint-disable-next-line 6 | const connextManager = new ConnextManager(); 7 | 8 | class App extends React.Component { 9 | render() { 10 | return ( 11 |
12 |
Testing
13 |
14 | ); 15 | } 16 | } 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /modules/iframe-app/src/config.ts: -------------------------------------------------------------------------------- 1 | import { VectorNodeConfig } from "@connext/vector-types"; 2 | 3 | const configEnv = process.env.REACT_APP_VECTOR_CONFIG; 4 | console.log("Using config: ", configEnv); 5 | 6 | export const config: VectorNodeConfig = JSON.parse(configEnv!); 7 | -------------------------------------------------------------------------------- /modules/iframe-app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById("root"), 10 | ); 11 | -------------------------------------------------------------------------------- /modules/iframe-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /modules/protocol/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "check-coverage": true, 5 | "include": ["src/**"], 6 | "exclude": ["src/testing/**"] 7 | } 8 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/constants.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcProvider } from "@ethersproject/providers"; 2 | import { Wallet } from "@ethersproject/wallet"; 3 | 4 | import { env } from "./env"; 5 | 6 | export const chainId = parseInt(Object.keys(env.chainProviders)[0]); 7 | export const tokenAddress = env.chainAddresses[chainId]?.testTokenAddress ?? ""; 8 | export const provider = new JsonRpcProvider(env.chainProviders[chainId], chainId); 9 | 10 | export const sugarDaddy = Wallet.fromMnemonic(env.sugarDaddyMnemonic).connect(provider); 11 | export const rando = Wallet.createRandom().connect(provider); 12 | 13 | export const alice = Wallet.createRandom().connect(provider); 14 | export const bob = Wallet.createRandom().connect(provider); 15 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/env.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | export const env = { 4 | chainAddresses: JSON.parse(process.env.CHAIN_ADDRESSES ?? "{}"), 5 | chainProviders: JSON.parse(process.env.CHAIN_PROVIDERS ?? '{"1337":"http://localhost:8545"}'), 6 | logLevel: (process.env.LOG_LEVEL || "silent") as pino.Level, 7 | sugarDaddyMnemonic: 8 | process.env.SUGAR_DADDY || "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", 9 | }; 10 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/global-hooks.ts: -------------------------------------------------------------------------------- 1 | import { alice, bob, rando } from "./constants"; 2 | import { fundAddress } from "./utils"; 3 | 4 | async function globalSetup(): Promise { 5 | await fundAddress(alice.address); 6 | await fundAddress(bob.address); 7 | await fundAddress(rando.address); 8 | global["wallet"] = rando; 9 | } 10 | 11 | export const mochaHooks = { 12 | async beforeAll(): Promise { 13 | await globalSetup(); 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/integration/setup.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | import { getTestLoggers } from "@connext/vector-utils"; 3 | import { IVectorProtocol } from "@connext/vector-types"; 4 | 5 | import { createVectorInstances, setupChannel } from "../utils"; 6 | import { env } from "../env"; 7 | 8 | const testName = "Setup Integrations"; 9 | const { log } = getTestLoggers(testName, env.logLevel); 10 | 11 | describe(testName, () => { 12 | let alice: IVectorProtocol; 13 | let bob: IVectorProtocol; 14 | let carol: IVectorProtocol; 15 | 16 | afterEach(async () => { 17 | await alice.off(); 18 | await bob.off(); 19 | }); 20 | 21 | beforeEach(async () => { 22 | [alice, bob, carol] = await createVectorInstances(true, 3); 23 | 24 | log.info({ 25 | alice: alice.publicIdentifier, 26 | bob: bob.publicIdentifier, 27 | tony: carol.publicIdentifier, 28 | }); 29 | }); 30 | 31 | it("should setup a channel between Alice and Bob", async () => { 32 | await setupChannel(alice, bob); 33 | }); 34 | 35 | it("should work concurrently for Alice + Bob and Alice + Carol channel", async () => { 36 | const concurrentResult = await Promise.all([setupChannel(alice, bob), setupChannel(alice, carol)]); 37 | log.info(concurrentResult); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/utils/funding.ts: -------------------------------------------------------------------------------- 1 | import { TestToken } from "@connext/vector-contracts"; 2 | import { Contract } from "@ethersproject/contracts"; 3 | import { parseEther } from "@ethersproject/units"; 4 | 5 | import { sugarDaddy, tokenAddress } from "../constants"; 6 | 7 | export const fundAddress = async (recipient: string): Promise => { 8 | const value = parseEther("100"); 9 | 10 | const ethTx = await sugarDaddy.sendTransaction({ 11 | to: recipient, 12 | value, 13 | }); 14 | if (!ethTx.hash) throw new Error(`Couldn't fund account ${recipient}`); 15 | await ethTx.wait(); 16 | 17 | const tokenTx = await new Contract(tokenAddress, TestToken.abi, sugarDaddy).transfer(recipient, value); 18 | await tokenTx.wait(); 19 | }; 20 | -------------------------------------------------------------------------------- /modules/protocol/src/testing/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./channel"; 2 | export * from "./funding"; 3 | export * from "./transfer"; 4 | -------------------------------------------------------------------------------- /modules/protocol/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "declarationDir": "dist/", 6 | "incremental": true, 7 | "module": "commonjs", 8 | "noUnusedLocals": false, 9 | "outDir": "dist", 10 | "strict": true, 11 | "target": "es6" 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/router/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src/**"], 5 | "exclude": ["src/test/**", "src/generated/**"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/router/examples/admin.http: -------------------------------------------------------------------------------- 1 | @routerUrl = http://localhost:8009 2 | 3 | ############## 4 | ### Auto Rebalance 5 | POST {{routerUrl}}/auto-rebalance 6 | Content-Type: application/json 7 | 8 | { 9 | "adminToken": "cxt1234" 10 | } -------------------------------------------------------------------------------- /modules/router/migrations-legacy/20201220171143-init/README.md: -------------------------------------------------------------------------------- 1 | # Migration `20201220171143-init` 2 | 3 | This migration has been generated at 12/20/2020, 5:11:43 PM. 4 | You can check out the [state of the schema](./schema.prisma) after the migration. 5 | 6 | ## Database Steps 7 | 8 | ```sql 9 | CREATE TABLE "QueuedUpdate" ( 10 | "id" TEXT NOT NULL, 11 | "type" TEXT NOT NULL, 12 | "channelAddress" TEXT NOT NULL, 13 | "updateData" TEXT NOT NULL, 14 | "status" TEXT NOT NULL, 15 | "context" TEXT, 16 | 17 | PRIMARY KEY ("id") 18 | ) 19 | ``` 20 | 21 | ## Changes 22 | 23 | ```diff 24 | diff --git schema.prisma schema.prisma 25 | migration ..20201220171143-init 26 | --- datamodel.dml 27 | +++ datamodel.dml 28 | @@ -1,0 +1,19 @@ 29 | +generator client { 30 | + provider = "prisma-client-js" 31 | + binaryTargets = ["native"] 32 | + output = "./src/generated/db-client" 33 | +} 34 | + 35 | +datasource db { 36 | + provider = ["postgresql", "sqlite"] 37 | + url = "***" 38 | +} 39 | + 40 | +model QueuedUpdate { 41 | + id String @id @default(uuid()) 42 | + type String 43 | + channelAddress String 44 | + updateData String 45 | + status String 46 | + context String? 47 | +} 48 | ``` 49 | 50 | 51 | -------------------------------------------------------------------------------- /modules/router/migrations-legacy/20201220171143-init/schema.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | binaryTargets = ["native"] 4 | output = "./src/generated/db-client" 5 | } 6 | 7 | datasource db { 8 | provider = ["postgresql", "sqlite"] 9 | url = "***" 10 | } 11 | 12 | model QueuedUpdate { 13 | id String @id @default(uuid()) 14 | type String 15 | channelAddress String 16 | updateData String 17 | status String 18 | context String? 19 | } 20 | -------------------------------------------------------------------------------- /modules/router/migrations-legacy/migrate.lock: -------------------------------------------------------------------------------- 1 | # Prisma Migrate lockfile v1 2 | 3 | 20201220171143-init -------------------------------------------------------------------------------- /modules/router/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY ops/package.json package.json 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY ops ops 24 | COPY prisma-postgres prisma-postgres 25 | COPY prisma-sqlite prisma-sqlite 26 | COPY dist dist 27 | COPY dist/generated/db-client /.prisma/client 28 | 29 | RUN chmod +x ./ops/entry.sh 30 | 31 | # USER node 32 | 33 | ENTRYPOINT ["bash", "ops/entry.sh"] 34 | -------------------------------------------------------------------------------- /modules/router/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "router", 3 | "description": "This is only used to install & pin versions for a few global packages in the prod-mode docker container", 4 | "dependencies": { 5 | "prisma": "2.22.0", 6 | "hardhat": "2.2.0", 7 | "pg": "8.5.1", 8 | "pino-pretty": "4.6.0", 9 | "sqlite3": "5.0.2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /modules/router/ops/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eE 3 | 4 | if [[ -d "modules/router" ]] 5 | then cd modules/router|| exit 1 6 | fi 7 | 8 | # Poke sqlite file 9 | sqlite_file=${VECTOR_SQLITE_FILE:-/tmp/store.sqlite} 10 | echo "Using SQLite store at $sqlite_file" 11 | touch "$sqlite_file" 12 | export VECTOR_DATABASE_URL="sqlite://$sqlite_file" 13 | 14 | # Migrate db 15 | prisma migrate deploy --preview-feature --schema prisma-sqlite/schema.prisma 16 | 17 | # Launch tests 18 | nyc ts-mocha --check-leaks --exit --timeout 60000 'src/**/*.spec.ts' "$@" 19 | -------------------------------------------------------------------------------- /modules/router/prisma-postgres/migrations/20210208141017_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "QueuedUpdate" ( 3 | "id" TEXT NOT NULL, 4 | "type" TEXT NOT NULL, 5 | "channelAddress" TEXT NOT NULL, 6 | "updateData" TEXT NOT NULL, 7 | "status" TEXT NOT NULL, 8 | "context" TEXT, 9 | 10 | PRIMARY KEY ("id") 11 | ); 12 | -------------------------------------------------------------------------------- /modules/router/prisma-postgres/migrations/20210315014934_add_autorebalance/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "AutoRebalance" ( 3 | "id" TEXT NOT NULL, 4 | "status" TEXT NOT NULL, 5 | "approveHash" TEXT, 6 | "executeHash" TEXT, 7 | "completeHash" TEXT, 8 | "fromChainId" TEXT NOT NULL, 9 | "fromAssetId" TEXT NOT NULL, 10 | "toChainId" TEXT NOT NULL, 11 | "toAssetId" TEXT NOT NULL, 12 | "priceType" TEXT NOT NULL, 13 | "hardcodedRate" TEXT NOT NULL, 14 | "rebalancerUrl" TEXT, 15 | "rebalanceThresholdPct" INTEGER, 16 | "percentageFee" INTEGER, 17 | "flatFee" TEXT, 18 | "gasSubsidyPercentage" INTEGER, 19 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 20 | "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 21 | 22 | PRIMARY KEY ("id") 23 | ); 24 | 25 | -- CreateIndex 26 | CREATE UNIQUE INDEX "AutoRebalance.fromChainId_toChainId_fromAssetId_toAssetId_unique" ON "AutoRebalance"("fromChainId", "toChainId", "fromAssetId", "toAssetId"); 27 | 28 | -- CreateIndex 29 | CREATE UNIQUE INDEX "AutoRebalance.approveHash_unique" ON "AutoRebalance"("approveHash"); 30 | 31 | -- CreateIndex 32 | CREATE UNIQUE INDEX "AutoRebalance.completeHash_unique" ON "AutoRebalance"("completeHash"); 33 | 34 | -- CreateIndex 35 | CREATE UNIQUE INDEX "AutoRebalance.executeHash_unique" ON "AutoRebalance"("executeHash"); 36 | -------------------------------------------------------------------------------- /modules/router/prisma-postgres/migrations/20210409193148_autorebalance_record_save_chain_i_ds_for_executed_txs/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "AutoRebalance" ADD COLUMN "approveChain" INTEGER, 3 | ADD COLUMN "executeChain" INTEGER, 4 | ADD COLUMN "completeChain" INTEGER; 5 | -------------------------------------------------------------------------------- /modules/router/prisma-postgres/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /modules/router/prisma-postgres/schema.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | binaryTargets = ["native"] 4 | output = "../src/generated/db-client" 5 | } 6 | 7 | datasource db { 8 | provider = "postgresql" 9 | url = env("VECTOR_DATABASE_URL") 10 | } 11 | 12 | model QueuedUpdate { 13 | id String @id @default(uuid()) 14 | type String 15 | channelAddress String 16 | updateData String 17 | status String 18 | context String? 19 | } 20 | 21 | model AutoRebalance { 22 | id String @id @default(uuid()) 23 | status String 24 | approveHash String? 25 | approveChain Int? 26 | executeHash String? 27 | executeChain Int? 28 | completeHash String? 29 | completeChain Int? 30 | 31 | // Swap info 32 | fromChainId String 33 | fromAssetId String 34 | toChainId String 35 | toAssetId String 36 | priceType String 37 | hardcodedRate String 38 | rebalancerUrl String? 39 | rebalanceThresholdPct Int? 40 | percentageFee Int? 41 | flatFee String? 42 | gasSubsidyPercentage Int? 43 | 44 | 45 | createdAt DateTime @default(now()) 46 | updatedAt DateTime @default(now()) 47 | 48 | @@unique([fromChainId, toChainId, fromAssetId, toAssetId]) 49 | @@unique(approveHash) 50 | @@unique(completeHash) 51 | @@unique(executeHash) 52 | } -------------------------------------------------------------------------------- /modules/router/prisma-sqlite/migrations/20210208152136_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "QueuedUpdate" ( 3 | "id" TEXT NOT NULL PRIMARY KEY, 4 | "type" TEXT NOT NULL, 5 | "channelAddress" TEXT NOT NULL, 6 | "updateData" TEXT NOT NULL, 7 | "status" TEXT NOT NULL, 8 | "context" TEXT 9 | ); 10 | -------------------------------------------------------------------------------- /modules/router/prisma-sqlite/migrations/20210315014920_add_autorebalance/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "AutoRebalance" ( 3 | "id" TEXT NOT NULL PRIMARY KEY, 4 | "status" TEXT NOT NULL, 5 | "approveHash" TEXT, 6 | "executeHash" TEXT, 7 | "completeHash" TEXT, 8 | "fromChainId" TEXT NOT NULL, 9 | "fromAssetId" TEXT NOT NULL, 10 | "toChainId" TEXT NOT NULL, 11 | "toAssetId" TEXT NOT NULL, 12 | "priceType" TEXT NOT NULL, 13 | "hardcodedRate" TEXT NOT NULL, 14 | "rebalancerUrl" TEXT, 15 | "rebalanceThresholdPct" INTEGER, 16 | "percentageFee" INTEGER, 17 | "flatFee" TEXT, 18 | "gasSubsidyPercentage" INTEGER, 19 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 20 | "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP 21 | ); 22 | -------------------------------------------------------------------------------- /modules/router/prisma-sqlite/migrations/20210409195115_autorebalance_record_save_chain_i_ds_for_executed_txs/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "AutoRebalance" ADD COLUMN "approveChain" TEXT; 3 | ALTER TABLE "AutoRebalance" ADD COLUMN "executeChain" TEXT; 4 | ALTER TABLE "AutoRebalance" ADD COLUMN "completeChain" TEXT; 5 | -------------------------------------------------------------------------------- /modules/router/prisma-sqlite/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /modules/router/prisma-sqlite/schema.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | binaryTargets = ["native"] 4 | output = "../src/generated/db-client" 5 | } 6 | 7 | datasource db { 8 | provider = "sqlite" 9 | url = env("VECTOR_DATABASE_URL") 10 | } 11 | 12 | model QueuedUpdate { 13 | id String @id @default(uuid()) 14 | type String 15 | channelAddress String 16 | updateData String 17 | status String 18 | context String? 19 | } 20 | 21 | model AutoRebalance { 22 | id String @id @default(uuid()) 23 | status String 24 | approveHash String? 25 | approveChain String? 26 | executeHash String? 27 | executeChain String? 28 | completeHash String? 29 | completeChain String? 30 | 31 | // Swap info 32 | fromChainId String 33 | fromAssetId String 34 | toChainId String 35 | toAssetId String 36 | priceType String 37 | hardcodedRate String 38 | rebalancerUrl String? 39 | rebalanceThresholdPct Int? 40 | percentageFee Int? 41 | flatFee String? 42 | gasSubsidyPercentage Int? 43 | 44 | 45 | createdAt DateTime @default(now()) 46 | updatedAt DateTime @default(now()) 47 | } -------------------------------------------------------------------------------- /modules/router/src/services/globalMetrics.ts: -------------------------------------------------------------------------------- 1 | import { register } from "prom-client"; 2 | 3 | import { signer } from ".."; 4 | import { IRouterMessagingService } from "./messaging"; 5 | 6 | export const startMetricsBroadcastTask = (interval: number, messaging: IRouterMessagingService): void => { 7 | setInterval(() => { 8 | metricsBroadcastTasks(messaging); 9 | }, interval); 10 | }; 11 | 12 | export const metricsBroadcastTasks = async (messaging: IRouterMessagingService) => { 13 | const metrics = await register.metrics(); 14 | await messaging.broadcastMetrics(signer.publicIdentifier, metrics); 15 | }; 16 | -------------------------------------------------------------------------------- /modules/router/src/services/rebalanceQueue.ts: -------------------------------------------------------------------------------- 1 | import { AllowedSwap } from "@connext/vector-types"; 2 | import PriorityQueue from "p-queue"; 3 | 4 | // Helper to create a pseudo 'hash-string' for an allowed swap to make it usable as a key. 5 | function getAllowedSwapKey(swap: AllowedSwap): string { 6 | return swap.fromChainId.toString() 7 | + swap.toChainId.toString() 8 | + swap.fromAssetId.toString() 9 | + swap.toAssetId.toString(); 10 | } 11 | 12 | // Used to track all the rebalances we are currently executing, to avoid 13 | // accidentally running operations on the same model (rebalance record) 14 | // at the same time. 15 | const rebalanceQueues: { [swap: string]: PriorityQueue } = {}; 16 | 17 | export async function queueRebalance( 18 | swap: AllowedSwap, 19 | rebalanceFn: () => Promise, 20 | ): Promise { 21 | const swapKey = getAllowedSwapKey(swap); 22 | // Check to see if resources are already being used for rebalancing for this 23 | // particular swap. 24 | if (!rebalanceQueues[swapKey]) { 25 | _createQueueForSwap(swap); 26 | } 27 | return await rebalanceQueues[swapKey].add(async () => { 28 | const res = await rebalanceFn(); 29 | return res; 30 | }); 31 | } 32 | 33 | // NOTE: Exported for use in unit testing. 34 | export function _createQueueForSwap(swap: AllowedSwap): PriorityQueue { 35 | const swapKey = getAllowedSwapKey(swap); 36 | const priorityQueue = new PriorityQueue({ concurrency: 1 }) 37 | rebalanceQueues[swapKey] = priorityQueue; 38 | return priorityQueue; 39 | } 40 | -------------------------------------------------------------------------------- /modules/router/src/services/swap.ts: -------------------------------------------------------------------------------- 1 | import { Result } from "@connext/vector-types"; 2 | import { calculateExchangeWad } from "@connext/vector-utils"; 3 | import { BigNumber } from "@ethersproject/bignumber"; 4 | 5 | import { SwapError } from "../errors"; 6 | import { getDecimals } from "../metrics"; 7 | 8 | import { getMatchingSwap } from "./config"; 9 | 10 | export const getSwappedAmount = async ( 11 | fromAmount: string, 12 | fromAssetId: string, 13 | fromChainId: number, 14 | toAssetId: string, 15 | toChainId: number, 16 | ): Promise> => { 17 | const swapRes = getMatchingSwap(fromAssetId, fromChainId, toAssetId, toChainId); 18 | if (swapRes.isError) { 19 | return Result.fail( 20 | new SwapError(SwapError.reasons.SwapNotAllowed, fromAmount, fromAssetId, fromChainId, toAssetId, toChainId), 21 | ); 22 | } 23 | const swap = swapRes.getValue(); 24 | 25 | // TODO: replace this with the actual current rate. 26 | if (swap.hardcodedRate) { 27 | const fromDecimals = await getDecimals(swap.fromChainId.toString(), swap.fromAssetId); 28 | const toDecimals = await getDecimals(swap.toChainId.toString(), swap.toAssetId); 29 | const exchange = calculateExchangeWad(BigNumber.from(fromAmount), fromDecimals, swap.hardcodedRate, toDecimals); 30 | return Result.ok(exchange.toString()); 31 | } 32 | return Result.fail( 33 | new SwapError(SwapError.reasons.SwapNotHardcoded, fromAmount, fromAssetId, fromChainId, toAssetId, toChainId), 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /modules/router/src/test/utils/mocks.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcProvider } from "@ethersproject/providers"; 2 | import { createStubInstance } from "sinon"; 3 | 4 | export const mockProvider = createStubInstance(JsonRpcProvider, { 5 | waitForTransaction: Promise.resolve({ logs: [] } as any), 6 | getNetwork: Promise.resolve({ chainId: 1337, name: "" }), 7 | }); 8 | -------------------------------------------------------------------------------- /modules/router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "module": "commonjs", 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "ES2017", 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "strict": true, 13 | "resolveJsonModule": true 14 | }, 15 | "include": ["src/*.ts", "src/**/*.ts"] 16 | } 17 | -------------------------------------------------------------------------------- /modules/server-node/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src/**"], 5 | "exclude": ["src/test/**", "src/generated/**", "src/**/*.spec.ts"] 6 | } 7 | -------------------------------------------------------------------------------- /modules/server-node/examples/1-setup.http: -------------------------------------------------------------------------------- 1 | @aliceUrl = http://localhost:8003 2 | @bobUrl = http://localhost:8004 3 | @carolUrl = http://localhost:8005 4 | @daveUrl = http://localhost:8006 5 | @rogerUrl = http://localhost:8007 6 | @aliceBobChannel = 0xD7b60870a3a0D52A2b9F7daBe5DCaB8EDC5bCD4e 7 | @carolRogerChannel = 0x66920C67620b492C3FF7f904af6DC3a8B58D7C9C 8 | @daveRogerChannel = 0x7E513218D56ef4465208d587e9eff56e9035cd02 9 | @adminToken = cxt1234 10 | @alicePublicIdentifier = vector8WxfqTu8EC2FLM6g4y6TgbSrx4EPP9jeDFQk3VBsBM7Jv8NakR 11 | @bobPublicIdentifier = vector5ArRsL26avPNyfvJd2qMAppsEVeJv11n31ex542T9gCd5B1cP3 12 | @carolPublicIdentifier = vector8ZaxNSdUM83kLXJSsmj5jrcq17CpZUwBirmboaNPtQMEXjVNrL 13 | @davePublicIdentifier = vector7mAydt3S3dDPWJMYSHZPdRo16Pru145qTNQYFoS8TrpXWW8HAj 14 | @rogerPublicIdentifier = vector8Uz1BdpA9hV5uTm6QUv5jj1PsUyCH8m8ciA94voCzsxVmrBRor 15 | @chainId = 1337 16 | 17 | @nodeUrl = {{carolUrl}} 18 | @nodePublicIdentifier = {{carolPublicIdentifier}} 19 | @counterpartyPublicIdentifier = {{rogerPublicIdentifier}} 20 | 21 | ############## 22 | ### Setup Channel 23 | POST {{nodeUrl}}/setup 24 | Content-Type: application/json 25 | 26 | { 27 | "counterpartyIdentifier": "{{counterpartyPublicIdentifier}}", 28 | "publicIdentifier": "{{nodePublicIdentifier}}", 29 | "chainId": "{{chainId}}", 30 | "timeout": "100000" 31 | } -------------------------------------------------------------------------------- /modules/server-node/examples/4-event-subscriptions.http: -------------------------------------------------------------------------------- 1 | @aliceUrl = http://localhost:8003 2 | @bobUrl = http://localhost:8004 3 | @carolUrl = http://localhost:8005 4 | @daveUrl = http://localhost:8006 5 | @rogerUrl = http://localhost:8007 6 | @alicePublicIdentifier = vector8WxfqTu8EC2FLM6g4y6TgbSrx4EPP9jeDFQk3VBsBM7Jv8NakR 7 | @bobPublicIdentifier = vector5ArRsL26avPNyfvJd2qMAppsEVeJv11n31ex542T9gCd5B1cP3 8 | @carolPublicIdentifier = vector8ZaxNSdUM83kLXJSsmj5jrcq17CpZUwBirmboaNPtQMEXjVNrL 9 | @davePublicIdentifier = vector7mAydt3S3dDPWJMYSHZPdRo16Pru145qTNQYFoS8TrpXWW8HAj 10 | @rogerPublicIdentifier = vector8Uz1BdpA9hV5uTm6QUv5jj1PsUyCH8m8ciA94voCzsxVmrBRor 11 | 12 | @eventName = CONDITIONAL_TRANSFER_CREATED 13 | @nodeUrl = {{bobUrl}} 14 | @nodePublicIdentifier = {{bobPublicIdentifier}} 15 | 16 | ############### 17 | ### Create Event Subscription 18 | POST {{nodeUrl}}/event/subscribe 19 | Content-Type: application/json 20 | 21 | { 22 | "publicIdentifier": "{{nodePublicIdentifier}}", 23 | "events": { 24 | "{{eventName}}": "http://localhost:1234" 25 | } 26 | } 27 | 28 | ############### 29 | ### Get Event Subscription 30 | GET {{nodeUrl}}/{{nodePublicIdentifier}}/event/{{eventName}} 31 | 32 | ### Get Event Subscriptions 33 | GET {{nodeUrl}}/{{nodePublicIdentifier}}/event -------------------------------------------------------------------------------- /modules/server-node/examples/6-restore.http: -------------------------------------------------------------------------------- 1 | @aliceUrl = http://localhost:8003 2 | @bobUrl = http://localhost:8004 3 | @carolUrl = http://localhost:8005 4 | @daveUrl = http://localhost:8006 5 | @rogerUrl = http://localhost:8007 6 | @aliceBobChannel = 0x47809CD3218c69aB21BeEe8ad6a7b7Ec5E026859 7 | @carolRogerChannel = 0x66920C67620b492C3FF7f904af6DC3a8B58D7C9C 8 | @daveRogerChannel = 0x7E513218D56ef4465208d587e9eff56e9035cd02 9 | @adminToken = cxt1234 10 | @alicePublicIdentifier = vector8WxfqTu8EC2FLM6g4y6TgbSrx4EPP9jeDFQk3VBsBM7Jv8NakR 11 | @bobPublicIdentifier = vector5ArRsL26avPNyfvJd2qMAppsEVeJv11n31ex542T9gCd5B1cP3 12 | @carolPublicIdentifier = vector8ZaxNSdUM83kLXJSsmj5jrcq17CpZUwBirmboaNPtQMEXjVNrL 13 | @davePublicIdentifier = vector7mAydt3S3dDPWJMYSHZPdRo16Pru145qTNQYFoS8TrpXWW8HAj 14 | @rogerPublicIdentifier = vector8Uz1BdpA9hV5uTm6QUv5jj1PsUyCH8m8ciA94voCzsxVmrBRor 15 | @chainId = 1337 16 | 17 | ############## 18 | ### Restore State 19 | POST {{aliceUrl}}/restore 20 | Content-Type: application/json 21 | 22 | { 23 | "counterpartyIdentifier": "{{bobPublicIdentifier}}", 24 | "chainId": "{{chainId}}", 25 | "publicIdentifier": "{{alicePublicIdentifier}}" 26 | } -------------------------------------------------------------------------------- /modules/server-node/examples/admin.http: -------------------------------------------------------------------------------- 1 | @rogerUrl = http://localhost:8007 2 | 3 | ############## 4 | ### Retry Withdrawal 5 | POST {{rogerUrl}}/withdraw/retry 6 | Content-Type: application/json 7 | 8 | { 9 | "adminToken": "", 10 | "transferId": "0xf1dc51cbccbd2778de3c397aee8cd6bfaba229117a2f0d25d772902a0c9cc869" 11 | } 12 | 13 | 14 | ############## 15 | ### Speed up tx 16 | POST {{rogerUrl}}/speed-up 17 | Content-Type: application/json 18 | 19 | { 20 | "adminToken": "cxt1234", 21 | "transactionHash": "0x9ed0c28027a045c2de9fae61e06eade573e9ddfcbab3a6514c5662781c874104", 22 | "publicIdentifier": "vector7tbbTxQp8ppEQUgPsbGiTrVdapLdU5dH7zTbVuXRf1M4CEBU9Q" 23 | } -------------------------------------------------------------------------------- /modules/server-node/examples/eth-rpc.http: -------------------------------------------------------------------------------- 1 | @ethNode = http://localhost:8545 2 | @sugarDaddy = 0x627306090abaB3A6e1400e9345bC60c78a8BEf57 3 | @alice = 0x119a11d0D1686C7330cA0650E26Fd6889Fbeb832 4 | @bob = 0x95B7e93A3aF19AcAE95aD120d4D8307bF1a6Be63 5 | @roger = 0x9CD130fE9aC1EF5173eEBE0C163C7a19f3E4ed2B 6 | @dave = 0x1b1968cAfFB691191CC05164d250a4bEF4aFaA65 7 | @carol = 0x65b70DfFdAEc7d8818F16f3caD4E86FaDD03993e 8 | 9 | @testToken = 0x9FBDa871d559710256a2502A2517b794B482Db40 10 | 11 | # 1 ETH 12 | @amount = 0xDE0B6B3A7640000 13 | 14 | ### SEND ETH 15 | POST {{ethNode}} 16 | Content-Type: application/json 17 | 18 | { 19 | "jsonrpc":"2.0", 20 | "method":"eth_sendTransaction", 21 | "params":[{ 22 | "from": "{{sugarDaddy}}", 23 | "to": "{{roger}}", 24 | "value": "{{amount}}" 25 | }], 26 | "id":1 27 | } 28 | 29 | ### GET BALANCE 30 | POST {{ethNode}} 31 | Content-Type: application/json 32 | 33 | { 34 | "jsonrpc":"2.0", 35 | "method":"eth_getBalance", 36 | "params":["{{roger}}", "latest"], 37 | "id":1 38 | } 39 | 40 | ### GET DECIMALS 41 | POST {{ethNode}} 42 | Content-Type: application/json 43 | 44 | { 45 | "jsonrpc":"2.0", 46 | "method":"eth_call", 47 | "params":[{ "to": "{{testToken}}", "data": "0x313ce567" }], 48 | "id":1 49 | } 50 | 51 | ### GET BLOCK NUMBER 52 | POST {{ethNode}} 53 | Content-Type: application/json 54 | 55 | { 56 | "method":"eth_blockNumber", 57 | "params":[] 58 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201030172744-dispute-flag/README.md: -------------------------------------------------------------------------------- 1 | # Migration `20201030172744-dispute-flag` 2 | 3 | This migration has been generated by LayneHaber at 10/30/2020, 11:27:44 AM. 4 | You can check out the [state of the schema](./schema.prisma) after the migration. 5 | 6 | ## Database Steps 7 | 8 | ```sql 9 | ALTER TABLE "public"."channel" ADD COLUMN "inDispute" boolean NOT NULL 10 | 11 | ALTER TABLE "public"."transfer" ADD COLUMN "inDispute" boolean NOT NULL 12 | ``` 13 | 14 | ## Changes 15 | 16 | ```diff 17 | diff --git schema.prisma schema.prisma 18 | migration 20201026173854-init..20201030172744-dispute-flag 19 | --- datamodel.dml 20 | +++ datamodel.dml 21 | @@ -5,9 +5,9 @@ 22 | } 23 | datasource db { 24 | provider = ["postgresql", "sqlite"] 25 | - url = "***" 26 | + url = "***" 27 | } 28 | model Balance { 29 | participant String 30 | @@ -39,8 +39,9 @@ 31 | chainId Int 32 | providerUrl String 33 | latestUpdate Update 34 | defundNonce String 35 | + inDispute Boolean 36 | activeTransfers Transfer[] 37 | OnchainTransaction OnchainTransaction[] 38 | @@ -104,8 +105,9 @@ 39 | model Transfer { 40 | transferId String @id 41 | routingId String 42 | + inDispute Boolean 43 | createUpdate Update? @relation(name: "CreatedTransfer", fields: [createUpdateChannelAddressId, createUpdateNonce], references: [channelAddressId, nonce]) 44 | resolveUpdate Update? @relation(name: "ResolvedTransfer", fields: [resolveUpdateChannelAddressId, resolveUpdateNonce], references: [channelAddressId, nonce]) 45 | ``` 46 | 47 | 48 | -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201030172744-dispute-flag/steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.3.14-fixed", 3 | "steps": [ 4 | { 5 | "tag": "CreateField", 6 | "model": "Channel", 7 | "field": "inDispute", 8 | "type": "Boolean", 9 | "arity": "Required" 10 | }, 11 | { 12 | "tag": "CreateField", 13 | "model": "Transfer", 14 | "field": "inDispute", 15 | "type": "Boolean", 16 | "arity": "Required" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201102150429-rm-mastercopy-address/README.md: -------------------------------------------------------------------------------- 1 | # Migration `20201102150429-rm-mastercopy-address` 2 | 3 | This migration has been generated by bohendo at 11/2/2020, 8:34:29 PM. 4 | You can check out the [state of the schema](./schema.prisma) after the migration. 5 | 6 | ## Database Steps 7 | 8 | ```sql 9 | ALTER TABLE "public"."channel" DROP COLUMN "channelMastercopyAddress" 10 | ``` 11 | 12 | ## Changes 13 | 14 | ```diff 15 | diff --git schema.prisma schema.prisma 16 | migration 20201026173854-init..20201102150429-rm-mastercopy-address 17 | --- datamodel.dml 18 | +++ datamodel.dml 19 | @@ -5,9 +5,9 @@ 20 | } 21 | datasource db { 22 | provider = ["postgresql", "sqlite"] 23 | - url = "***" 24 | + url = "***" 25 | } 26 | model Balance { 27 | participant String 28 | @@ -33,9 +33,8 @@ 29 | nonce Int 30 | merkleRoot String 31 | balances Balance[] 32 | channelFactoryAddress String 33 | - channelMastercopyAddress String 34 | transferRegistryAddress String 35 | chainId Int 36 | providerUrl String 37 | latestUpdate Update 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201102150429-rm-mastercopy-address/steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.3.14-fixed", 3 | "steps": [ 4 | { 5 | "tag": "DeleteField", 6 | "model": "Channel", 7 | "field": "channelMastercopyAddress" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201111192514-chain-id-fixes/steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.3.14-fixed", 3 | "steps": [ 4 | { 5 | "tag": "UpdateField", 6 | "model": "Channel", 7 | "field": "chainId", 8 | "type": "String" 9 | }, 10 | { 11 | "tag": "UpdateField", 12 | "model": "OnchainTransaction", 13 | "field": "chainId", 14 | "type": "String" 15 | }, 16 | { 17 | "tag": "CreateDirective", 18 | "location": { 19 | "path": { 20 | "tag": "Model", 21 | "model": "OnchainTransaction", 22 | "arguments": [ 23 | { 24 | "name": "", 25 | "value": "[transactionHash, chainId]" 26 | } 27 | ] 28 | }, 29 | "directive": "unique" 30 | } 31 | }, 32 | { 33 | "tag": "DeleteDirective", 34 | "location": { 35 | "path": { 36 | "tag": "Model", 37 | "model": "OnchainTransaction", 38 | "arguments": [ 39 | { 40 | "name": "", 41 | "value": "transactionHash" 42 | } 43 | ] 44 | }, 45 | "directive": "unique" 46 | } 47 | }, 48 | { 49 | "tag": "DeleteDirective", 50 | "location": { 51 | "path": { 52 | "tag": "Model", 53 | "model": "OnchainTransaction", 54 | "arguments": [ 55 | { 56 | "name": "", 57 | "value": "[from, nonce]" 58 | } 59 | ] 60 | }, 61 | "directive": "unique" 62 | } 63 | } 64 | ] 65 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201118004412-defund-array/steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.3.14-fixed", 3 | "steps": [ 4 | { 5 | "tag": "CreateField", 6 | "model": "Balance", 7 | "field": "defundNonce", 8 | "type": "String", 9 | "arity": "Required" 10 | }, 11 | { 12 | "tag": "DeleteField", 13 | "model": "Channel", 14 | "field": "defundNonce" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/20201215210233-add-transaction-nonce/steps.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.3.14-fixed", 3 | "steps": [ 4 | { 5 | "tag": "CreateField", 6 | "model": "Transfer", 7 | "field": "channelNonce", 8 | "type": "Int", 9 | "arity": "Required" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /modules/server-node/migrations-legacy/migrate.lock: -------------------------------------------------------------------------------- 1 | # Prisma Migrate lockfile v1 2 | 3 | 20201013125322-init 4 | 20201015144437-event-listeners 5 | 20210128085513-add-created-at -------------------------------------------------------------------------------- /modules/server-node/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY ops/package.json package.json 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY ops ops 24 | COPY prisma-postgres prisma-postgres 25 | COPY prisma-sqlite prisma-sqlite 26 | COPY dist dist 27 | COPY dist/generated/db-client /.prisma/client 28 | 29 | RUN chmod +x ./ops/entry.sh 30 | 31 | # USER node 32 | 33 | ENTRYPOINT ["bash", "ops/entry.sh"] 34 | -------------------------------------------------------------------------------- /modules/server-node/ops/arm.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm64v8/node:14.16.0-buster 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME="/app" \ 7 | PATH="/app/node_modules/.bin:./node_modules/.bin:${PATH}" \ 8 | PRISMA_QUERY_ENGINE_BINARY=/prisma-arm64/query-engine \ 9 | PRISMA_MIGRATION_ENGINE_BINARY=/prisma-arm64/migration-engine \ 10 | PRISMA_INTROSPECTION_ENGINE_BINARY=/prisma-arm64/introspection-engine \ 11 | PRISMA_FMT_BINARY=/prisma-arm64/prisma-fmt 12 | 13 | WORKDIR /app 14 | 15 | COPY ./prisma-binaries-armv8/ /prisma-arm64/ 16 | COPY package.json package.json 17 | 18 | RUN chmod +x /prisma-arm64/* &&\ 19 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 20 | chmod +x /bin/wait-for 21 | 22 | RUN npm install --production 23 | RUN npm audit --audit-level=critical 24 | RUN npm outdated || true 25 | 26 | COPY ops ops 27 | COPY prisma-postgres prisma-postgres 28 | COPY prisma-sqlite prisma-sqlite 29 | COPY dist dist 30 | COPY dist/generated/db-client /.prisma/client 31 | 32 | ENTRYPOINT ["bash", "ops/entry.sh"] 33 | -------------------------------------------------------------------------------- /modules/server-node/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-node", 3 | "description": "This is only used to install & pin versions for a few global packages in the prod-mode docker container", 4 | "dependencies": { 5 | "prisma": "2.22.0", 6 | "pg": "8.5.1", 7 | "pino-pretty": "4.6.0", 8 | "sqlite3": "5.0.2" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/server-node/ops/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eE 3 | 4 | if [[ -d "modules/server-node" ]] 5 | then cd modules/server-node || exit 1 6 | fi 7 | 8 | # Poke sqlite file 9 | sqlite_file=${VECTOR_SQLITE_FILE:-/tmp/store.sqlite} 10 | echo "Using SQLite store at $sqlite_file" 11 | touch "$sqlite_file" 12 | export VECTOR_DATABASE_URL="sqlite://$sqlite_file" 13 | 14 | # Migrate db 15 | prisma migrate deploy --preview-feature --schema prisma-sqlite/schema.prisma 16 | 17 | # Launch tests 18 | nyc ts-mocha --bail --check-leaks --exit --timeout 60000 'src/**/*.spec.ts' "$@" 19 | -------------------------------------------------------------------------------- /modules/server-node/prisma-binaries-armv8/introspection-engine: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/server-node/prisma-binaries-armv8/introspection-engine -------------------------------------------------------------------------------- /modules/server-node/prisma-binaries-armv8/migration-engine: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/server-node/prisma-binaries-armv8/migration-engine -------------------------------------------------------------------------------- /modules/server-node/prisma-binaries-armv8/prisma-fmt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/server-node/prisma-binaries-armv8/prisma-fmt -------------------------------------------------------------------------------- /modules/server-node/prisma-binaries-armv8/query-engine: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/server-node/prisma-binaries-armv8/query-engine -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/20210212024650_add_transaction/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - The migration will add a unique constraint covering the columns `[onchainTransactionId]` on the table `transfer`. If there are existing duplicate values, the migration will fail. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "transfer" ADD COLUMN "onchainTransactionId" TEXT, 9 | ADD COLUMN "transactionHash" TEXT; 10 | 11 | -- CreateIndex 12 | CREATE UNIQUE INDEX "transfer.onchainTransactionId_unique" ON "transfer"("onchainTransactionId"); 13 | 14 | -- AddForeignKey 15 | ALTER TABLE "transfer" ADD FOREIGN KEY ("transactionHash") REFERENCES "onchain_transaction"("transactionHash") ON DELETE SET NULL ON UPDATE CASCADE; 16 | -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/20210216034007_remove_unique_onchain_id/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropIndex 2 | DROP INDEX "transfer.onchainTransactionId_unique"; 3 | -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/20210223223007_remove_provider_url/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `providerUrl` on the `channel` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "channel" DROP COLUMN "providerUrl"; 9 | -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/20210225093205_update_config/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `mnemonic` on the `configuration` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- DropIndex 8 | DROP INDEX "configuration.mnemonic_unique"; 9 | 10 | -- AlterTable 11 | ALTER TABLE "configuration" DROP COLUMN "mnemonic"; 12 | -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/20210401215828_add_disputes/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `inDispute` on the `channel` table. All the data in the column will be lost. 5 | - You are about to drop the column `inDispute` on the `transfer` table. All the data in the column will be lost. 6 | 7 | */ 8 | -- AlterTable 9 | ALTER TABLE "channel" DROP COLUMN "inDispute"; 10 | 11 | -- AlterTable 12 | ALTER TABLE "transfer" DROP COLUMN "inDispute"; 13 | 14 | -- CreateTable 15 | CREATE TABLE "ChannelDispute" ( 16 | "channelAddress" TEXT NOT NULL, 17 | "channelStateHash" TEXT NOT NULL, 18 | "nonce" TEXT NOT NULL, 19 | "merkleRoot" TEXT NOT NULL, 20 | "consensusExpiry" TEXT NOT NULL, 21 | "defundExpiry" TEXT NOT NULL, 22 | 23 | PRIMARY KEY ("channelAddress") 24 | ); 25 | 26 | -- CreateTable 27 | CREATE TABLE "TransferDispute" ( 28 | "transferId" TEXT NOT NULL, 29 | "transferStateHash" TEXT NOT NULL, 30 | "transferDisputeExpiry" TEXT NOT NULL, 31 | "isDefunded" BOOLEAN NOT NULL, 32 | 33 | PRIMARY KEY ("transferId") 34 | ); 35 | 36 | -- AddForeignKey 37 | ALTER TABLE "ChannelDispute" ADD FOREIGN KEY ("channelAddress") REFERENCES "channel"("channelAddress") ON DELETE CASCADE ON UPDATE CASCADE; 38 | 39 | -- AddForeignKey 40 | ALTER TABLE "TransferDispute" ADD FOREIGN KEY ("transferId") REFERENCES "transfer"("transferId") ON DELETE CASCADE ON UPDATE CASCADE; 41 | -------------------------------------------------------------------------------- /modules/server-node/prisma-postgres/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /modules/server-node/prisma-sqlite/migrations/20210216033910_remove_unique_onchain_id/migration.sql: -------------------------------------------------------------------------------- 1 | -- DropIndex 2 | DROP INDEX "transfer.onchainTransactionId_unique"; 3 | -------------------------------------------------------------------------------- /modules/server-node/prisma-sqlite/migrations/20210225085644_update_config/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `mnemonic` on the `configuration` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- DropIndex 8 | DROP INDEX "configuration.mnemonic_unique"; 9 | 10 | -- RedefineTables 11 | PRAGMA foreign_keys=OFF; 12 | CREATE TABLE "new_configuration" ( 13 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT 14 | ); 15 | INSERT INTO "new_configuration" ("id") SELECT "id" FROM "configuration"; 16 | DROP TABLE "configuration"; 17 | ALTER TABLE "new_configuration" RENAME TO "configuration"; 18 | PRAGMA foreign_key_check; 19 | PRAGMA foreign_keys=ON; 20 | -------------------------------------------------------------------------------- /modules/server-node/prisma-sqlite/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /modules/server-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "module": "commonjs", 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "target": "ES2017", 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "sourceMap": true, 12 | "strict": true, 13 | "resolveJsonModule": true 14 | }, 15 | "include": ["src/*.ts", "src/**/*.ts"], 16 | } 17 | -------------------------------------------------------------------------------- /modules/test-runner/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Test Runner 3 | 4 | This code gets packaged into a docker image that be used to run integration tests against vector's various stacks. 5 | 6 | A stack's tests are run from: `src/${stack_name}/index.ts 7 | -------------------------------------------------------------------------------- /modules/test-runner/ops/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | WORKDIR /app 10 | 11 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 12 | npm config set unsafe-perm true &&\ 13 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 14 | chmod +x /bin/wait-for &&\ 15 | rm -rf /var/cache/apk/* /tmp/* 16 | 17 | COPY ops/package.json package.json 18 | 19 | RUN npm install 20 | RUN npm audit --audit-level=critical 21 | RUN npm outdated || true 22 | 23 | COPY ops ops 24 | COPY dist dist 25 | 26 | RUN chmod +x ./ops/entry.sh 27 | 28 | # USER node 29 | 30 | ENTRYPOINT ["bash", "ops/entry.sh"] 31 | -------------------------------------------------------------------------------- /modules/test-runner/ops/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-runner", 3 | "description": "This is only used to install & pin versions for a few global packages in the prod-mode docker container", 4 | "dependencies": { 5 | "mocha": "8.3.0", 6 | "nyc": "15.1.0", 7 | "pino-pretty": "4.6.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /modules/test-runner/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@connext/vector-test-runner", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc -p tsconfig.json", 8 | "build-bundle": "webpack --config ops/webpack.config.js", 9 | "test": "bash ops/entry.sh", 10 | "load-test-cyclical": "ts-node ./src/load/start-cyclical.ts | pino-pretty -t", 11 | "load-test-concurrency": "ts-node ./src/load/start-concurrency.ts | pino-pretty -t", 12 | "load-test-channel-bandwidth": "ts-node ./src/load/start-channel-bandwidth.ts | pino-pretty -t" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@connext/vector-contracts": "0.2.5-beta.21", 18 | "@connext/vector-types": "0.2.5-beta.21", 19 | "@connext/vector-utils": "0.2.5-beta.21", 20 | "@ethereum-waffle/chai": "3.3.0", 21 | "@types/chai": "4.2.15", 22 | "@types/chai-as-promised": "7.1.3", 23 | "@types/chai-subset": "1.3.3", 24 | "@types/mocha": "8.2.1", 25 | "axios": "0.21.1", 26 | "babel-loader": "8.1.0", 27 | "copy-webpack-plugin": "6.2.1", 28 | "ethers": "5.2.0", 29 | "evt": "1.9.12", 30 | "fastify": "3.13.0", 31 | "p-queue": "6.6.2", 32 | "ts-loader": "8.0.7", 33 | "ts-mocha": "8.0.0", 34 | "ts-node": "9.1.1", 35 | "typescript": "4.2.4", 36 | "webpack": "4.44.2", 37 | "webpack-cli": "4.1.0" 38 | }, 39 | "devDependencies": { 40 | "pino-pretty": "4.6.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /modules/test-runner/src/duet/config.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, RestServerNodeService, mkAddress } from "@connext/vector-utils"; 2 | import axios from "axios"; 3 | 4 | import { env, getTestLoggers } from "../utils"; 5 | 6 | const testName = "Duet Config"; 7 | 8 | const { log } = getTestLoggers(testName); 9 | 10 | describe(testName, () => { 11 | it("alice & bob should pong when pinged", async () => { 12 | const alicePong = (await axios.get(`${env.aliceUrl}/ping`)).data; 13 | const bobPong = (await axios.get(`${env.bobUrl}/ping`)).data; 14 | expect(alicePong).to.equal("pong\n"); 15 | expect(alicePong).to.equal(bobPong); 16 | }); 17 | 18 | it("should work with a default identifier", async () => { 19 | const alice = await RestServerNodeService.connect(env.aliceUrl, log, undefined, 0); 20 | 21 | const res = await alice.getConfig(); 22 | const val = res.getValue(); 23 | expect(val.length >= 1).to.be.true; 24 | expect(val[0].signerAddress).to.be.ok; 25 | expect(val[0].publicIdentifier).to.be.ok; 26 | 27 | const test = await alice.getStateChannel({ channelAddress: mkAddress("0xccc") }); 28 | 29 | const err = test.getError()!; 30 | expect(err.context.stack).to.be.ok; 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /modules/test-runner/src/duet/index.ts: -------------------------------------------------------------------------------- 1 | import "./eventSetup"; 2 | 3 | import "./config.test"; 4 | import "./happy.test"; 5 | import "./restore.test"; 6 | -------------------------------------------------------------------------------- /modules/test-runner/src/load/helpers/config.ts: -------------------------------------------------------------------------------- 1 | // test specific config 2 | 3 | type TestConfig = { 4 | numAgents: number; 5 | testDuration: number; 6 | maxConcurrency: number; 7 | queuedPayments: number; 8 | sugarDaddy: string; 9 | }; 10 | 11 | const numAgents = parseInt(process.env.NUM_AGENTS ?? "3"); 12 | const testDuration = parseInt(process.env.TEST_DURATION ?? "90") * 1_000; 13 | const maxConcurrency = parseInt(process.env.MAX_CONCURRENCY ?? "10"); 14 | const queuedPayments = parseInt(process.env.QUEUED_PAYMENTS ?? "25"); 15 | const sugarDaddy = 16 | process.env.SUGAR_DADDY ?? "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat"; 17 | 18 | export const config: TestConfig = { 19 | numAgents, 20 | testDuration, 21 | maxConcurrency, 22 | queuedPayments, 23 | sugarDaddy, 24 | }; 25 | 26 | console.log("Running tests with config", config); 27 | -------------------------------------------------------------------------------- /modules/test-runner/src/load/start-channel-bandwidth.ts: -------------------------------------------------------------------------------- 1 | import { startServer } from "./helpers/setupServer"; 2 | import { channelBandwidthTest } from "./helpers/test"; 3 | 4 | startServer().then(async () => { 5 | await channelBandwidthTest(); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/test-runner/src/load/start-concurrency.ts: -------------------------------------------------------------------------------- 1 | import { startServer } from "./helpers/setupServer"; 2 | import { concurrencyTest } from "./helpers/test"; 3 | 4 | startServer().then(async () => { 5 | await concurrencyTest(); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/test-runner/src/load/start-cyclical.ts: -------------------------------------------------------------------------------- 1 | import { startServer } from "./helpers/setupServer"; 2 | import { cyclicalTransferTest } from "./helpers/test"; 3 | 4 | startServer().then(async () => { 5 | await cyclicalTransferTest(); 6 | }); 7 | -------------------------------------------------------------------------------- /modules/test-runner/src/messaging/index.ts: -------------------------------------------------------------------------------- 1 | import "./auth.test"; 2 | -------------------------------------------------------------------------------- /modules/test-runner/src/node/config.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@connext/vector-utils"; 2 | import axios from "axios"; 3 | 4 | import { env } from "../utils"; 5 | 6 | describe("Node Config", () => { 7 | it("should ping when we pong", async () => { 8 | const res = await axios.get(`${env.nodeContainerUrl}/ping`); 9 | expect(res.data).to.equal("pong\n"); 10 | }); 11 | it("should create a node & provide it's status", async () => { 12 | const createRes = await axios.post(`${env.nodeContainerUrl}/node`, { index: 0 }); 13 | expect(createRes.data).to.be.ok; 14 | const pubId = createRes.data.publicIdentifier; 15 | expect(pubId).to.be.a("string"); 16 | const statusRes = await axios.get(`${env.nodeContainerUrl}/${pubId}/status`); 17 | expect(statusRes.data).to.be.ok; 18 | expect(statusRes.data.version).to.be.a("string"); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /modules/test-runner/src/node/index.ts: -------------------------------------------------------------------------------- 1 | import "./config.test"; 2 | -------------------------------------------------------------------------------- /modules/test-runner/src/router/config.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@connext/vector-utils"; 2 | import axios from "axios"; 3 | 4 | import { env } from "../utils"; 5 | 6 | describe("Router Config", () => { 7 | it("node should ping when we pong", async () => { 8 | const res = await axios.get(`${env.nodeUrl}/ping`); 9 | expect(res.data).to.equal("pong\n"); 10 | }); 11 | 12 | it("router should ping when we pong", async () => { 13 | const res = await axios.get(`${env.routerUrl}/ping`); 14 | expect(res.data).to.equal("pong\n"); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /modules/test-runner/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import "./config.test"; 2 | -------------------------------------------------------------------------------- /modules/test-runner/src/trio/config.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "@connext/vector-utils"; 2 | import axios from "axios"; 3 | 4 | import { env } from "../utils"; 5 | 6 | describe("Trio Config", () => { 7 | it("carol, dave, and roger should pong when pinged", async () => { 8 | const carolPong = (await axios.get(`${env.carolUrl}/ping`)).data; 9 | const davePong = (await axios.get(`${env.daveUrl}/ping`)).data; 10 | const rogerPong = (await axios.get(`${env.rogerUrl}/ping`)).data; 11 | expect(carolPong).to.equal("pong\n"); 12 | expect(carolPong).to.equal(davePong); 13 | expect(davePong).to.equal(rogerPong); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /modules/test-runner/src/trio/index.ts: -------------------------------------------------------------------------------- 1 | import "./eventSetup"; 2 | 3 | import "./config.test"; 4 | import "./happy.test"; 5 | -------------------------------------------------------------------------------- /modules/test-runner/src/utils/env.ts: -------------------------------------------------------------------------------- 1 | export const env = { 2 | adminToken: process.env.VECTOR_ADMIN_TOKEN || "cxt1234", 3 | aliceUrl: process.env.VECTOR_ALICE_URL || "http://alice:8000", 4 | aliceMnemonic: 5 | process.env.VECTOR_ALICE_MNEMONIC || 6 | "avoid post vessel voyage trigger real side ribbon pattern neither essence shine", 7 | messagingUrl: process.env.VECTOR_MESSAGING_URL || "http://messaging", 8 | bobUrl: process.env.VECTOR_BOB_URL || "http://bob:8000", 9 | bobMnemonic: 10 | process.env.VECTOR_BOB_MNEMONIC || "negative stamp rule dizzy embark worth ill popular hip ready truth abandon", 11 | carolUrl: process.env.VECTOR_CAROL_URL || "http://carol:8000", 12 | chainProviders: JSON.parse(process.env.VECTOR_CHAIN_PROVIDERS || "{}"), 13 | chainAddresses: JSON.parse(process.env.VECTOR_CHAIN_ADDRESSES || "{}"), 14 | daveUrl: process.env.VECTOR_DAVE_URL || "http://dave:8000", 15 | logLevel: process.env.VECTOR_LOG_LEVEL || "warn", 16 | nodeUrl: process.env.VECTOR_NODE_URL || "http://node:8000", 17 | nodeContainerUrl: process.env.VECTOR_NODE_CONTAINER_URL || "http://vector_node:8000", 18 | rogerUrl: process.env.VECTOR_ROGER_URL || "http://roger:8000", 19 | routerUrl: process.env.VECTOR_ROUTER_URL || "http://router:8008", 20 | sugarDaddy: process.env.SUGAR_DADDY || "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", 21 | port: parseInt(process.env.VECTOR_PORT || "8888"), 22 | testerName: process.env.VECTOR_TESTER_NAME || "vector_trio_test_runner", 23 | config: JSON.parse(process.env.VECTOR_CONFIG ?? "{}"), 24 | }; 25 | -------------------------------------------------------------------------------- /modules/test-runner/src/utils/ethereum.ts: -------------------------------------------------------------------------------- 1 | import { ERC20Abi } from "@connext/vector-types"; 2 | import { BigNumber, constants, Contract, providers, Wallet } from "ethers"; 3 | 4 | export const MAX_PATH_INDEX = 2147483647; 5 | 6 | export const getRandomIndex = (): number => Math.floor(Math.random() * MAX_PATH_INDEX); 7 | 8 | export const getOnchainBalance = async ( 9 | assetId: string, 10 | address: string, 11 | provider: providers.Provider, 12 | ): Promise => { 13 | return assetId === constants.AddressZero 14 | ? provider.getBalance(address) 15 | : new Contract(assetId, ERC20Abi, provider).balanceOf(address); 16 | }; 17 | 18 | export const fundIfBelow = async ( 19 | address: string, 20 | assetId: string, 21 | fundAmount: BigNumber, 22 | funder: Wallet, 23 | ): Promise => { 24 | const balance = await getOnchainBalance(assetId, address, funder.provider); 25 | if (balance.gte(fundAmount)) { 26 | return; 27 | } 28 | const funderBal = await getOnchainBalance(assetId, funder.address, funder.provider); 29 | const chain = await funder.getChainId(); 30 | if (funderBal.lt(fundAmount)) { 31 | throw new Error( 32 | `${ 33 | funder.address 34 | } has insufficient funds to gift to ${address} (requested: ${fundAmount.toString()}, balance: ${funderBal.toString()}, chain: ${chain})`, 35 | ); 36 | } 37 | const tx = 38 | assetId === constants.AddressZero 39 | ? await funder.sendTransaction({ to: address, value: fundAmount }) 40 | : await new Contract(assetId, ERC20Abi, funder).transfer(address, fundAmount); 41 | await tx.wait(); 42 | }; 43 | -------------------------------------------------------------------------------- /modules/test-runner/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./env"; 2 | export * from "./ethereum"; 3 | export * from "./logger"; 4 | -------------------------------------------------------------------------------- /modules/test-runner/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | export const getTestLoggers = ( 4 | name: string, 5 | level: pino.Level = "info", 6 | fast = 20, 7 | slow = 200, 8 | ): { log: pino.BaseLogger; timer: any } => { 9 | const log = pino({ level, name }); 10 | const timer = start => msg => { 11 | const diff = Date.now() - start; 12 | if (diff < fast) { 13 | log.debug(msg); 14 | } else if (diff < slow) { 15 | log.info(msg); 16 | } else { 17 | log.warn(msg); 18 | } 19 | }; 20 | return { log, timer }; 21 | }; 22 | -------------------------------------------------------------------------------- /modules/test-runner/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "declarationMap": false, 6 | "module": "commonjs", 7 | "outDir": "dist", 8 | "typeRoots": [ 9 | "./node_modules/@types", 10 | "../../node_modules/@types" 11 | ] 12 | }, 13 | "exclude": ["dist", "node_modules"], 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /modules/test-ui/README.md: -------------------------------------------------------------------------------- 1 | # Browser Node Test UI 2 | 3 | Basic UI to test that `browser-node` comes up properly. 4 | 5 | ## Running 6 | 7 | - Verify the `vector/node.config.json` (if provided) has the correct params, change the mnemonic if needed. By default it's configured to connect to a local messaging stack (see `vector/ops/config/*.default.json` for default config values) 8 | - Run `make start-messaging` from repo root. 9 | - Run `make start-test-ui` from repo root to start the UI. 10 | -------------------------------------------------------------------------------- /modules/test-ui/amplify.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | applications: 3 | - frontend: 4 | phases: 5 | preBuild: 6 | commands: 7 | - npm install 8 | build: 9 | commands: 10 | - npm run build 11 | artifacts: 12 | baseDirectory: build 13 | files: 14 | - "**/*" 15 | cache: 16 | paths: 17 | - node_modules/**/* 18 | appRoot: modules/test-ui 19 | -------------------------------------------------------------------------------- /modules/test-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@connext/vector-test-ui", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "@connext/vector-browser-node": "0.2.5-beta.21", 7 | "@connext/vector-types": "0.2.5-beta.21", 8 | "@connext/vector-utils": "0.2.5-beta.21", 9 | "@types/node": "14.14.31", 10 | "@types/react": "16.9.53", 11 | "@types/react-dom": "16.9.8", 12 | "antd": "4.13.0", 13 | "axios": "0.21.1", 14 | "ethers": "5.2.0", 15 | "pino": "6.11.1", 16 | "react": "17.0.1", 17 | "react-dom": "17.0.1", 18 | "react-scripts": "3.4.3", 19 | "react-copy-to-clipboard": "5.0.3", 20 | "typescript": "4.2.4" 21 | }, 22 | "scripts": { 23 | "start": "react-scripts start", 24 | "build": "react-scripts build", 25 | "test": "react-scripts test", 26 | "eject": "react-scripts eject" 27 | }, 28 | "eslintConfig": { 29 | "extends": "react-app" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/test-ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/test-ui/public/favicon.ico -------------------------------------------------------------------------------- /modules/test-ui/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/test-ui/public/logo192.png -------------------------------------------------------------------------------- /modules/test-ui/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connext/vector/6c0e900ca412a79ba9f91e04114a15b60de9be73/modules/test-ui/public/logo512.png -------------------------------------------------------------------------------- /modules/test-ui/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /modules/test-ui/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /modules/test-ui/src/App.css: -------------------------------------------------------------------------------- 1 | @import "~antd/dist/antd.css"; 2 | -------------------------------------------------------------------------------- /modules/test-ui/src/config.ts: -------------------------------------------------------------------------------- 1 | import { VectorNodeConfig } from "@connext/vector-types"; 2 | 3 | const configEnv = process.env.REACT_APP_VECTOR_CONFIG; 4 | console.log("Using config: ", configEnv); 5 | 6 | export const config: VectorNodeConfig = JSON.parse(configEnv!); 7 | -------------------------------------------------------------------------------- /modules/test-ui/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /modules/test-ui/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | 4 | import "./index.css"; 5 | import App from "./App"; 6 | import * as serviceWorker from "./serviceWorker"; 7 | 8 | ReactDOM.render(, document.getElementById("root")); 9 | 10 | // If you want your app to work offline and load faster, you can change 11 | // unregister() to register() below. Note this comes with some pitfalls. 12 | // Learn more about service workers: https://bit.ly/CRA-PWA 13 | serviceWorker.unregister(); 14 | -------------------------------------------------------------------------------- /modules/test-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": false, 10 | "forceConsistentCasingInFileNames": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | "jsx": "react" 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /modules/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@connext/vector-types", 3 | "version": "0.2.5-beta.21", 4 | "description": "TypeScript typings for common Connext types", 5 | "main": "dist/index.js", 6 | "module": "dist/index.esm.js", 7 | "types": "dist/src/index.d.ts", 8 | "iife": "dist/index-iife.js", 9 | "license": "MIT", 10 | "files": [ 11 | "dist", 12 | "src" 13 | ], 14 | "scripts": { 15 | "build": "rm -rf dist && tsc && rollup -c" 16 | }, 17 | "dependencies": { 18 | "@ethersproject/abstract-provider": "5.2.0", 19 | "@ethersproject/abstract-signer": "5.2.0", 20 | "@ethersproject/bignumber": "5.2.0", 21 | "@ethersproject/providers": "5.2.0", 22 | "@sinclair/typebox": "0.12.7", 23 | "evt": "1.9.12" 24 | }, 25 | "devDependencies": { 26 | "ethers": "5.2.0", 27 | "rollup": "2.40.0", 28 | "rollup-plugin-typescript2": "0.30.0", 29 | "typescript": "4.2.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /modules/types/rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from "rollup-plugin-typescript2"; 2 | 3 | import pkg from "./package.json"; 4 | 5 | export default [ 6 | { 7 | input: "./src/index.ts", 8 | output: [ 9 | { 10 | file: pkg.main, 11 | format: "cjs", 12 | }, 13 | { 14 | file: pkg.module, 15 | format: "esm", 16 | }, 17 | { 18 | file: pkg.iife, 19 | format: "iife", 20 | name: "window.types", 21 | }, 22 | ], 23 | plugins: [typescript()], 24 | }, 25 | ]; 26 | -------------------------------------------------------------------------------- /modules/types/src/basic.ts: -------------------------------------------------------------------------------- 1 | 2 | // strings aliases: these function more as documentation for devs than checked types 3 | export type ABIEncoding = string; // eg "tuple(address to, uint256 amount)" 4 | export type Address = string; // aka HexString of length 42 5 | export type AssetId = string; // aka Address of ERC20 token contract or AddressZero for ETH 6 | export type Bytes32 = string; // aka HexString of length 66 7 | export type DecString = string; // eg "3.14" 8 | export type HexString = string; // eg "0xabc123" of arbitrary length 9 | export type PublicIdentifier = string; // "vector" + base58() 10 | export type PublicKey = string; // aka HexString of length 132 11 | export type PrivateKey = string; // aka Bytes32 12 | export type SignatureString = string; // aka HexString of length 132 13 | export type UrlString = string; // eg "://[:]/ 14 | 15 | export type Omit = Pick>; 16 | -------------------------------------------------------------------------------- /modules/types/src/contracts.ts: -------------------------------------------------------------------------------- 1 | import { tidy } from "./utils"; 2 | 3 | export const BalanceEncoding = tidy(`tuple( 4 | uint256[2] amount, 5 | address[2] to 6 | )`); 7 | 8 | export const WithdrawDataEncoding = tidy(`tuple( 9 | address channelAddress, 10 | address assetId, 11 | address recipient, 12 | uint256 amount, 13 | uint256 nonce, 14 | address callTo, 15 | bytes callData 16 | )`); 17 | -------------------------------------------------------------------------------- /modules/types/src/crypto.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from "@ethersproject/abstract-signer"; 2 | import { Provider } from "@ethersproject/abstract-provider"; 3 | 4 | import { Address, PublicKey, PublicIdentifier } from "./basic"; 5 | 6 | export interface IChannelSigner extends Signer { 7 | address: Address; 8 | decrypt(message: string): Promise; 9 | encrypt(message: string, publicKey: string): Promise; 10 | signMessage(message: string): Promise; 11 | signUtilityMessage(message: string): Promise; 12 | publicKey: PublicKey; 13 | publicIdentifier: PublicIdentifier; 14 | connectProvider(provider: string | Provider): Promise; 15 | } 16 | -------------------------------------------------------------------------------- /modules/types/src/dispute.ts: -------------------------------------------------------------------------------- 1 | export type ChannelDispute = { 2 | channelStateHash: string; 3 | nonce: string; 4 | merkleRoot: string; 5 | consensusExpiry: string; 6 | defundExpiry: string; 7 | }; 8 | 9 | export type TransferDispute = { 10 | transferId: string; // From events 11 | transferStateHash: string; 12 | transferDisputeExpiry: string; 13 | isDefunded: boolean; 14 | }; 15 | -------------------------------------------------------------------------------- /modules/types/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./basic"; 2 | export * from "./chain"; 3 | export * from "./channel"; 4 | export * from "./constants"; 5 | export * from "./contracts"; 6 | export * from "./crypto"; 7 | export * from "./dispute"; 8 | export * from "./engine"; 9 | export * from "./error"; 10 | export * from "./event"; 11 | export * from "./externalValidation"; 12 | export * from "./lock"; 13 | export * from "./messaging"; 14 | export * from "./network"; 15 | export * from "./node"; 16 | export * from "./protocol"; 17 | export * from "./rpc"; 18 | export * from "./schemas"; 19 | export * from "./store"; 20 | export * from "./transferDefinitions"; 21 | export * from "./utils"; 22 | export * from "./vectorProvider"; 23 | -------------------------------------------------------------------------------- /modules/types/src/lock.ts: -------------------------------------------------------------------------------- 1 | export type LockInformation = { 2 | type: "acquire" | "release"; 3 | lockName: string; 4 | lockValue?: string; 5 | }; 6 | 7 | export interface ILockService { 8 | acquireLock( 9 | lockName: string /* Bytes32? */, 10 | isAlice?: boolean, 11 | counterpartyPublicIdentifier?: string, 12 | ): Promise; 13 | 14 | releaseLock( 15 | lockName: string /* Bytes32? */, 16 | lockValue: string, 17 | isAlice?: boolean, 18 | counterpartyPublicIdentifier?: string, 19 | ): Promise; 20 | } 21 | -------------------------------------------------------------------------------- /modules/types/src/network.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcProvider } from "@ethersproject/providers"; 2 | 3 | export type ChainProviders = { 4 | [chainId: number]: string; 5 | }; 6 | 7 | export type HydratedProviders = { 8 | [chainId: number]: JsonRpcProvider; 9 | }; 10 | -------------------------------------------------------------------------------- /modules/types/src/rpc.ts: -------------------------------------------------------------------------------- 1 | export type JsonRpcRequest = { 2 | id: number; 3 | jsonrpc: "2.0"; 4 | method: string; 5 | params: T; 6 | }; 7 | 8 | export type JsonRpcResponse = { 9 | id: number; 10 | jsonrpc: "2.0"; 11 | result: T; 12 | }; 13 | 14 | export type Rpc = { 15 | id?: number; 16 | methodName: string; 17 | parameters: { [key: string]: any } | any[]; 18 | }; 19 | -------------------------------------------------------------------------------- /modules/types/src/schemas/config.ts: -------------------------------------------------------------------------------- 1 | import { Static, Type } from "@sinclair/typebox"; 2 | 3 | import { TContractAddresses, TUrl } from "./basic"; 4 | 5 | export const VectorNodeConfigSchema = Type.Object({ 6 | adminToken: Type.String(), 7 | authUrl: Type.Optional(Type.String({ format: "uri" })), 8 | chainAddresses: Type.Dict(TContractAddresses), 9 | chainProviders: Type.Dict(TUrl), 10 | dbUrl: Type.Optional(TUrl), 11 | logLevel: Type.Optional( 12 | Type.Union([ 13 | Type.Literal("fatal"), 14 | Type.Literal("error"), 15 | Type.Literal("warn"), 16 | Type.Literal("info"), 17 | Type.Literal("debug"), 18 | Type.Literal("trace"), 19 | Type.Literal("silent"), 20 | ]), 21 | ), 22 | messagingUrl: Type.Optional(TUrl), 23 | mnemonic: Type.Optional(Type.String()), 24 | natsUrl: Type.Optional(TUrl), 25 | skipCheckIn: Type.Optional(Type.Boolean()), 26 | baseGasSubsidyPercentage: Type.Number({ minimum: 0, maximum: 100 }), 27 | }); 28 | 29 | export type VectorNodeConfig = Static; 30 | -------------------------------------------------------------------------------- /modules/types/src/schemas/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./autoRebalance"; 2 | export * from "./basic"; 3 | export * from "./config"; 4 | export * from "./engine"; 5 | export * from "./node"; 6 | export * from "./protocol"; 7 | export * from "./router"; 8 | -------------------------------------------------------------------------------- /modules/types/src/schemas/router.ts: -------------------------------------------------------------------------------- 1 | import { Type, Static } from "@sinclair/typebox"; 2 | 3 | import { TBytes32, TAddress, TChainId, TPublicIdentifier, TransferQuoteSchema } from "./basic"; 4 | 5 | //////////////////////////////////////// 6 | // Router Schemas 7 | 8 | // The router is a thin wrapper around a server-node 9 | // that allows the server-node to act as an intelligent 10 | // intermediary for routing payments. 11 | 12 | // The router will need to be able to parse metadata 13 | // from the server-node/engine to successfully forward 14 | // transfer creations/resolutions. While the server-node/ 15 | // engine/protocl can be unopinionated about the meta, the 16 | // router cannot. The meta is captured by the router listeners 17 | // and should be parsed/validated once it is registered. Only 18 | // transfers with valid routing metas should be routed 19 | 20 | const TPathSchema = Type.Object({ 21 | recipient: TPublicIdentifier, 22 | recipientChainId: TChainId, 23 | recipientAssetId: TAddress, 24 | }); 25 | 26 | const TRoutingMeta = Type.Object({ 27 | routingId: TBytes32, 28 | requireOnline: Type.Boolean(), 29 | path: Type.Array(TPathSchema), 30 | quote: Type.Optional(TransferQuoteSchema), 31 | }); 32 | 33 | // Namespace exports 34 | // eslint-disable-next-line @typescript-eslint/no-namespace 35 | export namespace RouterSchemas { 36 | export const RouterMeta = TRoutingMeta; 37 | export type RouterMeta = Static; 38 | } 39 | -------------------------------------------------------------------------------- /modules/types/src/transferDefinitions/hashlockTransfer.ts: -------------------------------------------------------------------------------- 1 | import { HexString } from "../basic"; 2 | import { tidy } from "../utils"; 3 | 4 | export const HashlockTransferName = "HashlockTransfer"; 5 | 6 | export type HashlockTransferState = { 7 | lockHash: HexString; 8 | expiry: string; 9 | }; 10 | 11 | export type HashlockTransferResolver = { 12 | preImage: HexString; 13 | }; 14 | 15 | export const HashlockTransferStateEncoding = tidy(`tuple( 16 | bytes32 lockHash, 17 | uint256 expiry 18 | )`); 19 | 20 | export const HashlockTransferResolverEncoding = tidy(`tuple( 21 | bytes32 preImage 22 | )`); 23 | -------------------------------------------------------------------------------- /modules/types/src/transferDefinitions/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./hashlockTransfer"; 2 | export * from "./shared"; 3 | export * from "./withdraw"; 4 | -------------------------------------------------------------------------------- /modules/types/src/transferDefinitions/withdraw.ts: -------------------------------------------------------------------------------- 1 | import { SignatureString, Address, Bytes32 } from "../basic"; 2 | import { NodeResponses } from "../schemas"; 3 | import { tidy } from "../utils"; 4 | 5 | export const WithdrawName = "Withdraw"; 6 | 7 | export type WithdrawState = { 8 | initiatorSignature: SignatureString; 9 | initiator: Address; 10 | responder: Address; 11 | data: Bytes32; 12 | nonce: string; 13 | fee: string; 14 | callTo: Address; 15 | callData: string; 16 | }; 17 | 18 | export type WithdrawResolver = { 19 | responderSignature: SignatureString; 20 | }; 21 | 22 | export const WithdrawStateEncoding = tidy(`tuple( 23 | bytes initiatorSignature, 24 | address initiator, 25 | address responder, 26 | bytes32 data, 27 | uint256 nonce, 28 | uint256 fee, 29 | address callTo, 30 | bytes callData 31 | )`); 32 | 33 | export const WithdrawResolverEncoding = tidy(`tuple( 34 | bytes responderSignature 35 | )`); 36 | 37 | export type WithdrawCommitmentJson = { 38 | aliceSignature?: string; 39 | bobSignature?: string; 40 | channelAddress: string; 41 | alice: string; 42 | bob: string; 43 | recipient: string; 44 | assetId: string; 45 | amount: string; 46 | nonce: string; 47 | callTo: string; 48 | callData: string; 49 | transactionHash?: string; 50 | }; 51 | 52 | export const WithdrawalQuoteEncoding = tidy(`tuple( 53 | address channelAddress, 54 | uint256 amount, 55 | address assetId, 56 | uint256 fee, 57 | uint256 expiry 58 | )`); 59 | -------------------------------------------------------------------------------- /modules/types/src/utils.ts: -------------------------------------------------------------------------------- 1 | // NOTE: These are very simple type-specific utils 2 | // To prevent cyclic dependencies, these should not be moved to the utils module 3 | 4 | // stolen from https://github.com/microsoft/TypeScript/issues/3192#issuecomment-261720275 5 | export const enumify = (x: T): T => x; 6 | 7 | export const tidy = (str: string): string => `${str.replace(/\n/g, "").replace(/ +/g, " ")}`; -------------------------------------------------------------------------------- /modules/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /modules/utils/.gitignore: -------------------------------------------------------------------------------- 1 | *.sw[op] 2 | .DS_Store 3 | .env 4 | .rpt2_cache 5 | dist 6 | node_modules 7 | types 8 | -------------------------------------------------------------------------------- /modules/utils/.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "cache": false, 3 | "extension": [".ts"], 4 | "include": ["src/**"] 5 | } 6 | -------------------------------------------------------------------------------- /modules/utils/README.md: -------------------------------------------------------------------------------- 1 | # @connext/utils 2 | 3 | Module containing crypto & other tools for Connext client 4 | 5 | Find documentation at [https://docs.connext.network/](https://docs.connext.network/) 6 | -------------------------------------------------------------------------------- /modules/utils/src/bigNumbers.ts: -------------------------------------------------------------------------------- 1 | import { HexString } from "@connext/vector-types"; 2 | import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; 3 | 4 | export const isBN = BigNumber.isBigNumber; 5 | 6 | // bigNumberifyJson & deBigNumberifyJson convert values between BigNumber & BigNumberJson 7 | export type BigNumberJson = { _hex: HexString; _isBigNumber: true }; 8 | 9 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 10 | export const isBNJson = (value: any): boolean => !isBN(value) && !!value._hex; 11 | 12 | export const toBN = (n: BigNumberish | BigNumberJson): BigNumber => 13 | BigNumber.from( 14 | n && typeof (n as BigNumberJson)._hex === "string" 15 | ? (n as BigNumberJson)._hex 16 | : typeof n.toString === "function" 17 | ? n.toString() 18 | : "0", 19 | ); 20 | 21 | export const toBNJson = (n: BigNumberish | BigNumberJson): BigNumberJson => ({ 22 | _hex: toBN(n).toHexString(), 23 | _isBigNumber: true, 24 | }); 25 | 26 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 27 | export const getBigNumberError = (value: any): string | undefined => 28 | isBN(value) ? undefined : `Value "${value}" is not a BigNumber`; 29 | 30 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 31 | export const getBigNumberishError = (value: any): string | undefined => { 32 | try { 33 | toBN(value); 34 | } catch (e) { 35 | return `Value "${value}" is not BigNumberish: ${e.message}`; 36 | } 37 | return undefined; 38 | }; 39 | -------------------------------------------------------------------------------- /modules/utils/src/caip.ts: -------------------------------------------------------------------------------- 1 | import { AccountID, ChainID, ChainIDParams } from "caip"; 2 | 3 | const EIP155_NAMESPACE = "eip155"; 4 | 5 | export const formatChainId = (chainId: number): ChainIDParams => { 6 | return { namespace: EIP155_NAMESPACE, reference: `${chainId}` }; 7 | }; 8 | 9 | export const parseChainId = (chainId: string | ChainIDParams): number => { 10 | if (typeof chainId === "string") { 11 | chainId = ChainID.parse(chainId); 12 | } 13 | if (chainId.namespace !== EIP155_NAMESPACE) { 14 | throw new Error("ChainId provided namespace does not match EIP155"); 15 | } 16 | return Number(chainId.reference); 17 | }; 18 | 19 | export const formatAssetId = (assetAddress: string, chainId: number): string => { 20 | return AccountID.format({ address: assetAddress, chainId: formatChainId(chainId) }); 21 | }; 22 | 23 | export const parseAssetId = (assetId: string): { assetAddress: string; chainId: number } => { 24 | const accountId = AccountID.parse(assetId); 25 | return { assetAddress: accountId.address, chainId: parseChainId(accountId.chainId) }; 26 | }; 27 | -------------------------------------------------------------------------------- /modules/utils/src/chainId.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcResponse } from "@connext/vector-types"; 2 | import { BigNumber } from "@ethersproject/bignumber"; 3 | import axios, { AxiosResponse } from "axios"; 4 | 5 | // Gets the chainId from the provider URL using a regular POST method 6 | // This is done as a workaround to get the network information before 7 | // creating the provider object: 8 | // https://github.com/connext/indra/issues/1281 9 | export const getChainId = async (ethProviderUrl: string): Promise => { 10 | const chainIdResponse: AxiosResponse = await axios.post( 11 | `${ethProviderUrl}`, 12 | { 13 | id: 1, 14 | jsonrpc: "2.0", 15 | method: "eth_chainId", 16 | params: [], 17 | }, 18 | { headers: { "content-type": "application/json" } }, 19 | ); 20 | return BigNumber.from(chainIdResponse.data.result).toNumber(); 21 | }; 22 | -------------------------------------------------------------------------------- /modules/utils/src/crypto.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { getRandomPublicKey, getPublicKeyError } from "./crypto"; 4 | 5 | describe("Crypto", () => { 6 | it("should generate a valid random public key", async () => { 7 | expect(getPublicKeyError(getRandomPublicKey())).to.be.undefined; 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /modules/utils/src/delay.ts: -------------------------------------------------------------------------------- 1 | export const delay = (ms: number): Promise => 2 | new Promise((res: any): any => setTimeout(res, ms)); 3 | 4 | export const delayAndThrow = (ms: number, msg = ""): Promise => 5 | new Promise((res: any, rej: any): any => setTimeout((): undefined => rej(new Error(msg)), ms)); 6 | -------------------------------------------------------------------------------- /modules/utils/src/env.ts: -------------------------------------------------------------------------------- 1 | export const isNode = (): boolean => 2 | typeof process !== "undefined" && 3 | typeof process.versions !== "undefined" && 4 | typeof process.versions.node !== "undefined"; 5 | -------------------------------------------------------------------------------- /modules/utils/src/error.ts: -------------------------------------------------------------------------------- 1 | import { BaseLogger } from "pino"; 2 | 3 | export const logAxiosError = ( 4 | logger: BaseLogger, 5 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 6 | error: any, 7 | additionalContext = {}, 8 | message = "Error sending request", 9 | ): void => { 10 | let errorObj: any = { message: error.message ?? message }; 11 | if (error.response) { 12 | // The request was made and the server responded with a status code 13 | // that falls out of the range of 2xx 14 | errorObj = { 15 | ...errorObj, 16 | data: error.response.data, 17 | status: error.response.status, 18 | headers: error.response.headers, 19 | }; 20 | } else if (error.request) { 21 | // The request was made but no response was received 22 | // `error.request` is an instance of XMLHttpRequest in the browser and an 23 | // instance of http.ClientRequest in node.js 24 | errorObj = { ...errorObj, request: "Error in request" }; 25 | } 26 | logger.error({ ...errorObj, ...additionalContext, config: error.config }, message); 27 | }; 28 | -------------------------------------------------------------------------------- /modules/utils/src/eth.ts: -------------------------------------------------------------------------------- 1 | import { ChainProviders, HydratedProviders } from "@connext/vector-types"; 2 | import { Provider } from "@ethersproject/abstract-provider"; 3 | import { BigNumber } from "@ethersproject/bignumber"; 4 | import { JsonRpcProvider, StaticJsonRpcProvider } from "@ethersproject/providers"; 5 | 6 | const classicProviders = ["https://www.ethercluster.com/etc"]; 7 | const classicChainIds = [61]; 8 | const minGasPrice = BigNumber.from(1_000); 9 | 10 | export const getEthProvider = (providerUrl: string, chainId?: number): JsonRpcProvider => 11 | new JsonRpcProvider( 12 | providerUrl, 13 | classicProviders.includes(providerUrl) || classicChainIds.includes(chainId) ? "classic" : undefined, 14 | ); 15 | 16 | // xDai hardcoded their gas price to 0 but it's not actually zero.. 17 | export const getGasPrice = async (provider: Provider, providedChainId?: number): Promise => { 18 | const chainId = providedChainId || (await provider.getNetwork())?.chainId; 19 | const price = await provider.getGasPrice(); 20 | return chainId === 100 && price.lt(minGasPrice) ? minGasPrice : price; 21 | }; 22 | 23 | export const hydrateProviders = (chainProviders: ChainProviders): HydratedProviders => { 24 | const hydratedProviders: { [url: string]: JsonRpcProvider } = {}; 25 | Object.entries(chainProviders).map(([chainId, url]) => { 26 | hydratedProviders[chainId] = new StaticJsonRpcProvider(url as string, parseInt(chainId)); 27 | }); 28 | return hydratedProviders; 29 | }; 30 | -------------------------------------------------------------------------------- /modules/utils/src/fs.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | export const isDirectory = async (path: string): Promise => { 4 | try { 5 | return fs.statSync(path).isDirectory(); 6 | } catch (e) { 7 | return false; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /modules/utils/src/identifiers.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { getPublicIdentifierError, getRandomIdentifier } from "./identifiers"; 4 | 5 | describe("Identifiers", () => { 6 | it("should generate a valid random public identifier", async () => { 7 | expect(getPublicIdentifierError(getRandomIdentifier())).to.be.undefined; 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /modules/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./bigNumbers"; 2 | export * from "./chainId"; 3 | export * from "./chainInfo"; 4 | export * from "./channel"; 5 | export * from "./channelSigner"; 6 | export * from "./comparisons"; 7 | export * from "./create2"; 8 | export * from "./crypto"; 9 | export * from "./currency"; 10 | export * from "./delay"; 11 | export * from "./env"; 12 | export * from "./error"; 13 | export * from "./eth"; 14 | export * from "./fs"; 15 | export * from "./hexStrings"; 16 | export * from "./identifiers"; 17 | export * from "./json"; 18 | export * from "./lock"; 19 | export * from "./fees"; 20 | export * from "./math"; 21 | export * from "./merkle"; 22 | export * from "./messaging"; 23 | export * from "./rpc"; 24 | export * from "./serverNode"; 25 | export * from "./strings"; 26 | export * from "./test"; 27 | export * from "./transfers"; 28 | export * from "./validateUpdateSignatures"; 29 | export * from "./testStore"; 30 | -------------------------------------------------------------------------------- /modules/utils/src/limitedCache.ts: -------------------------------------------------------------------------------- 1 | interface Node { 2 | next: Node | null; 3 | key: string; 4 | } 5 | 6 | /** 7 | * Caching class that limits is size to maxLength keys. A linked list 8 | * is used under-the-hood to keep track of the order of key insertion. 9 | * Keys are removed via a FIFO strategy. 10 | */ 11 | export class LimitedCache { 12 | public readonly maxLength: number; 13 | 14 | private length = 0; 15 | 16 | private head: Node | null = null; 17 | 18 | private tail: Node | null = null; 19 | 20 | private cache: { [k: string]: any } = {}; 21 | 22 | constructor(maxLength: number) { 23 | this.maxLength = maxLength; 24 | } 25 | 26 | set(k: string, v: T): void { 27 | const exists = !!this.cache[k]; 28 | this.cache[k] = v; 29 | if (exists) { 30 | return; 31 | } 32 | 33 | const node = { 34 | next: null, 35 | key: k, 36 | }; 37 | 38 | if (!this.tail) { 39 | this.cache[k] = v; 40 | this.head = this.tail = node; 41 | this.length++; 42 | return; 43 | } 44 | 45 | this.tail.next = node; 46 | this.tail = node; 47 | if (this.length === this.maxLength) { 48 | const head = this.head; 49 | delete this.cache[head.key]; 50 | this.head = head.next; 51 | return; 52 | } 53 | 54 | this.length++; 55 | } 56 | 57 | get(k: string): T | null { 58 | const res = this.cache[k]; 59 | if (!res) { 60 | return null; 61 | } 62 | return res; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /modules/utils/src/lock.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes } from "crypto"; 2 | 3 | import { ILockService } from "@connext/vector-types"; 4 | import { Mutex, MutexInterface } from "async-mutex"; 5 | 6 | type InternalLock = { 7 | lock: Mutex; 8 | releaser: MutexInterface.Releaser; 9 | timer: NodeJS.Timeout; 10 | secret: string; 11 | }; 12 | 13 | export const LOCK_TTL = 30_000; 14 | 15 | export class MemoryLockService implements ILockService { 16 | public readonly locks: Map = new Map(); 17 | private readonly ttl = LOCK_TTL; 18 | 19 | async acquireLock(lockName: string): Promise { 20 | let lock = this.locks.get(lockName)?.lock; 21 | if (!lock) { 22 | lock = new Mutex(); 23 | this.locks.set(lockName, { lock, releaser: undefined, timer: undefined, secret: undefined }); 24 | } 25 | 26 | const releaser = await lock.acquire(); 27 | const secret = this.randomValue(); 28 | const timer = setTimeout(() => this.releaseLock(lockName, secret), this.ttl); 29 | this.locks.set(lockName, { lock, releaser, timer, secret }); 30 | return secret; 31 | } 32 | 33 | async releaseLock(lockName: string, lockValue: string): Promise { 34 | const lock = this.locks.get(lockName); 35 | 36 | if (!lock) { 37 | throw new Error(`Can't release a lock that doesn't exist: ${lockName}`); 38 | } 39 | if (lockValue !== lock.secret) { 40 | throw new Error("Incorrect lock value"); 41 | } 42 | 43 | clearTimeout(lock.timer); 44 | return lock.releaser(); 45 | } 46 | 47 | private randomValue() { 48 | return randomBytes(16).toString("hex"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /modules/utils/src/merkle.ts: -------------------------------------------------------------------------------- 1 | import { CoreTransferState } from "@connext/vector-types"; 2 | import { HashZero } from "@ethersproject/constants"; 3 | import { keccak256 } from "ethereumjs-util"; 4 | import { MerkleTree } from "merkletreejs"; 5 | 6 | import { hashCoreTransferState } from "./transfers"; 7 | 8 | export const generateMerkleTreeData = (transfers: CoreTransferState[]): { root: string; tree: MerkleTree } => { 9 | // Sort transfers alphabetically by id 10 | const sorted = transfers.sort((a, b) => a.transferId.localeCompare(b.transferId)); 11 | 12 | // Create leaves 13 | const leaves = sorted.map((transfer) => { 14 | return hashCoreTransferState(transfer); 15 | }); 16 | 17 | // Generate tree 18 | const tree = new MerkleTree(leaves, keccak256, { sortPairs: true }); 19 | 20 | // Return 21 | const calculated = tree.getHexRoot(); 22 | return { 23 | root: calculated === "0x" ? HashZero : calculated, 24 | tree, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /modules/utils/src/rpc.ts: -------------------------------------------------------------------------------- 1 | import { ChannelRpcMethod, ChannelRpcMethodsPayloadMap, EngineParams } from "@connext/vector-types"; 2 | 3 | export function payloadId(): number { 4 | const date = new Date().getTime() * Math.pow(10, 3); 5 | const extra = Math.floor(Math.random() * Math.pow(10, 3)); 6 | return date + extra; 7 | } 8 | 9 | export const constructRpcRequest = ( 10 | method: T, 11 | params: ChannelRpcMethodsPayloadMap[T], 12 | ): EngineParams.RpcRequest => { 13 | return { 14 | id: payloadId(), 15 | jsonrpc: "2.0", 16 | method, 17 | params, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /modules/utils/src/strings.ts: -------------------------------------------------------------------------------- 1 | export const abbreviate = (str?: string, len = 4): string => 2 | !str ? "undefined" 3 | : str.startsWith("vector") ? `${str.substring(0, 5 + len)}..${str.substring(str.length - len)}` 4 | : str.startsWith("0x") ? `${str.substring(0, 2 + len)}..${str.substring(str.length - len)}` 5 | : `${str.substring(0, len)}..${str.substring(str.length - len)}`; 6 | 7 | export const abrv = (str?: string, len = 4): string => abbreviate(str, len); 8 | 9 | export const capitalize = (str: string): string => str.charAt(0).toUpperCase() + str.substring(1); 10 | -------------------------------------------------------------------------------- /modules/utils/src/test/expect.ts: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import promised from "chai-as-promised"; 3 | import subset from "chai-subset"; 4 | import { waffleChai } from "@ethereum-waffle/chai"; 5 | 6 | let chaiPlugin = chai.use(subset); 7 | chaiPlugin = chaiPlugin.use(promised); 8 | chaiPlugin = chaiPlugin.use(waffleChai); 9 | 10 | export const expect = chaiPlugin.expect; 11 | -------------------------------------------------------------------------------- /modules/utils/src/test/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./chain"; 2 | export * from "./channel"; 3 | export * from "./expect"; 4 | export * from "./logger"; 5 | export * from "./message"; 6 | export * from "./services"; 7 | export * from "./transfers"; 8 | export * from "./util"; -------------------------------------------------------------------------------- /modules/utils/src/test/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | export const getTestLoggers = ( 4 | name: string, 5 | level: pino.Level = "info", 6 | fast = 20, 7 | slow = 200, 8 | ): { log: pino.BaseLogger; timer: any } => { 9 | const log = pino({ level, name }); 10 | const timer = start => msg => { 11 | const diff = Date.now() - start; 12 | if (diff < fast) { 13 | log.debug(msg); 14 | } else if (diff < slow) { 15 | log.info(msg); 16 | } else { 17 | log.warn(msg); 18 | } 19 | }; 20 | return { log, timer }; 21 | }; 22 | -------------------------------------------------------------------------------- /modules/utils/src/test/message.ts: -------------------------------------------------------------------------------- 1 | import { UpdateType, VectorChannelMessage } from "@connext/vector-types"; 2 | 3 | import { createTestChannelUpdate, PartialChannelUpdate } from "./channel"; 4 | import { mkPublicIdentifier } from "./util"; 5 | 6 | type PartialVectorChannelMessageData = Partial<{ 7 | update: PartialChannelUpdate; 8 | latestUpdate: PartialChannelUpdate | undefined; 9 | }>; 10 | 11 | type PartialVectorChannelMessage = Partial< 12 | Omit, "data"> & { data: PartialVectorChannelMessageData } 13 | >; 14 | 15 | export function createVectorChannelMessage(overrides: PartialVectorChannelMessage = {}): VectorChannelMessage { 16 | // Generate the proper data fields given the overrides 17 | const { data, ...defaults } = overrides; 18 | const update = { 19 | ...createTestChannelUpdate(data?.update?.type ?? UpdateType.setup, data?.update), 20 | }; 21 | const latestUpdate = data?.latestUpdate && { 22 | ...createTestChannelUpdate(data?.latestUpdate?.type ?? UpdateType.setup, data?.latestUpdate), 23 | }; 24 | return { 25 | to: mkPublicIdentifier("vectorBBB"), 26 | from: mkPublicIdentifier("vectorAAA"), 27 | inbox: "test_inbox", 28 | data: { 29 | update: { 30 | ...update, 31 | fromIdentifier: defaults.from ?? update.fromIdentifier, 32 | toIdentifier: defaults.to ?? update.toIdentifier, 33 | }, 34 | latestUpdate, 35 | }, 36 | ...defaults, 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /modules/utils/src/test/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from "../../lock"; 2 | export * from "./messaging"; 3 | export * from "./store"; 4 | -------------------------------------------------------------------------------- /modules/utils/src/test/util.ts: -------------------------------------------------------------------------------- 1 | export const mkAddress = (prefix = "0x0"): string => { 2 | return prefix.padEnd(42, "0"); 3 | }; 4 | 5 | export const mkPublicIdentifier = (prefix = "vectorA"): string => { 6 | return prefix.padEnd(56, "0"); 7 | }; 8 | 9 | export const mkHash = (prefix = "0x"): string => { 10 | return prefix.padEnd(66, "0"); 11 | }; 12 | 13 | export const mkBytes32 = (prefix = "0xa"): string => { 14 | return prefix.padEnd(66, "0"); 15 | }; 16 | 17 | export const mkSig = (prefix = "0xa"): string => { 18 | return prefix.padEnd(132, "0"); 19 | }; 20 | -------------------------------------------------------------------------------- /modules/utils/src/transfer.spec.ts: -------------------------------------------------------------------------------- 1 | import { AddressZero } from "@ethersproject/constants"; 2 | 3 | import { expect } from "./test/expect"; 4 | import { getRandomChannelSigner } from "./channelSigner"; 5 | import { getRandomIdentifier } from "./identifiers"; 6 | import { encodeTransferQuote, decodeTransferQuote, encodeWithdrawalQuote, decodeWithdrawalQuote } from "./transfers"; 7 | 8 | describe("Transfers", () => { 9 | it("should encode and decode transfer quote properly", async () => { 10 | const router = getRandomChannelSigner(); 11 | const quote = { 12 | routerIdentifier: router.publicIdentifier, 13 | amount: "100", 14 | assetId: AddressZero, 15 | chainId: 35, 16 | recipient: getRandomIdentifier(), 17 | recipientChainId: 1, 18 | recipientAssetId: AddressZero, 19 | fee: "35", 20 | expiry: (Date.now() + 30_000).toString(), 21 | }; 22 | 23 | const encoded = encodeTransferQuote(quote); 24 | const decoded = decodeTransferQuote(encoded); 25 | 26 | expect(quote).to.be.deep.eq(decoded); 27 | }); 28 | 29 | it("should encode and decode withdraw quote properly", async () => { 30 | const router = getRandomChannelSigner(); 31 | const quote = { 32 | channelAddress: router.address, 33 | amount: "100", 34 | assetId: AddressZero, 35 | fee: "35", 36 | expiry: (Date.now() + 30_000).toString(), 37 | }; 38 | 39 | const encoded = encodeWithdrawalQuote(quote); 40 | const decoded = decodeWithdrawalQuote(encoded); 41 | 42 | expect(quote).to.be.deep.eq(decoded); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /modules/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "declarationDir": "dist/", 6 | "incremental": true, 7 | "module": "commonjs", 8 | "noUnusedLocals": false, 9 | "outDir": "dist", 10 | "strict": false, 11 | "target": "es6" 12 | }, 13 | "exclude": ["dist", "node_modules", "**/*spec.ts"], 14 | "include": ["src/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /ops/build-report.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e -o pipefail 3 | 4 | flags=.flags 5 | if [[ ! -d "$flags" ]] 6 | then echo "Nothing has been built yet. Try running: make" && exit 7 | fi 8 | 9 | echo 10 | echo " seconds | module" 11 | echo "---------+----------------" 12 | for step in $flags/* 13 | do echo "$(cat "$step") $step" | sed 's/.flags\///' 14 | done | sort -nr | awk '{printf(" %7s | %s\n", $1, $2)}' 15 | -------------------------------------------------------------------------------- /ops/builder/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.16.0-alpine3.13 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app \ 7 | PATH=/app/node_modules/.bin:./node_modules/.bin:${PATH} 8 | 9 | ARG LERNA_VERSION=4.0.0 10 | 11 | WORKDIR /app 12 | 13 | COPY entry.sh /entry.sh 14 | COPY test.sh /test.sh 15 | 16 | RUN apk add --no-cache bash curl g++ gcc git jq make python2 &&\ 17 | npm config set unsafe-perm true &&\ 18 | npm install -g lerna@$LERNA_VERSION &&\ 19 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 20 | chmod +x /bin/wait-for &&\ 21 | chmod +x /*.sh &&\ 22 | rm -rf /var/cache/apk/* /tmp/* 23 | 24 | # USER node 25 | 26 | ENTRYPOINT ["bash", "/entry.sh"] 27 | -------------------------------------------------------------------------------- /ops/builder/entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | this_user="$(id -u):$(id -g)" 5 | user="$1" 6 | cmd="$2" 7 | 8 | finish() { 9 | if [[ "$this_user" == "$user" ]] 10 | then echo "Same user, skipping permission fix" 11 | else 12 | echo "Fixing permissions for $user" 13 | find . -not -name "*.swp" -user "$(id -u)" -exec chown -R "$user" {} \; 14 | fi 15 | } 16 | trap finish EXIT 17 | 18 | echo "Running command as $this_user (target user: $user)" 19 | bash -c "$cmd" 20 | -------------------------------------------------------------------------------- /ops/config/browser.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "chainProviders": { 3 | "1337": "http://localhost:8545", 4 | "1338": "http://localhost:8546" 5 | }, 6 | "natsUrl": "ws://localhost:4221", 7 | "authUrl": "http://localhost:5040", 8 | "logLevel": "info" 9 | } 10 | -------------------------------------------------------------------------------- /ops/config/messaging.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "adminToken": "cxt1234", 3 | "domainName": "", 4 | "production": false 5 | } 6 | -------------------------------------------------------------------------------- /ops/config/node.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "adminToken": "cxt1234", 3 | "chainProviders": { 4 | "1337": "http://evm_1337:8545", 5 | "1338": "http://evm_1338:8545" 6 | }, 7 | "logLevel": "info", 8 | "messagingUrl": "", 9 | "production": false 10 | } 11 | -------------------------------------------------------------------------------- /ops/config/router.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "allowedSwaps": [ 3 | { 4 | "fromChainId": 1337, 5 | "toChainId": 1338, 6 | "fromAssetId": "0x0000000000000000000000000000000000000000", 7 | "toAssetId": "0x0000000000000000000000000000000000000000", 8 | "priceType": "hardcoded", 9 | "hardcodedRate": "1" 10 | }, 11 | { 12 | "fromChainId": 1337, 13 | "toChainId": 1338, 14 | "fromAssetId": "0x9FBDa871d559710256a2502A2517b794B482Db40", 15 | "toAssetId": "0x9FBDa871d559710256a2502A2517b794B482Db40", 16 | "priceType": "hardcoded", 17 | "hardcodedRate": "1" 18 | } 19 | ], 20 | "messagingUrl": "", 21 | "production": false, 22 | "rebalanceProfiles": [ 23 | { 24 | "chainId": 1337, 25 | "assetId": "0x0000000000000000000000000000000000000000", 26 | "reclaimThreshold": "1", 27 | "target": "0", 28 | "collateralizeThreshold": "0" 29 | }, 30 | { 31 | "chainId": 1338, 32 | "assetId": "0x0000000000000000000000000000000000000000", 33 | "reclaimThreshold": "1", 34 | "target": "0", 35 | "collateralizeThreshold": "0" 36 | }, 37 | { 38 | "chainId": 1337, 39 | "assetId": "0x9FBDa871d559710256a2502A2517b794B482Db40", 40 | "reclaimThreshold": "1", 41 | "target": "0", 42 | "collateralizeThreshold": "0" 43 | }, 44 | { 45 | "chainId": 1338, 46 | "assetId": "0x9FBDa871d559710256a2502A2517b794B482Db40", 47 | "reclaimThreshold": "1", 48 | "target": "0", 49 | "collateralizeThreshold": "0" 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /ops/database/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:12.6-alpine 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | WORKDIR /postgres 7 | 8 | RUN apk add --no-cache coreutils groff less mailcap py-pip &&\ 9 | pip install --upgrade awscli &&\ 10 | rm -rf /var/cache/apk/* /tmp/* 11 | 12 | COPY . . 13 | 14 | RUN chmod +x entry.sh &&\ 15 | chown -R postgres:postgres /postgres 16 | 17 | ENTRYPOINT ["bash", "entry.sh"] 18 | -------------------------------------------------------------------------------- /ops/database/backup-lifecycle.json: -------------------------------------------------------------------------------- 1 | { 2 | "Rules": [ 3 | { 4 | "ID": "Backups Lifecycle Configuration", 5 | "Status": "Enabled", 6 | "Prefix": "backups/", 7 | "Transitions": [ 8 | { 9 | "Days": 30, 10 | "StorageClass": "STANDARD_IA" 11 | } 12 | ], 13 | "Expiration": { 14 | "Days": 180 15 | }, 16 | "AbortIncompleteMultipartUpload": { 17 | "DaysAfterInitiation": 2 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /ops/database/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "driver": "pg", 4 | "database": {"ENV": "POSTGRES_DB"}, 5 | "user": {"ENV": "POSTGRES_USER"}, 6 | "password": {"ENV": "POSTGRES_PASSWORD"} 7 | }, 8 | "prod": { 9 | "driver": "pg", 10 | "database": {"ENV": "POSTGRES_DB"}, 11 | "user": {"ENV": "POSTGRES_USER"}, 12 | "password": {"ENV": "POSTGRES_PASSWORD"} 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ops/database/database.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": { 3 | "driver": "pg", 4 | "database": "vector" 5 | }, 6 | 7 | "dev": { 8 | "driver": "pg", 9 | "database": "vector" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ops/database/db.dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:12.6-alpine 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | WORKDIR /postgres 7 | 8 | RUN apk add --no-cache coreutils groff less mailcap py-pip &&\ 9 | pip install --upgrade awscli &&\ 10 | rm -rf /var/cache/apk/* /tmp/* 11 | 12 | COPY . . 13 | 14 | RUN chmod +x entry.sh &&\ 15 | chown -R postgres:postgres /postgres 16 | 17 | ENTRYPOINT ["bash", "entry.sh"] 18 | -------------------------------------------------------------------------------- /ops/database/run-backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | project="vector" 5 | service=${project}_database 6 | service_id="$(docker service ps -q $service | head -n 1)" 7 | id="$(docker inspect --format '{{.Status.ContainerStatus.ContainerID}}' "$service_id")" 8 | 9 | if [[ -z "$(docker service ps -q $service)" ]] 10 | then echo "Error: expected to see $service running" && exit 1 11 | fi 12 | 13 | docker exec "$id" bash backup.sh 14 | -------------------------------------------------------------------------------- /ops/db.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep '"name":' "$root/package.json" | head -n 1 | cut -d '"' -f 4) 6 | 7 | username=$project 8 | database=$project 9 | service=${project}_database 10 | service_id=$(docker service ps -q "$service" | head -n 1) 11 | 12 | if [[ -n "$service_id" ]] 13 | then 14 | container_id=$(docker inspect --format '{{.Status.ContainerStatus.ContainerID}}' "$service_id") 15 | else 16 | container_id=$( 17 | docker container ls --filter 'status=running' --format '{{.ID}} {{.Names}}' |\ 18 | cut -d "." -f 1 |\ 19 | grep "_database" |\ 20 | sort |\ 21 | head -n 1 |\ 22 | cut -d " " -f 1 23 | ) 24 | fi 25 | 26 | if [[ -z "$1" ]] 27 | then docker exec -it "$container_id" bash -c "psql $database --username=$username" 28 | else docker exec -it "$container_id" bash -c "psql $database --username=$username --command=\"$1\"" 29 | fi 30 | -------------------------------------------------------------------------------- /ops/grafana/grafana/provisioning/dashboards/dashboards.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: dashboards 5 | type: file 6 | updateIntervalSeconds: 30 7 | options: 8 | path: /etc/dashboards 9 | foldersFromFilesStructure: true 10 | -------------------------------------------------------------------------------- /ops/grafana/grafana/provisioning/datasources/datasources.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Prometheus 5 | type: prometheus 6 | access: proxy 7 | url: http://prometheus:9090 8 | -------------------------------------------------------------------------------- /ops/lint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 4 | eslint="$root/node_modules/.bin/eslint -c $root/.eslintrc.js" 5 | solhint="$root/node_modules/.bin/solhint -c $root/.solhint.json" 6 | 7 | for packagePath in modules/* 8 | do 9 | package=$(basename "$packagePath") 10 | echo "Linting ${package}" 11 | cd "${root}/modules/${package}" || exit 1 12 | if [[ -d "src" ]] 13 | then 14 | eval "$eslint 'src' $*" 15 | elif [[ -d "src.ts" && -d "src.sol" ]] 16 | then 17 | eval "$eslint 'src.ts' $*" 18 | eval "$solhint 'src.sol/**/*.sol' $*" 19 | fi 20 | cd "${root}" || exit 1 21 | done 22 | 23 | if [[ -z "$*" ]] 24 | then echo "Protip: run 'bash ops/lint.sh --fix' to auto-fix simple formatting inconsistencies" 25 | fi 26 | -------------------------------------------------------------------------------- /ops/logs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | target=$1 5 | shift 6 | 7 | service_id=$(docker service ls --format '{{.ID}} {{.Name}}' |\ 8 | grep "_$target" |\ 9 | head -n 1 |\ 10 | cut -d " " -f 1 11 | ) 12 | 13 | if [[ -n "$service_id" ]] 14 | then 15 | docker service ps --no-trunc "$service_id" 16 | sleep 0.5 17 | exec docker service logs --follow --raw --tail 100 "$service_id" "$@" 18 | fi 19 | 20 | container_id=$(docker container ls --filter 'status=running' --format '{{.ID}} {{.Names}}' |\ 21 | cut -d "." -f 1 |\ 22 | grep "_$target" |\ 23 | sort |\ 24 | head -n 1 |\ 25 | cut -d " " -f 1 26 | ) 27 | 28 | if [[ -n "$container_id" ]] 29 | then exec docker container logs --tail 100 --follow "$container_id" "$@" 30 | else echo "No service or running container names match: $target" 31 | fi 32 | -------------------------------------------------------------------------------- /ops/nats/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM provide/nats-server:indra as nats 2 | 3 | FROM alpine:3.13.3 4 | LABEL website="Secure Docker Images https://secureimages.dev" 5 | LABEL description="We secure your business from scratch" 6 | LABEL maintainer="support@secureimages.dev" 7 | 8 | COPY entry.sh /entry.sh 9 | COPY --from=nats /nats /nats 10 | 11 | RUN apk add --no-cache bash ca-certificates &&\ 12 | chmod +x /*.sh &&\ 13 | ln -ns /nats/bin/nats-server /bin/nats-server &&\ 14 | ln -ns /nats/bin/nats-server /nats-server &&\ 15 | ln -ns /nats/bin/nats-server /gnatsd &&\ 16 | rm -rf /var/cache/apk/* /tmp/* 17 | 18 | EXPOSE 4221 4222 5222 6222 8222 19 | 20 | ENTRYPOINT ["/entry.sh"] 21 | 22 | CMD ["nats-server", "-D", "-V"] 23 | -------------------------------------------------------------------------------- /ops/nats/entry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [[ -n "$JWT_SIGNER_PUBLIC_KEY" ]] 5 | then echo "Using public key provided by env var." 6 | elif [[ -n "$JWT_SIGNER_PUBLIC_KEY_FILE" ]] 7 | then JWT_SIGNER_PUBLIC_KEY="$(cat "$JWT_SIGNER_PUBLIC_KEY_FILE")" 8 | else echo "public key must be provided via either a secret or an env var." && exit 1 9 | fi 10 | 11 | # Ensure keys have proper newlines inserted (bc newlines are stripped from env vars) 12 | JWT_SIGNER_PUBLIC_KEY=$( 13 | echo "$JWT_SIGNER_PUBLIC_KEY" |\ 14 | tr -d '\n\r' |\ 15 | sed 's/-----BEGIN PUBLIC KEY-----/\n-----BEGIN PUBLIC KEY-----\n/' |\ 16 | sed 's/-----END PUBLIC KEY-----/\n-----END PUBLIC KEY-----\n/' 17 | ) 18 | 19 | export JWT_SIGNER_PUBLIC_KEY 20 | 21 | echo "===== Starting NATS " 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /ops/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: cadvisor 3 | scrape_interval: 15s 4 | static_configs: 5 | - targets: 6 | - cadvisor:8080 7 | - job_name: "prometheus" 8 | # Override the global default and scrape targets from this job every 5 seconds. 9 | scrape_interval: 15s 10 | static_configs: 11 | - targets: ["localhost:9090"] 12 | - job_name: "router" 13 | scrape_interval: 30s 14 | static_configs: 15 | - targets: ["router:8000"] 16 | -------------------------------------------------------------------------------- /ops/proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM haproxy:2.3.5-alpine 2 | LABEL website="Secure Docker Images https://secureimages.dev" 3 | LABEL description="We secure your business from scratch" 4 | LABEL maintainer="support@secureimages.dev" 5 | 6 | ENV HOME=/app 7 | 8 | WORKDIR /app 9 | 10 | COPY entry.sh /entry.sh 11 | COPY *.cfg /etc/haproxy/ 12 | 13 | RUN apk add --no-cache bash ca-certificates certbot curl iputils openssl git &&\ 14 | curl https://raw.githubusercontent.com/vishnubob/wait-for-it/$(git ls-remote https://github.com/vishnubob/wait-for-it.git refs/heads/master | cut -f1)/wait-for-it.sh > /bin/wait-for &&\ 15 | chmod +x /bin/wait-for &&\ 16 | chmod +x /*.sh &&\ 17 | rm -rf /var/cache/apk/* /tmp/* 18 | 19 | ENTRYPOINT ["/entry.sh"] 20 | 21 | CMD ["haproxy", "-db", "-f", "/etc/haproxy/https.cfg"] 22 | -------------------------------------------------------------------------------- /ops/proxy/http.cfg: -------------------------------------------------------------------------------- 1 | global 2 | log stdout local0 3 | maxconn 50000 4 | tune.ssl.default-dh-param 2048 5 | 6 | defaults 7 | log global 8 | mode http 9 | option dontlognull 10 | option http-server-close 11 | option httpclose 12 | option httplog 13 | option redispatch 14 | timeout client 300000 # 5 minutes 15 | timeout connect 3000 # 3 seconds 16 | timeout server 300000 # 5 minutes 17 | 18 | frontend public_http 19 | acl nats_ws_path path_beg /ws-nats 20 | bind *:80 21 | default_backend auth 22 | http-response del-header Access-Control-Allow-Headers 23 | http-response del-header Access-Control-Allow-Methods 24 | http-response del-header Access-Control-Allow-Origin 25 | http-response add-header Access-Control-Allow-Headers "*" 26 | http-response del-header Access-Control-Allow-Methods 27 | http-response add-header Access-Control-Allow-Origin "*" 28 | option forwardfor 29 | use_backend nats_ws if nats_ws_path 30 | 31 | frontend public_nats_tcp 32 | bind *:4222 33 | default_backend nats_tcp 34 | mode tcp 35 | option tcplog 36 | 37 | backend nats_tcp 38 | mode tcp 39 | server nats "$VECTOR_NATS_TCP_URL" 40 | 41 | backend nats_ws 42 | http-request replace-path /ws-nats / 43 | http-response add-header Access-Control-Allow-Methods "GET, OPTIONS" 44 | server nats "$VECTOR_NATS_WS_URL" 45 | 46 | backend auth 47 | http-response add-header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" 48 | server auth "$VECTOR_AUTH_URL" 49 | -------------------------------------------------------------------------------- /ops/push-images.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | registry=$(grep -m 1 '"registry":' "$root/package.json" | cut -d '"' -f 4) 7 | release=$(grep -m 1 '"version":' "$root/package.json" | cut -d '"' -f 4) 8 | commit=$(git rev-parse HEAD | head -c 8) 9 | 10 | images="auth builder database ethprovider messaging_proxy nats node router test_runner iframe_app" 11 | 12 | # Also push a semver-tagged image if we're on prod 13 | if [[ "$(git rev-parse --abbrev-ref HEAD)" == "prod" || "${GITHUB_REF##*/}" == "prod" ]] 14 | then semver="$release" 15 | else semver="" 16 | fi 17 | 18 | for image in $images 19 | do 20 | if [[ -n "$semver" ]] 21 | then 22 | echo "Tagging image ${project}_$image:$commit as ${project}_$image:$semver" 23 | docker tag "${project}_$image:$commit" "${project}_$image:$semver" || true 24 | fi 25 | for version in latest $commit $semver 26 | do 27 | echo "Tagging image ${project}_$image:$version as $registry/${project}_$image:$version" 28 | docker tag "${project}_$image:$version" "$registry/${project}_$image:$version" || true 29 | echo "Pushing image: $registry/${project}_$image:$version" 30 | docker push "$registry/${project}_$image:$version" || true 31 | done 32 | done 33 | -------------------------------------------------------------------------------- /ops/replace.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | old="$1" 4 | new="$2" 5 | 6 | if [[ -z "$old" || -z "$new" ]] 7 | then echo "Exactly two args required: bash ops/replace.sh " && exit 1 8 | fi 9 | 10 | # set sed flags so that they're valid on either linux or mac 11 | if [[ "$(uname)" == "Darwin" ]] 12 | then sedFlag=(-i '') 13 | else sedFlag=(-i) 14 | fi 15 | 16 | echo "Before:" 17 | bash ops/search.sh "$old" 18 | echo 19 | echo "After:" 20 | bash ops/search.sh "$old" | sed "s|$old|$new|g" | grep --color=always "$new" 21 | echo 22 | echo "Does the above replacement look good? (y/n)" 23 | echo -n "> " 24 | read -r response 25 | echo 26 | 27 | if [[ "$response" == "y" ]] 28 | then 29 | 30 | find \ 31 | .github/workflows/* \ 32 | Makefile \ 33 | modules/*/migrations \ 34 | modules/*/ops \ 35 | modules/*/README.md \ 36 | modules/*/src \ 37 | modules/*/src.sol \ 38 | modules/*/src.ts \ 39 | modules/server-node/schema.prisma \ 40 | ops \ 41 | -type f -not -name "*.swp" -exec sed "${sedFlag[@]}" "s|$old|$new|g" {} \; 42 | 43 | else echo "Goodbye" 44 | fi 45 | -------------------------------------------------------------------------------- /ops/save-secret.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | 7 | docker swarm init 2> /dev/null || true 8 | 9 | secret_name="${1:-${project}_mnemonic}"; 10 | secret_value="$2" 11 | 12 | # NOTE: any newlines or carriage returns will be stripped out of the secret value 13 | 14 | if grep -qs "$secret_name\>" <<<"$(docker secret ls)" 15 | then 16 | echo "A secret called $secret_name already exists, skipping secret setup." 17 | echo "To overwrite this secret, remove the existing one first: 'docker secret rm $secret_name'" 18 | else 19 | 20 | if [[ -z "$secret_value" ]] 21 | then 22 | # Prepare to load the node's private key into the server's secret store 23 | echo "Copy the $secret_name secret to your clipboard then paste it below & hit enter (no echo)" 24 | echo -n "> " 25 | read -rs secret_value 26 | echo 27 | if [[ -z "$secret_value" ]] 28 | then echo "No secret_value provided, skipping secret creation" && exit 0; 29 | fi 30 | fi 31 | 32 | if echo "$secret_value" | tr -d '\n\r' | docker secret create "$secret_name" - 33 | then echo "Successfully saved secret $secret_name" 34 | else echo "Something went wrong creating a secret called $secret_name" 35 | fi 36 | 37 | fi 38 | -------------------------------------------------------------------------------- /ops/search.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | target="$1"; 4 | shift; 5 | 6 | if [[ -z "$target" ]] 7 | then echo "One arg required: bash ops/search.sh " && exit 1 8 | fi 9 | 10 | grep "$@" --exclude=*.swp --exclude=*.pdf --color=auto -r "$target" \ 11 | .github/workflows/* \ 12 | Makefile \ 13 | modules/*/migrations \ 14 | modules/*/ops \ 15 | modules/*/package.json \ 16 | modules/*/README.md \ 17 | modules/*/src \ 18 | modules/*/src.sol \ 19 | modules/*/src.ts \ 20 | modules/server-node/schema.prisma \ 21 | ops \ 22 | package.json 23 | -------------------------------------------------------------------------------- /ops/ssh-action/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.10 2 | RUN apk add bash openssh 3 | COPY entry.sh /entry.sh 4 | ENTRYPOINT ["bash", "/entry.sh"] 5 | -------------------------------------------------------------------------------- /ops/ssh-action/action.yml: -------------------------------------------------------------------------------- 1 | name: 'SSH Action' 2 | description: 'Run a command on a remote server via SSH' 3 | inputs: 4 | SSH_KEY: 5 | description: 'SSH private key' 6 | required: true 7 | HOST: 8 | description: 'user@domainname:port of server to connect to' 9 | required: true 10 | runs: 11 | using: 'docker' 12 | image: 'Dockerfile' 13 | args: 14 | - ${{ inputs.HOST }} 15 | - ${{ inputs.SSH_KEY }} 16 | - ${{ inputs.CMD }} 17 | 18 | -------------------------------------------------------------------------------- /ops/start-iframe-app.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | 7 | # make sure a network for this project has been created 8 | docker swarm init 2> /dev/null || true 9 | docker network create --attachable --driver overlay "$project" 2> /dev/null || true 10 | 11 | #################### 12 | ## Load Config 13 | 14 | # Load the config with defaults if it does not exist 15 | if [[ ! -f "$root/browser.config.json" ]] 16 | then cp "$root/ops/config/browser.default.json" "$root/browser.config.json" 17 | fi 18 | 19 | config=$(cat "$root/browser.config.json") 20 | 21 | # If file descriptors 0-2 exist, then we're prob running via interactive shell instead of on CD/CI 22 | if [[ -t 0 && -t 1 && -t 2 ]] 23 | then interactive=(--interactive --tty) 24 | else echo "Running in non-interactive mode" 25 | fi 26 | 27 | #################### 28 | ## Launch it 29 | 30 | docker run \ 31 | "${interactive[@]}" \ 32 | --entrypoint="bash" \ 33 | --env="REACT_APP_VECTOR_CONFIG=$config" \ 34 | --env="SKIP_PREFLIGHT_CHECK=true" \ 35 | --name="${project}_iframe_app" \ 36 | --publish="3030:3030" \ 37 | --network "$project" \ 38 | --rm \ 39 | --tmpfs="/tmp" \ 40 | --volume="$root:/app" \ 41 | "${project}_builder" -c "cd ./modules/iframe-app && npm start" 42 | -------------------------------------------------------------------------------- /ops/start-test-ui.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | 7 | # make sure a network for this project has been created 8 | docker swarm init 2> /dev/null || true 9 | docker network create --attachable --driver overlay "$project" 2> /dev/null || true 10 | 11 | #################### 12 | ## Load Config 13 | 14 | # Load the config with defaults if it does not exist 15 | if [[ ! -f "$root/browser.config.json" ]] 16 | then cp "$root/ops/config/browser.default.json" "$root/browser.config.json" 17 | fi 18 | 19 | config=$(cat "$root/browser.config.json") 20 | 21 | # If file descriptors 0-2 exist, then we're prob running via interactive shell instead of on CD/CI 22 | if [[ -t 0 && -t 1 && -t 2 ]] 23 | then interactive=(--interactive --tty) 24 | else echo "Running in non-interactive mode" 25 | fi 26 | 27 | docker run \ 28 | "${interactive[@]}" \ 29 | --entrypoint="bash" \ 30 | --env="SKIP_PREFLIGHT_CHECK=true" \ 31 | --env="REACT_APP_VECTOR_CONFIG=$config" \ 32 | --name="${project}_browser_node" \ 33 | --publish="3333:3000" \ 34 | --network "$project" \ 35 | --rm \ 36 | --tmpfs="/tmp" \ 37 | --volume="$root:/app" \ 38 | "${project}_builder" -c "cd ./modules/test-ui && npm start" 39 | -------------------------------------------------------------------------------- /ops/test-network.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | 7 | # make sure a network for this project has been created 8 | docker swarm init 2> /dev/null || true 9 | docker network create --attachable --driver overlay "$project" 2> /dev/null || true 10 | 11 | # If file descriptors 0-2 exist, then we're prob running via interactive shell instead of on CD/CI 12 | if [[ -t 0 && -t 1 && -t 2 ]] 13 | then interactive=(--interactive --tty) 14 | else echo "Running in non-interactive mode" 15 | fi 16 | 17 | evm="${1:-hardhat}" 18 | chain_providers="${2}" 19 | cmd="npx hardhat test --network $evm" 20 | 21 | ######################################## 22 | # If we need a chain for these tests, start the evm & stop it when we're done 23 | 24 | eth_mnemonic="${3:-candy maple cake sugar pudding cream honey rich smooth crumble sweet treat}" 25 | 26 | # Build necessary packages 27 | make contracts 28 | 29 | # TODO: should just start chains here as well 30 | if [[ "$evm" == "hardhat" ]] 31 | then echo "Use 'make test-contracts' for local chains" && exit 1 32 | else echo "Running tests against remote node" 33 | fi 34 | 35 | docker run \ 36 | "${interactive[@]}" \ 37 | --entrypoint="bash" \ 38 | --env="LOG_LEVEL=$LOG_LEVEL" \ 39 | --env="SUGAR_DADDY=$eth_mnemonic" \ 40 | --env="CHAIN_PROVIDERS=$chain_providers" \ 41 | --name="${project}_test_${evm}" \ 42 | --network "$project" \ 43 | --rm \ 44 | --tmpfs="/tmp" \ 45 | --volume="$root:/app" \ 46 | "${project}_builder" -c "cd ./modules/contracts && $cmd" 47 | -------------------------------------------------------------------------------- /ops/upgrade-package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | package="$1" 5 | version="$2" 6 | 7 | # set sed flags so that they're valid on either linux or mac 8 | if [[ "$(uname)" == "Darwin" ]] 9 | then sedFlag=(-i '') 10 | else sedFlag=(-i) 11 | fi 12 | 13 | if [[ -z "$version" ]] 14 | then version=$(npm info "$package" version) 15 | fi 16 | 17 | if [[ -z "$package" || -z "$version" || -n "$3" ]] 18 | then echo "Usage: bash ops/upgrade-package.sh " && exit 1 19 | else echo "Setting package $package to version $version in all modules that depend on it" 20 | fi 21 | 22 | echo 23 | echo "Before:" 24 | grep -r '"'"$package"'": "' modules/*/package.json modules/*/ops/package.json package.json 25 | echo 26 | 27 | find modules/*/package.json modules/*/ops/package.json package.json \ 28 | -type f \ 29 | -not -path "*/node_modules/*" \ 30 | -not -path "*/dist/*" \ 31 | -exec sed "${sedFlag[@]}" -E 's|"'"$package"'": "[a-z0-9.^-]+"|"'"$package"'": "'"$version"'"|g' {} \; 32 | 33 | echo "After:" 34 | grep -r '"'"$package"'": "' modules/*/package.json modules/*/ops/package.json package.json 35 | echo 36 | -------------------------------------------------------------------------------- /ops/version-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd ) 5 | project=$(grep -m 1 '"name":' "$root/package.json" | cut -d '"' -f 4) 6 | 7 | # Packages that we should never report as being out-of-date: 8 | do_not_upgrade='@connext/' 9 | 10 | # Format string describing how each line looks 11 | function format { 12 | awk '{printf("| %-32s|%8s -> %-8s|\n", $1, $3, $4)}' 13 | } 14 | 15 | # Create the sed command to remove any ignored rows. 16 | # the first non-default delimiter needs to be \escaped if it's the first char 17 | filter_cmd="" 18 | for ignored in $do_not_upgrade 19 | do filter_cmd="$filter_cmd\| $ignored|d;" 20 | done 21 | 22 | echo "===== Package: $project/package.json" 23 | npm outdated -D | tail -n +2 | awk '$3 != $4' | format 24 | echo 25 | 26 | for package in modules/*/package.json modules/*/ops/package.json 27 | do 28 | cd "$(dirname "$package")" || exit 1 29 | echo "===== Package: $project/$(dirname "$package")/package.json" 30 | mv package.json package.json.backup 31 | sed /@connext/d < package.json.backup > package.json 32 | npm outdated | tail -n +2 | awk '$3 != $4' | format 33 | echo "-----" 34 | npm outdated -D | tail -n +2 | awk '$3 != $4' | format 35 | rm package.json 36 | mv package.json.backup package.json 37 | cd "$root" || exit 1 38 | echo 39 | done 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vector", 3 | "version": "0.2.5-beta.21", 4 | "description": "Vector is an ultra-minimal state channel implementation that borrows ideas from the Counterfactual framework, the v1 Connext Payment Channel Hub, and the StateChannels framework.", 5 | "registry": "docker.io/connextproject", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/connext/vector.git" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "bugs": { 14 | "url": "https://github.com/connext/vector/issues" 15 | }, 16 | "homepage": "https://github.com/connext/vector#readme", 17 | "devDependencies": { 18 | "@typescript-eslint/eslint-plugin": "4.16.1", 19 | "@typescript-eslint/parser": "4.16.1", 20 | "cypress": "^6.5.0", 21 | "eslint": "7.21.0", 22 | "eslint-config-prettier": "8.1.0", 23 | "eslint-plugin-import": "2.22.1", 24 | "eslint-plugin-prettier": "3.3.1", 25 | "lerna": "4.0.0", 26 | "pino-pretty": "4.6.0" 27 | }, 28 | "dependencies": { 29 | "g": "2.0.1", 30 | "node-ts": "5.1.1", 31 | "nodemon": "2.0.7", 32 | "ts-node": "9.1.1", 33 | "typescript": "4.2.4" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "allowSyntheticDefaultImports": true, 5 | "declaration": true, 6 | "declarationMap": true, 7 | "emitDecoratorMetadata": true, 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "lib": ["es2017", "dom", "esnext.asynciterable", "ES2019"], 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "noImplicitAny": false, 15 | "noImplicitReturns": true, 16 | "noLib": false, 17 | "noUnusedLocals": false, 18 | "noUnusedParameters": false, 19 | "removeComments": true, 20 | "resolveJsonModule": true, 21 | "skipLibCheck": true, 22 | "sourceMap": true, 23 | "strict": true, 24 | "target": "es2017", 25 | "typeRoots": ["./node_modules/@types"] 26 | } 27 | } 28 | --------------------------------------------------------------------------------