├── .env.example ├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── Makefile ├── README.md ├── abis ├── Allowlist.abi ├── BackupRecovery.abi ├── ContractResolver.abi ├── DevKeyDeriver.abi ├── DomainWalletOracle.abi ├── DomainWalletRegistry.abi ├── IKeyDeriver.abi ├── KeyDeriver.abi ├── LITToken.abi ├── Multisender.abi ├── PKPHelper.abi ├── PKPNFT.abi ├── PKPNFTMetadata.abi ├── PKPPermissions.abi ├── PaymentDelegation.abi ├── PubkeyRouter.abi ├── RateLimitNFT.abi ├── ReleaseRegister.abi ├── Staking.abi ├── StakingBalances.abi ├── WLIT.abi ├── copyAbis.ts └── generated.ts ├── ci └── anvil │ ├── Dockerfile │ ├── README.md │ └── start_anvil.sh ├── contracts ├── domain-wallets │ ├── DomainWalletRegistry.sol │ └── DomainWalletRegistry │ │ ├── DomainWalletRegistryFacet.sol │ │ ├── DomainWalletRegistryViewsFacet.sol │ │ └── LibDomainWalletRegistryStorage.sol ├── facets │ ├── DiamondCutFacet.sol │ ├── DiamondLoupeFacet.sol │ ├── DiamondLoupeFacetNoERC165.sol │ └── OwnershipFacet.sol ├── interfaces │ ├── IDiamond.sol │ ├── IDiamondCut.sol │ ├── IDiamondLoupe.sol │ ├── IERC165.sol │ └── IERC173.sol ├── libraries │ └── LibDiamond.sol ├── lit-core │ ├── ContractResolver.sol │ └── ReleaseRegister.sol ├── lit-node │ ├── Allowlist.sol │ ├── BackupRecovery.sol │ ├── BackupRecovery │ │ ├── BackupRecoveryFacet.sol │ │ ├── BackupRecoveryNodeStatusFacet.sol │ │ ├── BackupRecoveryTestFacet.sol │ │ ├── BackupRecoveryViewFacet.sol │ │ └── LibBackupRecoveryStorage.sol │ ├── HDKeyDeriver.sol │ ├── LITToken.sol │ ├── Multisender.sol │ ├── PKPHelper.sol │ ├── PKPHelperV2.sol │ ├── PKPNFT.sol │ ├── PKPNFT │ │ ├── LibPKPNFTStorage.sol │ │ └── PKPNFTFacet.sol │ ├── PKPNFTMetadata.sol │ ├── PKPPermissions.sol │ ├── PKPPermissions │ │ ├── LibPKPPermissionsStorage.sol │ │ └── PKPPermissionsFacet.sol │ ├── PaymentDelegation.sol │ ├── PaymentDelegation │ │ ├── LibPaymentDelegationStorage.sol │ │ └── PaymentDelegationFacet.sol │ ├── PubkeyRouter.sol │ ├── PubkeyRouter │ │ ├── LibPubkeyRouterStorage.sol │ │ └── PubkeyRouterFacet.sol │ ├── RateLimitNFT.sol │ ├── RateLimitNFT │ │ ├── LibRateLimitNFTStorage.sol │ │ ├── RateLimitNFTFacet.sol │ │ └── RateLimitNFTViewsFacet.sol │ ├── Staking.sol │ ├── Staking │ │ ├── LibStakingStorage.sol │ │ ├── StakingFacet.sol │ │ ├── StakingVersionFacet.sol │ │ └── StakingViewsFacet.sol │ ├── StakingBalances.sol │ ├── StakingBalances │ │ ├── LibStakingBalancesStorage.sol │ │ └── StakingBalancesFacet.sol │ └── WLIT.sol └── upgradeInitializers │ ├── DiamondInit.sol │ └── DiamondMultiInit.sol ├── copy_contracts_from_monorepo.sh ├── foundry.toml ├── gas_costs.txt ├── hardhat.config.ts ├── package-lock.json ├── package.json ├── scripts ├── add_to_allowlist.js ├── admin │ └── changeOwners.js ├── commsKeyPrivateToPublic.js ├── constants.ts ├── count_all_pkp_mints_from_all_contracts.js ├── count_nft_mints_from_specific_contract.js ├── createFreeMint.js ├── deploy.ts ├── deployAndSetReleaseRegisterRoles.js ├── deployConfig │ ├── askDeployConfig.ts │ ├── common.ts │ ├── configs │ │ └── ci-config.json │ ├── deployCoreConfig.ts │ ├── deployNodeConfig.ts │ ├── getDeployConfig.ts │ ├── index.ts │ └── models.ts ├── deployContract.ts ├── deployDiamond.ts ├── deployDiamondContract.ts ├── deployInit.sh ├── deployLITToken.js ├── deployLitCore.ts ├── deployOneContract.js ├── deployWithConfig.ts ├── deploy_PKP_and_Router.js ├── deploy_all.js ├── deploy_all_celo.js ├── deploy_lit_node_contracts.js ├── diamondContracts │ ├── .gitignore │ ├── README.md │ ├── appendDiamondCutManifest.ts │ ├── diamondCut.ts │ ├── lib │ │ ├── diamondCutManifest.ts │ │ ├── removeFacet.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── removeFacet.ts │ └── tryReplaceAllFacets.ts ├── fundAndMintWallets.js ├── fundAndStakeNodes.ts ├── generate_wallet_and_add_as_alias.ts ├── generate_wallet_and_add_as_alias_manifest.template.json ├── ipfsIdToAllowlistHash.js ├── ipfsIdToBytes.js ├── lockValidators.ts ├── mint_all_pkps.js ├── multisend.js ├── newProv.js ├── postDeploy.ts ├── pubkeyToRoutingData.js ├── rejoinAllNodes.ts ├── replaceContractResolver.ts ├── requestToJoin.ts ├── requestToLeave.ts ├── sample-script.js ├── set_epoch_state_restore.ts ├── set_ip_addresses_in_staking_contract.js ├── start_remixd_for_localhost.sh ├── update_recovery_party.ts ├── utils.ts ├── verifyOnChain.sh └── walletsAndStaking │ ├── getNodeInfo.js │ ├── getNodeVersions.js │ ├── newWallet.js │ ├── requestToJoinFromWallet.js │ ├── stakeFromWallet.js │ └── utils │ ├── join.js │ └── stake.js ├── tenderly.yaml ├── test ├── domain-wallets │ └── DomainWalletRegistry.ts ├── lit-core │ ├── ContractResolver.js │ └── ReleaseRegister.js └── lit-node │ ├── Allowlist.js │ ├── BackupRecovery.js │ ├── LITToken.js │ ├── PKPHelper.js │ ├── PKPNFT.js │ ├── PKPPermissions.js │ ├── PaymentDelegation.js │ ├── PubkeyRouter.js │ ├── RateLimitNFT.js │ └── Staking.js ├── tsconfig.json ├── utils ├── contract.ts ├── index.js └── index.ts └── wagmi.config.ts /.env.example: -------------------------------------------------------------------------------- 1 | # API Key to communicate with IPFS gateways 2 | IPFS_API_KEY=your_api_key -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Hardhat tests 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [16.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - run: yarn 24 | - run: yarn test 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | #Hardhat files 4 | cache 5 | artifacts 6 | .deps 7 | lit_config*env 8 | wallets 9 | alias_node_configs 10 | node_configs 11 | .DS_Store 12 | deployments 13 | deployed*contracts-temp.json 14 | scripts/deployConfig/configs/* 15 | scripts/generate_wallet_and_add_as_alias_manifest.json 16 | 17 | # IDEs 18 | *.iml 19 | .idea 20 | *.gz 21 | *.core 22 | yarn-error.log 23 | npm-*.log 24 | typechain-types 25 | 26 | anvil.log 27 | 28 | .env* 29 | !.env*.example 30 | networkContext.json 31 | 32 | abis/*.json -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | artifacts 2 | cache 3 | wallets 4 | .prettierrc* 5 | *.json 6 | *.yaml 7 | typechain-types -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "endOfLine": "lf", 5 | "htmlWhitespaceSensitivity": "css", 6 | "insertPragma": false, 7 | "singleAttributePerLine": false, 8 | "bracketSameLine": false, 9 | "jsxBracketSameLine": false, 10 | "jsxSingleQuote": false, 11 | "printWidth": 80, 12 | "proseWrap": "preserve", 13 | "quoteProps": "as-needed", 14 | "requirePragma": false, 15 | "semi": true, 16 | "singleQuote": true, 17 | "tabWidth": 2, 18 | "trailingComma": "es5", 19 | "useTabs": false, 20 | "vueIndentScriptAndStyle": false, 21 | "overrides": [ 22 | { 23 | "files": "*.sol", 24 | "options": { 25 | "printWidth": 80, 26 | "tabWidth": 4, 27 | "useTabs": false, 28 | "singleQuote": false, 29 | "bracketSpacing": true, 30 | "parser": "solidity-parse" 31 | } 32 | }, { 33 | "files": "*.md", 34 | "options": { 35 | "tabWidth": 2, 36 | "parser": "markdown" 37 | } 38 | } 39 | ], 40 | "parser": "babel-ts" 41 | } 42 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | run-test: 2 | pkill -9 anvil || true 3 | anvil -a 10 > anvil.log 2>&1 & 4 | npm run test:ci -------------------------------------------------------------------------------- /abis/DevKeyDeriver.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "inputs": [ 9 | { 10 | "internalType": "bytes32", 11 | "name": "derivedKeyId", 12 | "type": "bytes32" 13 | }, 14 | { 15 | "components": [ 16 | { 17 | "internalType": "bytes", 18 | "name": "pubkey", 19 | "type": "bytes" 20 | }, 21 | { 22 | "internalType": "uint256", 23 | "name": "keyType", 24 | "type": "uint256" 25 | } 26 | ], 27 | "internalType": "struct IPubkeyRouter.RootKey[]", 28 | "name": "rootHDKeys", 29 | "type": "tuple[]" 30 | }, 31 | { 32 | "internalType": "uint256", 33 | "name": "keyType", 34 | "type": "uint256" 35 | } 36 | ], 37 | "name": "computeHDPubKey", 38 | "outputs": [ 39 | { 40 | "internalType": "bool", 41 | "name": "", 42 | "type": "bool" 43 | }, 44 | { 45 | "internalType": "bytes", 46 | "name": "", 47 | "type": "bytes" 48 | } 49 | ], 50 | "stateMutability": "view", 51 | "type": "function" 52 | } 53 | ] 54 | -------------------------------------------------------------------------------- /abis/IKeyDeriver.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "bytes32", 6 | "name": "derivedKeyId", 7 | "type": "bytes32" 8 | }, 9 | { 10 | "components": [ 11 | { 12 | "internalType": "bytes", 13 | "name": "pubkey", 14 | "type": "bytes" 15 | }, 16 | { 17 | "internalType": "uint256", 18 | "name": "keyType", 19 | "type": "uint256" 20 | } 21 | ], 22 | "internalType": "struct IPubkeyRouter.RootKey[]", 23 | "name": "rootHDKeys", 24 | "type": "tuple[]" 25 | }, 26 | { 27 | "internalType": "uint256", 28 | "name": "keyType", 29 | "type": "uint256" 30 | } 31 | ], 32 | "name": "computeHDPubKey", 33 | "outputs": [ 34 | { 35 | "internalType": "bool", 36 | "name": "", 37 | "type": "bool" 38 | }, 39 | { 40 | "internalType": "bytes", 41 | "name": "", 42 | "type": "bytes" 43 | } 44 | ], 45 | "stateMutability": "view", 46 | "type": "function" 47 | } 48 | ] 49 | -------------------------------------------------------------------------------- /abis/KeyDeriver.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "inputs": [], 9 | "name": "HD_KDF", 10 | "outputs": [ 11 | { 12 | "internalType": "address", 13 | "name": "", 14 | "type": "address" 15 | } 16 | ], 17 | "stateMutability": "view", 18 | "type": "function" 19 | }, 20 | { 21 | "inputs": [ 22 | { 23 | "internalType": "bytes32", 24 | "name": "derivedKeyId", 25 | "type": "bytes32" 26 | }, 27 | { 28 | "components": [ 29 | { 30 | "internalType": "bytes", 31 | "name": "pubkey", 32 | "type": "bytes" 33 | }, 34 | { 35 | "internalType": "uint256", 36 | "name": "keyType", 37 | "type": "uint256" 38 | } 39 | ], 40 | "internalType": "struct IPubkeyRouter.RootKey[]", 41 | "name": "rootHDKeys", 42 | "type": "tuple[]" 43 | }, 44 | { 45 | "internalType": "uint256", 46 | "name": "keyType", 47 | "type": "uint256" 48 | } 49 | ], 50 | "name": "computeHDPubKey", 51 | "outputs": [ 52 | { 53 | "internalType": "bool", 54 | "name": "", 55 | "type": "bool" 56 | }, 57 | { 58 | "internalType": "bytes", 59 | "name": "", 60 | "type": "bytes" 61 | } 62 | ], 63 | "stateMutability": "view", 64 | "type": "function" 65 | } 66 | ] 67 | -------------------------------------------------------------------------------- /abis/Multisender.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "previousOwner", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "newOwner", 15 | "type": "address" 16 | } 17 | ], 18 | "name": "OwnershipTransferred", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [], 23 | "name": "owner", 24 | "outputs": [ 25 | { 26 | "internalType": "address", 27 | "name": "", 28 | "type": "address" 29 | } 30 | ], 31 | "stateMutability": "view", 32 | "type": "function" 33 | }, 34 | { 35 | "inputs": [], 36 | "name": "renounceOwnership", 37 | "outputs": [], 38 | "stateMutability": "nonpayable", 39 | "type": "function" 40 | }, 41 | { 42 | "inputs": [ 43 | { 44 | "internalType": "address[]", 45 | "name": "_recipients", 46 | "type": "address[]" 47 | } 48 | ], 49 | "name": "sendEth", 50 | "outputs": [], 51 | "stateMutability": "payable", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [ 56 | { 57 | "internalType": "address[]", 58 | "name": "_recipients", 59 | "type": "address[]" 60 | }, 61 | { 62 | "internalType": "address", 63 | "name": "tokenContract", 64 | "type": "address" 65 | } 66 | ], 67 | "name": "sendTokens", 68 | "outputs": [], 69 | "stateMutability": "nonpayable", 70 | "type": "function" 71 | }, 72 | { 73 | "inputs": [ 74 | { 75 | "internalType": "address", 76 | "name": "newOwner", 77 | "type": "address" 78 | } 79 | ], 80 | "name": "transferOwnership", 81 | "outputs": [], 82 | "stateMutability": "nonpayable", 83 | "type": "function" 84 | }, 85 | { 86 | "inputs": [], 87 | "name": "withdraw", 88 | "outputs": [], 89 | "stateMutability": "nonpayable", 90 | "type": "function" 91 | }, 92 | { 93 | "inputs": [ 94 | { 95 | "internalType": "address", 96 | "name": "tokenContract", 97 | "type": "address" 98 | } 99 | ], 100 | "name": "withdrawTokens", 101 | "outputs": [], 102 | "stateMutability": "nonpayable", 103 | "type": "function" 104 | } 105 | ] 106 | -------------------------------------------------------------------------------- /abis/PKPNFTMetadata.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_resolver", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "enum ContractResolver.Env", 11 | "name": "_env", 12 | "type": "uint8" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [ 20 | { 21 | "internalType": "bytes", 22 | "name": "buffer", 23 | "type": "bytes" 24 | } 25 | ], 26 | "name": "bytesToHex", 27 | "outputs": [ 28 | { 29 | "internalType": "string", 30 | "name": "", 31 | "type": "string" 32 | } 33 | ], 34 | "stateMutability": "pure", 35 | "type": "function" 36 | }, 37 | { 38 | "inputs": [], 39 | "name": "contractResolver", 40 | "outputs": [ 41 | { 42 | "internalType": "contract ContractResolver", 43 | "name": "", 44 | "type": "address" 45 | } 46 | ], 47 | "stateMutability": "view", 48 | "type": "function" 49 | }, 50 | { 51 | "inputs": [], 52 | "name": "env", 53 | "outputs": [ 54 | { 55 | "internalType": "enum ContractResolver.Env", 56 | "name": "", 57 | "type": "uint8" 58 | } 59 | ], 60 | "stateMutability": "view", 61 | "type": "function" 62 | }, 63 | { 64 | "inputs": [ 65 | { 66 | "internalType": "uint256", 67 | "name": "tokenId", 68 | "type": "uint256" 69 | } 70 | ], 71 | "name": "removeProfileForPkp", 72 | "outputs": [], 73 | "stateMutability": "nonpayable", 74 | "type": "function" 75 | }, 76 | { 77 | "inputs": [ 78 | { 79 | "internalType": "uint256", 80 | "name": "tokenId", 81 | "type": "uint256" 82 | } 83 | ], 84 | "name": "removeUrlForPKP", 85 | "outputs": [], 86 | "stateMutability": "nonpayable", 87 | "type": "function" 88 | }, 89 | { 90 | "inputs": [ 91 | { 92 | "internalType": "uint256", 93 | "name": "tokenId", 94 | "type": "uint256" 95 | }, 96 | { 97 | "internalType": "string", 98 | "name": "imgUrl", 99 | "type": "string" 100 | } 101 | ], 102 | "name": "setProfileForPKP", 103 | "outputs": [], 104 | "stateMutability": "nonpayable", 105 | "type": "function" 106 | }, 107 | { 108 | "inputs": [ 109 | { 110 | "internalType": "uint256", 111 | "name": "tokenId", 112 | "type": "uint256" 113 | }, 114 | { 115 | "internalType": "string", 116 | "name": "url", 117 | "type": "string" 118 | } 119 | ], 120 | "name": "setUrlForPKP", 121 | "outputs": [], 122 | "stateMutability": "nonpayable", 123 | "type": "function" 124 | }, 125 | { 126 | "inputs": [ 127 | { 128 | "internalType": "uint256", 129 | "name": "tokenId", 130 | "type": "uint256" 131 | }, 132 | { 133 | "internalType": "bytes", 134 | "name": "pubKey", 135 | "type": "bytes" 136 | }, 137 | { 138 | "internalType": "address", 139 | "name": "ethAddress", 140 | "type": "address" 141 | } 142 | ], 143 | "name": "tokenURI", 144 | "outputs": [ 145 | { 146 | "internalType": "string", 147 | "name": "", 148 | "type": "string" 149 | } 150 | ], 151 | "stateMutability": "view", 152 | "type": "function" 153 | } 154 | ] 155 | -------------------------------------------------------------------------------- /ci/anvil/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the latest foundry image 2 | FROM ghcr.io/lit-protocol/foundry 3 | 4 | COPY ./start_anvil.sh ./start_anvil.sh 5 | RUN chmod +x ./start_anvil.sh 6 | 7 | EXPOSE 8545 8 | 9 | # Define service as up when anvil is listening. 10 | HEALTHCHECK --interval=5s --timeout=3s \ 11 | CMD grep 'Listening on 0.0.0.0:8545' anvil.log 12 | 13 | # Start the anvil server with 10 accounts 14 | ENTRYPOINT ["./start_anvil.sh"] -------------------------------------------------------------------------------- /ci/anvil/README.md: -------------------------------------------------------------------------------- 1 | # Build 2 | 3 | ```bash 4 | docker build . -t anvil 5 | ``` 6 | 7 | # Run 8 | 9 | ```bash 10 | docker run anvil 11 | ``` 12 | 13 | # Debug 14 | 15 | ```bash 16 | docker exec -it /bin/sh 17 | ``` 18 | -------------------------------------------------------------------------------- /ci/anvil/start_anvil.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | anvil -a 10 --host 0.0.0.0 > anvil.log 2>&1 -------------------------------------------------------------------------------- /contracts/domain-wallets/DomainWalletRegistry.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 5 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 6 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 7 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 8 | 9 | import { LibDomainWalletRegistryStorage } from "./DomainWalletRegistry/LibDomainWalletRegistryStorage.sol"; 10 | 11 | // When no function exists for function called 12 | error FunctionNotFound(bytes4 _functionSelector); 13 | 14 | struct ConstructorArgs { 15 | address owner; 16 | address init; 17 | bytes initCalldata; 18 | address contractResolver; 19 | ContractResolver.Env env; 20 | } 21 | 22 | contract DomainWalletRegistry { 23 | constructor( 24 | IDiamondCut.FacetCut[] memory _diamondCut, 25 | ConstructorArgs memory _args 26 | ) payable { 27 | LibDiamond.setContractOwner(_args.owner); 28 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 29 | 30 | LibDomainWalletRegistryStorage.getStorage().domainCharLimit = 32; 31 | // Code can be added here to perform actions and set state variables. 32 | LibDomainWalletRegistryStorage 33 | .getStorage() 34 | .contractResolver = ContractResolver(_args.contractResolver); 35 | LibDomainWalletRegistryStorage.getStorage().env = _args.env; 36 | } 37 | 38 | // Find facet for function that is called and execute the 39 | // function if a facet is found and return any value. 40 | fallback() external payable { 41 | LibDiamond.DiamondStorage storage ds; 42 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 43 | // get diamond storage 44 | assembly { 45 | ds.slot := position 46 | } 47 | // get facet from function selector 48 | address facet = ds 49 | .facetAddressAndSelectorPosition[msg.sig] 50 | .facetAddress; 51 | if (facet == address(0)) { 52 | revert FunctionNotFound(msg.sig); 53 | } 54 | // Execute external function from facet using delegatecall and return any value. 55 | assembly { 56 | // copy function selector and any arguments 57 | calldatacopy(0, 0, calldatasize()) 58 | // execute function call using the facet 59 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 60 | // get any return value 61 | returndatacopy(0, 0, returndatasize()) 62 | // return any return value or error back to the caller 63 | switch result 64 | case 0 { 65 | revert(0, returndatasize()) 66 | } 67 | default { 68 | return(0, returndatasize()) 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /contracts/domain-wallets/DomainWalletRegistry/DomainWalletRegistryViewsFacet.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 5 | import { LibDomainWalletRegistryStorage } from "./LibDomainWalletRegistryStorage.sol"; 6 | 7 | contract DomainWalletRegistryViewsFacet { 8 | /* ========== ERRORS ========== */ 9 | error DomainAlreadyRegistered(bytes uri, uint256 pkpTokenId); 10 | 11 | /* ========== VIEWS ========== */ 12 | 13 | function getStorage() 14 | internal 15 | pure 16 | returns ( 17 | LibDomainWalletRegistryStorage.DomainWalletRegistryStorage storage 18 | ) 19 | { 20 | return LibDomainWalletRegistryStorage.getStorage(); 21 | } 22 | 23 | function getDomainCharacterLimit() public view returns (uint) { 24 | return getStorage().domainCharLimit; 25 | } 26 | 27 | function getDomainWalletRegistryAddress() public view returns (address) { 28 | return 29 | getStorage().contractResolver.getContract( 30 | getStorage().contractResolver.DOMAIN_WALLET_REGISTRY(), 31 | getStorage().env 32 | ); 33 | } 34 | 35 | function getPkpHelperAddress() public view returns (address) { 36 | return 37 | getStorage().contractResolver.getContract( 38 | getStorage().contractResolver.PKP_HELPER_CONTRACT(), 39 | getStorage().env 40 | ); 41 | } 42 | 43 | function getPkpTokenId(uint64 id) public view returns (uint256) { 44 | return 45 | getStorage() 46 | .pkpOwners[getStorage().domainWallets[id].pkpTokenId] 47 | .pkpTokenId; 48 | } 49 | 50 | function getDomainIdByTokenId( 51 | uint256 pkpTokenId 52 | ) public view returns (uint64) { 53 | return getStorage().pkpOwners[pkpTokenId].id; 54 | } 55 | 56 | function isOwner(uint256 pkpTokenId) public view returns (bool) { 57 | return getStorage().pkpOwners[pkpTokenId].isRegistered; 58 | } 59 | 60 | function isRouted(uint256 pkpTokenId) public view returns (bool) { 61 | return getStorage().pkpOwners[pkpTokenId].isRegistered; 62 | } 63 | 64 | function hasOwner(uint256 pkpTokenId) public view returns (bool) { 65 | return getStorage().pkpOwners[pkpTokenId].isRegistered; 66 | } 67 | 68 | function getDomainTokenIdByUri( 69 | bytes memory uri 70 | ) public view returns (uint256) { 71 | return getStorage().ownerLookup[uri]; 72 | } 73 | 74 | function getDomainUri( 75 | uint256 pkpTokenId 76 | ) public view returns (bytes memory) { 77 | return getStorage().pkpOwners[pkpTokenId].uri; 78 | } 79 | 80 | function getExpiration(uint256 pkpTokenId) public view returns (uint) { 81 | return getStorage().pkpOwners[pkpTokenId].ttl; 82 | } 83 | 84 | function getRecord(uint256 pkpTokenId) public view returns (bytes memory) { 85 | return getStorage().pkpOwners[pkpTokenId].cname; 86 | } 87 | 88 | function checkRegistration(bytes memory uri) public view { 89 | if (getStorage().ownerLookup[uri] != 0) { 90 | revert DomainAlreadyRegistered(uri, getStorage().ownerLookup[uri]); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /contracts/domain-wallets/DomainWalletRegistry/LibDomainWalletRegistryStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 5 | 6 | struct DomainWallet { 7 | bytes user_id; 8 | uint64 id; 9 | uint256 pkpTokenId; 10 | bytes uri; 11 | uint ttl; 12 | bool isWallet; 13 | bool isRegistered; 14 | bytes cname; 15 | } 16 | 17 | library LibDomainWalletRegistryStorage { 18 | bytes32 constant DOMAIN_WALLET_REGISTRY_POSITION = 19 | keccak256("domainwalletregistry.storage"); 20 | 21 | struct DomainWalletRegistryStorage { 22 | ContractResolver contractResolver; 23 | ContractResolver.Env env; 24 | // id to domain wallet instance 25 | mapping(uint64 => DomainWallet) domainWallets; 26 | // pkpTokenId to DomainWallet 27 | mapping(uint256 => DomainWallet) pkpOwners; 28 | // mapping of domain to tokenId for look ups 29 | mapping(bytes => uint256) ownerLookup; 30 | // counter for tracking registrations 31 | uint64 idCounter; 32 | //tracks max characters allowed in a domain name, set in the constructor 33 | uint domainCharLimit; 34 | } 35 | 36 | // Return storage struct for reading and writing 37 | function getStorage() 38 | internal 39 | pure 40 | returns (DomainWalletRegistryStorage storage storageStruct) 41 | { 42 | bytes32 position = DOMAIN_WALLET_REGISTRY_POSITION; 43 | assembly { 44 | storageStruct.slot := position 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/facets/DiamondCutFacet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | /******************************************************************************/ 8 | 9 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 10 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 11 | 12 | // Remember to add the loupe functions from DiamondLoupeFacet to the diamond. 13 | // The loupe functions are required by the EIP2535 Diamonds standard 14 | 15 | contract DiamondCutFacet is IDiamondCut { 16 | /// @notice Add/replace/remove any number of functions and optionally execute 17 | /// a function with delegatecall 18 | /// @param _diamondCut Contains the facet addresses and function selectors 19 | /// @param _init The address of the contract or facet to execute _calldata 20 | /// @param _calldata A function call, including function selector and arguments 21 | /// _calldata is executed with delegatecall on _init 22 | function diamondCut( 23 | FacetCut[] calldata _diamondCut, 24 | address _init, 25 | bytes calldata _calldata 26 | ) external override { 27 | LibDiamond.enforceIsContractOwner(); 28 | LibDiamond.diamondCut(_diamondCut, _init, _calldata); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/facets/OwnershipFacet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 5 | import { IERC173 } from "../interfaces/IERC173.sol"; 6 | 7 | contract OwnershipFacet is IERC173 { 8 | function transferOwnership(address _newOwner) external override { 9 | LibDiamond.enforceIsContractOwner(); 10 | LibDiamond.setContractOwner(_newOwner); 11 | } 12 | 13 | function owner() external view override returns (address owner_) { 14 | owner_ = LibDiamond.contractOwner(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/IDiamond.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | /******************************************************************************/ 8 | 9 | interface IDiamond { 10 | enum FacetCutAction { 11 | Add, 12 | Replace, 13 | Remove 14 | } 15 | // Add=0, Replace=1, Remove=2 16 | 17 | struct FacetCut { 18 | address facetAddress; 19 | FacetCutAction action; 20 | bytes4[] functionSelectors; 21 | } 22 | 23 | event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/interfaces/IDiamondCut.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | /******************************************************************************/ 8 | 9 | import { IDiamond } from "./IDiamond.sol"; 10 | 11 | interface IDiamondCut is IDiamond { 12 | /// @notice Add/replace/remove any number of functions and optionally execute 13 | /// a function with delegatecall 14 | /// @param _diamondCut Contains the facet addresses and function selectors 15 | /// @param _init The address of the contract or facet to execute _calldata 16 | /// @param _calldata A function call, including function selector and arguments 17 | /// _calldata is executed with delegatecall on _init 18 | function diamondCut( 19 | FacetCut[] calldata _diamondCut, 20 | address _init, 21 | bytes calldata _calldata 22 | ) external; 23 | } 24 | -------------------------------------------------------------------------------- /contracts/interfaces/IDiamondLoupe.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | /******************************************************************************/ 8 | 9 | // A loupe is a small magnifying glass used to look at diamonds. 10 | // These functions look at diamonds 11 | interface IDiamondLoupe { 12 | /// These functions are expected to be called frequently 13 | /// by tools. 14 | 15 | struct Facet { 16 | address facetAddress; 17 | bytes4[] functionSelectors; 18 | } 19 | 20 | /// @notice Gets all facet addresses and their four byte function selectors. 21 | /// @return facets_ Facet 22 | function facets() external view returns (Facet[] memory facets_); 23 | 24 | /// @notice Gets all the function selectors supported by a specific facet. 25 | /// @param _facet The facet address. 26 | /// @return facetFunctionSelectors_ 27 | function facetFunctionSelectors( 28 | address _facet 29 | ) external view returns (bytes4[] memory facetFunctionSelectors_); 30 | 31 | /// @notice Get all the facet addresses used by a diamond. 32 | /// @return facetAddresses_ 33 | function facetAddresses() 34 | external 35 | view 36 | returns (address[] memory facetAddresses_); 37 | 38 | /// @notice Gets the facet that supports the given selector. 39 | /// @dev If facet is not found return address(0). 40 | /// @param _functionSelector The function selector. 41 | /// @return facetAddress_ The facet address. 42 | function facetAddress( 43 | bytes4 _functionSelector 44 | ) external view returns (address facetAddress_); 45 | } 46 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC165.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | interface IERC165 { 5 | /// @notice Query if a contract implements an interface 6 | /// @param interfaceId The interface identifier, as specified in ERC-165 7 | /// @dev Interface identification is specified in ERC-165. This function 8 | /// uses less than 30,000 gas. 9 | /// @return `true` if the contract implements `interfaceID` and 10 | /// `interfaceID` is not 0xffffffff, `false` otherwise 11 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC173.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /// @title ERC-173 Contract Ownership Standard 5 | /// Note: the ERC-165 identifier for this interface is 0x7f5828d0 6 | /* is ERC165 */ 7 | interface IERC173 { 8 | /// @dev This emits when ownership of a contract changes. 9 | event OwnershipTransferred( 10 | address indexed previousOwner, 11 | address indexed newOwner 12 | ); 13 | 14 | /// @notice Get the address of the owner 15 | /// @return owner_ The address of the owner. 16 | function owner() external view returns (address owner_); 17 | 18 | /// @notice Set the address of the new owner of the contract 19 | /// @dev Set _newOwner to address(0) to renounce any ownership. 20 | /// @param _newOwner The address of the new owner of the contract 21 | function transferOwnership(address _newOwner) external; 22 | } 23 | -------------------------------------------------------------------------------- /contracts/lit-node/Allowlist.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; 5 | import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 6 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 7 | 8 | import "hardhat/console.sol"; 9 | 10 | contract Allowlist is Ownable, ReentrancyGuard { 11 | using EnumerableSet for EnumerableSet.AddressSet; 12 | 13 | /* ========== STATE VARIABLES ========== */ 14 | 15 | mapping(bytes32 => bool) public allowedItems; 16 | EnumerableSet.AddressSet admins; 17 | bool public allowAll; 18 | 19 | /* ========== CONSTRUCTOR ========== */ 20 | constructor() { 21 | admins.add(msg.sender); 22 | } 23 | 24 | /* ========== VIEWS ========== */ 25 | 26 | function isAllowed(bytes32 key) external view returns (bool) { 27 | if (allowAll) { 28 | return true; 29 | } 30 | return allowedItems[key]; 31 | } 32 | 33 | /* ========== MUTATIVE FUNCTIONS ========== */ 34 | 35 | function setAllowed(bytes32 key) external { 36 | require(admins.contains(msg.sender), "Not an admin"); 37 | allowedItems[key] = true; 38 | emit ItemAllowed(key); 39 | } 40 | 41 | function setNotAllowed(bytes32 key) external { 42 | require(admins.contains(msg.sender), "Not an admin"); 43 | allowedItems[key] = false; 44 | emit ItemNotAllowed(key); 45 | } 46 | 47 | function addAdmin(address newAdmin) public onlyOwner { 48 | admins.add(newAdmin); 49 | emit AdminAdded(newAdmin); 50 | } 51 | 52 | function removeAdmin(address newAdmin) public onlyOwner { 53 | admins.remove(newAdmin); 54 | emit AdminRemoved(newAdmin); 55 | } 56 | 57 | function setAllowAll(bool _allowAll) public onlyOwner { 58 | allowAll = _allowAll; 59 | } 60 | 61 | /* ========== EVENTS ========== */ 62 | 63 | event ItemAllowed(bytes32 indexed key); 64 | event ItemNotAllowed(bytes32 indexed key); 65 | event AdminAdded(address indexed newAdmin); 66 | event AdminRemoved(address indexed newAdmin); 67 | } 68 | -------------------------------------------------------------------------------- /contracts/lit-node/BackupRecovery.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 15 | import { IPubkeyRouter } from "../lit-node/PubkeyRouter/LibPubkeyRouterStorage.sol"; 16 | import { Staking } from "../lit-node/Staking.sol"; 17 | import { StakingViewsFacet } from "./Staking/StakingViewsFacet.sol"; 18 | import { LibStakingStorage } from "./Staking/LibStakingStorage.sol"; 19 | import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; 20 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 21 | import { LibBackupRecoveryStorage } from "./BackupRecovery/LibBackupRecoveryStorage.sol"; 22 | 23 | // When no function exists for function called 24 | error FunctionNotFound(bytes4 _functionSelector); 25 | 26 | // This is used in diamond constructor 27 | // more arguments are added to this struct 28 | // this avoids stack too deep errors 29 | struct BackupRecoveryArgs { 30 | address owner; 31 | address init; 32 | bytes initCalldata; 33 | address contractResolver; 34 | ContractResolver.Env env; 35 | } 36 | 37 | contract BackupRecovery { 38 | /* ========== CONSTRUCTOR ========== */ 39 | constructor( 40 | IDiamondCut.FacetCut[] memory _diamondCut, 41 | BackupRecoveryArgs memory _args 42 | ) { 43 | LibDiamond.setContractOwner(_args.owner); 44 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 45 | ContractResolver resolver = ContractResolver(_args.contractResolver); 46 | LibBackupRecoveryStorage.getStorage().resolver = resolver; 47 | LibBackupRecoveryStorage.getStorage().env = _args.env; 48 | // Current verification version: 1 49 | LibBackupRecoveryStorage.getStorage().verificationVersion = bytes1( 50 | 0x01 51 | ); 52 | } 53 | 54 | // Find facet for function that is called and execute the 55 | // function if a facet is found and return any value. 56 | fallback() external payable { 57 | LibDiamond.DiamondStorage storage ds; 58 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 59 | // get diamond storage 60 | assembly { 61 | ds.slot := position 62 | } 63 | // get facet from function selector 64 | address facet = ds 65 | .facetAddressAndSelectorPosition[msg.sig] 66 | .facetAddress; 67 | if (facet == address(0)) { 68 | revert FunctionNotFound(msg.sig); 69 | } 70 | // Execute external function from facet using delegatecall and return any value. 71 | assembly { 72 | // copy function selector and any arguments 73 | calldatacopy(0, 0, calldatasize()) 74 | // execute function call using the facet 75 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 76 | // get any return value 77 | returndatacopy(0, 0, returndatasize()) 78 | // return any return value or error back to the caller 79 | switch result 80 | case 0 { 81 | revert(0, returndatasize()) 82 | } 83 | default { 84 | return(0, returndatasize()) 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/lit-node/BackupRecovery/BackupRecoveryNodeStatusFacet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 5 | import { LibBackupRecoveryStorage } from "./LibBackupRecoveryStorage.sol"; 6 | import { StakingViewsFacet } from "./../Staking/StakingViewsFacet.sol"; 7 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 8 | import "hardhat/console.sol"; 9 | import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; 10 | 11 | contract BackupRecoveryNodeStatusFacet { 12 | uint256 public constant CURRENT = 0; 13 | 14 | function s() 15 | internal 16 | pure 17 | returns (LibBackupRecoveryStorage.BackupRecoveryStorage storage) 18 | { 19 | return LibBackupRecoveryStorage.getStorage(); 20 | } 21 | 22 | /** 23 | * @dev 24 | * Registers the status of the node 25 | */ 26 | function setNodeRecoveryStatus( 27 | LibBackupRecoveryStorage.NodeRecoveryStatus status 28 | ) external { 29 | require( 30 | checkValidatorSetForAddress(msg.sender), 31 | "BackupRecovery: not a member of the validator set" 32 | ); 33 | 34 | for (uint256 i = 0; i < s().nodeStatusMap[CURRENT].length; i++) { 35 | if (s().nodeStatusMap[CURRENT][i].node_address == msg.sender) { 36 | s().nodeStatusMap[CURRENT][i].status = status; 37 | return; 38 | } 39 | } 40 | 41 | s().nodeStatusMap[CURRENT].push( 42 | LibBackupRecoveryStorage.NodeRecoveryStatusMap(msg.sender, status) 43 | ); 44 | } 45 | 46 | /** 47 | * @dev 48 | * Reports the recovery status of the nodes 49 | */ 50 | function getNodeRecoveryStatus() 51 | external 52 | view 53 | returns (LibBackupRecoveryStorage.NodeRecoveryStatusMap[] memory) 54 | { 55 | return s().nodeStatusMap[CURRENT]; 56 | } 57 | 58 | /** 59 | * @dev 60 | * Clears the recovery status of the nodes after the recovery 61 | */ 62 | function clearNodeRecoveryStatus() external { 63 | require( 64 | msg.sender == LibDiamond.contractOwner(), 65 | "BackupRecovery: caller not the admin" 66 | ); 67 | 68 | delete s().nodeStatusMap[CURRENT]; 69 | } 70 | 71 | function getStakingViewFacet() internal view returns (StakingViewsFacet) { 72 | address stakingAddress = s().resolver.getContract( 73 | s().resolver.STAKING_CONTRACT(), 74 | s().env 75 | ); 76 | return StakingViewsFacet(stakingAddress); 77 | } 78 | 79 | function checkValidatorSetForAddress( 80 | address sender 81 | ) internal view returns (bool) { 82 | address[] memory validators = getStakingViewFacet() 83 | .getValidatorsInCurrentEpoch(); 84 | 85 | for (uint256 i = 0; i < validators.length; i++) { 86 | address stakerAddressOfSender = getStakingViewFacet() 87 | .nodeAddressToStakerAddress(sender); 88 | if (validators[i] == stakerAddressOfSender) { 89 | return true; 90 | } 91 | } 92 | 93 | return false; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/lit-node/BackupRecovery/BackupRecoveryTestFacet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import { LibBackupRecoveryStorage } from "./LibBackupRecoveryStorage.sol"; 5 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 6 | import "hardhat/console.sol"; 7 | import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; 8 | 9 | contract BackupRecoveryTestFacet { 10 | function s() 11 | internal 12 | pure 13 | returns (LibBackupRecoveryStorage.BackupRecoveryStorage storage) 14 | { 15 | return LibBackupRecoveryStorage.getStorage(); 16 | } 17 | 18 | /** 19 | * @dev 20 | * Sets the contract state by registering a new set of backup members 21 | */ 22 | function setBackupPartyState( 23 | bytes calldata bls12381G1EncKey, 24 | bytes calldata secp256K1EcdsaPubKey, 25 | address[] calldata partyMembers 26 | ) public { 27 | require( 28 | partyMembers.length > 1, 29 | "BackupRecovery: cannot vote for empty party set" 30 | ); 31 | 32 | // Set a mock state 33 | s().recoveryState[0].bls12381G1EncKey = bls12381G1EncKey; 34 | s().recoveryState[0].secp256K1EcdsaPubKey = secp256K1EcdsaPubKey; 35 | if (partyMembers.length == 2) { 36 | s().recoveryState[0].partyThreshold = 2; 37 | } else { 38 | s().recoveryState[0].partyThreshold = (partyMembers.length * 2) / 3; 39 | } 40 | s().recoveryState[0].sessionId = "Test_session_id"; 41 | s().recoveryState[0].partyMembers = partyMembers; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/lit-node/BackupRecovery/BackupRecoveryViewFacet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | import { LibBackupRecoveryStorage } from "./LibBackupRecoveryStorage.sol"; 4 | import { StakingViewsFacet } from "./../Staking/StakingViewsFacet.sol"; 5 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 6 | import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; 7 | 8 | contract BackupRecoveryViewFacet { 9 | function getNonSubmitingBackupMembersInNextState() 10 | public 11 | view 12 | returns (address[] memory missingRecoveryMembers) 13 | { 14 | LibBackupRecoveryStorage.NextState 15 | storage nextState = LibBackupRecoveryStorage.getStorage().nextState[ 16 | 0 17 | ]; 18 | 19 | // Alloc the size of the whole backup party set on the stack 20 | // this allows us to not use sotrage and keep the method view 21 | // the returned array will contained zeroized elements for the indexes in 22 | // the array which map to the parties position in their storage array. 23 | address[] memory nonRegisteredPartyMembers = new address[]( 24 | nextState.partyMembers.length 25 | ); 26 | for (uint256 i = 0; i < nextState.partyMembers.length; i++) { 27 | if (!nextState.keysRecieved[nextState.partyMembers[i]]) { 28 | nonRegisteredPartyMembers[i] = nextState.partyMembers[i]; 29 | } 30 | } 31 | 32 | return nonRegisteredPartyMembers; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/lit-node/BackupRecovery/LibBackupRecoveryStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { IPubkeyRouter } from "../../lit-node/PubkeyRouter/LibPubkeyRouterStorage.sol"; 6 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 7 | import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; 8 | 9 | library LibBackupRecoveryStorage { 10 | using EnumerableSet for EnumerableSet.AddressSet; 11 | bytes32 constant BACKUP_RECOVERY_POSITION = 12 | keccak256("backuprecovery.storage"); 13 | 14 | /** 15 | * @dev 16 | * Simply maps a backup party member to the node that generated their backup share 17 | */ 18 | struct RecoveryPair { 19 | address backupPartyAddress; 20 | address nodeAddress; 21 | bool isRegistered; 22 | } 23 | 24 | /** 25 | * @dev 26 | * Holds the current backup party state 27 | */ 28 | struct BackupRecoveryState { 29 | bytes sessionId; 30 | bytes bls12381G1EncKey; 31 | bytes secp256K1EcdsaPubKey; 32 | uint256 partyThreshold; 33 | address[] partyMembers; 34 | } 35 | 36 | struct RecoveryKey { 37 | bytes pubkey; 38 | uint256 keyType; // 1 = BLS, 2 = ECDSA. Not doing this in an enum so we can add more keytypes in the future without redeploying. 39 | } 40 | 41 | /** 42 | * @dev 43 | * Holds the votes per Recovery pubKey 44 | */ 45 | struct VotesToRegisterRecoveryKey { 46 | uint256 votes; 47 | mapping(address => bool) voted; 48 | } 49 | 50 | /** 51 | * @dev 52 | * Holds the next state of the backup party 53 | */ 54 | struct NextState { 55 | address[] partyMembers; 56 | mapping(address => address) peerToBackupMemberMapping; 57 | uint nodesAssignedCount; 58 | mapping(address => address) backupMemberPeerMapping; 59 | mapping(address => bool) keysRecieved; 60 | mapping(address => K256Proof) proofsRecieved; 61 | // pubkey -> votes 62 | mapping(bytes => VotesToRegisterRecoveryKey) votesToRegisterRecoveryKeys; 63 | RecoveryKey[] registeredRecoveryKeys; 64 | bytes sessionId; 65 | bytes encryptedBlsKey; 66 | uint256 partyThreshold; 67 | bytes pubkey; 68 | bytes curve; 69 | } 70 | 71 | struct K256Proof { 72 | bytes1 version; 73 | uint256 timestamp; 74 | bytes1 particpantId; 75 | bytes schnorrProof; 76 | bytes schnorrVerification; 77 | bytes ecdsaProof; 78 | bytes ecdsaVerificationKey; 79 | } 80 | 81 | struct NextStateDownloadable { 82 | address[] partyMembers; 83 | RecoveryKey[] registeredRecoveryKeys; 84 | } 85 | 86 | struct BackupRecoveryStorage { 87 | bytes1 verificationVersion; 88 | // current state of the backup recovery 89 | mapping(uint256 => BackupRecoveryState) recoveryState; 90 | // holds the next party state until promoted to active 91 | mapping(uint256 => NextState) nextState; 92 | // holds past states after a new backup party is registered 93 | mapping(bytes => BackupRecoveryState) pastBackupStates; 94 | // proof submission mapping 95 | mapping(address => uint256[]) submittedProofs; 96 | // instance of the deployed contract resolver 97 | ContractResolver resolver; 98 | // env context 99 | ContractResolver.Env env; 100 | // Status of the recovering nodes 101 | mapping(uint256 => NodeRecoveryStatusMap[]) nodeStatusMap; 102 | } 103 | 104 | function getStorage() 105 | internal 106 | pure 107 | returns (BackupRecoveryStorage storage storageStruct) 108 | { 109 | bytes32 position = BACKUP_RECOVERY_POSITION; 110 | assembly { 111 | storageStruct.slot := position 112 | } 113 | } 114 | 115 | enum NodeRecoveryStatus { 116 | Null, 117 | StartedInRestoreState, 118 | BackupsAreLoaded, 119 | AllKeysAreRestored, 120 | AbandonedRecoveryDueToNetworkState 121 | } 122 | 123 | struct NodeRecoveryStatusMap { 124 | address node_address; 125 | NodeRecoveryStatus status; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /contracts/lit-node/HDKeyDeriver.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity ^0.8.17; 4 | import { IPubkeyRouter } from "./PubkeyRouter/LibPubkeyRouterStorage.sol"; 5 | 6 | abstract contract IKeyDeriver { 7 | function computeHDPubKey( 8 | bytes32 derivedKeyId, 9 | IPubkeyRouter.RootKey[] memory rootHDKeys, 10 | uint256 keyType 11 | ) public view virtual returns (bool, bytes memory); 12 | } 13 | 14 | contract KeyDeriver is IKeyDeriver { 15 | // address for HD public KDF 16 | address public constant HD_KDF = 0x00000000000000000000000000000000000000F5; 17 | // hd kdf ctx 18 | string constant HD_KDF_CTX = "LIT_HD_KEY_ID_K256_XMD:SHA-256_SSWU_RO_NUL_"; 19 | 20 | constructor() {} 21 | 22 | function computeHDPubKey( 23 | bytes32 derivedKeyId, 24 | IPubkeyRouter.RootKey[] memory rootHDKeys, 25 | uint256 keyType 26 | ) public view override returns (bool, bytes memory) { 27 | bytes memory args = _buildArgs(derivedKeyId, rootHDKeys, keyType); 28 | (bool success, bytes memory data) = HD_KDF.staticcall(args); 29 | return (success, data); 30 | } 31 | 32 | function _buildArgs( 33 | bytes32 derivedKeyId, 34 | IPubkeyRouter.RootKey[] memory rootHDKeys, 35 | uint256 keyType 36 | ) internal pure returns (bytes memory) { 37 | // empty array for concating pubkeys 38 | bytes memory rootPubkeys = new bytes(0); 39 | uint32 numRootPubkeys = 0; 40 | for (uint256 i = 0; i < rootHDKeys.length; i++) { 41 | if (rootHDKeys[i].keyType == keyType) { 42 | rootPubkeys = abi.encodePacked( 43 | rootPubkeys, 44 | rootHDKeys[i].pubkey 45 | ); 46 | numRootPubkeys++; 47 | } 48 | } 49 | 50 | // so in Lit land, we use 2 for ECDSA secp256k1 keyType. 51 | // but the precompile expects 1 for secp256k1 52 | // someday, we may add keyType 3 for ECDSA p256, which the precompile expects as "0" 53 | if (keyType == 2) { 54 | keyType = 1; 55 | // assuming p256 curve type will be value '3' 56 | } else if (keyType == 3) { 57 | keyType = 0; 58 | } 59 | 60 | bytes memory CTX = bytes(HD_KDF_CTX); 61 | bytes1 kt = bytes1(uint8(keyType)); 62 | bytes4 id_len = bytes4(uint32(derivedKeyId.length)); 63 | bytes4 ctx_len = bytes4(uint32(CTX.length)); 64 | bytes4 pubkey_len = bytes4(numRootPubkeys); 65 | 66 | bytes memory args_bytes = abi.encodePacked( 67 | kt, // 1st arg is a byte for the curve type, 0 is Nist Prime256, 1 is secp256k1 68 | id_len, // 2nd arg is a 4 byte big-endian integer for the number of bytes in id 69 | derivedKeyId, // 3rd arg is the byte sequence for id 70 | ctx_len, // 4th arg is a 4 byte big-endian integer for the number of bytes in cxt 71 | CTX, // 5th arg is the byte sequence for cxt 72 | pubkey_len, // 6th arg is a 4 byte big-endian integer for the number of root keys 73 | rootPubkeys // 7th arg is a variable number of root keys each 33 bytes (compressed) or 65 bytes (uncompressed) in length 74 | ); 75 | 76 | return args_bytes; 77 | } 78 | } 79 | 80 | contract DevKeyDeriver is IKeyDeriver { 81 | constructor() {} 82 | 83 | function computeHDPubKey( 84 | bytes32 derivedKeyId, 85 | IPubkeyRouter.RootKey[] memory rootHDKeys, 86 | uint256 keyType 87 | ) public view override returns (bool, bytes memory) { 88 | // TODO: This is a temporary fix for lack of precompiles in test enviorments 89 | // this is a non ideal as it does not truly exercise our KDF 90 | // reference for followup refactor: https://linear.app/litprotocol/issue/LIT-1192/add-precompiles-to-anvil-through-forked-version-of-revm 91 | 92 | bytes 93 | memory pubkey = hex"047c3647345020536e8aaccac7f73c5248bf3609677997fb615c290cc58e8ac1dcad1fa1d4f6eedf516f023dee11fbc06310434c5a7ee40f5f8c49e255b1d1bfb6"; 94 | return (true, pubkey); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /contracts/lit-node/Multisender.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; 5 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | // This contract does one thing, simply. it allows you to send eth or tokens to multiple recipients. Useful for setting up a testnet and funding all the validators and stakers. 8 | 9 | contract Multisender is Ownable { 10 | function sendEth(address[] calldata _recipients) public payable { 11 | uint256 val = msg.value / _recipients.length; 12 | for (uint256 i = 0; i < _recipients.length; i++) { 13 | payable(_recipients[i]).transfer(val); 14 | } 15 | } 16 | 17 | function sendTokens( 18 | address[] calldata _recipients, 19 | address tokenContract 20 | ) public { 21 | ERC20 tkn = ERC20(tokenContract); 22 | uint256 bal = tkn.balanceOf(address(this)); 23 | uint256 val = bal / _recipients.length; 24 | for (uint256 i = 0; i < _recipients.length; i++) { 25 | tkn.transfer(_recipients[i], val); 26 | } 27 | } 28 | 29 | function withdraw() public onlyOwner { 30 | payable(msg.sender).transfer(address(this).balance); 31 | } 32 | 33 | function withdrawTokens(address tokenContract) public onlyOwner { 34 | ERC20 tkn = ERC20(tokenContract); 35 | uint256 bal = tkn.balanceOf(address(this)); 36 | tkn.transfer(msg.sender, bal); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contracts/lit-node/PKPNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 17 | 18 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 19 | import { LibPKPNFTStorage } from "./PKPNFT/LibPKPNFTStorage.sol"; 20 | 21 | // When no function exists for function called 22 | error FunctionNotFound(bytes4 _functionSelector); 23 | 24 | // This is used in diamond constructor 25 | // more arguments are added to this struct 26 | // this avoids stack too deep errors 27 | struct StakingArgs { 28 | address owner; 29 | address init; 30 | bytes initCalldata; 31 | address contractResolver; 32 | ContractResolver.Env env; 33 | } 34 | 35 | contract PKPNFT { 36 | constructor( 37 | IDiamondCut.FacetCut[] memory _diamondCut, 38 | StakingArgs memory _args 39 | ) payable { 40 | LibDiamond.setContractOwner(_args.owner); 41 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 42 | 43 | // Code can be added here to perform actions and set state variables. 44 | LibPKPNFTStorage.getStorage().contractResolver = ContractResolver( 45 | _args.contractResolver 46 | ); 47 | LibPKPNFTStorage.getStorage().env = _args.env; 48 | 49 | LibPKPNFTStorage.getStorage().mintCost = 1; // 1 wei 50 | LibPKPNFTStorage.getStorage().freeMintSigner = _args.owner; 51 | } 52 | 53 | // Find facet for function that is called and execute the 54 | // function if a facet is found and return any value. 55 | fallback() external payable { 56 | LibDiamond.DiamondStorage storage ds; 57 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 58 | // get diamond storage 59 | assembly { 60 | ds.slot := position 61 | } 62 | // get facet from function selector 63 | address facet = ds 64 | .facetAddressAndSelectorPosition[msg.sig] 65 | .facetAddress; 66 | if (facet == address(0)) { 67 | revert FunctionNotFound(msg.sig); 68 | } 69 | // Execute external function from facet using delegatecall and return any value. 70 | assembly { 71 | // copy function selector and any arguments 72 | calldatacopy(0, 0, calldatasize()) 73 | // execute function call using the facet 74 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 75 | // get any return value 76 | returndatacopy(0, 0, returndatasize()) 77 | // return any return value or error back to the caller 78 | switch result 79 | case 0 { 80 | revert(0, returndatasize()) 81 | } 82 | default { 83 | return(0, returndatasize()) 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /contracts/lit-node/PKPNFT/LibPKPNFTStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; 6 | import "solidity-bytes-utils/contracts/BytesLib.sol"; 7 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 8 | import { IPubkeyRouter } from "../PubkeyRouter/LibPubkeyRouterStorage.sol"; 9 | 10 | library LibPKPNFTStorage { 11 | using EnumerableSet for EnumerableSet.AddressSet; 12 | 13 | bytes32 constant PKP_NFT_POSITION = keccak256("pkpnft.storage"); 14 | 15 | struct ClaimMaterial { 16 | uint256 keyType; 17 | bytes32 derivedKeyId; 18 | IPubkeyRouter.Signature[] signatures; 19 | } 20 | 21 | struct PKPNFTStorage { 22 | ContractResolver contractResolver; 23 | ContractResolver.Env env; 24 | uint256 mintCost; 25 | address freeMintSigner; 26 | mapping(uint256 => bool) redeemedFreeMintIds; 27 | } 28 | 29 | // Return ERC721 storage struct for reading and writing 30 | function getStorage() 31 | internal 32 | pure 33 | returns (PKPNFTStorage storage storageStruct) 34 | { 35 | bytes32 position = PKP_NFT_POSITION; 36 | assembly { 37 | storageStruct.slot := position 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/lit-node/PKPPermissions.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | 17 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 18 | import { LibPKPPermissionsStorage } from "./PKPPermissions/LibPKPPermissionsStorage.sol"; 19 | 20 | // When no function exists for function called 21 | error FunctionNotFound(bytes4 _functionSelector); 22 | 23 | // This is used in diamond constructor 24 | // more arguments are added to this struct 25 | // this avoids stack too deep errors 26 | struct PKPPermissionsArgs { 27 | address owner; 28 | address init; 29 | bytes initCalldata; 30 | address contractResolver; 31 | ContractResolver.Env env; 32 | } 33 | 34 | contract PKPPermissions { 35 | constructor( 36 | IDiamondCut.FacetCut[] memory _diamondCut, 37 | PKPPermissionsArgs memory _args 38 | ) payable { 39 | LibDiamond.setContractOwner(_args.owner); 40 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 41 | 42 | // Code can be added here to perform actions and set state variables. 43 | LibPKPPermissionsStorage 44 | .getStorage() 45 | .contractResolver = ContractResolver(_args.contractResolver); 46 | LibPKPPermissionsStorage.getStorage().env = _args.env; 47 | } 48 | 49 | // Find facet for function that is called and execute the 50 | // function if a facet is found and return any value. 51 | fallback() external { 52 | LibDiamond.DiamondStorage storage ds; 53 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 54 | // get diamond storage 55 | assembly { 56 | ds.slot := position 57 | } 58 | // get facet from function selector 59 | address facet = ds 60 | .facetAddressAndSelectorPosition[msg.sig] 61 | .facetAddress; 62 | if (facet == address(0)) { 63 | revert FunctionNotFound(msg.sig); 64 | } 65 | // Execute external function from facet using delegatecall and return any value. 66 | assembly { 67 | // copy function selector and any arguments 68 | calldatacopy(0, 0, calldatasize()) 69 | // execute function call using the facet 70 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 71 | // get any return value 72 | returndatacopy(0, 0, returndatasize()) 73 | // return any return value or error back to the caller 74 | switch result 75 | case 0 { 76 | revert(0, returndatasize()) 77 | } 78 | default { 79 | return(0, returndatasize()) 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /contracts/lit-node/PKPPermissions/LibPKPPermissionsStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; 6 | import "solidity-bytes-utils/contracts/BytesLib.sol"; 7 | 8 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 9 | 10 | library LibPKPPermissionsStorage { 11 | using EnumerableSet for EnumerableSet.AddressSet; 12 | using EnumerableSet for EnumerableSet.Bytes32Set; 13 | using EnumerableSet for EnumerableSet.UintSet; 14 | using BytesLib for bytes; 15 | using BitMaps for BitMaps.BitMap; 16 | 17 | bytes32 constant PKP_PERMISSIONS_POSITION = 18 | keccak256("pkppermissions.storage"); 19 | 20 | struct AuthMethod { 21 | uint256 authMethodType; // 1 = address, 2 = action, 3 = WebAuthn, 4 = Discord, 5 = Google, 6 = Google JWT, 7 = OTP, 8 = Apple JWT. Not doing this in an enum so that we can add more auth methods in the future without redeploying. 22 | bytes id; // the id of the auth method. For address, this is an eth address. For action, this is an IPFS CID. For WebAuthn, this is the credentialId. For Discord, this is the user's Discord ID. For Google, this is the user's Google ID. 23 | bytes userPubkey; // the user's pubkey. This is used for WebAuthn. 24 | } 25 | 26 | struct PKPPermissionsStorage { 27 | ContractResolver contractResolver; 28 | ContractResolver.Env env; 29 | // map the keccack256(uncompressed pubkey) -> set of auth methods 30 | mapping(uint256 => EnumerableSet.UintSet) permittedAuthMethods; 31 | // map the keccack256(uncompressed pubkey) -> auth_method_id -> scope id 32 | mapping(uint256 => mapping(uint256 => BitMaps.BitMap)) permittedAuthMethodScopes; 33 | // map the keccack256(authMethodType, userId) -> the actual AuthMethod struct 34 | mapping(uint256 => AuthMethod) authMethods; 35 | // map the AuthMethod hash to the pubkeys that it's allowed to sign for 36 | // this makes it possible to be given a discord id and then lookup all the pubkeys that are allowed to sign for that discord id 37 | mapping(uint256 => EnumerableSet.UintSet) authMethodToPkpIds; 38 | // map the keccack256(uncompressed pubkey) -> (group => merkle tree root hash) 39 | mapping(uint256 => mapping(uint256 => bytes32)) _rootHashes; 40 | } 41 | 42 | // Return ERC721 storage struct for reading and writing 43 | function getStorage() 44 | internal 45 | pure 46 | returns (PKPPermissionsStorage storage storageStruct) 47 | { 48 | bytes32 position = PKP_PERMISSIONS_POSITION; 49 | assembly { 50 | storageStruct.slot := position 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/lit-node/PaymentDelegation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | 15 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 16 | import { LibStakingStorage } from "./Staking/LibStakingStorage.sol"; 17 | 18 | // When no function exists for function called 19 | error FunctionNotFound(bytes4 _functionSelector); 20 | 21 | // This is used in diamond constructor 22 | // more arguments are added to this struct 23 | // this avoids stack too deep errors 24 | struct PaymentDelegationArgs { 25 | address owner; 26 | address init; 27 | bytes initCalldata; 28 | } 29 | 30 | contract PaymentDelegation { 31 | constructor( 32 | IDiamondCut.FacetCut[] memory _diamondCut, 33 | PaymentDelegationArgs memory _args 34 | ) payable { 35 | LibDiamond.setContractOwner(_args.owner); 36 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 37 | } 38 | 39 | // Find facet for function that is called and execute the 40 | // function if a facet is found and return any value. 41 | fallback() external { 42 | LibDiamond.DiamondStorage storage ds; 43 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 44 | // get diamond storage 45 | assembly { 46 | ds.slot := position 47 | } 48 | // get facet from function selector 49 | address facet = ds 50 | .facetAddressAndSelectorPosition[msg.sig] 51 | .facetAddress; 52 | if (facet == address(0)) { 53 | revert FunctionNotFound(msg.sig); 54 | } 55 | // Execute external function from facet using delegatecall and return any value. 56 | assembly { 57 | // copy function selector and any arguments 58 | calldatacopy(0, 0, calldatasize()) 59 | // execute function call using the facet 60 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 61 | // get any return value 62 | returndatacopy(0, 0, returndatasize()) 63 | // return any return value or error back to the caller 64 | switch result 65 | case 0 { 66 | revert(0, returndatasize()) 67 | } 68 | default { 69 | return(0, returndatasize()) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/lit-node/PaymentDelegation/LibPaymentDelegationStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | 6 | library LibPaymentDelegationStorage { 7 | using EnumerableSet for EnumerableSet.AddressSet; 8 | 9 | bytes32 constant PAYMENT_DELEGATION_POSITION = 10 | keccak256("payment_delegation.storage"); 11 | 12 | // this lets the app put restrictions on how much they want to pay in a given period, per user. 13 | // this is set globally for each payer, but is applied on a per user basis. 14 | // so if you had a restriction of 10 requests per 10 minutes, that means 1 million users can make 10 requests each in the 10 minute window for 10 million total requests in 10 minutes. 15 | struct Restriction { 16 | uint requestsPerPeriod; 17 | uint periodSeconds; 18 | } 19 | 20 | struct PaymentDelegationStorage { 21 | mapping(address => EnumerableSet.AddressSet) payers; // maps user wallet to payer wallet 22 | mapping(address => Restriction) restrictions; // maps payer wallet to restrictions. these are optional. 23 | mapping(address => EnumerableSet.AddressSet) users; // maps payer wallet to user wallets 24 | } 25 | 26 | // Return ERC721 storage struct for reading and writing 27 | function getStorage() 28 | internal 29 | pure 30 | returns (PaymentDelegationStorage storage storageStruct) 31 | { 32 | bytes32 position = PAYMENT_DELEGATION_POSITION; 33 | assembly { 34 | storageStruct.slot := position 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/lit-node/PaymentDelegation/PaymentDelegationFacet.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 5 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 6 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 7 | 8 | import { LibPaymentDelegationStorage } from "./LibPaymentDelegationStorage.sol"; 9 | 10 | // import "hardhat/console.sol"; 11 | 12 | contract PaymentDelegationFacet { 13 | using EnumerableSet for EnumerableSet.AddressSet; 14 | 15 | /* ========== VIEWS ========== */ 16 | function s() 17 | internal 18 | pure 19 | returns (LibPaymentDelegationStorage.PaymentDelegationStorage storage) 20 | { 21 | return LibPaymentDelegationStorage.getStorage(); 22 | } 23 | 24 | function getPayersAndRestrictions( 25 | address[] memory users 26 | ) 27 | public 28 | view 29 | returns ( 30 | address[][] memory, 31 | LibPaymentDelegationStorage.Restriction[][] memory 32 | ) 33 | { 34 | address[][] memory payers = new address[][](users.length); 35 | LibPaymentDelegationStorage.Restriction[][] 36 | memory restrictions = new LibPaymentDelegationStorage.Restriction[][]( 37 | users.length 38 | ); 39 | for (uint i = 0; i < users.length; i++) { 40 | payers[i] = s().payers[users[i]].values(); 41 | LibPaymentDelegationStorage.Restriction[] 42 | memory tempRestrictionsArray = new LibPaymentDelegationStorage.Restriction[]( 43 | payers[i].length 44 | ); 45 | for (uint j = 0; j < payers[i].length; j++) { 46 | tempRestrictionsArray[j] = s().restrictions[payers[i][j]]; 47 | } 48 | restrictions[i] = tempRestrictionsArray; 49 | } 50 | return (payers, restrictions); 51 | } 52 | 53 | function getUsers(address payer) public view returns (address[] memory) { 54 | return s().users[payer].values(); 55 | } 56 | 57 | function getRestriction( 58 | address payer 59 | ) public view returns (LibPaymentDelegationStorage.Restriction memory) { 60 | return s().restrictions[payer]; 61 | } 62 | 63 | function getPayers(address user) public view returns (address[] memory) { 64 | return s().payers[user].values(); 65 | } 66 | 67 | /* ========== MUTATIVE FUNCTIONS ========== */ 68 | function delegatePayments(address user) public { 69 | s().payers[user].add(msg.sender); // this guarantees the auth - that the payer made this txn, because msg.sender is authed. 70 | s().users[msg.sender].add(user); 71 | } 72 | 73 | function undelegatePayments(address user) public { 74 | require( 75 | s().payers[user].contains(msg.sender), 76 | "not authorized to undelegate payments" 77 | ); 78 | s().payers[user].remove(msg.sender); 79 | s().users[msg.sender].remove(user); 80 | } 81 | 82 | function delegatePaymentsBatch(address[] memory users) public { 83 | for (uint i = 0; i < users.length; i++) { 84 | s().payers[users[i]].add(msg.sender); 85 | s().users[msg.sender].add(users[i]); 86 | } 87 | } 88 | 89 | function undelegatePaymentsBatch(address[] memory users) public { 90 | for (uint i = 0; i < users.length; i++) { 91 | require( 92 | s().payers[users[i]].contains(msg.sender), 93 | "not authorized to undelegate payments" 94 | ); 95 | s().payers[users[i]].remove(msg.sender); 96 | s().users[msg.sender].remove(users[i]); 97 | } 98 | } 99 | 100 | function setRestriction( 101 | LibPaymentDelegationStorage.Restriction memory r 102 | ) public { 103 | s().restrictions[msg.sender] = r; 104 | } 105 | 106 | /* ========== EVENTS ========== */ 107 | 108 | event RestrictionSet( 109 | address indexed payer, 110 | LibPaymentDelegationStorage.Restriction restriction 111 | ); 112 | } 113 | -------------------------------------------------------------------------------- /contracts/lit-node/PubkeyRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | 17 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 18 | import { LibPubkeyRouterStorage } from "./PubkeyRouter/LibPubkeyRouterStorage.sol"; 19 | 20 | // When no function exists for function called 21 | error FunctionNotFound(bytes4 _functionSelector); 22 | 23 | // This is used in diamond constructor 24 | // more arguments are added to this struct 25 | // this avoids stack too deep errors 26 | struct PubkeyRouterArgs { 27 | address owner; 28 | address init; 29 | bytes initCalldata; 30 | address contractResolver; 31 | ContractResolver.Env env; 32 | } 33 | 34 | contract PubkeyRouter { 35 | constructor( 36 | IDiamondCut.FacetCut[] memory _diamondCut, 37 | PubkeyRouterArgs memory _args 38 | ) payable { 39 | LibDiamond.setContractOwner(_args.owner); 40 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 41 | 42 | // Code can be added here to perform actions and set state variables. 43 | LibPubkeyRouterStorage.getStorage().contractResolver = ContractResolver( 44 | _args.contractResolver 45 | ); 46 | LibPubkeyRouterStorage.getStorage().env = _args.env; 47 | } 48 | 49 | // Find facet for function that is called and execute the 50 | // function if a facet is found and return any value. 51 | fallback() external { 52 | LibDiamond.DiamondStorage storage ds; 53 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 54 | // get diamond storage 55 | assembly { 56 | ds.slot := position 57 | } 58 | // get facet from function selector 59 | address facet = ds 60 | .facetAddressAndSelectorPosition[msg.sig] 61 | .facetAddress; 62 | if (facet == address(0)) { 63 | revert FunctionNotFound(msg.sig); 64 | } 65 | // Execute external function from facet using delegatecall and return any value. 66 | assembly { 67 | // copy function selector and any arguments 68 | calldatacopy(0, 0, calldatasize()) 69 | // execute function call using the facet 70 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 71 | // get any return value 72 | returndatacopy(0, 0, returndatasize()) 73 | // return any return value or error back to the caller 74 | switch result 75 | case 0 { 76 | revert(0, returndatasize()) 77 | } 78 | default { 79 | return(0, returndatasize()) 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /contracts/lit-node/PubkeyRouter/LibPubkeyRouterStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; 6 | import "solidity-bytes-utils/contracts/BytesLib.sol"; 7 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 8 | 9 | interface IPubkeyRouter { 10 | struct RootKey { 11 | bytes pubkey; 12 | uint256 keyType; // 1 = BLS, 2 = ECDSA. Not doing this in an enum so we can add more keytypes in the future without redeploying. 13 | } 14 | 15 | struct Signature { 16 | bytes32 r; 17 | bytes32 s; 18 | uint8 v; 19 | } 20 | } 21 | 22 | library LibPubkeyRouterStorage { 23 | using EnumerableSet for EnumerableSet.AddressSet; 24 | using EnumerableSet for EnumerableSet.Bytes32Set; 25 | using EnumerableSet for EnumerableSet.UintSet; 26 | using BytesLib for bytes; 27 | using BitMaps for BitMaps.BitMap; 28 | 29 | bytes32 constant PUBKEY_ROUTER_POSITION = keccak256("pubkeyrouter.storage"); 30 | 31 | struct PubkeyRoutingData { 32 | bytes pubkey; 33 | uint256 keyType; // 1 = BLS, 2 = ECDSA. Not doing this in an enum so we can add more keytypes in the future without redeploying. 34 | bytes32 derivedKeyId; 35 | } 36 | 37 | struct VoteToRegisterRootKey { 38 | uint256 votes; 39 | mapping(address => bool) voted; 40 | } 41 | 42 | struct PubkeyRouterStorage { 43 | ContractResolver contractResolver; 44 | ContractResolver.Env env; 45 | // map staking address -> uncompressed pubkey -> VoteToRegisterRootKey 46 | mapping(address => mapping(bytes => VoteToRegisterRootKey)) votesToRegisterRootKeys; 47 | // map the keccack256(uncompressed pubkey) -> PubkeyRoutingData 48 | mapping(uint256 => PubkeyRoutingData) pubkeys; 49 | // map the eth address to a pkp id 50 | mapping(address => uint256) ethAddressToPkpId; 51 | // map staking contract to root keys 52 | mapping(address => IPubkeyRouter.RootKey[]) rootKeys; 53 | } 54 | 55 | // Return ERC721 storage struct for reading and writing 56 | function getStorage() 57 | internal 58 | pure 59 | returns (PubkeyRouterStorage storage storageStruct) 60 | { 61 | bytes32 position = PUBKEY_ROUTER_POSITION; 62 | assembly { 63 | storageStruct.slot := position 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/lit-node/RateLimitNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 17 | 18 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 19 | import { LibRateLimitNFTStorage } from "./RateLimitNFT/LibRateLimitNFTStorage.sol"; 20 | 21 | // When no function exists for function called 22 | error FunctionNotFound(bytes4 _functionSelector); 23 | 24 | // This is used in diamond constructor 25 | // more arguments are added to this struct 26 | // this avoids stack too deep errors 27 | struct StakingArgs { 28 | address owner; 29 | address init; 30 | bytes initCalldata; 31 | address contractResolver; 32 | ContractResolver.Env env; 33 | } 34 | 35 | contract RateLimitNFT { 36 | constructor( 37 | IDiamondCut.FacetCut[] memory _diamondCut, 38 | StakingArgs memory _args 39 | ) payable { 40 | LibDiamond.setContractOwner(_args.owner); 41 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 42 | 43 | // Code can be added here to perform actions and set state variables. 44 | LibRateLimitNFTStorage.getStorage().contractResolver = ContractResolver( 45 | _args.contractResolver 46 | ); 47 | LibRateLimitNFTStorage.getStorage().env = _args.env; 48 | 49 | LibRateLimitNFTStorage 50 | .getStorage() 51 | .additionalRequestsPerKilosecondCost = 1000000; // 1,000,000 wei 52 | // 24 hours in seconds 53 | LibRateLimitNFTStorage.getStorage().defaultRateLimitWindowSeconds = 54 | 60 * 55 | 60 * 56 | 24; 57 | // 24 hours in seconds 58 | LibRateLimitNFTStorage.getStorage().RLIHolderRateLimitWindowSeconds = 59 | 60 * 60 | 60 * 61 | 24; 62 | LibRateLimitNFTStorage.getStorage().freeRequestsPerRateLimitWindow = 0; 63 | LibRateLimitNFTStorage.getStorage().maxRequestsPerKilosecond = 10000; 64 | LibRateLimitNFTStorage.getStorage().maxExpirationSeconds = 2592000; // 1 month in seconds 65 | } 66 | 67 | // Find facet for function that is called and execute the 68 | // function if a facet is found and return any value. 69 | fallback() external payable { 70 | LibDiamond.DiamondStorage storage ds; 71 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 72 | // get diamond storage 73 | assembly { 74 | ds.slot := position 75 | } 76 | // get facet from function selector 77 | address facet = ds 78 | .facetAddressAndSelectorPosition[msg.sig] 79 | .facetAddress; 80 | if (facet == address(0)) { 81 | revert FunctionNotFound(msg.sig); 82 | } 83 | // Execute external function from facet using delegatecall and return any value. 84 | assembly { 85 | // copy function selector and any arguments 86 | calldatacopy(0, 0, calldatasize()) 87 | // execute function call using the facet 88 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 89 | // get any return value 90 | returndatacopy(0, 0, returndatasize()) 91 | // return any return value or error back to the caller 92 | switch result 93 | case 0 { 94 | revert(0, returndatasize()) 95 | } 96 | default { 97 | return(0, returndatasize()) 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /contracts/lit-node/RateLimitNFT/LibRateLimitNFTStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; 6 | import "solidity-bytes-utils/contracts/BytesLib.sol"; 7 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 8 | 9 | library LibRateLimitNFTStorage { 10 | using EnumerableSet for EnumerableSet.AddressSet; 11 | 12 | struct RateLimit { 13 | uint256 requestsPerKilosecond; 14 | uint256 expiresAt; 15 | } 16 | 17 | bytes32 constant RATELIMIT_NFT_POSITION = keccak256("ratelimitnft.storage"); 18 | 19 | struct RateLimitNFTStorage { 20 | ContractResolver contractResolver; 21 | ContractResolver.Env env; 22 | address freeMintSigner; 23 | uint256 additionalRequestsPerKilosecondCost; 24 | uint256 tokenIdCounter; 25 | uint256 defaultRateLimitWindowSeconds; 26 | uint256 RLIHolderRateLimitWindowSeconds; 27 | uint256 freeRequestsPerRateLimitWindow; 28 | mapping(uint256 => RateLimit) capacity; 29 | mapping(bytes32 => bool) redeemedFreeMints; 30 | uint256 maxRequestsPerKilosecond; 31 | uint256 maxExpirationSeconds; 32 | // maps midnight timestamps (divisible by 86400) to the total requests sold that will expire at that time 33 | mapping(uint256 => uint256) totalSoldRequestsPerKilosecondByExpirationTime; 34 | } 35 | 36 | // Return ERC721 storage struct for reading and writing 37 | function getStorage() 38 | internal 39 | pure 40 | returns (RateLimitNFTStorage storage storageStruct) 41 | { 42 | bytes32 position = RATELIMIT_NFT_POSITION; 43 | assembly { 44 | storageStruct.slot := position 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/lit-node/Staking/StakingVersionFacet.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 5 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 6 | import { StakingBalances } from "../StakingBalances.sol"; 7 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 8 | import { LibDiamond } from "../../libraries/LibDiamond.sol"; 9 | import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; 10 | 11 | import { LibStakingStorage } from "./LibStakingStorage.sol"; 12 | 13 | // import "hardhat/console.sol"; 14 | 15 | contract StakingVersionFacet { 16 | error CallerNotOwner(); 17 | 18 | /* ========== Modifiers ========== */ 19 | 20 | modifier onlyOwner() { 21 | if (msg.sender != LibDiamond.contractOwner()) revert CallerNotOwner(); 22 | _; 23 | } 24 | 25 | /* ========== VIEWS ========== */ 26 | 27 | function getMinVersion() 28 | external 29 | view 30 | returns (LibStakingStorage.Version memory) 31 | { 32 | return LibStakingStorage.getStorage().versionRequirements[0]; 33 | } 34 | 35 | function getMaxVersion() 36 | external 37 | view 38 | returns (LibStakingStorage.Version memory) 39 | { 40 | return LibStakingStorage.getStorage().versionRequirements[1]; 41 | } 42 | 43 | function getMinVersionString() external view returns (string memory) { 44 | LibStakingStorage.Version storage minVersion = LibStakingStorage 45 | .getStorage() 46 | .versionRequirements[0]; 47 | 48 | return 49 | string( 50 | abi.encodePacked( 51 | Strings.toString(minVersion.major), 52 | ".", 53 | Strings.toString(minVersion.minor), 54 | ".", 55 | Strings.toString(minVersion.patch) 56 | ) 57 | ); 58 | } 59 | 60 | function getMaxVersionString() external view returns (string memory) { 61 | LibStakingStorage.Version storage maxVersion = LibStakingStorage 62 | .getStorage() 63 | .versionRequirements[1]; 64 | 65 | return 66 | string( 67 | abi.encodePacked( 68 | Strings.toString(maxVersion.major), 69 | ".", 70 | Strings.toString(maxVersion.minor), 71 | ".", 72 | Strings.toString(maxVersion.patch) 73 | ) 74 | ); 75 | } 76 | 77 | /* ========== MUTATIVE FUNCTIONS ========== */ 78 | 79 | function setMinVersion( 80 | LibStakingStorage.Version memory version 81 | ) external onlyOwner { 82 | LibStakingStorage.getStorage().versionRequirements[0] = version; 83 | emit VersionRequirementsUpdated(0, version); 84 | } 85 | 86 | function setMaxVersion( 87 | LibStakingStorage.Version memory version 88 | ) external onlyOwner { 89 | LibStakingStorage.getStorage().versionRequirements[1] = version; 90 | emit VersionRequirementsUpdated(1, version); 91 | } 92 | 93 | function checkVersion( 94 | LibStakingStorage.Version memory version 95 | ) public view returns (bool) { 96 | LibStakingStorage.Version storage minVersion = LibStakingStorage 97 | .getStorage() 98 | .versionRequirements[0]; 99 | LibStakingStorage.Version storage maxVersion = LibStakingStorage 100 | .getStorage() 101 | .versionRequirements[1]; 102 | 103 | if ( 104 | (version.major > minVersion.major && 105 | version.major < maxVersion.major) || 106 | (version.major == minVersion.major && 107 | version.minor > minVersion.minor) || 108 | (version.major == maxVersion.major && 109 | version.minor < maxVersion.minor) || 110 | (version.major == minVersion.major && 111 | version.minor == minVersion.minor && 112 | version.patch >= minVersion.patch) || 113 | (version.major == maxVersion.major && 114 | version.minor == maxVersion.minor && 115 | version.patch <= maxVersion.patch) 116 | ) { 117 | return true; 118 | } else { 119 | return false; 120 | } 121 | } 122 | 123 | /* ========== EVENTS ========== */ 124 | 125 | event VersionRequirementsUpdated( 126 | uint256 index, 127 | LibStakingStorage.Version version 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /contracts/lit-node/StakingBalances.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 13 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 17 | 18 | import { ContractResolver } from "../lit-core/ContractResolver.sol"; 19 | import { LibStakingBalancesStorage } from "./StakingBalances/LibStakingBalancesStorage.sol"; 20 | 21 | // When no function exists for function called 22 | error FunctionNotFound(bytes4 _functionSelector); 23 | 24 | // This is used in diamond constructor 25 | // more arguments are added to this struct 26 | // this avoids stack too deep errors 27 | struct StakingArgs { 28 | address owner; 29 | address init; 30 | bytes initCalldata; 31 | address contractResolver; 32 | ContractResolver.Env env; 33 | } 34 | 35 | contract StakingBalances { 36 | constructor( 37 | IDiamondCut.FacetCut[] memory _diamondCut, 38 | StakingArgs memory _args 39 | ) payable { 40 | LibDiamond.setContractOwner(_args.owner); 41 | LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata); 42 | 43 | // Code can be added here to perform actions and set state variables. 44 | LibStakingBalancesStorage 45 | .getStorage() 46 | .contractResolver = ContractResolver(_args.contractResolver); 47 | LibStakingBalancesStorage.getStorage().env = _args.env; 48 | 49 | LibStakingBalancesStorage.getStorage().minimumStake = 1 * (10 ** 18); 50 | LibStakingBalancesStorage 51 | .getStorage() 52 | .maximumStake = LibStakingBalancesStorage.getStorage().minimumStake; 53 | LibStakingBalancesStorage.getStorage().maxAliasCount = 1; 54 | } 55 | 56 | // Find facet for function that is called and execute the 57 | // function if a facet is found and return any value. 58 | fallback() external payable { 59 | LibDiamond.DiamondStorage storage ds; 60 | bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION; 61 | // get diamond storage 62 | assembly { 63 | ds.slot := position 64 | } 65 | // get facet from function selector 66 | address facet = ds 67 | .facetAddressAndSelectorPosition[msg.sig] 68 | .facetAddress; 69 | if (facet == address(0)) { 70 | revert FunctionNotFound(msg.sig); 71 | } 72 | // Execute external function from facet using delegatecall and return any value. 73 | assembly { 74 | // copy function selector and any arguments 75 | calldatacopy(0, 0, calldatasize()) 76 | // execute function call using the facet 77 | let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) 78 | // get any return value 79 | returndatacopy(0, 0, returndatasize()) 80 | // return any return value or error back to the caller 81 | switch result 82 | case 0 { 83 | revert(0, returndatasize()) 84 | } 85 | default { 86 | return(0, returndatasize()) 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /contracts/lit-node/StakingBalances/LibStakingBalancesStorage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 5 | import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; 6 | import "solidity-bytes-utils/contracts/BytesLib.sol"; 7 | import { ContractResolver } from "../../lit-core/ContractResolver.sol"; 8 | 9 | library LibStakingBalancesStorage { 10 | using EnumerableSet for EnumerableSet.AddressSet; 11 | 12 | struct VoteToKickValidatorInNextEpoch { 13 | uint256 votes; 14 | mapping(address => bool) voted; 15 | } 16 | 17 | bytes32 constant STAKING_BALANCES_POSITION = 18 | keccak256("stakingbalances.storage"); 19 | 20 | struct StakingBalancesStorage { 21 | ContractResolver contractResolver; 22 | ContractResolver.Env env; 23 | mapping(address => uint256) balances; 24 | mapping(address => uint256) rewards; 25 | // allowed stakers 26 | mapping(address => bool) permittedStakers; 27 | // maps alias address to real staker address 28 | mapping(address => address) aliases; 29 | // maps staker address to alias count 30 | mapping(address => uint256) aliasCounts; 31 | uint256 minimumStake; 32 | uint256 maximumStake; 33 | uint256 totalStaked; 34 | bool permittedStakersOn; 35 | uint256 maxAliasCount; 36 | uint256 penaltyBalance; 37 | } 38 | 39 | // Return ERC721 storage struct for reading and writing 40 | function getStorage() 41 | internal 42 | pure 43 | returns (StakingBalancesStorage storage storageStruct) 44 | { 45 | bytes32 position = STAKING_BALANCES_POSITION; 46 | assembly { 47 | storageStruct.slot := position 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/lit-node/WLIT.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity ^0.8.17; 3 | 4 | contract WLIT { 5 | string public name = "Wrapped Lit"; 6 | string public symbol = "WLIT"; 7 | uint8 public decimals = 18; 8 | 9 | event Approval(address indexed src, address indexed guy, uint wad); 10 | event Transfer(address indexed src, address indexed dst, uint wad); 11 | event Deposit(address indexed dst, uint wad); 12 | event Withdrawal(address indexed src, uint wad); 13 | 14 | mapping(address => uint) public balanceOf; 15 | mapping(address => mapping(address => uint)) public allowance; 16 | 17 | fallback() external payable { 18 | deposit(); 19 | } 20 | 21 | receive() external payable { 22 | deposit(); 23 | } 24 | 25 | function deposit() public payable { 26 | balanceOf[msg.sender] += msg.value; 27 | emit Deposit(msg.sender, msg.value); 28 | } 29 | 30 | function withdraw(uint wad) public { 31 | require(balanceOf[msg.sender] >= wad); 32 | balanceOf[msg.sender] -= wad; 33 | payable(msg.sender).transfer(wad); 34 | emit Withdrawal(msg.sender, wad); 35 | } 36 | 37 | function totalSupply() public view returns (uint) { 38 | return address(this).balance; 39 | } 40 | 41 | function approve(address guy, uint wad) public returns (bool) { 42 | allowance[msg.sender][guy] = wad; 43 | emit Approval(msg.sender, guy, wad); 44 | return true; 45 | } 46 | 47 | function transfer(address dst, uint wad) public returns (bool) { 48 | return transferFrom(msg.sender, dst, wad); 49 | } 50 | 51 | function transferFrom( 52 | address src, 53 | address dst, 54 | uint wad 55 | ) public returns (bool) { 56 | require(balanceOf[src] >= wad); 57 | 58 | if ( 59 | src != msg.sender && allowance[src][msg.sender] != type(uint256).max 60 | ) { 61 | require(allowance[src][msg.sender] >= wad); 62 | allowance[src][msg.sender] -= wad; 63 | } 64 | 65 | balanceOf[src] -= wad; 66 | balanceOf[dst] += wad; 67 | 68 | emit Transfer(src, dst, wad); 69 | 70 | return true; 71 | } 72 | 73 | function burn(uint256 amount) internal virtual { 74 | transferFrom(msg.sender, address(0), amount); 75 | } 76 | 77 | function burnFrom(address account, uint256 amount) public virtual { 78 | transferFrom(account, address(0), amount); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /contracts/upgradeInitializers/DiamondInit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | import { IDiamondLoupe } from "../interfaces/IDiamondLoupe.sol"; 13 | import { IDiamondCut } from "../interfaces/IDiamondCut.sol"; 14 | import { IERC173 } from "../interfaces/IERC173.sol"; 15 | import { IERC165 } from "../interfaces/IERC165.sol"; 16 | 17 | // It is expected that this contract is customized if you want to deploy your diamond 18 | // with data from a deployment script. Use the init function to initialize state variables 19 | // of your diamond. Add parameters to the init funciton if you need to. 20 | 21 | // Adding parameters to the `init` or other functions you add here can make a single deployed 22 | // DiamondInit contract reusable accross upgrades, and can be used for multiple diamonds. 23 | 24 | contract DiamondInit { 25 | // You can add parameters to this function in order to pass in 26 | // data to set your own state variables 27 | function init() external { 28 | // adding ERC165 data 29 | LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); 30 | ds.supportedInterfaces[type(IERC165).interfaceId] = true; 31 | ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true; 32 | ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true; 33 | ds.supportedInterfaces[type(IERC173).interfaceId] = true; 34 | 35 | // add your own state variables 36 | // EIP-2535 specifies that the `diamondCut` function takes two optional 37 | // arguments: address _init and bytes calldata _calldata 38 | // These arguments are used to execute an arbitrary function using delegatecall 39 | // in order to set state variables in the diamond during deployment or an upgrade 40 | // More info here: https://eips.ethereum.org/EIPS/eip-2535#diamond-interface 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /contracts/upgradeInitializers/DiamondMultiInit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /******************************************************************************\ 5 | * Author: Nick Mudge (https://twitter.com/mudgen) 6 | * EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535 7 | * 8 | * Implementation of a diamond. 9 | /******************************************************************************/ 10 | 11 | import { LibDiamond } from "../libraries/LibDiamond.sol"; 12 | 13 | error AddressAndCalldataLengthDoNotMatch( 14 | uint256 _addressesLength, 15 | uint256 _calldataLength 16 | ); 17 | 18 | contract DiamondMultiInit { 19 | // This function is provided in the third parameter of the `diamondCut` function. 20 | // The `diamondCut` function executes this function to execute multiple initializer functions for a single upgrade. 21 | 22 | function multiInit( 23 | address[] calldata _addresses, 24 | bytes[] calldata _calldata 25 | ) external { 26 | if (_addresses.length != _calldata.length) { 27 | revert AddressAndCalldataLengthDoNotMatch( 28 | _addresses.length, 29 | _calldata.length 30 | ); 31 | } 32 | for (uint i; i < _addresses.length; i++) { 33 | LibDiamond.initializeDiamondCut(_addresses[i], _calldata[i]); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /copy_contracts_from_monorepo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rsync -avr --progress --exclude='node_modules/' --exclude='wallets' --exclude='artifacts' --include='*/' --include='*' /Users/chris/Documents/WorkStuff/LIT/lit-assets/blockchain/contracts/ ./ -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'out' 4 | libs = ['node_modules', 'lib'] 5 | test = 'test' 6 | cache_path = 'cache_forge' -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lit-assets-blockchain", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "GPL-3.0-or-later", 6 | "scripts": { 7 | "test": "npx hardhat test --network localchain | tee gas_costs.txt; npx hardhat size-contracts | tee -a gas_costs.txt", 8 | "test:ci": "LIT_SLOW_DOWN_PROVIDER=true npx hardhat test --network localchain", 9 | "compile": "npx hardhat compile", 10 | "convertPubkey": "node pubkeyToRoutingData.js", 11 | "convertIpfsId": "node ipfsIdToParts.js", 12 | "hashIpfsId": "node ipfsIdToHash.js", 13 | "prettier:check": "npx prettier --config .prettierrc.json --check .", 14 | "prettier:write": "npx prettier --config .prettierrc.json --write .", 15 | "deploy": "npx ts-node scripts/deploy.ts" 16 | }, 17 | "devDependencies": { 18 | "@nomicfoundation/hardhat-toolbox": "^3.0.0", 19 | "@openzeppelin/merkle-tree": "^1.0.1", 20 | "@types/chai": "^4.3.4", 21 | "@types/inquirer": "^8.1.0", 22 | "@types/mocha": "^10.0.1", 23 | "@types/node": "^18.15.11", 24 | "@types/yargs": "^17.0.24", 25 | "@wagmi/cli": "^2.1.4", 26 | "glob": "^10.2.1", 27 | "hardhat": "^2.20.1", 28 | "hardhat-contract-sizer": "^2.10.0", 29 | "hardhat-ethernal": "^3.2.0", 30 | "prettier": "^2.7.1", 31 | "prettier-plugin-solidity": "^1.1.3", 32 | "simple-git": "^3.24.0", 33 | "ts-node": "^10.9.1", 34 | "typescript": "^5.0.4", 35 | "yargs": "^17.7.1" 36 | }, 37 | "dependencies": { 38 | "@gnus.ai/contracts-upgradeable-diamond": "GeniusVentures/openzeppelin-contracts-diamond", 39 | "@iarna/toml": "^2.2.5", 40 | "@kingdomstudios/hardhat-diamond-abi": "^2.2.0", 41 | "@noble/ed25519": "^1.7.1", 42 | "@openzeppelin/contracts": "^4.9.6", 43 | "axios": "^1.6.2", 44 | "bs58": "^5.0.0", 45 | "dotenv": "^16.4.5", 46 | "ethers": "^6.1.0", 47 | "ethers-v5": "npm:ethers@5.7.1", 48 | "hardhat-tracer": "^2.8.1", 49 | "inquirer": "8.0.1", 50 | "solidity-bytes-utils": "^0.8.2", 51 | "tweetnacl": "^1.0.3", 52 | "uint8arrays": "3", 53 | "uuid": "^8.3.2" 54 | }, 55 | "resolutions": { 56 | "ethereumjs-abi": "0.6.5" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /scripts/add_to_allowlist.js: -------------------------------------------------------------------------------- 1 | /* This file is not completed yet, since the private key for the allowlist admin 2 | * lives in metamask. This is probably almost working though 3 | */ 4 | const hre = require('hardhat'); 5 | const fs = require('fs'); 6 | var spawn = require('child_process').spawn; 7 | const { getBytesFromMultihash } = require('../utils'); 8 | const { ethers } = hre; 9 | const chainName = hre.network.name; 10 | const rpcUrl = hre.network.config.url; 11 | 12 | async function getChainId() { 13 | const { chainId } = await ethers.provider.getNetwork(); 14 | return chainId; 15 | } 16 | 17 | const getSigner = async () => { 18 | const [deployer] = await ethers.getSigners(); 19 | return deployer; 20 | }; 21 | 22 | async function main() { 23 | const signer = await getSigner(); 24 | 25 | const rl = require('readline').createInterface({ 26 | input: process.stdin, 27 | output: process.stdout, 28 | }); 29 | 30 | const allowlistContractAddress = await new Promise((resolve) => { 31 | rl.question('What is the Allowlist contract address? ', resolve); 32 | }); 33 | 34 | let ipfsId = await new Promise((resolve) => { 35 | rl.question('What is the IPFS CID? ', resolve); 36 | }); 37 | 38 | // convert the ipfsId to bytes 39 | const ipfsIdBytes = getBytesFromMultihash(ipfsId); 40 | 41 | const allowlistContract = await ethers.getContractAt( 42 | 'Allowlist', 43 | allowlistContractAddress, 44 | signer 45 | ); 46 | 47 | const addTx = await allowlistContract.setAllowed(ipfsIdBytes); 48 | console.log('Success!'); 49 | process.exit(0); 50 | } 51 | 52 | // We recommend this pattern to be able to use async/await everywhere 53 | // and properly handle errors. 54 | main().catch((error) => { 55 | console.error(error); 56 | process.exitCode = 1; 57 | }); 58 | -------------------------------------------------------------------------------- /scripts/commsKeyPrivateToPublic.js: -------------------------------------------------------------------------------- 1 | const nacl = require('tweetnacl'); 2 | const { fromString } = require('uint8arrays/from-string'); 3 | const { toString } = require('uint8arrays/to-string'); 4 | 5 | async function main() { 6 | const rl = require('readline').createInterface({ 7 | input: process.stdin, 8 | output: process.stdout, 9 | }); 10 | 11 | const secretKey = await new Promise((resolve) => { 12 | rl.question( 13 | 'What is the comms key private key you wish to make into a public key? ', 14 | resolve 15 | ); 16 | }); 17 | 18 | const keys = nacl.box.keyPair.fromSecretKey(fromString(secretKey, 'base16')); 19 | console.log('Public key: ', toString(keys.publicKey, 'base16')); 20 | } 21 | 22 | // We recommend this pattern to be able to use async/await everywhere 23 | // and properly handle errors. 24 | main() 25 | .then(() => { 26 | process.exit(0); 27 | }) 28 | .catch((error) => { 29 | console.error(error); 30 | process.exit(1); 31 | }); 32 | -------------------------------------------------------------------------------- /scripts/constants.ts: -------------------------------------------------------------------------------- 1 | export const CONTRACT_NAME_TO_JSON_CONTRACT_ADDRESS_KEY = { 2 | Staking: 'stakingContractAddress', 3 | Multisender: 'multisenderContractAddress', 4 | LITToken: 'litTokenContractAddress', 5 | AccessControlConditions: 'accessControlConditionsContractAddress', 6 | PubkeyRouter: 'pubkeyRouterContractAddress', 7 | PKPNFT: 'pkpNftContractAddress', 8 | RateLimitNFT: 'rateLimitNftContractAddress', 9 | PKPHelper: 'pkpHelperContractAddress', 10 | PKPPermissions: 'pkpPermissionsContractAddress', 11 | PKPNFTMetadata: 'pkpNftMetadataContractAddress', 12 | Allowlist: 'allowlistContractAddress', 13 | ContractResolver: 'resolverContractAddress', 14 | DomainWalletRegistry: 'domainWalletRegistryAddress', 15 | KeyDeriver: 'KeyDeriverAddress', 16 | PaymentDelegation: 'paymentDelegationAddress', 17 | }; 18 | 19 | export const CONTRACT_NAME_TO_DIAMOND_ABI_PATH = { 20 | Staking: 21 | '../artifacts/hardhat-diamond-abi/StakingDiamond.sol/StakingDiamond.json', 22 | PKPPermissions: 23 | '../artifacts/hardhat-diamond-abi/PKPPermissionsDiamond.sol/PKPPermissionsDiamond.json', 24 | PubkeyRouter: 25 | '../artifacts/hardhat-diamond-abi/PubkeyRouterDiamond.sol/PubkeyRouterDiamond.json', 26 | RateLimitNFT: 27 | '../artifacts/hardhat-diamond-abi/RateLimitNFTDiamond.sol/RateLimitNFTDiamond.json', 28 | StakingBalances: 29 | '../artifacts/hardhat-diamond-abi/StakingBalancesDiamond.sol/StakingBalancesDiamond.json', 30 | PKPNFT: 31 | '../artifacts/hardhat-diamond-abi/PKPNFTDiamond.sol/PKPNFTDiamond.json', 32 | DomainWalletRegistry: 33 | '../artifacts/hardhat-diamond-abi/DomainWalletRegistryDiamond.sol/DomainWalletRegistryDiamond.json', 34 | PaymentDelegation: 35 | '../artifacts/hardhat-diamond-abi/PaymentDelegationDiamond.sol/PaymentDelegationDiamond.json', 36 | }; 37 | -------------------------------------------------------------------------------- /scripts/createFreeMint.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('ethers'); 2 | const uuid = require('uuid'); 3 | 4 | const PKP_CONTRACT_ADDRESS = '0x6A275664C0d1789A59a8f8141A21409a1508a2f7'; 5 | 6 | const go = async () => { 7 | const walletJson = JSON.parse(process.env.LIT_FREE_MINT_KEY); 8 | 9 | const wallet = new ethers.Wallet(walletJson.privateKey); 10 | 11 | const freeMintId = ethers.hexlify(uuid.parse(uuid.v4())); 12 | 13 | // sign for real 14 | const toSign = ethers.solidityPackedKeccak256( 15 | ['address', 'uint256'], 16 | [PKP_CONTRACT_ADDRESS, freeMintId] 17 | ); 18 | let sig = await wallet.signMessage(ethers.getBytes(toSign)); 19 | console.log('sig', sig); 20 | 21 | const r = sig.slice(0, 66); 22 | const s = '0x' + sig.slice(66, 130); 23 | const v = '0x' + sig.slice(130, 132); 24 | 25 | console.log('r: ', r); 26 | console.log('s: ', s); 27 | console.log('v: ', v); 28 | 29 | const msgHash = ethers.solidityPackedKeccak256( 30 | ['string', 'bytes32'], 31 | ['\x19Ethereum Signed Message:\n32', toSign] 32 | ); 33 | 34 | console.log( 35 | `Now Call pkpContract.freeMintNext(2, ${freeMintId}, ${msgHash}, ${v}, ${r}, ${s})` 36 | ); 37 | }; 38 | 39 | go(); 40 | -------------------------------------------------------------------------------- /scripts/deploy.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process'; 2 | import yargs from 'yargs/yargs'; 3 | import { getDeployConfig, readDeployConfig } from './deployConfig'; 4 | import { waitForProcessToExit } from './utils'; 5 | 6 | const SUPPORTED_NETWORKS = [ 7 | 'celo', 8 | 'mumbai', 9 | 'alfajores', 10 | 'polygon', 11 | 'litTestnet', 12 | 'lit', 13 | 'localchain', 14 | 'etna', 15 | ]; 16 | 17 | const networkToRequiredEnvVars: { [key: string]: string[] } = { 18 | celo: ['LIT_CELOSCAN_API_KEY,LIT_CELO_DEPLOYER_PRIVATE_KEY'], 19 | mumbai: ['LIT_POLYGONSCAN_API_KEY,LIT_MUMBAI_DEPLOYER_PRIVATE_KEY'], 20 | alfajores: ['LIT_ALFAJORES_DEPLOYER_PRIVATE_KEY'], 21 | polygon: ['LIT_POLYGONSCAN_API_KEY,LIT_POLYGON_DEPLOYER_PRIVATE_KEY'], 22 | litTestnet: ['LIT_ROLLUP_TESTNET_DEPLOYER_PRIVATE_KEY'], 23 | lit: ['LIT_ROLLUP_MAINNET_DEPLOYER_PRIVATE_KEY'], 24 | etna: ['LIT_ROLLUP_MAINNET_DEPLOYER_PRIVATE_KEY'], 25 | }; 26 | 27 | async function run() { 28 | console.info('Loading environment variables'); 29 | require('dotenv').config(); 30 | 31 | console.log('Running deploy script'); 32 | // Check if there is --deploy-config option passed. 33 | const argv = await yargs(process.argv.slice(2)).options({ 34 | deployConfig: { type: 'string' }, 35 | network: { 36 | type: 'string', 37 | choices: SUPPORTED_NETWORKS, 38 | }, 39 | verbose: { 40 | type: 'boolean', 41 | alias: 'v', 42 | describe: 'Run with verbose logging', 43 | }, 44 | }).argv; 45 | 46 | // Get CLI parameters. 47 | const { deployFullConfigPath, networkName } = 48 | await getDeployCommandParameters(argv); 49 | 50 | // Validate environment variables. 51 | validateEnvVars(networkName); 52 | 53 | // Run deployWithConfig.ts as child_process with the deployConfigPath as an environment variable, 54 | // since hardhat doesn't support passing arguments to scripts. 55 | console.info('Deploying...'); 56 | 57 | const deployWithHardhat = spawn( 58 | `npx hardhat run --network ${networkName} scripts/deployWithConfig.ts`, 59 | { 60 | stdio: 'inherit', 61 | shell: true, 62 | env: { 63 | ...process.env, 64 | IS_VERBOSE: argv.verbose ? 'true' : 'false', 65 | DEPLOY_FULL_CONFIG_PATH: deployFullConfigPath, 66 | }, 67 | } 68 | ); 69 | 70 | // only exit once the child process has exited. 71 | const exitCode = await waitForProcessToExit(deployWithHardhat); 72 | process.exit(exitCode); 73 | } 74 | 75 | async function getDeployCommandParameters(argv: { 76 | deployConfig?: string; 77 | network?: string; 78 | }): Promise<{ 79 | deployFullConfigPath: string; 80 | networkName: string; 81 | }> { 82 | const isDeployConfigSpecified = !!argv.deployConfig; 83 | 84 | if (!isDeployConfigSpecified) { 85 | // Check if network arg is specified. 86 | if (!argv.network) { 87 | throw new Error('Network must be specified'); 88 | } 89 | 90 | const networkName = argv.network; 91 | 92 | // Note that this is an INTERACTIVE function - it will ask the user for input. 93 | const res = await getDeployConfig(networkName); 94 | 95 | return { 96 | deployFullConfigPath: res.deployFullConfigPath, 97 | networkName, 98 | }; 99 | } 100 | 101 | // --deploy-config option passed, so pass to deployWithConfig.ts. 102 | const deployFullConfigPath = argv.deployConfig!; 103 | 104 | // We read the deploy config file to retrieve the network name. 105 | const deployFullConfig = await readDeployConfig(deployFullConfigPath); 106 | 107 | return { 108 | deployFullConfigPath, 109 | networkName: deployFullConfig.deployCoreConfig.networkName, 110 | }; 111 | } 112 | 113 | function validateEnvVars(network: string): void { 114 | const requiredEnvVars = networkToRequiredEnvVars[network] 115 | ? networkToRequiredEnvVars[network] 116 | : []; 117 | for (const envVar of requiredEnvVars) { 118 | if (!process.env[envVar]) { 119 | throw new Error(`Missing environment variable: ${envVar}`); 120 | } 121 | } 122 | } 123 | 124 | run().catch((err) => { 125 | console.error(err.toString()); 126 | process.exit(1); 127 | }); 128 | -------------------------------------------------------------------------------- /scripts/deployAndSetReleaseRegisterRoles.js: -------------------------------------------------------------------------------- 1 | /* global ethers */ 2 | /* eslint prefer-const: "off" */ 3 | 4 | const hre = require('hardhat'); 5 | const { hardhatDeployAndVerifySingleContract } = require('./utils'); 6 | const chainName = hre.network.name; 7 | const { grantRolesTo } = require('./deployLitCore'); 8 | 9 | async function setRoles( 10 | releaseRegister, 11 | { subnetOwnerAddress, subnetProvAddress, subnetAdminPublicKey } 12 | ) { 13 | console.log('Setting roles for ReleaseRegister contract...'); 14 | 15 | await grantRolesTo(releaseRegister, subnetOwnerAddress, [ 16 | await releaseRegister.ADMIN_ROLE(), 17 | await releaseRegister.CREATOR_ROLE(), 18 | await releaseRegister.ACTIVATOR_ROLE(), 19 | await releaseRegister.DEACTIVATOR_ROLE(), 20 | await releaseRegister.BURNER_ROLE(), 21 | ]); 22 | await grantRolesTo(releaseRegister, subnetProvAddress, [ 23 | await releaseRegister.CREATOR_ROLE(), 24 | await releaseRegister.ACTIVATOR_ROLE(), 25 | ]); 26 | 27 | console.log( 28 | 'Adding allowed admin public keys to ReleaseRegister contract...' 29 | ); 30 | 31 | await releaseRegister.addAllowedAdminSigningPublicKey(subnetAdminPublicKey); 32 | 33 | console.log('Done!'); 34 | } 35 | 36 | async function deployContractAndSetRoles( 37 | contractName, 38 | args = [], 39 | releaseRegisterKeys 40 | ) { 41 | const contract = await hardhatDeployAndVerifySingleContract( 42 | hre.ethers, 43 | hre.network.name, 44 | contractName, 45 | { 46 | deploymentArgs: args, 47 | } 48 | ); 49 | await setRoles(contract, releaseRegisterKeys); 50 | } 51 | 52 | // We recommend this pattern to be able to use async/await everywhere 53 | // and properly handle errors. 54 | if (require.main === module) { 55 | // regular contract 56 | deployContractAndSetRoles('ReleaseRegister', [2n], { 57 | subnetOwnerAddress: '0x67EE5dDE3a1b522176A3676D7f74c759dFb98951', 58 | subnetProvAddress: '0x0E718ca881D47f942983DdA74A2Fe2b8D884f98d', 59 | subnetAdminPublicKey: 60 | '0x047f56f199ca45f3ffe645191975ffc3acf2e3bce83cba7e5a07d412d6097ee940fb16a24ff0ce7e69ad8d646e218aa6daf385634792f21ac6aa4b76d359e576d0', 61 | }); // 2n is the env == prod 62 | } 63 | -------------------------------------------------------------------------------- /scripts/deployConfig/askDeployConfig.ts: -------------------------------------------------------------------------------- 1 | import inquirer from 'inquirer'; 2 | import { 3 | askForConfirm, 4 | askForEnvConfirmOrInput, 5 | askForEnvConfirmOrListChoice, 6 | } from './common'; 7 | import { askDeployCoreConfig } from './deployCoreConfig'; 8 | import { askDeployNodeConfig } from './deployNodeConfig'; 9 | import { 10 | DeployEnvironment, 11 | DeployFullConfig, 12 | DeploymentSelection, 13 | } from './models'; 14 | 15 | export async function askDeployConfig( 16 | networkName: string 17 | ): Promise { 18 | const deploymentSelection = await askForDeploymentSelection(); 19 | 20 | const environment = (await askForEnv()) as DeployEnvironment; 21 | 22 | const deployCoreConfig = await askDeployCoreConfig(environment, networkName); 23 | 24 | if (deploymentSelection === DeploymentSelection.LIT_CORE) { 25 | console.info('Deployment config', { deployCoreConfig }); 26 | await askForDeployConfigConfirmation(); 27 | return { deploymentSelection, deployCoreConfig }; 28 | } 29 | 30 | const deployNodeConfig = await askDeployNodeConfig( 31 | deploymentSelection, 32 | environment, 33 | networkName 34 | ); 35 | console.info('Deployment config', { deployCoreConfig, deployNodeConfig }); 36 | await askForDeployConfigConfirmation(); 37 | return { deploymentSelection, deployNodeConfig, deployCoreConfig }; 38 | } 39 | 40 | async function askForEnv(): Promise { 41 | return askForEnvConfirmOrListChoice( 42 | 'LIT_ENV', 43 | `Are you sure you want to deploy with "${process.env.LIT_ENV}" as the environment?`, 44 | 'environment', 45 | 'What is the environment?', 46 | Object.values(DeployEnvironment) 47 | ); 48 | } 49 | 50 | export async function askForDeploymentSelection(): Promise { 51 | const answer = await inquirer.prompt([ 52 | { 53 | type: 'list', 54 | name: 'deploymentSelection', 55 | message: 'What would you like to deploy?', 56 | choices: Object.values(DeploymentSelection), 57 | }, 58 | ]); 59 | 60 | return answer.deploymentSelection; 61 | } 62 | 63 | // Finally, ask the user to confirm the config used for deployment. 64 | async function askForDeployConfigConfirmation(): Promise { 65 | const confirmed = await askForConfirm( 66 | 'deployConfig', 67 | `Would you like to deploy with the above configuration?` 68 | ); 69 | if (!confirmed) { 70 | throw new Error('Deployment configuration rejected'); 71 | } 72 | return; 73 | } 74 | -------------------------------------------------------------------------------- /scripts/deployConfig/configs/ci-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "deploymentSelection": "lit-core + lit-node", 3 | "deployNodeConfig": { 4 | "environment": "dev", 5 | "networkName": "localchain", 6 | "newOwnerAddress": "0x4259E44670053491E7b4FE4A120C70be1eAD646b", 7 | "numberOfStakedAndJoinedWallets": 12, 8 | "numberOfStakedOnlyWallets": 12, 9 | "resolverContractAddress": "TBD", 10 | "useLitCoreDeploymentResolverContractAddress": true, 11 | "outputTempFilePath": "./deployed-lit-node-contracts-temp.json", 12 | "copyNodeConfigsToRustProject": true, 13 | "ipAddresses": [ 14 | "127.0.0.1:7470", 15 | "127.0.0.1:7471", 16 | "127.0.0.1:7472", 17 | "127.0.0.1:7473", 18 | "127.0.0.1:7474", 19 | "127.0.0.1:7475", 20 | "127.0.0.1:7476", 21 | "127.0.0.1:7477", 22 | "127.0.0.1:7478", 23 | "127.0.0.1:7479", 24 | "127.0.0.1:7480", 25 | "127.0.0.1:7481", 26 | "127.0.0.1:7482", 27 | "127.0.0.1:7483", 28 | "127.0.0.1:7484", 29 | "127.0.0.1:7485", 30 | "127.0.0.1:7486", 31 | "127.0.0.1:7487", 32 | "127.0.0.1:7488", 33 | "127.0.0.1:7489", 34 | "127.0.0.1:7490", 35 | "127.0.0.1:7491", 36 | "127.0.0.1:7492", 37 | "127.0.0.1:7493" 38 | ], 39 | "keyTypes": [ 40 | 1, 41 | 2 42 | ] 43 | }, 44 | "deployCoreConfig": { 45 | "environment": "dev", 46 | "networkName": "localchain", 47 | "subnetOwnerAddress": "0xB77AEBbC262Bb809933D991A919A0e4A6A3b2f65", 48 | "subnetAdminPublicKey": "0x045f96e860435fccf287d9c2592fa129edfca7159c8dd2260cf2def38a9d5ee627ba73afef636467bc95fe551f10c862e910f18eafb751226d6901eab7d5b2794a", 49 | "subnetProvAddress": "0x3324439C8b9181eF07D54030E32d2CD22FF0C6A7", 50 | "outputTempFilePath": "./deployed-lit-core-contracts-temp.json" 51 | } 52 | } -------------------------------------------------------------------------------- /scripts/deployConfig/deployCoreConfig.ts: -------------------------------------------------------------------------------- 1 | import { DEPLOY_LIT_CORE_OUTPUT_TEMP_FILE_PATH } from '.'; 2 | import { 3 | askForConfirm, 4 | askForConfirmParameter, 5 | askForNetworkNameConfirmation, 6 | } from './common'; 7 | import { DeployCoreConfig, DeployEnvironment } from './models'; 8 | 9 | export async function askDeployCoreConfig( 10 | environment: DeployEnvironment, 11 | networkName: string 12 | ): Promise { 13 | await askForNetworkNameConfirmation(networkName); 14 | const ownerAddress = await getOwnerAddress(environment); 15 | const adminPublicKey = await getAdminPublicKey(environment); 16 | const provAddress = await getProvAddress(environment); 17 | 18 | const deployConfig: DeployCoreConfig = { 19 | environment, 20 | networkName, 21 | subnetOwnerAddress: ownerAddress, 22 | subnetAdminPublicKey: adminPublicKey, 23 | subnetProvAddress: provAddress, 24 | outputTempFilePath: DEPLOY_LIT_CORE_OUTPUT_TEMP_FILE_PATH, 25 | }; 26 | 27 | return deployConfig; 28 | } 29 | 30 | const getOwnerAddress = async ( 31 | environment: DeployEnvironment 32 | ): Promise => { 33 | if (process.env.LIT_SUBNET_OWNER_ADDRESS) { 34 | return askForConfirmParameter( 35 | 'subnetOwnerAddress', 36 | process.env.LIT_SUBNET_OWNER_ADDRESS, 37 | 'the subnet owner address' 38 | ); 39 | } 40 | 41 | switch (environment) { 42 | case DeployEnvironment.DEV: 43 | return '0xB77AEBbC262Bb809933D991A919A0e4A6A3b2f65'; 44 | case DeployEnvironment.STAGING: 45 | return '0x8660Fa1d5Ca425B5098830cf6d6E343C76a5eb45'; 46 | case DeployEnvironment.PROD: 47 | throw new Error( 48 | 'owner for prod not implemented (use LIT_SUBNET_OWNER_ADDRESS)' 49 | ); 50 | default: 51 | throw new Error('ENV is invalid'); 52 | } 53 | }; 54 | 55 | const getAdminPublicKey = async ( 56 | environment: DeployEnvironment 57 | ): Promise => { 58 | if (process.env.LIT_SUBNET_ADMIN_PUBLIC_KEY) { 59 | return askForConfirmParameter( 60 | 'subnetAdminPublicKey', 61 | process.env.LIT_SUBNET_ADMIN_PUBLIC_KEY, 62 | 'the subnet admin public key' 63 | ); 64 | } 65 | 66 | switch (environment) { 67 | case DeployEnvironment.DEV: 68 | return '0x045f96e860435fccf287d9c2592fa129edfca7159c8dd2260cf2def38a9d5ee627ba73afef636467bc95fe551f10c862e910f18eafb751226d6901eab7d5b2794a'; 69 | case DeployEnvironment.STAGING: 70 | return '0x04befba05710dc3eed6508a31d9515a80a5c036c9a165c2db19eb44fc3dceedad44572aa11c832ed4e4e98fa087017c950232ad5810a923599d724fc9d292e356d'; 71 | case DeployEnvironment.PROD: 72 | throw new Error( 73 | 'admin public key for prod not implemented (use LIT_SUBNET_ADMIN_PUBLIC_KEY)' 74 | ); 75 | default: 76 | throw new Error('ENV is invalid'); 77 | } 78 | }; 79 | 80 | const getProvAddress = async ( 81 | environment: DeployEnvironment 82 | ): Promise => { 83 | if (process.env.LIT_SUBNET_PROV_ADDRESS) { 84 | return askForConfirmParameter( 85 | 'subnetProvAddress', 86 | process.env.LIT_SUBNET_PROV_ADDRESS, 87 | 'the subnet prov address' 88 | ); 89 | } 90 | 91 | switch (environment) { 92 | case DeployEnvironment.DEV: 93 | return '0x3324439C8b9181eF07D54030E32d2CD22FF0C6A7'; 94 | case DeployEnvironment.STAGING: 95 | return '0xAd50f87Ea7d17D1a830AEC612751155726d8854F'; 96 | case DeployEnvironment.PROD: 97 | throw new Error( 98 | 'prov for prod not implemented (use LIT_SUBNET_PROV_ADDRESS)' 99 | ); 100 | default: 101 | throw new Error('ENV is invalid'); 102 | } 103 | }; 104 | -------------------------------------------------------------------------------- /scripts/deployConfig/index.ts: -------------------------------------------------------------------------------- 1 | export * from './models'; 2 | export { askDeployConfig } from './askDeployConfig'; 3 | export { getDeployConfig } from './getDeployConfig'; 4 | export * from './common'; 5 | 6 | export const DEPLOY_CONFIGS_DIR = './scripts/deployConfig/configs'; 7 | export const DEPLOY_CONFIGURATION_PATTERN = 'deploy-config-*.json'; 8 | export const DEPLOY_LIT_CORE_OUTPUT_TEMP_FILE_PATH = 9 | './deployed-lit-core-contracts-temp.json'; 10 | export const DEPLOY_LIT_NODE_OUTPUT_TEMP_FILE_PATH = 11 | './deployed-lit-node-contracts-temp.json'; 12 | -------------------------------------------------------------------------------- /scripts/deployConfig/models.ts: -------------------------------------------------------------------------------- 1 | import { Wallet } from 'ethers'; 2 | 3 | export enum DeployEnvironment { 4 | DEV = 'dev', 5 | STAGING = 'staging', 6 | PROD = 'prod', 7 | } 8 | 9 | export interface DeploySensitiveConfig { 10 | ipfsApiKey: string; 11 | } 12 | 13 | export interface DeployBaseConfig { 14 | environment: DeployEnvironment; 15 | networkName: string; 16 | } 17 | 18 | export interface DeployNodeConfig extends DeployBaseConfig { 19 | newOwnerAddress: string; 20 | newDomainWalletAdminAddress?: string; 21 | numberOfStakedOnlyWallets: number; 22 | numberOfStakedAndJoinedWallets: number; 23 | useLitCoreDeploymentResolverContractAddress: boolean; 24 | outputTempFilePath: string; 25 | resolverContractAddress: string; 26 | copyNodeConfigsToRustProject: boolean; 27 | ipAddresses?: string[]; 28 | existingContracts?: Partial; 29 | keyTypes: number[]; 30 | nodePrivateKeys?: string[]; 31 | chainPollingInterval?: string; 32 | customNodeRuntimeConfigPath?: string; 33 | backupRecoveryAddresses?: string[]; 34 | backupRecoveryKeys?: string[]; 35 | } 36 | 37 | export interface DeployCoreConfig extends DeployBaseConfig { 38 | subnetAdminPublicKey: string; 39 | subnetOwnerAddress: string; 40 | subnetProvAddress: string; 41 | outputTempFilePath: string; 42 | } 43 | 44 | export interface DeployCoreOutput { 45 | contractResolver: string; 46 | releaseRegisterContractAddress: string; 47 | } 48 | 49 | export interface FundAndStakeNodesOutput { 50 | nodeOperatorsCredentials: Array; 51 | contracts: ParsedNodeContracts; 52 | } 53 | 54 | export enum DeploymentSelection { 55 | LIT_CORE_AND_LIT_NODE = 'lit-core + lit-node', 56 | LIT_CORE = 'lit-core', 57 | LIT_NODE = 'lit-node', 58 | } 59 | 60 | export interface DeployFullConfig { 61 | deployCoreConfig: DeployCoreConfig; 62 | deployNodeConfig?: DeployNodeConfig; 63 | deploymentSelection: DeploymentSelection; 64 | } 65 | 66 | export interface ParsedDomainWalletContracts { 67 | domainWalletRegistryAddress: string; 68 | } 69 | 70 | export interface ParsedNodeContracts extends ParsedDomainWalletContracts { 71 | stakingBalancesContractAddress: string; 72 | stakingContractAddress: string; 73 | multisenderContractAddress: string; 74 | litTokenContractAddress: string; 75 | pubkeyRouterContractAddress: string; 76 | pkpNftContractAddress: string; 77 | rateLimitNftContractAddress: string; 78 | pkpHelperContractAddress: string; 79 | pkpPermissionsContractAddress: string; 80 | pkpNftMetadataContractAddress: string; 81 | allowlistContractAddress: string; 82 | resolverContractAddress: string; 83 | chainId: number; 84 | rpcUrl: string; 85 | chainName: string; 86 | litNodeDomainName: string; 87 | litNodePort: number; 88 | rocketPort: number; 89 | } 90 | 91 | export interface ComsKeys { 92 | publicKey: string; 93 | privateKey: string; 94 | } 95 | 96 | export interface NodeOperatorCredentials { 97 | nodeWallet: Wallet; 98 | stakerWallet: Wallet; 99 | comsKeysSender: ComsKeys; 100 | comsKeysReceiver: ComsKeys; 101 | } 102 | -------------------------------------------------------------------------------- /scripts/deployContract.ts: -------------------------------------------------------------------------------- 1 | // Full command: HARDHAT_NETWORK npx ts-node --files scripts/deployContract.ts --deployer-private-key --new-contract-name 2 | 3 | import hre from 'hardhat'; 4 | import yargs from 'yargs'; 5 | 6 | import { hardhatDeployAndVerifySingleContract } from './utils'; 7 | 8 | const { ethers } = hre; 9 | 10 | // CONFIGURE THIS // 11 | const args: any[] = []; 12 | 13 | async function run() { 14 | const inputs = await getInputsFromCliOptions(); 15 | 16 | const deployer = new ethers.Wallet(inputs.deployerPrivateKey).connect( 17 | ethers.provider 18 | ); 19 | hardhatDeployAndVerifySingleContract( 20 | ethers, 21 | hre.network.name, 22 | inputs.newContractName, 23 | { 24 | signer: deployer, 25 | deploymentArgs: args, 26 | } 27 | ); 28 | } 29 | 30 | run(); 31 | 32 | async function getInputsFromCliOptions(): Promise { 33 | const argv = await yargs(process.argv.slice(2)).options({ 34 | 'deployer-private-key': { 35 | type: 'string', 36 | describe: 37 | 'Private key of the wallet that will be used to deploy the new contract', 38 | required: true, 39 | }, 40 | 'new-contract-name': { 41 | type: 'string', 42 | describe: 'Name of the new contract', 43 | required: true, 44 | }, 45 | }).argv; 46 | 47 | return argv; 48 | } 49 | 50 | interface Inputs { 51 | deployerPrivateKey: string; 52 | newContractName: string; 53 | } 54 | -------------------------------------------------------------------------------- /scripts/deployDiamondContract.ts: -------------------------------------------------------------------------------- 1 | import hre from 'hardhat'; 2 | import yargs from 'yargs'; 3 | 4 | import { Environment } from '../utils/contract'; 5 | import { deployDiamond } from './deployDiamond'; 6 | 7 | const { ethers } = hre; 8 | 9 | async function run() { 10 | const { newDiamondName, facets, deployerPrivateKey, contractResolver, env } = 11 | await getInputsFromCliOptions(); 12 | 13 | const deployer = new ethers.Wallet(deployerPrivateKey).connect( 14 | ethers.provider 15 | ); 16 | 17 | console.log(`Deploying ${newDiamondName}`, { 18 | facets, 19 | env, 20 | contractResolver, 21 | }); 22 | const deployed = await deployDiamond(newDiamondName, contractResolver, env, { 23 | additionalFacets: facets, 24 | signer: deployer, 25 | }); 26 | 27 | const diamondContract = deployed.diamond; 28 | const deployedFacets = deployed.facets; 29 | console.log( 30 | `${newDiamondName} deployed to ${await diamondContract.getAddress()}` 31 | ); 32 | 33 | console.log('contract address: ', await diamondContract.getAddress()); 34 | console.log('facets: ', JSON.stringify(deployedFacets, null, 2)); 35 | } 36 | 37 | run(); 38 | 39 | async function getInputsFromCliOptions(): Promise { 40 | const argv = await yargs(process.argv.slice(2)).options({ 41 | 'deployer-private-key': { 42 | type: 'string', 43 | describe: 44 | 'Private key of the wallet that will be used to deploy the new contract', 45 | required: true, 46 | }, 47 | 'new-diamond-name': { 48 | type: 'string', 49 | describe: 'Name of the new diamond contract', 50 | required: true, 51 | }, 52 | facets: { 53 | type: 'array', 54 | describe: 'List of facets to deploy', 55 | required: true, 56 | }, 57 | 'contract-resolver': { 58 | type: 'string', 59 | describe: 'Resolver contract address', 60 | required: true, 61 | }, 62 | env: { 63 | type: 'number', 64 | describe: 'Environment', 65 | required: true, 66 | }, 67 | }).argv; 68 | 69 | for (const facet of argv.facets) { 70 | if (typeof facet !== 'string') { 71 | throw new Error('Facets must be strings'); 72 | } 73 | } 74 | 75 | return argv as Inputs; 76 | } 77 | 78 | interface Inputs { 79 | deployerPrivateKey: string; 80 | newDiamondName: string; 81 | facets: string[]; 82 | contractResolver: string; 83 | env: Environment; 84 | } 85 | -------------------------------------------------------------------------------- /scripts/deployInit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | export LIT_ENV="$1" 6 | export RESOLVER_CONTRACT_ADDRESS="$2" 7 | export NETWORK="$3" 8 | 9 | export SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 10 | export LIT_OS_DIR="${SCRIPT_DIR}/lit-os" 11 | 12 | if [ -z "${LIT_ENV}" ]; then 13 | echo "Usage: $0 " 14 | exit 2 15 | fi 16 | 17 | if [ "${LIT_ENV}" != "dev" ] && [ "${LIT_ENV}" != "staging" ] && [ "${LIT_ENV}" != "prod" ]; then 18 | echo "Invalid environment (valid: dev, staging, prod)" 19 | exit 2 20 | fi 21 | 22 | if [ -z "${NETWORK}" ]; then 23 | NETWORK="mumbai" 24 | fi 25 | 26 | if [ "${NETWORK}" == "localchain" ]; then 27 | if [ "$(pidof anvil)" != "" ]; then 28 | echo "Killing anvil..." 29 | kill $(pidof anvil) 30 | fi 31 | 32 | anvil & 33 | fi 34 | 35 | if [ -z "${RESOLVER_CONTRACT_ADDRESS}" ]; then 36 | if [ -z "${LIT_RESOLVER_CONTRACT_ADDRESS}" ]; then 37 | # deploy the resolver etc. 38 | ./scripts/deployLitOs.sh "${LIT_ENV}" "${NETWORK}" 39 | 40 | export RESOLVER_CONTRACT_ADDRESS=$(cat deployed-contracts-temp.json | jq -r ".contractResolver") 41 | else 42 | # Default from LIT_RESOLVER_CONTRACT_ADDRESS 43 | export RESOLVER_CONTRACT_ADDRESS="${LIT_RESOLVER_CONTRACT_ADDRESS}" 44 | fi 45 | fi 46 | -------------------------------------------------------------------------------- /scripts/deployLITToken.js: -------------------------------------------------------------------------------- 1 | // We require the Hardhat Runtime Environment explicitly here. This is optional 2 | // but useful for running the script in a standalone fashion through `node