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