├── .envrc ├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ ├── programs-e2e.yml │ ├── programs-unit.yml │ └── release.yml ├── .gitignore ├── .husky └── pre-commit ├── .mocharc.js ├── .prettierignore ├── .vscode ├── extensions.json └── settings.json ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-interactive-tools.cjs │ │ └── plugin-typescript.cjs ├── releases │ └── yarn-3.1.1.cjs └── sdks │ ├── eslint │ ├── bin │ │ └── eslint.js │ ├── lib │ │ └── api.js │ └── package.json │ ├── integrations.yml │ ├── prettier │ ├── index.js │ └── package.json │ └── typescript │ ├── bin │ ├── tsc │ └── tsserver │ ├── lib │ ├── tsc.js │ ├── tsserver.js │ ├── tsserverlibrary.js │ └── typescript.js │ └── package.json ├── .yarnrc.yml ├── Anchor.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── ci.nix ├── flake.lock ├── flake.nix ├── images └── banner.png ├── package.json ├── programs └── venko │ ├── Cargo.toml │ ├── README.md │ ├── README.tpl │ ├── Xargo.toml │ └── src │ ├── instructions │ ├── create_stream.rs │ ├── mod.rs │ ├── redeem.rs │ └── revoke.rs │ ├── lib.rs │ ├── macros.rs │ └── state.rs ├── scripts ├── download-programs.sh ├── generate-idl-types.sh └── parse-idls.sh ├── src ├── constants.ts ├── index.ts ├── programs │ ├── index.ts │ └── venko.ts ├── sdk.ts └── wrappers │ ├── index.ts │ └── venko │ ├── index.ts │ ├── math.ts │ ├── pda.ts │ └── venko.ts ├── tests ├── spec-key.json ├── venko.spec.ts └── workspace │ ├── index.ts │ └── workspace.ts ├── tsconfig.build.json ├── tsconfig.esm.json ├── tsconfig.json └── yarn.lock /.envrc: -------------------------------------------------------------------------------- 1 | watch_file flake.nix 2 | watch_file flake.lock 3 | mkdir -p .direnv 4 | eval "$(nix print-dev-env --profile "$(direnv_layout_dir)/flake-profile")" 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | require("@rushstack/eslint-patch/modern-module-resolution"); 2 | 3 | module.exports = { 4 | root: true, 5 | ignorePatterns: ["dist/", "*.js", "target/"], 6 | parserOptions: { 7 | tsconfigRootDir: __dirname, 8 | project: "tsconfig.json", 9 | }, 10 | extends: ["@saberhq"], 11 | }; 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | - package-ecosystem: "npm" 8 | directory: "/" 9 | schedule: 10 | interval: "daily" 11 | - package-ecosystem: "cargo" 12 | directory: "/" 13 | schedule: 14 | interval: "daily" 15 | -------------------------------------------------------------------------------- /.github/workflows/programs-e2e.yml: -------------------------------------------------------------------------------- 1 | name: E2E 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | SOLANA_VERSION: "1.8.11" 12 | RUST_TOOLCHAIN: nightly-2021-12-09 13 | 14 | jobs: 15 | sdk: 16 | runs-on: ubuntu-latest 17 | name: Build the SDK 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - uses: cachix/install-nix-action@v16 22 | with: 23 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 24 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 25 | extra_nix_config: | 26 | experimental-features = nix-command flakes 27 | - name: Setup Cachix 28 | uses: cachix/cachix-action@v10 29 | with: 30 | name: v 31 | extraPullNames: saber 32 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 33 | - name: Parse IDLs 34 | run: nix shell .#ci --command ./scripts/parse-idls.sh 35 | 36 | - name: Setup Node 37 | uses: actions/setup-node@v2 38 | with: 39 | always-auth: true 40 | 41 | - name: Get yarn cache directory path 42 | id: yarn-cache-dir-path 43 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 44 | - name: Yarn Cache 45 | uses: actions/cache@v2 46 | with: 47 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 48 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 49 | restore-keys: | 50 | ${{ runner.os }}-modules- 51 | 52 | - name: Install Yarn dependencies 53 | run: yarn install 54 | - run: ./scripts/generate-idl-types.sh 55 | - run: yarn build 56 | - run: yarn typecheck 57 | - run: yarn lint 58 | - run: yarn doctor 59 | 60 | integration-tests: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v2 64 | 65 | # Install Rust and Anchor 66 | - name: Install Rust nightly 67 | uses: actions-rs/toolchain@v1 68 | with: 69 | override: true 70 | profile: minimal 71 | toolchain: ${{ env.RUST_TOOLCHAIN }} 72 | - uses: Swatinem/rust-cache@v1 73 | - name: Install Linux dependencies 74 | run: | 75 | sudo apt-get update 76 | sudo apt-get install -y pkg-config build-essential libudev-dev 77 | 78 | # Install Cachix 79 | - uses: cachix/install-nix-action@v16 80 | with: 81 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 82 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 83 | extra_nix_config: | 84 | experimental-features = nix-command flakes 85 | - name: Setup Cachix 86 | uses: cachix/cachix-action@v10 87 | with: 88 | name: v 89 | extraPullNames: saber 90 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 91 | 92 | # Install Solana 93 | - name: Cache Solana binaries 94 | id: solana-cache 95 | uses: actions/cache@v2 96 | with: 97 | path: | 98 | ~/.cache/solana 99 | ~/.local/share/solana/install 100 | key: ${{ runner.os }}-${{ env.SOLANA_VERSION }} 101 | - name: Install Solana 102 | if: steps.solana-cache.outputs.cache-hit != 'true' 103 | run: | 104 | nix shell .#ci --command solana-install init ${{ env.SOLANA_VERSION }} 105 | - name: Setup Solana Path 106 | run: | 107 | echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH 108 | export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" 109 | solana --version 110 | 111 | # Run build 112 | - name: Build program 113 | run: nix shell .#ci --command anchor build 114 | - name: Download programs 115 | run: ./scripts/download-programs.sh 116 | 117 | - name: Get yarn cache directory path 118 | id: yarn-cache-dir-path 119 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 120 | - name: Yarn Cache 121 | uses: actions/cache@v2 122 | with: 123 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 124 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 125 | restore-keys: | 126 | ${{ runner.os }}-modules- 127 | 128 | - run: nix shell .#ci --command yarn install 129 | - name: Generate IDL types 130 | run: nix shell .#ci --command yarn idl:generate:nolint 131 | - run: yarn build 132 | - name: Run e2e tests 133 | run: nix shell .#ci --command yarn test:e2e 134 | -------------------------------------------------------------------------------- /.github/workflows/programs-unit.yml: -------------------------------------------------------------------------------- 1 | name: Unit 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - .github/workflows/programs-unit.yml 8 | - programs/** 9 | - Cargo.toml 10 | - Cargo.lock 11 | pull_request: 12 | branches: [master] 13 | paths: 14 | - .github/workflows/programs-unit.yml 15 | - programs/** 16 | - Cargo.toml 17 | - Cargo.lock 18 | 19 | env: 20 | CARGO_TERM_COLOR: always 21 | RUST_TOOLCHAIN: nightly-2021-12-10 22 | 23 | jobs: 24 | lint: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v2 28 | - name: Install Rust nightly 29 | uses: actions-rs/toolchain@v1 30 | with: 31 | override: true 32 | profile: minimal 33 | toolchain: ${{ env.RUST_TOOLCHAIN }} 34 | components: rustfmt, clippy 35 | - uses: Swatinem/rust-cache@v1 36 | - name: Run fmt 37 | run: cargo fmt -- --check 38 | - name: Run clippy 39 | run: cargo clippy --all-targets -- --deny=warnings 40 | - name: Check if publish works 41 | run: cargo publish --no-verify --dry-run 42 | 43 | unit-tests: 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v2 47 | - name: Install Rust nightly 48 | uses: actions-rs/toolchain@v1 49 | with: 50 | override: true 51 | profile: minimal 52 | toolchain: ${{ env.RUST_TOOLCHAIN }} 53 | components: rustfmt, clippy 54 | - uses: Swatinem/rust-cache@v1 55 | - name: Run unit tests 56 | run: cargo test --lib 57 | 58 | doc: 59 | runs-on: ubuntu-latest 60 | steps: 61 | - uses: actions/checkout@v2 62 | - name: Install Rust nightly 63 | uses: actions-rs/toolchain@v1 64 | with: 65 | override: true 66 | profile: minimal 67 | toolchain: ${{ env.RUST_TOOLCHAIN }} 68 | components: rustfmt, clippy 69 | - uses: Swatinem/rust-cache@v1 70 | - name: Generate docs 71 | run: cargo doc 72 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: {} 5 | push: 6 | tags: 7 | - "v*.*.*" 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | RUST_TOOLCHAIN: nightly-2021-12-09 12 | NPM_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} 13 | 14 | jobs: 15 | release-sdk: 16 | runs-on: ubuntu-latest 17 | name: Release SDK on NPM 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - uses: cachix/install-nix-action@v16 22 | with: 23 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 24 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 25 | extra_nix_config: | 26 | experimental-features = nix-command flakes 27 | - name: Setup Cachix 28 | uses: cachix/cachix-action@v10 29 | with: 30 | name: v 31 | extraPullNames: saber 32 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 33 | 34 | - name: Setup Node 35 | uses: actions/setup-node@v2 36 | with: 37 | always-auth: true 38 | 39 | - name: Get yarn cache directory path 40 | id: yarn-cache-dir-path 41 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 42 | - name: Yarn Cache 43 | uses: actions/cache@v2 44 | with: 45 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 46 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 47 | restore-keys: | 48 | ${{ runner.os }}-modules- 49 | 50 | - name: Install Yarn dependencies 51 | run: yarn install 52 | - name: Parse IDLs 53 | run: nix shell .#ci --command yarn idl:generate 54 | - run: yarn build 55 | - run: | 56 | echo 'npmAuthToken: "${NPM_AUTH_TOKEN}"' >> .yarnrc.yml 57 | - name: Publish 58 | run: yarn npm publish 59 | 60 | release-crate: 61 | runs-on: ubuntu-latest 62 | name: Release crate on crates.io 63 | steps: 64 | - uses: actions/checkout@v2 65 | 66 | - uses: cachix/install-nix-action@v16 67 | with: 68 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 69 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 70 | extra_nix_config: | 71 | experimental-features = nix-command flakes 72 | - name: Setup Cachix 73 | uses: cachix/cachix-action@v10 74 | with: 75 | name: v 76 | extraPullNames: saber 77 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 78 | 79 | - name: Install Rust nightly 80 | uses: actions-rs/toolchain@v1 81 | with: 82 | override: true 83 | profile: minimal 84 | toolchain: ${{ env.RUST_TOOLCHAIN }} 85 | - uses: Swatinem/rust-cache@v1 86 | - name: Publish crates 87 | run: nix shell .#ci --command cargo workspaces publish --from-git --yes --skip-published --token ${{ secrets.CARGO_PUBLISH_TOKEN }} 88 | 89 | release-binaries: 90 | runs-on: ubuntu-latest 91 | name: Release verifiable binaries 92 | steps: 93 | - uses: actions/checkout@v2 94 | - uses: cachix/install-nix-action@v16 95 | with: 96 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 97 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 98 | extra_nix_config: | 99 | experimental-features = nix-command flakes 100 | - name: Setup Cachix 101 | uses: cachix/cachix-action@v10 102 | with: 103 | name: v 104 | extraPullNames: saber 105 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 106 | 107 | - name: Build programs 108 | run: nix shell .#ci --command anchor build --verifiable 109 | - name: Release 110 | uses: softprops/action-gh-release@v1 111 | with: 112 | files: | 113 | target/deploy/* 114 | target/idl/* 115 | target/verifiable/* 116 | 117 | site: 118 | runs-on: ubuntu-latest 119 | steps: 120 | - name: Checkout 121 | uses: actions/checkout@v2 122 | 123 | - uses: cachix/install-nix-action@v16 124 | with: 125 | install_url: https://nixos-nix-install-tests.cachix.org/serve/i6laym9jw3wg9mw6ncyrk6gjx4l34vvx/install 126 | install_options: "--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve" 127 | extra_nix_config: | 128 | experimental-features = nix-command flakes 129 | - name: Setup Cachix 130 | uses: cachix/cachix-action@v10 131 | with: 132 | name: v 133 | extraPullNames: saber 134 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 135 | 136 | - name: Get yarn cache directory path 137 | id: yarn-cache-dir-path 138 | run: echo "::set-output name=dir::$(yarn config get cacheFolder)" 139 | - name: Yarn Cache 140 | uses: actions/cache@v2 141 | with: 142 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 143 | key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} 144 | restore-keys: | 145 | ${{ runner.os }}-modules- 146 | 147 | - name: Install Yarn dependencies 148 | run: yarn install 149 | - name: Parse IDLs 150 | run: nix shell .#ci --command yarn idl:generate 151 | - run: yarn docs:generate 152 | - run: cp -R images/ site/ 153 | 154 | - name: Deploy 🚀 155 | uses: JamesIves/github-pages-deploy-action@v4.2.2 156 | with: 157 | branch: gh-pages 158 | folder: site 159 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Mac OS noise 2 | .DS_Store 3 | 4 | # Ignore the build directory for Rust/Anchor 5 | target 6 | 7 | # Ignore backup files creates by cargo fmt. 8 | **/*.rs.bk 9 | 10 | # Ignore logs 11 | .anchor 12 | yarn-error.log 13 | lerna-debug.log 14 | 15 | # Ignore node modules 16 | node_modules 17 | .eslintcache 18 | 19 | # Ignore submodule dependencies 20 | deps 21 | 22 | # VM 23 | .vagrant/ 24 | test-ledger/ 25 | 26 | # Generated IDL types 27 | artifacts/ 28 | dist/ 29 | src/idls/ 30 | 31 | site/ 32 | 33 | .yarn/* 34 | !.yarn/patches 35 | !.yarn/releases 36 | !.yarn/plugins 37 | !.yarn/sdks 38 | !.yarn/versions 39 | .pnp.* 40 | 41 | deployments/ 42 | Captain.toml 43 | .goki/ 44 | 45 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.mocharc.js: -------------------------------------------------------------------------------- 1 | require("./.pnp.cjs").setup(); 2 | 3 | module.exports = { 4 | timeout: 30_000, 5 | require: [require.resolve("ts-node/register")], 6 | }; 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn/ 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "arcanis.vscode-zipfs", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/.yarn": true, 4 | "**/.pnp.*": true 5 | }, 6 | "eslint.nodePath": ".yarn/sdks", 7 | "prettier.prettierPath": ".yarn/sdks/prettier/index.js", 8 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 9 | "typescript.enablePromptUseWorkspaceTsdk": true 10 | } 11 | -------------------------------------------------------------------------------- /.yarn/plugins/@yarnpkg/plugin-typescript.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | //prettier-ignore 3 | module.exports = { 4 | name: "@yarnpkg/plugin-typescript", 5 | factory: function (require) { 6 | var plugin=(()=>{var Ft=Object.create,H=Object.defineProperty,Bt=Object.defineProperties,Kt=Object.getOwnPropertyDescriptor,zt=Object.getOwnPropertyDescriptors,Gt=Object.getOwnPropertyNames,Q=Object.getOwnPropertySymbols,$t=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty,De=Object.prototype.propertyIsEnumerable;var Re=(e,t,r)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,u=(e,t)=>{for(var r in t||(t={}))ne.call(t,r)&&Re(e,r,t[r]);if(Q)for(var r of Q(t))De.call(t,r)&&Re(e,r,t[r]);return e},g=(e,t)=>Bt(e,zt(t)),Lt=e=>H(e,"__esModule",{value:!0});var R=(e,t)=>{var r={};for(var s in e)ne.call(e,s)&&t.indexOf(s)<0&&(r[s]=e[s]);if(e!=null&&Q)for(var s of Q(e))t.indexOf(s)<0&&De.call(e,s)&&(r[s]=e[s]);return r};var I=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Vt=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Qt=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Gt(t))!ne.call(e,s)&&s!=="default"&&H(e,s,{get:()=>t[s],enumerable:!(r=Kt(t,s))||r.enumerable});return e},C=e=>Qt(Lt(H(e!=null?Ft($t(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var xe=I(J=>{"use strict";Object.defineProperty(J,"__esModule",{value:!0});function _(e){let t=[...e.caches],r=t.shift();return r===void 0?ve():{get(s,n,a={miss:()=>Promise.resolve()}){return r.get(s,n,a).catch(()=>_({caches:t}).get(s,n,a))},set(s,n){return r.set(s,n).catch(()=>_({caches:t}).set(s,n))},delete(s){return r.delete(s).catch(()=>_({caches:t}).delete(s))},clear(){return r.clear().catch(()=>_({caches:t}).clear())}}}function ve(){return{get(e,t,r={miss:()=>Promise.resolve()}){return t().then(n=>Promise.all([n,r.miss(n)])).then(([n])=>n)},set(e,t){return Promise.resolve(t)},delete(e){return Promise.resolve()},clear(){return Promise.resolve()}}}J.createFallbackableCache=_;J.createNullCache=ve});var Ee=I(($s,qe)=>{qe.exports=xe()});var Te=I(ae=>{"use strict";Object.defineProperty(ae,"__esModule",{value:!0});function Jt(e={serializable:!0}){let t={};return{get(r,s,n={miss:()=>Promise.resolve()}){let a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);let o=s(),d=n&&n.miss||(()=>Promise.resolve());return o.then(y=>d(y)).then(()=>o)},set(r,s){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(s):s,Promise.resolve(s)},delete(r){return delete t[JSON.stringify(r)],Promise.resolve()},clear(){return t={},Promise.resolve()}}}ae.createInMemoryCache=Jt});var we=I((Vs,Me)=>{Me.exports=Te()});var Ce=I(M=>{"use strict";Object.defineProperty(M,"__esModule",{value:!0});function Xt(e,t,r){let s={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers(){return e===oe.WithinHeaders?s:{}},queryParameters(){return e===oe.WithinQueryParameters?s:{}}}}function Yt(e){let t=0,r=()=>(t++,new Promise(s=>{setTimeout(()=>{s(e(r))},Math.min(100*t,1e3))}));return e(r)}function ke(e,t=(r,s)=>Promise.resolve()){return Object.assign(e,{wait(r){return ke(e.then(s=>Promise.all([t(s,r),s])).then(s=>s[1]))}})}function Zt(e){let t=e.length-1;for(t;t>0;t--){let r=Math.floor(Math.random()*(t+1)),s=e[t];e[t]=e[r],e[r]=s}return e}function er(e,t){return Object.keys(t!==void 0?t:{}).forEach(r=>{e[r]=t[r](e)}),e}function tr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}var rr="4.2.0",sr=e=>()=>e.transporter.requester.destroy(),oe={WithinQueryParameters:0,WithinHeaders:1};M.AuthMode=oe;M.addMethods=er;M.createAuth=Xt;M.createRetryablePromise=Yt;M.createWaitablePromise=ke;M.destroy=sr;M.encode=tr;M.shuffle=Zt;M.version=rr});var F=I((Js,Ue)=>{Ue.exports=Ce()});var Ne=I(ie=>{"use strict";Object.defineProperty(ie,"__esModule",{value:!0});var nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};ie.MethodEnum=nr});var B=I((Ys,We)=>{We.exports=Ne()});var Ze=I(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});var He=B();function ce(e,t){let r=e||{},s=r.data||{};return Object.keys(r).forEach(n=>{["timeout","headers","queryParameters","data","cacheable"].indexOf(n)===-1&&(s[n]=r[n])}),{data:Object.entries(s).length>0?s:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var X={Read:1,Write:2,Any:3},U={Up:1,Down:2,Timeouted:3},_e=2*60*1e3;function ue(e,t=U.Up){return g(u({},e),{status:t,lastUpdate:Date.now()})}function Fe(e){return e.status===U.Up||Date.now()-e.lastUpdate>_e}function Be(e){return e.status===U.Timeouted&&Date.now()-e.lastUpdate<=_e}function le(e){return{protocol:e.protocol||"https",url:e.url,accept:e.accept||X.Any}}function ar(e,t){return Promise.all(t.map(r=>e.get(r,()=>Promise.resolve(ue(r))))).then(r=>{let s=r.filter(d=>Fe(d)),n=r.filter(d=>Be(d)),a=[...s,...n],o=a.length>0?a.map(d=>le(d)):t;return{getTimeout(d,y){return(n.length===0&&d===0?1:n.length+3+d)*y},statelessHosts:o}})}var or=({isTimedOut:e,status:t})=>!e&&~~t==0,ir=e=>{let t=e.status;return e.isTimedOut||or(e)||~~(t/100)!=2&&~~(t/100)!=4},cr=({status:e})=>~~(e/100)==2,ur=(e,t)=>ir(e)?t.onRetry(e):cr(e)?t.onSucess(e):t.onFail(e);function Qe(e,t,r,s){let n=[],a=$e(r,s),o=Le(e,s),d=r.method,y=r.method!==He.MethodEnum.Get?{}:u(u({},r.data),s.data),b=u(u(u({"x-algolia-agent":e.userAgent.value},e.queryParameters),y),s.queryParameters),f=0,p=(h,S)=>{let O=h.pop();if(O===void 0)throw Ve(de(n));let P={data:a,headers:o,method:d,url:Ge(O,r.path,b),connectTimeout:S(f,e.timeouts.connect),responseTimeout:S(f,s.timeout)},x=j=>{let T={request:P,response:j,host:O,triesLeft:h.length};return n.push(T),T},v={onSucess:j=>Ke(j),onRetry(j){let T=x(j);return j.isTimedOut&&f++,Promise.all([e.logger.info("Retryable failure",pe(T)),e.hostsCache.set(O,ue(O,j.isTimedOut?U.Timeouted:U.Down))]).then(()=>p(h,S))},onFail(j){throw x(j),ze(j,de(n))}};return e.requester.send(P).then(j=>ur(j,v))};return ar(e.hostsCache,t).then(h=>p([...h.statelessHosts].reverse(),h.getTimeout))}function lr(e){let{hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,hosts:y,queryParameters:b,headers:f}=e,p={hostsCache:t,logger:r,requester:s,requestsCache:n,responsesCache:a,timeouts:o,userAgent:d,headers:f,queryParameters:b,hosts:y.map(h=>le(h)),read(h,S){let O=ce(S,p.timeouts.read),P=()=>Qe(p,p.hosts.filter(j=>(j.accept&X.Read)!=0),h,O);if((O.cacheable!==void 0?O.cacheable:h.cacheable)!==!0)return P();let v={request:h,mappedRequestOptions:O,transporter:{queryParameters:p.queryParameters,headers:p.headers}};return p.responsesCache.get(v,()=>p.requestsCache.get(v,()=>p.requestsCache.set(v,P()).then(j=>Promise.all([p.requestsCache.delete(v),j]),j=>Promise.all([p.requestsCache.delete(v),Promise.reject(j)])).then(([j,T])=>T)),{miss:j=>p.responsesCache.set(v,j)})},write(h,S){return Qe(p,p.hosts.filter(O=>(O.accept&X.Write)!=0),h,ce(S,p.timeouts.write))}};return p}function dr(e){let t={value:`Algolia for JavaScript (${e})`,add(r){let s=`; ${r.segment}${r.version!==void 0?` (${r.version})`:""}`;return t.value.indexOf(s)===-1&&(t.value=`${t.value}${s}`),t}};return t}function Ke(e){try{return JSON.parse(e.content)}catch(t){throw Je(t.message,e)}}function ze({content:e,status:t},r){let s=e;try{s=JSON.parse(e).message}catch(n){}return Xe(s,t,r)}function pr(e,...t){let r=0;return e.replace(/%s/g,()=>encodeURIComponent(t[r++]))}function Ge(e,t,r){let s=Ye(r),n=`${e.protocol}://${e.url}/${t.charAt(0)==="/"?t.substr(1):t}`;return s.length&&(n+=`?${s}`),n}function Ye(e){let t=r=>Object.prototype.toString.call(r)==="[object Object]"||Object.prototype.toString.call(r)==="[object Array]";return Object.keys(e).map(r=>pr("%s=%s",r,t(e[r])?JSON.stringify(e[r]):e[r])).join("&")}function $e(e,t){if(e.method===He.MethodEnum.Get||e.data===void 0&&t.data===void 0)return;let r=Array.isArray(e.data)?e.data:u(u({},e.data),t.data);return JSON.stringify(r)}function Le(e,t){let r=u(u({},e.headers),t.headers),s={};return Object.keys(r).forEach(n=>{let a=r[n];s[n.toLowerCase()]=a}),s}function de(e){return e.map(t=>pe(t))}function pe(e){let t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return g(u({},e),{request:g(u({},e.request),{headers:u(u({},e.request.headers),t)})})}function Xe(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}function Je(e,t){return{name:"DeserializationError",message:e,response:t}}function Ve(e){return{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:e}}A.CallEnum=X;A.HostStatusEnum=U;A.createApiError=Xe;A.createDeserializationError=Je;A.createMappedRequestOptions=ce;A.createRetryError=Ve;A.createStatefulHost=ue;A.createStatelessHost=le;A.createTransporter=lr;A.createUserAgent=dr;A.deserializeFailure=ze;A.deserializeSuccess=Ke;A.isStatefulHostTimeouted=Be;A.isStatefulHostUp=Fe;A.serializeData=$e;A.serializeHeaders=Le;A.serializeQueryParameters=Ye;A.serializeUrl=Ge;A.stackFrameWithoutCredentials=pe;A.stackTraceWithoutCredentials=de});var K=I((en,et)=>{et.exports=Ze()});var tt=I(w=>{"use strict";Object.defineProperty(w,"__esModule",{value:!0});var N=F(),mr=K(),z=B(),hr=e=>{let t=e.region||"us",r=N.createAuth(N.AuthMode.WithinHeaders,e.appId,e.apiKey),s=mr.createTransporter(g(u({hosts:[{url:`analytics.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n=e.appId;return N.addMethods({appId:n,transporter:s},e.methods)},yr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:"2/abtests",data:t},r),gr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Delete,path:N.encode("2/abtests/%s",t)},r),fr=e=>(t,r)=>e.transporter.read({method:z.MethodEnum.Get,path:N.encode("2/abtests/%s",t)},r),br=e=>t=>e.transporter.read({method:z.MethodEnum.Get,path:"2/abtests"},t),Pr=e=>(t,r)=>e.transporter.write({method:z.MethodEnum.Post,path:N.encode("2/abtests/%s/stop",t)},r);w.addABTest=yr;w.createAnalyticsClient=hr;w.deleteABTest=gr;w.getABTest=fr;w.getABTests=br;w.stopABTest=Pr});var st=I((rn,rt)=>{rt.exports=tt()});var at=I(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});var me=F(),jr=K(),nt=B(),Or=e=>{let t=e.region||"us",r=me.createAuth(me.AuthMode.WithinHeaders,e.appId,e.apiKey),s=jr.createTransporter(g(u({hosts:[{url:`recommendation.${t}.algolia.com`}]},e),{headers:u(g(u({},r.headers()),{"content-type":"application/json"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)}));return me.addMethods({appId:e.appId,transporter:s},e.methods)},Ir=e=>t=>e.transporter.read({method:nt.MethodEnum.Get,path:"1/strategies/personalization"},t),Ar=e=>(t,r)=>e.transporter.write({method:nt.MethodEnum.Post,path:"1/strategies/personalization",data:t},r);G.createRecommendationClient=Or;G.getPersonalizationStrategy=Ir;G.setPersonalizationStrategy=Ar});var it=I((nn,ot)=>{ot.exports=at()});var jt=I(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});var l=F(),q=K(),m=B(),Sr=require("crypto");function Y(e){let t=r=>e.request(r).then(s=>{if(e.batch!==void 0&&e.batch(s.hits),!e.shouldStop(s))return s.cursor?t({cursor:s.cursor}):t({page:(r.page||0)+1})});return t({})}var Dr=e=>{let t=e.appId,r=l.createAuth(e.authMode!==void 0?e.authMode:l.AuthMode.WithinHeaders,t,e.apiKey),s=q.createTransporter(g(u({hosts:[{url:`${t}-dsn.algolia.net`,accept:q.CallEnum.Read},{url:`${t}.algolia.net`,accept:q.CallEnum.Write}].concat(l.shuffle([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}]))},e),{headers:u(g(u({},r.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:u(u({},r.queryParameters()),e.queryParameters)})),n={transporter:s,appId:t,addAlgoliaAgent(a,o){s.userAgent.add({segment:a,version:o})},clearCache(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then(()=>{})}};return l.addMethods(n,e.methods)};function ct(){return{name:"MissingObjectIDError",message:"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option."}}function ut(){return{name:"ObjectNotFoundError",message:"Object not found."}}function lt(){return{name:"ValidUntilNotFoundError",message:"ValidUntil not found in given secured api key."}}var Rr=e=>(t,r)=>{let d=r||{},{queryParameters:s}=d,n=R(d,["queryParameters"]),a=u({acl:t},s!==void 0?{queryParameters:s}:{}),o=(y,b)=>l.createRetryablePromise(f=>$(e)(y.key,b).catch(p=>{if(p.status!==404)throw p;return f()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/keys",data:a},n),o)},vr=e=>(t,r,s)=>{let n=q.createMappedRequestOptions(s);return n.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping",data:{cluster:r}},n)},xr=e=>(t,r,s)=>e.transporter.write({method:m.MethodEnum.Post,path:"1/clusters/mapping/batch",data:{users:t,cluster:r}},s),Z=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"copy",destination:r}},s),n)},qr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Rules]})),Er=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Settings]})),Tr=e=>(t,r,s)=>Z(e)(t,r,g(u({},s),{scope:[ee.Synonyms]})),Mr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).then(o).catch(d=>{if(d.status!==404)throw d}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/keys/%s",t)},r),s)},wr=()=>(e,t)=>{let r=q.serializeQueryParameters(t),s=Sr.createHmac("sha256",e).update(r).digest("hex");return Buffer.from(s+r).toString("base64")},$=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/keys/%s",t)},r),kr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/logs"},t),Cr=()=>e=>{let t=Buffer.from(e,"base64").toString("ascii"),r=/validUntil=(\d+)/,s=t.match(r);if(s===null)throw lt();return parseInt(s[1],10)-Math.round(new Date().getTime()/1e3)},Ur=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/top"},t),Nr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/clusters/mapping/%s",t)},r),Wr=e=>t=>{let n=t||{},{retrieveMappings:r}=n,s=R(n,["retrieveMappings"]);return r===!0&&(s.getClusters=!0),e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping/pending"},s)},L=e=>(t,r={})=>{let s={transporter:e.transporter,appId:e.appId,indexName:t};return l.addMethods(s,r.methods)},Hr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/keys"},t),_r=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters"},t),Fr=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/indexes"},t),Br=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:"1/clusters/mapping"},t),Kr=e=>(t,r,s)=>{let n=(a,o)=>L(e)(t,{methods:{waitTask:D}}).waitTask(a.taskID,o);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",t),data:{operation:"move",destination:r}},s),n)},zr=e=>(t,r)=>{let s=(n,a)=>Promise.all(Object.keys(n.taskID).map(o=>L(e)(o,{methods:{waitTask:D}}).waitTask(n.taskID[o],a)));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:"1/indexes/*/batch",data:{requests:t}},r),s)},Gr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:t}},r),$r=e=>(t,r)=>{let s=t.map(n=>g(u({},n),{params:q.serializeQueryParameters(n.params||{})}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/queries",data:{requests:s},cacheable:!0},r)},Lr=e=>(t,r)=>Promise.all(t.map(s=>{let d=s.params,{facetName:n,facetQuery:a}=d,o=R(d,["facetName","facetQuery"]);return L(e)(s.indexName,{methods:{searchForFacetValues:dt}}).searchForFacetValues(n,a,u(u({},r),o))})),Vr=e=>(t,r)=>{let s=q.createMappedRequestOptions(r);return s.queryParameters["X-Algolia-User-ID"]=t,e.transporter.write({method:m.MethodEnum.Delete,path:"1/clusters/mapping"},s)},Qr=e=>(t,r)=>{let s=(n,a)=>l.createRetryablePromise(o=>$(e)(t,a).catch(d=>{if(d.status!==404)throw d;return o()}));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/keys/%s/restore",t)},r),s)},Jr=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:"1/clusters/mapping/search",data:{query:t}},r),Xr=e=>(t,r)=>{let s=Object.assign({},r),f=r||{},{queryParameters:n}=f,a=R(f,["queryParameters"]),o=n?{queryParameters:n}:{},d=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"],y=p=>Object.keys(s).filter(h=>d.indexOf(h)!==-1).every(h=>p[h]===s[h]),b=(p,h)=>l.createRetryablePromise(S=>$(e)(t,h).then(O=>y(O)?Promise.resolve():S()));return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/keys/%s",t),data:o},a),b)},pt=e=>(t,r)=>{let s=(n,a)=>D(e)(n.taskID,a);return l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/batch",e.indexName),data:{requests:t}},r),s)},Yr=e=>t=>Y(g(u({},t),{shouldStop:r=>r.cursor===void 0,request:r=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/browse",e.indexName),data:r},t)})),Zr=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},es=e=>t=>{let r=u({hitsPerPage:1e3},t);return Y(g(u({},r),{shouldStop:s=>s.hits.lengthg(u({},n),{hits:n.hits.map(a=>(delete a._highlightResult,a))}))}}))},te=e=>(t,r,s)=>{let y=s||{},{batchSize:n}=y,a=R(y,["batchSize"]),o={taskIDs:[],objectIDs:[]},d=(b=0)=>{let f=[],p;for(p=b;p({action:r,body:h})),a).then(h=>(o.objectIDs=o.objectIDs.concat(h.objectIDs),o.taskIDs.push(h.taskID),p++,d(p)))};return l.createWaitablePromise(d(),(b,f)=>Promise.all(b.taskIDs.map(p=>D(e)(p,f))))},ts=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/clear",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),rs=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ss=e=>t=>{let a=t||{},{forwardToReplicas:r}=a,s=R(a,["forwardToReplicas"]),n=q.createMappedRequestOptions(s);return r&&(n.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/clear",e.indexName)},n),(o,d)=>D(e)(o.taskID,d))},ns=e=>(t,r)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/deleteByQuery",e.indexName),data:t},r),(s,n)=>D(e)(s.taskID,n)),as=e=>t=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s",e.indexName)},t),(r,s)=>D(e)(r.taskID,s)),os=e=>(t,r)=>l.createWaitablePromise(yt(e)([t],r).then(s=>({taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),yt=e=>(t,r)=>{let s=t.map(n=>({objectID:n}));return te(e)(s,k.DeleteObject,r)},is=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},cs=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Delete,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},a),(d,y)=>D(e)(d.taskID,y))},us=e=>t=>gt(e)(t).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),ls=e=>(t,r)=>{let y=r||{},{query:s,paginate:n}=y,a=R(y,["query","paginate"]),o=0,d=()=>ft(e)(s||"",g(u({},a),{page:o})).then(b=>{for(let[f,p]of Object.entries(b.hits))if(t(p))return{object:p,position:parseInt(f,10),page:o};if(o++,n===!1||o>=b.nbPages)throw ut();return d()});return d()},ds=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/%s",e.indexName,t)},r),ps=()=>(e,t)=>{for(let[r,s]of Object.entries(e.hits))if(s.objectID===t)return parseInt(r,10);return-1},ms=e=>(t,r)=>{let o=r||{},{attributesToRetrieve:s}=o,n=R(o,["attributesToRetrieve"]),a=t.map(d=>u({indexName:e.indexName,objectID:d},s?{attributesToRetrieve:s}:{}));return e.transporter.read({method:m.MethodEnum.Post,path:"1/indexes/*/objects",data:{requests:a}},n)},hs=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/rules/%s",e.indexName,t)},r),gt=e=>t=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/settings",e.indexName),data:{getVersion:2}},t),ys=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/synonyms/%s",e.indexName,t)},r),bt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Get,path:l.encode("1/indexes/%s/task/%s",e.indexName,t.toString())},r),gs=e=>(t,r)=>l.createWaitablePromise(Pt(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),Pt=e=>(t,r)=>{let o=r||{},{createIfNotExists:s}=o,n=R(o,["createIfNotExists"]),a=s?k.PartialUpdateObject:k.PartialUpdateObjectNoCreate;return te(e)(t,a,n)},fs=e=>(t,r)=>{let O=r||{},{safe:s,autoGenerateObjectIDIfNotExist:n,batchSize:a}=O,o=R(O,["safe","autoGenerateObjectIDIfNotExist","batchSize"]),d=(P,x,v,j)=>l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/operation",P),data:{operation:v,destination:x}},j),(T,V)=>D(e)(T.taskID,V)),y=Math.random().toString(36).substring(7),b=`${e.indexName}_tmp_${y}`,f=he({appId:e.appId,transporter:e.transporter,indexName:b}),p=[],h=d(e.indexName,b,"copy",g(u({},o),{scope:["settings","synonyms","rules"]}));p.push(h);let S=(s?h.wait(o):h).then(()=>{let P=f(t,g(u({},o),{autoGenerateObjectIDIfNotExist:n,batchSize:a}));return p.push(P),s?P.wait(o):P}).then(()=>{let P=d(b,e.indexName,"move",o);return p.push(P),s?P.wait(o):P}).then(()=>Promise.all(p)).then(([P,x,v])=>({objectIDs:x.objectIDs,taskIDs:[P.taskID,...x.taskIDs,v.taskID]}));return l.createWaitablePromise(S,(P,x)=>Promise.all(p.map(v=>v.wait(x))))},bs=e=>(t,r)=>ye(e)(t,g(u({},r),{clearExistingRules:!0})),Ps=e=>(t,r)=>ge(e)(t,g(u({},r),{replaceExistingSynonyms:!0})),js=e=>(t,r)=>l.createWaitablePromise(he(e)([t],r).then(s=>({objectID:s.objectIDs[0],taskID:s.taskIDs[0]})),(s,n)=>D(e)(s.taskID,n)),he=e=>(t,r)=>{let o=r||{},{autoGenerateObjectIDIfNotExist:s}=o,n=R(o,["autoGenerateObjectIDIfNotExist"]),a=s?k.AddObject:k.UpdateObject;if(a===k.UpdateObject){for(let d of t)if(d.objectID===void 0)return l.createWaitablePromise(Promise.reject(ct()))}return te(e)(t,a,n)},Os=e=>(t,r)=>ye(e)([t],r),ye=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,clearExistingRules:n}=d,a=R(d,["forwardToReplicas","clearExistingRules"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.clearExistingRules=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},Is=e=>(t,r)=>ge(e)([t],r),ge=e=>(t,r)=>{let d=r||{},{forwardToReplicas:s,replaceExistingSynonyms:n}=d,a=R(d,["forwardToReplicas","replaceExistingSynonyms"]),o=q.createMappedRequestOptions(a);return s&&(o.queryParameters.forwardToReplicas=1),n&&(o.queryParameters.replaceExistingSynonyms=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/batch",e.indexName),data:t},o),(y,b)=>D(e)(y.taskID,b))},ft=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),dt=e=>(t,r,s)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},s),mt=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/rules/search",e.indexName),data:{query:t}},r),ht=e=>(t,r)=>e.transporter.read({method:m.MethodEnum.Post,path:l.encode("1/indexes/%s/synonyms/search",e.indexName),data:{query:t}},r),As=e=>(t,r)=>{let o=r||{},{forwardToReplicas:s}=o,n=R(o,["forwardToReplicas"]),a=q.createMappedRequestOptions(n);return s&&(a.queryParameters.forwardToReplicas=1),l.createWaitablePromise(e.transporter.write({method:m.MethodEnum.Put,path:l.encode("1/indexes/%s/settings",e.indexName),data:t},a),(d,y)=>D(e)(d.taskID,y))},D=e=>(t,r)=>l.createRetryablePromise(s=>bt(e)(t,r).then(n=>n.status!=="published"?s():void 0)),Ss={AddObject:"addObject",Analytics:"analytics",Browser:"browse",DeleteIndex:"deleteIndex",DeleteObject:"deleteObject",EditSettings:"editSettings",ListIndexes:"listIndexes",Logs:"logs",Recommendation:"recommendation",Search:"search",SeeUnretrievableAttributes:"seeUnretrievableAttributes",Settings:"settings",Usage:"usage"},k={AddObject:"addObject",UpdateObject:"updateObject",PartialUpdateObject:"partialUpdateObject",PartialUpdateObjectNoCreate:"partialUpdateObjectNoCreate",DeleteObject:"deleteObject"},ee={Settings:"settings",Synonyms:"synonyms",Rules:"rules"},Ds={None:"none",StopIfEnoughMatches:"stopIfEnoughMatches"},Rs={Synonym:"synonym",OneWaySynonym:"oneWaySynonym",AltCorrection1:"altCorrection1",AltCorrection2:"altCorrection2",Placeholder:"placeholder"};i.ApiKeyACLEnum=Ss;i.BatchActionEnum=k;i.ScopeEnum=ee;i.StrategyEnum=Ds;i.SynonymEnum=Rs;i.addApiKey=Rr;i.assignUserID=vr;i.assignUserIDs=xr;i.batch=pt;i.browseObjects=Yr;i.browseRules=Zr;i.browseSynonyms=es;i.chunkedBatch=te;i.clearObjects=ts;i.clearRules=rs;i.clearSynonyms=ss;i.copyIndex=Z;i.copyRules=qr;i.copySettings=Er;i.copySynonyms=Tr;i.createBrowsablePromise=Y;i.createMissingObjectIDError=ct;i.createObjectNotFoundError=ut;i.createSearchClient=Dr;i.createValidUntilNotFoundError=lt;i.deleteApiKey=Mr;i.deleteBy=ns;i.deleteIndex=as;i.deleteObject=os;i.deleteObjects=yt;i.deleteRule=is;i.deleteSynonym=cs;i.exists=us;i.findObject=ls;i.generateSecuredApiKey=wr;i.getApiKey=$;i.getLogs=kr;i.getObject=ds;i.getObjectPosition=ps;i.getObjects=ms;i.getRule=hs;i.getSecuredApiKeyRemainingValidity=Cr;i.getSettings=gt;i.getSynonym=ys;i.getTask=bt;i.getTopUserIDs=Ur;i.getUserID=Nr;i.hasPendingMappings=Wr;i.initIndex=L;i.listApiKeys=Hr;i.listClusters=_r;i.listIndices=Fr;i.listUserIDs=Br;i.moveIndex=Kr;i.multipleBatch=zr;i.multipleGetObjects=Gr;i.multipleQueries=$r;i.multipleSearchForFacetValues=Lr;i.partialUpdateObject=gs;i.partialUpdateObjects=Pt;i.removeUserID=Vr;i.replaceAllObjects=fs;i.replaceAllRules=bs;i.replaceAllSynonyms=Ps;i.restoreApiKey=Qr;i.saveObject=js;i.saveObjects=he;i.saveRule=Os;i.saveRules=ye;i.saveSynonym=Is;i.saveSynonyms=ge;i.search=ft;i.searchForFacetValues=dt;i.searchRules=mt;i.searchSynonyms=ht;i.searchUserIDs=Jr;i.setSettings=As;i.updateApiKey=Xr;i.waitTask=D});var It=I((on,Ot)=>{Ot.exports=jt()});var At=I(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});function vs(){return{debug(e,t){return Promise.resolve()},info(e,t){return Promise.resolve()},error(e,t){return Promise.resolve()}}}var xs={Debug:1,Info:2,Error:3};re.LogLevelEnum=xs;re.createNullLogger=vs});var Dt=I((un,St)=>{St.exports=At()});var xt=I(fe=>{"use strict";Object.defineProperty(fe,"__esModule",{value:!0});var Rt=require("http"),vt=require("https"),qs=require("url");function Es(){let e={keepAlive:!0},t=new Rt.Agent(e),r=new vt.Agent(e);return{send(s){return new Promise(n=>{let a=qs.parse(s.url),o=a.query===null?a.pathname:`${a.pathname}?${a.query}`,d=u({agent:a.protocol==="https:"?r:t,hostname:a.hostname,path:o,method:s.method,headers:s.headers},a.port!==void 0?{port:a.port||""}:{}),y=(a.protocol==="https:"?vt:Rt).request(d,h=>{let S="";h.on("data",O=>S+=O),h.on("end",()=>{clearTimeout(f),clearTimeout(p),n({status:h.statusCode||0,content:S,isTimedOut:!1})})}),b=(h,S)=>setTimeout(()=>{y.abort(),n({status:0,content:S,isTimedOut:!0})},h*1e3),f=b(s.connectTimeout,"Connection timeout"),p;y.on("error",h=>{clearTimeout(f),clearTimeout(p),n({status:0,content:h.message,isTimedOut:!1})}),y.once("response",()=>{clearTimeout(f),p=b(s.responseTimeout,"Socket timeout")}),s.data!==void 0&&y.write(s.data),y.end()})},destroy(){return t.destroy(),r.destroy(),Promise.resolve()}}}fe.createNodeHttpRequester=Es});var Et=I((dn,qt)=>{qt.exports=xt()});var kt=I((pn,Tt)=>{"use strict";var Mt=Ee(),Ts=we(),W=st(),be=F(),Pe=it(),c=It(),Ms=Dt(),ws=Et(),ks=K();function wt(e,t,r){let s={appId:e,apiKey:t,timeouts:{connect:2,read:5,write:30},requester:ws.createNodeHttpRequester(),logger:Ms.createNullLogger(),responsesCache:Mt.createNullCache(),requestsCache:Mt.createNullCache(),hostsCache:Ts.createInMemoryCache(),userAgent:ks.createUserAgent(be.version).add({segment:"Node.js",version:process.versions.node})};return c.createSearchClient(g(u(u({},s),r),{methods:{search:c.multipleQueries,searchForFacetValues:c.multipleSearchForFacetValues,multipleBatch:c.multipleBatch,multipleGetObjects:c.multipleGetObjects,multipleQueries:c.multipleQueries,copyIndex:c.copyIndex,copySettings:c.copySettings,copyRules:c.copyRules,copySynonyms:c.copySynonyms,moveIndex:c.moveIndex,listIndices:c.listIndices,getLogs:c.getLogs,listClusters:c.listClusters,multipleSearchForFacetValues:c.multipleSearchForFacetValues,getApiKey:c.getApiKey,addApiKey:c.addApiKey,listApiKeys:c.listApiKeys,updateApiKey:c.updateApiKey,deleteApiKey:c.deleteApiKey,restoreApiKey:c.restoreApiKey,assignUserID:c.assignUserID,assignUserIDs:c.assignUserIDs,getUserID:c.getUserID,searchUserIDs:c.searchUserIDs,listUserIDs:c.listUserIDs,getTopUserIDs:c.getTopUserIDs,removeUserID:c.removeUserID,hasPendingMappings:c.hasPendingMappings,generateSecuredApiKey:c.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:c.getSecuredApiKeyRemainingValidity,destroy:be.destroy,initIndex:n=>a=>c.initIndex(n)(a,{methods:{batch:c.batch,delete:c.deleteIndex,getObject:c.getObject,getObjects:c.getObjects,saveObject:c.saveObject,saveObjects:c.saveObjects,search:c.search,searchForFacetValues:c.searchForFacetValues,waitTask:c.waitTask,setSettings:c.setSettings,getSettings:c.getSettings,partialUpdateObject:c.partialUpdateObject,partialUpdateObjects:c.partialUpdateObjects,deleteObject:c.deleteObject,deleteObjects:c.deleteObjects,deleteBy:c.deleteBy,clearObjects:c.clearObjects,browseObjects:c.browseObjects,getObjectPosition:c.getObjectPosition,findObject:c.findObject,exists:c.exists,saveSynonym:c.saveSynonym,saveSynonyms:c.saveSynonyms,getSynonym:c.getSynonym,searchSynonyms:c.searchSynonyms,browseSynonyms:c.browseSynonyms,deleteSynonym:c.deleteSynonym,clearSynonyms:c.clearSynonyms,replaceAllObjects:c.replaceAllObjects,replaceAllSynonyms:c.replaceAllSynonyms,searchRules:c.searchRules,getRule:c.getRule,deleteRule:c.deleteRule,saveRule:c.saveRule,saveRules:c.saveRules,replaceAllRules:c.replaceAllRules,browseRules:c.browseRules,clearRules:c.clearRules}}),initAnalytics:()=>n=>W.createAnalyticsClient(g(u(u({},s),n),{methods:{addABTest:W.addABTest,getABTest:W.getABTest,getABTests:W.getABTests,stopABTest:W.stopABTest,deleteABTest:W.deleteABTest}})),initRecommendation:()=>n=>Pe.createRecommendationClient(g(u(u({},s),n),{methods:{getPersonalizationStrategy:Pe.getPersonalizationStrategy,setPersonalizationStrategy:Pe.setPersonalizationStrategy}}))}}))}wt.version=be.version;Tt.exports=wt});var Ut=I((mn,je)=>{var Ct=kt();je.exports=Ct;je.exports.default=Ct});var Ws={};Vt(Ws,{default:()=>Ks});var Oe=C(require("@yarnpkg/core")),E=C(require("@yarnpkg/core")),Ie=C(require("@yarnpkg/plugin-essentials")),Ht=C(require("semver"));var se=C(require("@yarnpkg/core")),Nt=C(Ut()),Cs="e8e1bd300d860104bb8c58453ffa1eb4",Us="OFCNCOG2CU",Wt=async(e,t)=>{var a;let r=se.structUtils.stringifyIdent(e),n=Ns(t).initIndex("npm-search");try{return((a=(await n.getObject(r,{attributesToRetrieve:["types"]})).types)==null?void 0:a.ts)==="definitely-typed"}catch(o){return!1}},Ns=e=>(0,Nt.default)(Us,Cs,{requester:{async send(r){try{let s=await se.httpUtils.request(r.url,r.data||null,{configuration:e,headers:r.headers});return{content:s.body,isTimedOut:!1,status:s.statusCode}}catch(s){return{content:s.response.body,isTimedOut:!1,status:s.response.statusCode}}}}});var _t=e=>e.scope?`${e.scope}__${e.name}`:`${e.name}`,Hs=async(e,t,r,s)=>{if(r.scope==="types")return;let{project:n}=e,{configuration:a}=n,o=a.makeResolver(),d={project:n,resolver:o,report:new E.ThrowReport};if(!await Wt(r,a))return;let b=_t(r),f=E.structUtils.parseRange(r.range).selector;if(!E.semverUtils.validRange(f)){let P=await o.getCandidates(r,new Map,d);f=E.structUtils.parseRange(P[0].reference).selector}let p=Ht.default.coerce(f);if(p===null)return;let h=`${Ie.suggestUtils.Modifier.CARET}${p.major}`,S=E.structUtils.makeDescriptor(E.structUtils.makeIdent("types",b),h),O=E.miscUtils.mapAndFind(n.workspaces,P=>{var T,V;let x=(T=P.manifest.dependencies.get(r.identHash))==null?void 0:T.descriptorHash,v=(V=P.manifest.devDependencies.get(r.identHash))==null?void 0:V.descriptorHash;if(x!==r.descriptorHash&&v!==r.descriptorHash)return E.miscUtils.mapAndFind.skip;let j=[];for(let Ae of Oe.Manifest.allDependencies){let Se=P.manifest[Ae].get(S.identHash);typeof Se!="undefined"&&j.push([Ae,Se])}return j.length===0?E.miscUtils.mapAndFind.skip:j});if(typeof O!="undefined")for(let[P,x]of O)e.manifest[P].set(x.identHash,x);else{try{if((await o.getCandidates(S,new Map,d)).length===0)return}catch{return}e.manifest[Ie.suggestUtils.Target.DEVELOPMENT].set(S.identHash,S)}},_s=async(e,t,r)=>{if(r.scope==="types")return;let s=_t(r),n=E.structUtils.makeIdent("types",s);for(let a of Oe.Manifest.allDependencies)typeof e.manifest[a].get(n.identHash)!="undefined"&&e.manifest[a].delete(n.identHash)},Fs=(e,t)=>{t.publishConfig&&t.publishConfig.typings&&(t.typings=t.publishConfig.typings),t.publishConfig&&t.publishConfig.types&&(t.types=t.publishConfig.types)},Bs={hooks:{afterWorkspaceDependencyAddition:Hs,afterWorkspaceDependencyRemoval:_s,beforeWorkspacePacking:Fs}},Ks=Bs;return Ws;})(); 7 | return plugin; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/bin/eslint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require eslint/bin/eslint.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real eslint/bin/eslint.js your application uses 20 | module.exports = absRequire(`eslint/bin/eslint.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/api.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require eslint 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real eslint your application uses 20 | module.exports = absRequire(`eslint`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint", 3 | "version": "8.6.0-sdk", 4 | "main": "./lib/api.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vscode 6 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require prettier/index.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real prettier/index.js your application uses 20 | module.exports = absRequire(`prettier/index.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prettier", 3 | "version": "2.5.1-sdk", 4 | "main": "./index.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsc 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsc your application uses 20 | module.exports = absRequire(`typescript/bin/tsc`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/bin/tsserver 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/bin/tsserver your application uses 20 | module.exports = absRequire(`typescript/bin/tsserver`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/tsc.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/tsc.js your application uses 20 | module.exports = absRequire(`typescript/lib/tsc.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserver.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 22 | 23 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 24 | return `${locator.name}@${locator.reference}`; 25 | })); 26 | 27 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 28 | // doesn't understand. This layer makes sure to remove the protocol 29 | // before forwarding it to TS, and to add it back on all returned paths. 30 | 31 | function toEditorPath(str) { 32 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 33 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 34 | // We also take the opportunity to turn virtual paths into physical ones; 35 | // this makes it much easier to work with workspaces that list peer 36 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 37 | // file instances instead of the real ones. 38 | // 39 | // We only do this to modules owned by the the dependency tree roots. 40 | // This avoids breaking the resolution when jumping inside a vendor 41 | // with peer dep (otherwise jumping into react-dom would show resolution 42 | // errors on react). 43 | // 44 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 45 | if (resolved) { 46 | const locator = pnpApi.findPackageLocator(resolved); 47 | if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) { 48 | str = resolved; 49 | } 50 | } 51 | 52 | str = normalize(str); 53 | 54 | if (str.match(/\.zip\//)) { 55 | switch (hostInfo) { 56 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 57 | // VSCode only adds it automatically for supported schemes, 58 | // so we have to do it manually for the `zip` scheme. 59 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 60 | // 61 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 62 | // 63 | // Update Oct 8 2021: VSCode changed their format in 1.61. 64 | // Before | ^zip:/c:/foo/bar.zip/package.json 65 | // After | ^/zip//c:/foo/bar.zip/package.json 66 | // 67 | case `vscode <1.61`: { 68 | str = `^zip:${str}`; 69 | } break; 70 | 71 | case `vscode`: { 72 | str = `^/zip/${str}`; 73 | } break; 74 | 75 | // To make "go to definition" work, 76 | // We have to resolve the actual file system path from virtual path 77 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 78 | case `coc-nvim`: { 79 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 80 | str = resolve(`zipfile:${str}`); 81 | } break; 82 | 83 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 84 | // We have to resolve the actual file system path from virtual path, 85 | // everything else is up to neovim 86 | case `neovim`: { 87 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 88 | str = `zipfile:${str}`; 89 | } break; 90 | 91 | default: { 92 | str = `zip:${str}`; 93 | } break; 94 | } 95 | } 96 | } 97 | 98 | return str; 99 | } 100 | 101 | function fromEditorPath(str) { 102 | switch (hostInfo) { 103 | case `coc-nvim`: 104 | case `neovim`: { 105 | str = str.replace(/\.zip::/, `.zip/`); 106 | // The path for coc-nvim is in format of //zipfile://.yarn/... 107 | // So in order to convert it back, we use .* to match all the thing 108 | // before `zipfile:` 109 | return process.platform === `win32` 110 | ? str.replace(/^.*zipfile:\//, ``) 111 | : str.replace(/^.*zipfile:/, ``); 112 | } break; 113 | 114 | case `vscode`: 115 | default: { 116 | return process.platform === `win32` 117 | ? str.replace(/^\^?(zip:|\/zip)\/+/, ``) 118 | : str.replace(/^\^?(zip:|\/zip)\/+/, `/`); 119 | } break; 120 | } 121 | } 122 | 123 | // Force enable 'allowLocalPluginLoads' 124 | // TypeScript tries to resolve plugins using a path relative to itself 125 | // which doesn't work when using the global cache 126 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 127 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 128 | // TypeScript already does local loads and if this code is running the user trusts the workspace 129 | // https://github.com/microsoft/vscode/issues/45856 130 | const ConfiguredProject = tsserver.server.ConfiguredProject; 131 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 132 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 133 | this.projectService.allowLocalPluginLoads = true; 134 | return originalEnablePluginsWithOptions.apply(this, arguments); 135 | }; 136 | 137 | // And here is the point where we hijack the VSCode <-> TS communications 138 | // by adding ourselves in the middle. We locate everything that looks 139 | // like an absolute path of ours and normalize it. 140 | 141 | const Session = tsserver.server.Session; 142 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 143 | let hostInfo = `unknown`; 144 | 145 | Object.assign(Session.prototype, { 146 | onMessage(/** @type {string} */ message) { 147 | const parsedMessage = JSON.parse(message) 148 | 149 | if ( 150 | parsedMessage != null && 151 | typeof parsedMessage === `object` && 152 | parsedMessage.arguments && 153 | typeof parsedMessage.arguments.hostInfo === `string` 154 | ) { 155 | hostInfo = parsedMessage.arguments.hostInfo; 156 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK && process.env.VSCODE_IPC_HOOK.match(/Code\/1\.([1-5][0-9]|60)\./)) { 157 | hostInfo += ` <1.61`; 158 | } 159 | } 160 | 161 | return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => { 162 | return typeof value === `string` ? fromEditorPath(value) : value; 163 | })); 164 | }, 165 | 166 | send(/** @type {any} */ msg) { 167 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 168 | return typeof value === `string` ? toEditorPath(value) : value; 169 | }))); 170 | } 171 | }); 172 | 173 | return tsserver; 174 | }; 175 | 176 | if (existsSync(absPnpApiPath)) { 177 | if (!process.versions.pnp) { 178 | // Setup the environment to be able to require typescript/lib/tsserver.js 179 | require(absPnpApiPath).setup(); 180 | } 181 | } 182 | 183 | // Defer to the real typescript/lib/tsserver.js your application uses 184 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`)); 185 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsserverlibrary.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | const moduleWrapper = tsserver => { 13 | if (!process.versions.pnp) { 14 | return tsserver; 15 | } 16 | 17 | const {isAbsolute} = require(`path`); 18 | const pnpApi = require(`pnpapi`); 19 | 20 | const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//); 21 | const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`); 22 | 23 | const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => { 24 | return `${locator.name}@${locator.reference}`; 25 | })); 26 | 27 | // VSCode sends the zip paths to TS using the "zip://" prefix, that TS 28 | // doesn't understand. This layer makes sure to remove the protocol 29 | // before forwarding it to TS, and to add it back on all returned paths. 30 | 31 | function toEditorPath(str) { 32 | // We add the `zip:` prefix to both `.zip/` paths and virtual paths 33 | if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) { 34 | // We also take the opportunity to turn virtual paths into physical ones; 35 | // this makes it much easier to work with workspaces that list peer 36 | // dependencies, since otherwise Ctrl+Click would bring us to the virtual 37 | // file instances instead of the real ones. 38 | // 39 | // We only do this to modules owned by the the dependency tree roots. 40 | // This avoids breaking the resolution when jumping inside a vendor 41 | // with peer dep (otherwise jumping into react-dom would show resolution 42 | // errors on react). 43 | // 44 | const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str; 45 | if (resolved) { 46 | const locator = pnpApi.findPackageLocator(resolved); 47 | if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) { 48 | str = resolved; 49 | } 50 | } 51 | 52 | str = normalize(str); 53 | 54 | if (str.match(/\.zip\//)) { 55 | switch (hostInfo) { 56 | // Absolute VSCode `Uri.fsPath`s need to start with a slash. 57 | // VSCode only adds it automatically for supported schemes, 58 | // so we have to do it manually for the `zip` scheme. 59 | // The path needs to start with a caret otherwise VSCode doesn't handle the protocol 60 | // 61 | // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910 62 | // 63 | // Update Oct 8 2021: VSCode changed their format in 1.61. 64 | // Before | ^zip:/c:/foo/bar.zip/package.json 65 | // After | ^/zip//c:/foo/bar.zip/package.json 66 | // 67 | case `vscode <1.61`: { 68 | str = `^zip:${str}`; 69 | } break; 70 | 71 | case `vscode`: { 72 | str = `^/zip/${str}`; 73 | } break; 74 | 75 | // To make "go to definition" work, 76 | // We have to resolve the actual file system path from virtual path 77 | // and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip) 78 | case `coc-nvim`: { 79 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 80 | str = resolve(`zipfile:${str}`); 81 | } break; 82 | 83 | // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server) 84 | // We have to resolve the actual file system path from virtual path, 85 | // everything else is up to neovim 86 | case `neovim`: { 87 | str = normalize(resolved).replace(/\.zip\//, `.zip::`); 88 | str = `zipfile:${str}`; 89 | } break; 90 | 91 | default: { 92 | str = `zip:${str}`; 93 | } break; 94 | } 95 | } 96 | } 97 | 98 | return str; 99 | } 100 | 101 | function fromEditorPath(str) { 102 | switch (hostInfo) { 103 | case `coc-nvim`: 104 | case `neovim`: { 105 | str = str.replace(/\.zip::/, `.zip/`); 106 | // The path for coc-nvim is in format of //zipfile://.yarn/... 107 | // So in order to convert it back, we use .* to match all the thing 108 | // before `zipfile:` 109 | return process.platform === `win32` 110 | ? str.replace(/^.*zipfile:\//, ``) 111 | : str.replace(/^.*zipfile:/, ``); 112 | } break; 113 | 114 | case `vscode`: 115 | default: { 116 | return process.platform === `win32` 117 | ? str.replace(/^\^?(zip:|\/zip)\/+/, ``) 118 | : str.replace(/^\^?(zip:|\/zip)\/+/, `/`); 119 | } break; 120 | } 121 | } 122 | 123 | // Force enable 'allowLocalPluginLoads' 124 | // TypeScript tries to resolve plugins using a path relative to itself 125 | // which doesn't work when using the global cache 126 | // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238 127 | // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but 128 | // TypeScript already does local loads and if this code is running the user trusts the workspace 129 | // https://github.com/microsoft/vscode/issues/45856 130 | const ConfiguredProject = tsserver.server.ConfiguredProject; 131 | const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype; 132 | ConfiguredProject.prototype.enablePluginsWithOptions = function() { 133 | this.projectService.allowLocalPluginLoads = true; 134 | return originalEnablePluginsWithOptions.apply(this, arguments); 135 | }; 136 | 137 | // And here is the point where we hijack the VSCode <-> TS communications 138 | // by adding ourselves in the middle. We locate everything that looks 139 | // like an absolute path of ours and normalize it. 140 | 141 | const Session = tsserver.server.Session; 142 | const {onMessage: originalOnMessage, send: originalSend} = Session.prototype; 143 | let hostInfo = `unknown`; 144 | 145 | Object.assign(Session.prototype, { 146 | onMessage(/** @type {string} */ message) { 147 | const parsedMessage = JSON.parse(message) 148 | 149 | if ( 150 | parsedMessage != null && 151 | typeof parsedMessage === `object` && 152 | parsedMessage.arguments && 153 | typeof parsedMessage.arguments.hostInfo === `string` 154 | ) { 155 | hostInfo = parsedMessage.arguments.hostInfo; 156 | if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK && process.env.VSCODE_IPC_HOOK.match(/Code\/1\.([1-5][0-9]|60)\./)) { 157 | hostInfo += ` <1.61`; 158 | } 159 | } 160 | 161 | return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => { 162 | return typeof value === `string` ? fromEditorPath(value) : value; 163 | })); 164 | }, 165 | 166 | send(/** @type {any} */ msg) { 167 | return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => { 168 | return typeof value === `string` ? toEditorPath(value) : value; 169 | }))); 170 | } 171 | }); 172 | 173 | return tsserver; 174 | }; 175 | 176 | if (existsSync(absPnpApiPath)) { 177 | if (!process.versions.pnp) { 178 | // Setup the environment to be able to require typescript/lib/tsserverlibrary.js 179 | require(absPnpApiPath).setup(); 180 | } 181 | } 182 | 183 | // Defer to the real typescript/lib/tsserverlibrary.js your application uses 184 | module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`)); 185 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, createRequireFromPath} = require(`module`); 5 | const {resolve} = require(`path`); 6 | 7 | const relPnpApiPath = "../../../../.pnp.cjs"; 8 | 9 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 10 | const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath); 11 | 12 | if (existsSync(absPnpApiPath)) { 13 | if (!process.versions.pnp) { 14 | // Setup the environment to be able to require typescript/lib/typescript.js 15 | require(absPnpApiPath).setup(); 16 | } 17 | } 18 | 19 | // Defer to the real typescript/lib/typescript.js your application uses 20 | module.exports = absRequire(`typescript/lib/typescript.js`); 21 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "4.5.4-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs" 6 | } 7 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | enableGlobalCache: true 2 | 3 | nodeLinker: pnp 4 | 5 | plugins: 6 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs 7 | spec: "@yarnpkg/plugin-interactive-tools" 8 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs 9 | spec: "@yarnpkg/plugin-typescript" 10 | 11 | yarnPath: .yarn/releases/yarn-3.1.1.cjs 12 | -------------------------------------------------------------------------------- /Anchor.toml: -------------------------------------------------------------------------------- 1 | anchor_version = "0.20.1" 2 | solana_version = "1.8.11" 3 | 4 | [scripts] 5 | test = "yarn mocha" 6 | 7 | [provider] 8 | cluster = "localnet" 9 | wallet = "./tests/spec-key.json" 10 | 11 | [[test.genesis]] 12 | address = "CRATwLpu6YZEeiVq9ajjxs61wPQ9f29s1UoQR9siJCRs" 13 | program = "./artifacts/deploy/crate_token.so" 14 | 15 | [programs.localnet] 16 | venko = "AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ" 17 | 18 | [programs.devnet] 19 | venko = "AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ" 20 | 21 | [programs.testnet] 22 | venko = "AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ" 23 | 24 | [programs.mainnet] 25 | venko = "AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ" 26 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.4.7" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" 10 | 11 | [[package]] 12 | name = "aho-corasick" 13 | version = "0.7.18" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 16 | dependencies = [ 17 | "memchr", 18 | ] 19 | 20 | [[package]] 21 | name = "anchor-attribute-access-control" 22 | version = "0.20.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "105c443a613f29212755fb6c5f946fa82dcf94a80528f643e0faa9d9faeb626b" 25 | dependencies = [ 26 | "anchor-syn", 27 | "anyhow", 28 | "proc-macro2", 29 | "quote", 30 | "regex", 31 | "syn", 32 | ] 33 | 34 | [[package]] 35 | name = "anchor-attribute-account" 36 | version = "0.20.1" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "fdae15851aa41972e9c18c987613c50a916c48c88c97ea3316156a5c772e5faa" 39 | dependencies = [ 40 | "anchor-syn", 41 | "anyhow", 42 | "bs58 0.4.0", 43 | "proc-macro2", 44 | "quote", 45 | "rustversion", 46 | "syn", 47 | ] 48 | 49 | [[package]] 50 | name = "anchor-attribute-constant" 51 | version = "0.20.1" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "6356865217881d0bbea8aa70625937bec6d9952610f1ba2a2452a8e427000687" 54 | dependencies = [ 55 | "anchor-syn", 56 | "proc-macro2", 57 | "syn", 58 | ] 59 | 60 | [[package]] 61 | name = "anchor-attribute-error" 62 | version = "0.20.1" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "ebe998ce4e6e0cb0e291d1a1626bd30791cdfdd9d05523111bdf4fd053f08636" 65 | dependencies = [ 66 | "anchor-syn", 67 | "proc-macro2", 68 | "quote", 69 | "syn", 70 | ] 71 | 72 | [[package]] 73 | name = "anchor-attribute-event" 74 | version = "0.20.1" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "c5810498a20554c20354f5648b6041172f2035e58d09ad40dc051dc0d1501f80" 77 | dependencies = [ 78 | "anchor-syn", 79 | "anyhow", 80 | "proc-macro2", 81 | "quote", 82 | "syn", 83 | ] 84 | 85 | [[package]] 86 | name = "anchor-attribute-interface" 87 | version = "0.20.1" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "ac83f085b2be8b3a3412989cf96cf7f683561db7d357c5aa4aa11d48bbb22213" 90 | dependencies = [ 91 | "anchor-syn", 92 | "anyhow", 93 | "heck", 94 | "proc-macro2", 95 | "quote", 96 | "syn", 97 | ] 98 | 99 | [[package]] 100 | name = "anchor-attribute-program" 101 | version = "0.20.1" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "73c56be575d89abcb192afa29deb87b2cdb3c39033abc02f2d16e6af999b23b7" 104 | dependencies = [ 105 | "anchor-syn", 106 | "anyhow", 107 | "proc-macro2", 108 | "quote", 109 | "syn", 110 | ] 111 | 112 | [[package]] 113 | name = "anchor-attribute-state" 114 | version = "0.20.1" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "62ab002353b01fcb4f72cca256d5d62db39f9ff39b1d072280deee9798f1f524" 117 | dependencies = [ 118 | "anchor-syn", 119 | "anyhow", 120 | "proc-macro2", 121 | "quote", 122 | "syn", 123 | ] 124 | 125 | [[package]] 126 | name = "anchor-derive-accounts" 127 | version = "0.20.1" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "e9e653cdb322078d95221384c4a527a403560e509ac7cb2b53d3bd664b23c4d6" 130 | dependencies = [ 131 | "anchor-syn", 132 | "anyhow", 133 | "proc-macro2", 134 | "quote", 135 | "syn", 136 | ] 137 | 138 | [[package]] 139 | name = "anchor-lang" 140 | version = "0.20.1" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "4815ad6334fd2f561f7ddcc3cfbeed87ed3003724171bd80ebe6383d5173ee8f" 143 | dependencies = [ 144 | "anchor-attribute-access-control", 145 | "anchor-attribute-account", 146 | "anchor-attribute-constant", 147 | "anchor-attribute-error", 148 | "anchor-attribute-event", 149 | "anchor-attribute-interface", 150 | "anchor-attribute-program", 151 | "anchor-attribute-state", 152 | "anchor-derive-accounts", 153 | "arrayref", 154 | "base64 0.13.0", 155 | "bincode", 156 | "borsh", 157 | "bytemuck", 158 | "solana-program", 159 | "thiserror", 160 | ] 161 | 162 | [[package]] 163 | name = "anchor-spl" 164 | version = "0.20.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "9ea94b04fc9a0aaae4d4473b0595fb5f55b6c9b38e0d6f596df8c8060f95f096" 167 | dependencies = [ 168 | "anchor-lang", 169 | "solana-program", 170 | "spl-associated-token-account", 171 | "spl-token", 172 | ] 173 | 174 | [[package]] 175 | name = "anchor-syn" 176 | version = "0.20.1" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "3be7bfb6991d79cce3495fb6ce0892f58a5c75a74c8d1c2fc6f62926066eb9f4" 179 | dependencies = [ 180 | "anyhow", 181 | "bs58 0.3.1", 182 | "heck", 183 | "proc-macro2", 184 | "proc-macro2-diagnostics", 185 | "quote", 186 | "serde", 187 | "serde_json", 188 | "sha2", 189 | "syn", 190 | "thiserror", 191 | ] 192 | 193 | [[package]] 194 | name = "anyhow" 195 | version = "1.0.52" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" 198 | 199 | [[package]] 200 | name = "arrayref" 201 | version = "0.3.6" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 204 | 205 | [[package]] 206 | name = "arrayvec" 207 | version = "0.7.2" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" 210 | 211 | [[package]] 212 | name = "atty" 213 | version = "0.2.14" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 216 | dependencies = [ 217 | "hermit-abi", 218 | "libc", 219 | "winapi", 220 | ] 221 | 222 | [[package]] 223 | name = "autocfg" 224 | version = "1.0.1" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 227 | 228 | [[package]] 229 | name = "base64" 230 | version = "0.12.3" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 233 | 234 | [[package]] 235 | name = "base64" 236 | version = "0.13.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 239 | 240 | [[package]] 241 | name = "bincode" 242 | version = "1.3.3" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 245 | dependencies = [ 246 | "serde", 247 | ] 248 | 249 | [[package]] 250 | name = "bit-set" 251 | version = "0.5.2" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" 254 | dependencies = [ 255 | "bit-vec", 256 | ] 257 | 258 | [[package]] 259 | name = "bit-vec" 260 | version = "0.6.3" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 263 | 264 | [[package]] 265 | name = "bitflags" 266 | version = "1.3.2" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 269 | 270 | [[package]] 271 | name = "blake3" 272 | version = "1.3.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "882e99e4a0cb2ae6cb6e442102e8e6b7131718d94110e64c3e6a34ea9b106f37" 275 | dependencies = [ 276 | "arrayref", 277 | "arrayvec", 278 | "cc", 279 | "cfg-if", 280 | "constant_time_eq", 281 | "digest 0.10.1", 282 | ] 283 | 284 | [[package]] 285 | name = "block-buffer" 286 | version = "0.9.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 289 | dependencies = [ 290 | "block-padding", 291 | "generic-array", 292 | ] 293 | 294 | [[package]] 295 | name = "block-buffer" 296 | version = "0.10.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" 299 | dependencies = [ 300 | "generic-array", 301 | ] 302 | 303 | [[package]] 304 | name = "block-padding" 305 | version = "0.2.1" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" 308 | 309 | [[package]] 310 | name = "borsh" 311 | version = "0.9.1" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "18dda7dc709193c0d86a1a51050a926dc3df1cf262ec46a23a25dba421ea1924" 314 | dependencies = [ 315 | "borsh-derive", 316 | "hashbrown", 317 | ] 318 | 319 | [[package]] 320 | name = "borsh-derive" 321 | version = "0.9.1" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "684155372435f578c0fa1acd13ebbb182cc19d6b38b64ae7901da4393217d264" 324 | dependencies = [ 325 | "borsh-derive-internal", 326 | "borsh-schema-derive-internal", 327 | "proc-macro-crate 0.1.5", 328 | "proc-macro2", 329 | "syn", 330 | ] 331 | 332 | [[package]] 333 | name = "borsh-derive-internal" 334 | version = "0.9.1" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "2102f62f8b6d3edeab871830782285b64cc1830168094db05c8e458f209bc5c3" 337 | dependencies = [ 338 | "proc-macro2", 339 | "quote", 340 | "syn", 341 | ] 342 | 343 | [[package]] 344 | name = "borsh-schema-derive-internal" 345 | version = "0.9.1" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "196c978c4c9b0b142d446ef3240690bf5a8a33497074a113ff9a337ccb750483" 348 | dependencies = [ 349 | "proc-macro2", 350 | "quote", 351 | "syn", 352 | ] 353 | 354 | [[package]] 355 | name = "bs58" 356 | version = "0.3.1" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" 359 | 360 | [[package]] 361 | name = "bs58" 362 | version = "0.4.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 365 | 366 | [[package]] 367 | name = "bumpalo" 368 | version = "3.9.1" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" 371 | 372 | [[package]] 373 | name = "bv" 374 | version = "0.11.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" 377 | dependencies = [ 378 | "feature-probe", 379 | "serde", 380 | ] 381 | 382 | [[package]] 383 | name = "bytemuck" 384 | version = "1.7.3" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" 387 | dependencies = [ 388 | "bytemuck_derive", 389 | ] 390 | 391 | [[package]] 392 | name = "bytemuck_derive" 393 | version = "1.0.1" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" 396 | dependencies = [ 397 | "proc-macro2", 398 | "quote", 399 | "syn", 400 | ] 401 | 402 | [[package]] 403 | name = "byteorder" 404 | version = "1.4.3" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 407 | 408 | [[package]] 409 | name = "cc" 410 | version = "1.0.72" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 413 | 414 | [[package]] 415 | name = "cfg-if" 416 | version = "1.0.0" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 419 | 420 | [[package]] 421 | name = "console_error_panic_hook" 422 | version = "0.1.7" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 425 | dependencies = [ 426 | "cfg-if", 427 | "wasm-bindgen", 428 | ] 429 | 430 | [[package]] 431 | name = "console_log" 432 | version = "0.2.0" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" 435 | dependencies = [ 436 | "log", 437 | "web-sys", 438 | ] 439 | 440 | [[package]] 441 | name = "constant_time_eq" 442 | version = "0.1.5" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 445 | 446 | [[package]] 447 | name = "cpufeatures" 448 | version = "0.2.1" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" 451 | dependencies = [ 452 | "libc", 453 | ] 454 | 455 | [[package]] 456 | name = "crate-token" 457 | version = "0.4.1" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "7760d4e459b24f4314790a5f0d677a15a51e4b889ea30791542b5772334413d1" 460 | dependencies = [ 461 | "anchor-lang", 462 | "anchor-spl", 463 | "num-traits", 464 | "static-pubkey", 465 | "vipers", 466 | ] 467 | 468 | [[package]] 469 | name = "crunchy" 470 | version = "0.2.2" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 473 | 474 | [[package]] 475 | name = "crypto-common" 476 | version = "0.1.1" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" 479 | dependencies = [ 480 | "generic-array", 481 | ] 482 | 483 | [[package]] 484 | name = "crypto-mac" 485 | version = "0.8.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 488 | dependencies = [ 489 | "generic-array", 490 | "subtle", 491 | ] 492 | 493 | [[package]] 494 | name = "curve25519-dalek" 495 | version = "3.2.0" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" 498 | dependencies = [ 499 | "byteorder", 500 | "digest 0.9.0", 501 | "rand_core 0.5.1", 502 | "subtle", 503 | "zeroize", 504 | ] 505 | 506 | [[package]] 507 | name = "digest" 508 | version = "0.9.0" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 511 | dependencies = [ 512 | "generic-array", 513 | ] 514 | 515 | [[package]] 516 | name = "digest" 517 | version = "0.10.1" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" 520 | dependencies = [ 521 | "block-buffer 0.10.0", 522 | "crypto-common", 523 | "generic-array", 524 | "subtle", 525 | ] 526 | 527 | [[package]] 528 | name = "either" 529 | version = "1.6.1" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 532 | 533 | [[package]] 534 | name = "env_logger" 535 | version = "0.9.0" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" 538 | dependencies = [ 539 | "atty", 540 | "humantime", 541 | "log", 542 | "regex", 543 | "termcolor", 544 | ] 545 | 546 | [[package]] 547 | name = "fastrand" 548 | version = "1.6.0" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2" 551 | dependencies = [ 552 | "instant", 553 | ] 554 | 555 | [[package]] 556 | name = "feature-probe" 557 | version = "0.1.1" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" 560 | 561 | [[package]] 562 | name = "fnv" 563 | version = "1.0.7" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 566 | 567 | [[package]] 568 | name = "generic-array" 569 | version = "0.14.5" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" 572 | dependencies = [ 573 | "serde", 574 | "typenum", 575 | "version_check", 576 | ] 577 | 578 | [[package]] 579 | name = "getrandom" 580 | version = "0.1.16" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 583 | dependencies = [ 584 | "cfg-if", 585 | "js-sys", 586 | "libc", 587 | "wasi 0.9.0+wasi-snapshot-preview1", 588 | "wasm-bindgen", 589 | ] 590 | 591 | [[package]] 592 | name = "getrandom" 593 | version = "0.2.4" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" 596 | dependencies = [ 597 | "cfg-if", 598 | "libc", 599 | "wasi 0.10.2+wasi-snapshot-preview1", 600 | ] 601 | 602 | [[package]] 603 | name = "hashbrown" 604 | version = "0.9.1" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 607 | dependencies = [ 608 | "ahash", 609 | ] 610 | 611 | [[package]] 612 | name = "heck" 613 | version = "0.3.3" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 616 | dependencies = [ 617 | "unicode-segmentation", 618 | ] 619 | 620 | [[package]] 621 | name = "hermit-abi" 622 | version = "0.1.19" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 625 | dependencies = [ 626 | "libc", 627 | ] 628 | 629 | [[package]] 630 | name = "hmac" 631 | version = "0.8.1" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 634 | dependencies = [ 635 | "crypto-mac", 636 | "digest 0.9.0", 637 | ] 638 | 639 | [[package]] 640 | name = "hmac-drbg" 641 | version = "0.3.0" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" 644 | dependencies = [ 645 | "digest 0.9.0", 646 | "generic-array", 647 | "hmac", 648 | ] 649 | 650 | [[package]] 651 | name = "humantime" 652 | version = "2.1.0" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 655 | 656 | [[package]] 657 | name = "instant" 658 | version = "0.1.12" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 661 | dependencies = [ 662 | "cfg-if", 663 | ] 664 | 665 | [[package]] 666 | name = "itertools" 667 | version = "0.10.3" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 670 | dependencies = [ 671 | "either", 672 | ] 673 | 674 | [[package]] 675 | name = "itoa" 676 | version = "1.0.1" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 679 | 680 | [[package]] 681 | name = "js-sys" 682 | version = "0.3.55" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" 685 | dependencies = [ 686 | "wasm-bindgen", 687 | ] 688 | 689 | [[package]] 690 | name = "keccak" 691 | version = "0.1.0" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" 694 | 695 | [[package]] 696 | name = "lazy_static" 697 | version = "1.4.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 700 | 701 | [[package]] 702 | name = "libc" 703 | version = "0.2.112" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" 706 | 707 | [[package]] 708 | name = "libsecp256k1" 709 | version = "0.6.0" 710 | source = "registry+https://github.com/rust-lang/crates.io-index" 711 | checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" 712 | dependencies = [ 713 | "arrayref", 714 | "base64 0.12.3", 715 | "digest 0.9.0", 716 | "hmac-drbg", 717 | "libsecp256k1-core", 718 | "libsecp256k1-gen-ecmult", 719 | "libsecp256k1-gen-genmult", 720 | "rand 0.7.3", 721 | "serde", 722 | "sha2", 723 | "typenum", 724 | ] 725 | 726 | [[package]] 727 | name = "libsecp256k1-core" 728 | version = "0.2.2" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" 731 | dependencies = [ 732 | "crunchy", 733 | "digest 0.9.0", 734 | "subtle", 735 | ] 736 | 737 | [[package]] 738 | name = "libsecp256k1-gen-ecmult" 739 | version = "0.2.1" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" 742 | dependencies = [ 743 | "libsecp256k1-core", 744 | ] 745 | 746 | [[package]] 747 | name = "libsecp256k1-gen-genmult" 748 | version = "0.2.1" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" 751 | dependencies = [ 752 | "libsecp256k1-core", 753 | ] 754 | 755 | [[package]] 756 | name = "lock_api" 757 | version = "0.4.5" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 760 | dependencies = [ 761 | "scopeguard", 762 | ] 763 | 764 | [[package]] 765 | name = "log" 766 | version = "0.4.14" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 769 | dependencies = [ 770 | "cfg-if", 771 | ] 772 | 773 | [[package]] 774 | name = "memchr" 775 | version = "2.4.1" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 778 | 779 | [[package]] 780 | name = "memmap2" 781 | version = "0.5.2" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" 784 | dependencies = [ 785 | "libc", 786 | ] 787 | 788 | [[package]] 789 | name = "num-derive" 790 | version = "0.3.3" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 793 | dependencies = [ 794 | "proc-macro2", 795 | "quote", 796 | "syn", 797 | ] 798 | 799 | [[package]] 800 | name = "num-traits" 801 | version = "0.2.14" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 804 | dependencies = [ 805 | "autocfg", 806 | ] 807 | 808 | [[package]] 809 | name = "num_enum" 810 | version = "0.5.6" 811 | source = "registry+https://github.com/rust-lang/crates.io-index" 812 | checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" 813 | dependencies = [ 814 | "num_enum_derive", 815 | ] 816 | 817 | [[package]] 818 | name = "num_enum_derive" 819 | version = "0.5.6" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" 822 | dependencies = [ 823 | "proc-macro-crate 1.1.0", 824 | "proc-macro2", 825 | "quote", 826 | "syn", 827 | ] 828 | 829 | [[package]] 830 | name = "opaque-debug" 831 | version = "0.3.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 834 | 835 | [[package]] 836 | name = "parking_lot" 837 | version = "0.11.2" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 840 | dependencies = [ 841 | "instant", 842 | "lock_api", 843 | "parking_lot_core", 844 | ] 845 | 846 | [[package]] 847 | name = "parking_lot_core" 848 | version = "0.8.5" 849 | source = "registry+https://github.com/rust-lang/crates.io-index" 850 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 851 | dependencies = [ 852 | "cfg-if", 853 | "instant", 854 | "libc", 855 | "redox_syscall", 856 | "smallvec", 857 | "winapi", 858 | ] 859 | 860 | [[package]] 861 | name = "ppv-lite86" 862 | version = "0.2.16" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 865 | 866 | [[package]] 867 | name = "proc-macro-crate" 868 | version = "0.1.5" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 871 | dependencies = [ 872 | "toml", 873 | ] 874 | 875 | [[package]] 876 | name = "proc-macro-crate" 877 | version = "1.1.0" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" 880 | dependencies = [ 881 | "thiserror", 882 | "toml", 883 | ] 884 | 885 | [[package]] 886 | name = "proc-macro2" 887 | version = "1.0.36" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" 890 | dependencies = [ 891 | "unicode-xid", 892 | ] 893 | 894 | [[package]] 895 | name = "proc-macro2-diagnostics" 896 | version = "0.9.1" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" 899 | dependencies = [ 900 | "proc-macro2", 901 | "quote", 902 | "syn", 903 | "version_check", 904 | "yansi", 905 | ] 906 | 907 | [[package]] 908 | name = "proptest" 909 | version = "1.0.0" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" 912 | dependencies = [ 913 | "bit-set", 914 | "bitflags", 915 | "byteorder", 916 | "lazy_static", 917 | "num-traits", 918 | "quick-error 2.0.1", 919 | "rand 0.8.4", 920 | "rand_chacha 0.3.1", 921 | "rand_xorshift", 922 | "regex-syntax", 923 | "rusty-fork", 924 | "tempfile", 925 | ] 926 | 927 | [[package]] 928 | name = "quick-error" 929 | version = "1.2.3" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 932 | 933 | [[package]] 934 | name = "quick-error" 935 | version = "2.0.1" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 938 | 939 | [[package]] 940 | name = "quote" 941 | version = "1.0.14" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" 944 | dependencies = [ 945 | "proc-macro2", 946 | ] 947 | 948 | [[package]] 949 | name = "rand" 950 | version = "0.7.3" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 953 | dependencies = [ 954 | "getrandom 0.1.16", 955 | "libc", 956 | "rand_chacha 0.2.2", 957 | "rand_core 0.5.1", 958 | "rand_hc", 959 | ] 960 | 961 | [[package]] 962 | name = "rand" 963 | version = "0.8.4" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 966 | dependencies = [ 967 | "libc", 968 | "rand_chacha 0.3.1", 969 | "rand_core 0.6.3", 970 | ] 971 | 972 | [[package]] 973 | name = "rand_chacha" 974 | version = "0.2.2" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 977 | dependencies = [ 978 | "ppv-lite86", 979 | "rand_core 0.5.1", 980 | ] 981 | 982 | [[package]] 983 | name = "rand_chacha" 984 | version = "0.3.1" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 987 | dependencies = [ 988 | "ppv-lite86", 989 | "rand_core 0.6.3", 990 | ] 991 | 992 | [[package]] 993 | name = "rand_core" 994 | version = "0.5.1" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 997 | dependencies = [ 998 | "getrandom 0.1.16", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "rand_core" 1003 | version = "0.6.3" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1006 | dependencies = [ 1007 | "getrandom 0.2.4", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "rand_hc" 1012 | version = "0.2.0" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1015 | dependencies = [ 1016 | "rand_core 0.5.1", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "rand_xorshift" 1021 | version = "0.3.0" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" 1024 | dependencies = [ 1025 | "rand_core 0.6.3", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "redox_syscall" 1030 | version = "0.2.10" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1033 | dependencies = [ 1034 | "bitflags", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "regex" 1039 | version = "1.5.4" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1042 | dependencies = [ 1043 | "aho-corasick", 1044 | "memchr", 1045 | "regex-syntax", 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "regex-syntax" 1050 | version = "0.6.25" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1053 | 1054 | [[package]] 1055 | name = "remove_dir_all" 1056 | version = "0.5.3" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1059 | dependencies = [ 1060 | "winapi", 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "rustc_version" 1065 | version = "0.4.0" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1068 | dependencies = [ 1069 | "semver", 1070 | ] 1071 | 1072 | [[package]] 1073 | name = "rustversion" 1074 | version = "1.0.6" 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" 1076 | checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" 1077 | 1078 | [[package]] 1079 | name = "rusty-fork" 1080 | version = "0.3.0" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" 1083 | dependencies = [ 1084 | "fnv", 1085 | "quick-error 1.2.3", 1086 | "tempfile", 1087 | "wait-timeout", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "ryu" 1092 | version = "1.0.9" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" 1095 | 1096 | [[package]] 1097 | name = "scopeguard" 1098 | version = "1.1.0" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1101 | 1102 | [[package]] 1103 | name = "semver" 1104 | version = "1.0.4" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" 1107 | 1108 | [[package]] 1109 | name = "serde" 1110 | version = "1.0.133" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" 1113 | dependencies = [ 1114 | "serde_derive", 1115 | ] 1116 | 1117 | [[package]] 1118 | name = "serde_bytes" 1119 | version = "0.11.5" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" 1122 | dependencies = [ 1123 | "serde", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "serde_derive" 1128 | version = "1.0.133" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" 1131 | dependencies = [ 1132 | "proc-macro2", 1133 | "quote", 1134 | "syn", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "serde_json" 1139 | version = "1.0.74" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" 1142 | dependencies = [ 1143 | "itoa", 1144 | "ryu", 1145 | "serde", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "sha2" 1150 | version = "0.9.9" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1153 | dependencies = [ 1154 | "block-buffer 0.9.0", 1155 | "cfg-if", 1156 | "cpufeatures", 1157 | "digest 0.9.0", 1158 | "opaque-debug", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "sha3" 1163 | version = "0.9.1" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" 1166 | dependencies = [ 1167 | "block-buffer 0.9.0", 1168 | "digest 0.9.0", 1169 | "keccak", 1170 | "opaque-debug", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "smallvec" 1175 | version = "1.8.0" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 1178 | 1179 | [[package]] 1180 | name = "solana-frozen-abi" 1181 | version = "1.9.4" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "c89bcde59ac3e8d4dbf7c4d990b0627b8ca0d25394c4ce17896dde7a1452e40c" 1184 | dependencies = [ 1185 | "bs58 0.4.0", 1186 | "bv", 1187 | "generic-array", 1188 | "log", 1189 | "memmap2", 1190 | "rustc_version", 1191 | "serde", 1192 | "serde_derive", 1193 | "sha2", 1194 | "solana-frozen-abi-macro", 1195 | "solana-logger", 1196 | "thiserror", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "solana-frozen-abi-macro" 1201 | version = "1.9.4" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "56a7d630da35993631ecc4dd155f92d0d58000cdde3d5e2764fe9fd49d20a3a8" 1204 | dependencies = [ 1205 | "proc-macro2", 1206 | "quote", 1207 | "rustc_version", 1208 | "syn", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "solana-logger" 1213 | version = "1.9.4" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "6eaf925bb665de46f96fcea2c8a900d0d870a96fd1f50cf2bad16e22a1da71c4" 1216 | dependencies = [ 1217 | "env_logger", 1218 | "lazy_static", 1219 | "log", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "solana-program" 1224 | version = "1.9.4" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "2fc4d7a0baa649a3bda06d6a1cc30bd3d8ac692702a75fa8e76369cf7b3f6329" 1227 | dependencies = [ 1228 | "base64 0.13.0", 1229 | "bincode", 1230 | "bitflags", 1231 | "blake3", 1232 | "borsh", 1233 | "borsh-derive", 1234 | "bs58 0.4.0", 1235 | "bv", 1236 | "bytemuck", 1237 | "console_error_panic_hook", 1238 | "console_log", 1239 | "curve25519-dalek", 1240 | "getrandom 0.1.16", 1241 | "itertools", 1242 | "js-sys", 1243 | "lazy_static", 1244 | "libsecp256k1", 1245 | "log", 1246 | "num-derive", 1247 | "num-traits", 1248 | "parking_lot", 1249 | "rand 0.7.3", 1250 | "rustc_version", 1251 | "rustversion", 1252 | "serde", 1253 | "serde_bytes", 1254 | "serde_derive", 1255 | "sha2", 1256 | "sha3", 1257 | "solana-frozen-abi", 1258 | "solana-frozen-abi-macro", 1259 | "solana-logger", 1260 | "solana-sdk-macro", 1261 | "thiserror", 1262 | "wasm-bindgen", 1263 | ] 1264 | 1265 | [[package]] 1266 | name = "solana-sdk-macro" 1267 | version = "1.9.4" 1268 | source = "registry+https://github.com/rust-lang/crates.io-index" 1269 | checksum = "ec22a924c73abe3376a2046715a2f6a9ae4094095b8ea08e8e56e8de198264ad" 1270 | dependencies = [ 1271 | "bs58 0.4.0", 1272 | "proc-macro2", 1273 | "quote", 1274 | "rustversion", 1275 | "syn", 1276 | ] 1277 | 1278 | [[package]] 1279 | name = "spl-associated-token-account" 1280 | version = "1.0.3" 1281 | source = "registry+https://github.com/rust-lang/crates.io-index" 1282 | checksum = "393e2240d521c3dd770806bff25c2c00d761ac962be106e14e22dd912007f428" 1283 | dependencies = [ 1284 | "solana-program", 1285 | "spl-token", 1286 | ] 1287 | 1288 | [[package]] 1289 | name = "spl-token" 1290 | version = "3.2.0" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "93bfdd5bd7c869cb565c7d7635c4fafe189b988a0bdef81063cd9585c6b8dc01" 1293 | dependencies = [ 1294 | "arrayref", 1295 | "num-derive", 1296 | "num-traits", 1297 | "num_enum", 1298 | "solana-program", 1299 | "thiserror", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "static-pubkey" 1304 | version = "1.0.2" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "e390e1e75910fd6c02265a4743f06c85775bb357c70f58384e867b3dc84a8011" 1307 | dependencies = [ 1308 | "bs58 0.4.0", 1309 | "proc-macro2", 1310 | "quote", 1311 | "syn", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "subtle" 1316 | version = "2.4.1" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1319 | 1320 | [[package]] 1321 | name = "syn" 1322 | version = "1.0.85" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" 1325 | dependencies = [ 1326 | "proc-macro2", 1327 | "quote", 1328 | "unicode-xid", 1329 | ] 1330 | 1331 | [[package]] 1332 | name = "tempfile" 1333 | version = "3.3.0" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 1336 | dependencies = [ 1337 | "cfg-if", 1338 | "fastrand", 1339 | "libc", 1340 | "redox_syscall", 1341 | "remove_dir_all", 1342 | "winapi", 1343 | ] 1344 | 1345 | [[package]] 1346 | name = "termcolor" 1347 | version = "1.1.2" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1350 | dependencies = [ 1351 | "winapi-util", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "thiserror" 1356 | version = "1.0.30" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1359 | dependencies = [ 1360 | "thiserror-impl", 1361 | ] 1362 | 1363 | [[package]] 1364 | name = "thiserror-impl" 1365 | version = "1.0.30" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1368 | dependencies = [ 1369 | "proc-macro2", 1370 | "quote", 1371 | "syn", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "toml" 1376 | version = "0.5.8" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1379 | dependencies = [ 1380 | "serde", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "typenum" 1385 | version = "1.15.0" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 1388 | 1389 | [[package]] 1390 | name = "unicode-segmentation" 1391 | version = "1.8.0" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1394 | 1395 | [[package]] 1396 | name = "unicode-xid" 1397 | version = "0.2.2" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1400 | 1401 | [[package]] 1402 | name = "venko" 1403 | version = "0.1.1" 1404 | dependencies = [ 1405 | "anchor-lang", 1406 | "anchor-spl", 1407 | "crate-token", 1408 | "num-traits", 1409 | "proptest", 1410 | "vipers", 1411 | ] 1412 | 1413 | [[package]] 1414 | name = "version_check" 1415 | version = "0.9.4" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1418 | 1419 | [[package]] 1420 | name = "vipers" 1421 | version = "1.5.7" 1422 | source = "registry+https://github.com/rust-lang/crates.io-index" 1423 | checksum = "1935f0ecff8eada4bfdcec252fcbbeb8d98e87c656e0d70f0a83fe0386eef4d7" 1424 | dependencies = [ 1425 | "anchor-lang", 1426 | "anchor-spl", 1427 | "spl-associated-token-account", 1428 | ] 1429 | 1430 | [[package]] 1431 | name = "wait-timeout" 1432 | version = "0.2.0" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 1435 | dependencies = [ 1436 | "libc", 1437 | ] 1438 | 1439 | [[package]] 1440 | name = "wasi" 1441 | version = "0.9.0+wasi-snapshot-preview1" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1444 | 1445 | [[package]] 1446 | name = "wasi" 1447 | version = "0.10.2+wasi-snapshot-preview1" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1450 | 1451 | [[package]] 1452 | name = "wasm-bindgen" 1453 | version = "0.2.78" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 1456 | dependencies = [ 1457 | "cfg-if", 1458 | "wasm-bindgen-macro", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "wasm-bindgen-backend" 1463 | version = "0.2.78" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 1466 | dependencies = [ 1467 | "bumpalo", 1468 | "lazy_static", 1469 | "log", 1470 | "proc-macro2", 1471 | "quote", 1472 | "syn", 1473 | "wasm-bindgen-shared", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "wasm-bindgen-macro" 1478 | version = "0.2.78" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 1481 | dependencies = [ 1482 | "quote", 1483 | "wasm-bindgen-macro-support", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "wasm-bindgen-macro-support" 1488 | version = "0.2.78" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 1491 | dependencies = [ 1492 | "proc-macro2", 1493 | "quote", 1494 | "syn", 1495 | "wasm-bindgen-backend", 1496 | "wasm-bindgen-shared", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "wasm-bindgen-shared" 1501 | version = "0.2.78" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 1504 | 1505 | [[package]] 1506 | name = "web-sys" 1507 | version = "0.3.55" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" 1510 | dependencies = [ 1511 | "js-sys", 1512 | "wasm-bindgen", 1513 | ] 1514 | 1515 | [[package]] 1516 | name = "winapi" 1517 | version = "0.3.9" 1518 | source = "registry+https://github.com/rust-lang/crates.io-index" 1519 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1520 | dependencies = [ 1521 | "winapi-i686-pc-windows-gnu", 1522 | "winapi-x86_64-pc-windows-gnu", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "winapi-i686-pc-windows-gnu" 1527 | version = "0.4.0" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1530 | 1531 | [[package]] 1532 | name = "winapi-util" 1533 | version = "0.1.5" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1536 | dependencies = [ 1537 | "winapi", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "winapi-x86_64-pc-windows-gnu" 1542 | version = "0.4.0" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1545 | 1546 | [[package]] 1547 | name = "yansi" 1548 | version = "0.5.0" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" 1551 | 1552 | [[package]] 1553 | name = "zeroize" 1554 | version = "1.5.0" 1555 | source = "registry+https://github.com/rust-lang/crates.io-index" 1556 | checksum = "cc222aec311c323c717f56060324f32b82da1ce1dd81d9a09aa6a9030bfe08db" 1557 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["programs/*"] 3 | 4 | [profile.release] 5 | lto = "fat" 6 | codegen-units = 1 7 | 8 | [profile.release.build-override] 9 | opt-level = 3 10 | incremental = false 11 | codegen-units = 1 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # venko ✌️ 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/venko)](https://crates.io/crates/venko) 4 | [![Docs.rs](https://img.shields.io/docsrs/venko)](https://docs.rs/venko) 5 | [![License](https://img.shields.io/crates/l/venko)](https://github.com/VenkoApp/venko/blob/master/LICENSE) 6 | [![Build Status](https://img.shields.io/github/workflow/status/VenkoApp/venko/E2E/master)](https://github.com/VenkoApp/venko/actions/workflows/programs-e2e.yml?query=branch%3Amaster) 7 | [![Contributors](https://img.shields.io/github/contributors/VenkoApp/venko)](https://github.com/VenkoApp/venko/graphs/contributors) 8 | [![NPM](https://img.shields.io/npm/v/@venkoapp/venko)](https://www.npmjs.com/package/@venkoapp/venko) 9 | 10 |

11 | 12 |

13 | 14 | Venko: Rails for realtime finance on Solana. 15 | 16 | ## About 17 | 18 | Venko is a protocol for issuing streams of tokens. It is designed for a variety 19 | of usecases, including: 20 | 21 | - **Token lockups.** Issue team tokens over a schedule, irrevocably. 22 | - **Grants.** Issue revocable grants with a cliff and release schedule. 23 | - **Escrow.** Send tokens to someone with a cancellation period, allowing you to cancel the payment if it was sent to the wrong address. 24 | 25 | We're in active development. For the latest updates, please join our community: 26 | 27 | - Twitter: 28 | 29 | ## Note 30 | 31 | - **Venko is in active development, so all APIs are subject to change.** 32 | - **This code is unaudited. Use at your own risk.** 33 | 34 | ## Addresses 35 | 36 | Program addresses are the same on devnet, testnet, and mainnet-beta. 37 | 38 | - Venko: [`AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ`](https://explorer.solana.com/address/AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ) 39 | 40 | ## Contribution 41 | 42 | Thank you for your interest in contributing to Venko Protocol! All contributions are welcome no matter how big or small. This includes 43 | (but is not limited to) filing issues, adding documentation, fixing bugs, creating examples, and implementing features. 44 | 45 | When contributing, please make sure your code adheres to some basic coding guidlines: 46 | 47 | - Code must be formatted with the configured formatters (e.g. `rustfmt` and `prettier`). 48 | - Comment lines should be no longer than 80 characters and written with proper grammar and punctuation. 49 | - Commit messages should be prefixed with the package(s) they modify. Changes affecting multiple packages should list all packages. In rare cases, changes may omit the package name prefix. 50 | 51 | ## License 52 | 53 | Venko Protocol is licensed under the GNU Affero General Public License v3.0. 54 | -------------------------------------------------------------------------------- /ci.nix: -------------------------------------------------------------------------------- 1 | { pkgs, saber-pkgs }: 2 | pkgs.buildEnv { 3 | name = "ci"; 4 | paths = with pkgs; 5 | with saber-pkgs; 6 | (pkgs.lib.optionals pkgs.stdenv.isLinux ([ libudev ])) ++ [ 7 | anchor-0_20_0 8 | cargo-workspaces 9 | solana-install 10 | 11 | # sdk 12 | nodejs 13 | yarn 14 | python3 15 | 16 | pkgconfig 17 | openssl 18 | jq 19 | gnused 20 | 21 | libiconv 22 | ] ++ (pkgs.lib.optionals pkgs.stdenv.isDarwin [ 23 | pkgs.darwin.apple_sdk.frameworks.AppKit 24 | pkgs.darwin.apple_sdk.frameworks.IOKit 25 | pkgs.darwin.apple_sdk.frameworks.Foundation 26 | ]); 27 | } 28 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "locked": { 5 | "lastModified": 1638122382, 6 | "narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=", 7 | "owner": "numtide", 8 | "repo": "flake-utils", 9 | "rev": "74f7e4319258e287b0f9cb95426c9853b282730b", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "numtide", 14 | "repo": "flake-utils", 15 | "type": "github" 16 | } 17 | }, 18 | "flake-utils_2": { 19 | "locked": { 20 | "lastModified": 1638122382, 21 | "narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=", 22 | "owner": "numtide", 23 | "repo": "flake-utils", 24 | "rev": "74f7e4319258e287b0f9cb95426c9853b282730b", 25 | "type": "github" 26 | }, 27 | "original": { 28 | "owner": "numtide", 29 | "repo": "flake-utils", 30 | "type": "github" 31 | } 32 | }, 33 | "flake-utils_3": { 34 | "locked": { 35 | "lastModified": 1637014545, 36 | "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", 37 | "owner": "numtide", 38 | "repo": "flake-utils", 39 | "rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4", 40 | "type": "github" 41 | }, 42 | "original": { 43 | "owner": "numtide", 44 | "repo": "flake-utils", 45 | "type": "github" 46 | } 47 | }, 48 | "nixpkgs": { 49 | "locked": { 50 | "lastModified": 1641909823, 51 | "narHash": "sha256-Uxo+Wm6c/ijNhaJlYtFLJG9mh75FYZaBreMC2ZE0nEY=", 52 | "owner": "NixOS", 53 | "repo": "nixpkgs", 54 | "rev": "f0f67400bc49c44f305d6fe17698a2f1ce1c29a0", 55 | "type": "github" 56 | }, 57 | "original": { 58 | "owner": "NixOS", 59 | "ref": "nixpkgs-unstable", 60 | "repo": "nixpkgs", 61 | "type": "github" 62 | } 63 | }, 64 | "nixpkgs_2": { 65 | "locked": { 66 | "lastModified": 1638366923, 67 | "narHash": "sha256-Sh6+Pm0ShdtqW+BGynIJX+F12Lqs0xJq6qWmDkZN2uA=", 68 | "owner": "NixOS", 69 | "repo": "nixpkgs", 70 | "rev": "1fbcb733eb9daf23ab9e70e58e76fa0b767dc033", 71 | "type": "github" 72 | }, 73 | "original": { 74 | "owner": "NixOS", 75 | "ref": "nixpkgs-unstable", 76 | "repo": "nixpkgs", 77 | "type": "github" 78 | } 79 | }, 80 | "nixpkgs_3": { 81 | "locked": { 82 | "lastModified": 1641909823, 83 | "narHash": "sha256-Uxo+Wm6c/ijNhaJlYtFLJG9mh75FYZaBreMC2ZE0nEY=", 84 | "owner": "NixOS", 85 | "repo": "nixpkgs", 86 | "rev": "f0f67400bc49c44f305d6fe17698a2f1ce1c29a0", 87 | "type": "github" 88 | }, 89 | "original": { 90 | "owner": "NixOS", 91 | "ref": "nixpkgs-unstable", 92 | "repo": "nixpkgs", 93 | "type": "github" 94 | } 95 | }, 96 | "root": { 97 | "inputs": { 98 | "flake-utils": "flake-utils", 99 | "nixpkgs": "nixpkgs", 100 | "saber-overlay": "saber-overlay" 101 | } 102 | }, 103 | "rust-overlay": { 104 | "inputs": { 105 | "flake-utils": "flake-utils_3", 106 | "nixpkgs": "nixpkgs_3" 107 | }, 108 | "locked": { 109 | "lastModified": 1638325128, 110 | "narHash": "sha256-xNixLjQeH06A9JImD1Z5MFnck1vpUasH2GQqmP2VpCU=", 111 | "owner": "oxalica", 112 | "repo": "rust-overlay", 113 | "rev": "058e0be9f556a7d3d175144b70b19132eb3d15f8", 114 | "type": "github" 115 | }, 116 | "original": { 117 | "owner": "oxalica", 118 | "repo": "rust-overlay", 119 | "type": "github" 120 | } 121 | }, 122 | "saber-overlay": { 123 | "inputs": { 124 | "flake-utils": "flake-utils_2", 125 | "nixpkgs": "nixpkgs_2", 126 | "rust-overlay": "rust-overlay" 127 | }, 128 | "locked": { 129 | "lastModified": 1641769255, 130 | "narHash": "sha256-ZOriVlZvRSd9ugTkF4FAH7tQx2JeKTM2ywBnxT4AAAs=", 131 | "owner": "saber-hq", 132 | "repo": "saber-overlay", 133 | "rev": "abbb59e0c742756480da0a12916fed9217dd6bb7", 134 | "type": "github" 135 | }, 136 | "original": { 137 | "owner": "saber-hq", 138 | "repo": "saber-overlay", 139 | "type": "github" 140 | } 141 | } 142 | }, 143 | "root": "root", 144 | "version": 7 145 | } 146 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Venko development environment."; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | saber-overlay.url = "github:saber-hq/saber-overlay"; 7 | flake-utils.url = "github:numtide/flake-utils"; 8 | }; 9 | 10 | outputs = { self, nixpkgs, saber-overlay, flake-utils }: 11 | flake-utils.lib.eachSystem [ 12 | "aarch64-darwin" 13 | "x86_64-linux" 14 | "x86_64-darwin" 15 | ] (system: 16 | let 17 | pkgs = import nixpkgs { inherit system; }; 18 | saber-pkgs = saber-overlay.packages.${system}; 19 | ci = import ./ci.nix { inherit pkgs saber-pkgs; }; 20 | in { 21 | packages.ci = ci; 22 | devShell = pkgs.mkShell { 23 | buildInputs = with pkgs; [ ci rustup cargo-deps gh cargo-readme ]; 24 | }; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VenkoApp/venko/1f1b28ffc2a7757cd8538c759aa0788ebb6de955/images/banner.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@venkoapp/venko", 3 | "version": "0.1.2", 4 | "description": "The TypeScript SDK for Venko.", 5 | "keywords": [ 6 | "solana", 7 | "venko" 8 | ], 9 | "main": "dist/cjs/index.js", 10 | "module": "dist/esm/index.js", 11 | "repository": "git@github.com:VenkoApp/venko.git", 12 | "author": "Andriy Yakovenko ", 13 | "bugs": { 14 | "url": "https://github.com/VenkoApp/venko/issues", 15 | "email": "team@venko.app" 16 | }, 17 | "homepage": "https://venko.app", 18 | "license": "AGPL-3.0", 19 | "scripts": { 20 | "build": "rm -fr dist/ && tsc -P tsconfig.build.json && tsc -P tsconfig.esm.json", 21 | "clean": "rm -fr dist/", 22 | "idl:generate": "./scripts/parse-idls.sh && ./scripts/generate-idl-types.sh", 23 | "idl:generate:nolint": "./scripts/parse-idls.sh && RUN_ESLINT=none ./scripts/generate-idl-types.sh", 24 | "typecheck": "tsc", 25 | "lint": "eslint . --cache", 26 | "lint:ci": "eslint . --max-warnings=0", 27 | "test:e2e": "anchor test --skip-build 'tests/**/*.ts'", 28 | "docs:generate": "typedoc --excludePrivate --includeVersion --out site/ts/ src/index.ts", 29 | "prepare": "husky install", 30 | "cargo-readme": "cd programs/venko/ && cargo readme > README.md && cd ../../ && rm -f README.md && cp programs/venko/README.md README.md" 31 | }, 32 | "devDependencies": { 33 | "@gokiprotocol/client": "^0.5.4", 34 | "@project-serum/anchor": "^0.20.1", 35 | "@rushstack/eslint-patch": "^1.1.0", 36 | "@saberhq/anchor-contrib": "^1.12.29", 37 | "@saberhq/chai-solana": "^1.12.29", 38 | "@saberhq/eslint-config": "^1.12.29", 39 | "@saberhq/solana-contrib": "^1.12.29", 40 | "@saberhq/token-utils": "^1.12.29", 41 | "@saberhq/tsconfig": "^1.12.29", 42 | "@solana/web3.js": "^1.31.0", 43 | "@tribecahq/tribeca-sdk": "^0.3.1", 44 | "@types/bn.js": "^5.1.0", 45 | "@types/chai": "^4.3.0", 46 | "@types/lodash": "^4.14.178", 47 | "@types/mocha": "^9.0.0", 48 | "@types/node": "^17.0.8", 49 | "@types/prettier": "^2.4.3", 50 | "@yarnpkg/doctor": "^3.1.0", 51 | "bn.js": "^5.2.0", 52 | "chai": "^4.3.4", 53 | "eslint": "^8.6.0", 54 | "eslint-import-resolver-node": "^0.3.6", 55 | "eslint-plugin-import": "^2.25.4", 56 | "husky": "^7.0.4", 57 | "jsbi": "^4.1.0", 58 | "lint-staged": "^12.1.7", 59 | "lodash": "^4.17.21", 60 | "mocha": "^9.1.4", 61 | "prettier": "^2.5.1", 62 | "ts-node": "^10.4.0", 63 | "typedoc": "^0.22.10", 64 | "typescript": "^4.5.4" 65 | }, 66 | "peerDependencies": { 67 | "@project-serum/anchor": ">=0.19", 68 | "@saberhq/anchor-contrib": "^1.10.6", 69 | "@saberhq/solana-contrib": "^1.10.6", 70 | "@saberhq/token-utils": "^1.10.6", 71 | "@solana/web3.js": "^1.29.2", 72 | "bn.js": "^5.2.0" 73 | }, 74 | "resolutions": { 75 | "bn.js": "^5.2.0", 76 | "@types/bn.js": "^5.1.0" 77 | }, 78 | "publishConfig": { 79 | "access": "public" 80 | }, 81 | "files": [ 82 | "dist/", 83 | "src/" 84 | ], 85 | "lint-staged": { 86 | "*.{ts,tsx}": "eslint --cache --fix", 87 | "*.{js,json,jsx,html,css,md}": "prettier --write" 88 | }, 89 | "dependencies": { 90 | "@crateprotocol/crate-sdk": "^0.4.1", 91 | "tiny-invariant": "^1.2.0", 92 | "tslib": "^2.3.1" 93 | }, 94 | "packageManager": "yarn@3.1.1" 95 | } 96 | -------------------------------------------------------------------------------- /programs/venko/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "venko" 3 | version = "0.1.1" 4 | description = "Program for issuing token streams on Solana." 5 | edition = "2021" 6 | homepage = "https://venko.app" 7 | repository = "https://github.com/VenkoApp/venko" 8 | authors = ["Venko Team "] 9 | license = "AGPL-3.0" 10 | keywords = ["solana", "anchor", "finance", "venko"] 11 | 12 | [lib] 13 | crate-type = ["cdylib", "lib"] 14 | name = "venko" 15 | path = "src/lib.rs" 16 | 17 | [features] 18 | no-entrypoint = [] 19 | no-idl = [] 20 | cpi = ["no-entrypoint"] 21 | default = [] 22 | 23 | [dependencies] 24 | anchor-lang = ">=0.17" 25 | anchor-spl = ">=0.17" 26 | num-traits = "0.2" 27 | crate-token = { version = "0.4.0", features = ["cpi"] } 28 | vipers = "1.5.5" 29 | 30 | [dev-dependencies] 31 | proptest = { version = "1.0" } 32 | -------------------------------------------------------------------------------- /programs/venko/README.md: -------------------------------------------------------------------------------- 1 | # venko ✌️ 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/venko)](https://crates.io/crates/venko) 4 | [![Docs.rs](https://img.shields.io/docsrs/venko)](https://docs.rs/venko) 5 | [![License](https://img.shields.io/crates/l/venko)](https://github.com/VenkoApp/venko/blob/master/LICENSE) 6 | [![Build Status](https://img.shields.io/github/workflow/status/VenkoApp/venko/E2E/master)](https://github.com/VenkoApp/venko/actions/workflows/programs-e2e.yml?query=branch%3Amaster) 7 | [![Contributors](https://img.shields.io/github/contributors/VenkoApp/venko)](https://github.com/VenkoApp/venko/graphs/contributors) 8 | [![NPM](https://img.shields.io/npm/v/@venkoapp/venko)](https://www.npmjs.com/package/@venkoapp/venko) 9 | 10 |

11 | 12 |

13 | 14 | Venko: Rails for realtime finance on Solana. 15 | 16 | ## About 17 | 18 | Venko is a protocol for issuing streams of tokens. It is designed for a variety 19 | of usecases, including: 20 | 21 | - **Token lockups.** Issue team tokens over a schedule, irrevocably. 22 | - **Grants.** Issue revocable grants with a cliff and release schedule. 23 | - **Escrow.** Send tokens to someone with a cancellation period, allowing you to cancel the payment if it was sent to the wrong address. 24 | 25 | We're in active development. For the latest updates, please join our community: 26 | 27 | - Twitter: 28 | 29 | ## Note 30 | 31 | - **Venko is in active development, so all APIs are subject to change.** 32 | - **This code is unaudited. Use at your own risk.** 33 | 34 | ## Addresses 35 | 36 | Program addresses are the same on devnet, testnet, and mainnet-beta. 37 | 38 | - Venko: [`AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ`](https://explorer.solana.com/address/AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ) 39 | 40 | ## Contribution 41 | 42 | Thank you for your interest in contributing to Venko Protocol! All contributions are welcome no matter how big or small. This includes 43 | (but is not limited to) filing issues, adding documentation, fixing bugs, creating examples, and implementing features. 44 | 45 | When contributing, please make sure your code adheres to some basic coding guidlines: 46 | 47 | - Code must be formatted with the configured formatters (e.g. `rustfmt` and `prettier`). 48 | - Comment lines should be no longer than 80 characters and written with proper grammar and punctuation. 49 | - Commit messages should be prefixed with the package(s) they modify. Changes affecting multiple packages should list all packages. In rare cases, changes may omit the package name prefix. 50 | 51 | ## License 52 | 53 | Venko Protocol is licensed under the GNU Affero General Public License v3.0. 54 | -------------------------------------------------------------------------------- /programs/venko/README.tpl: -------------------------------------------------------------------------------- 1 | # {{crate}} ✌️ 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/{{crate}})](https://crates.io/crates/{{crate}}) 4 | [![Docs.rs](https://img.shields.io/docsrs/{{crate}})](https://docs.rs/{{crate}}) 5 | [![License](https://img.shields.io/crates/l/{{crate}})](https://github.com/VenkoApp/venko/blob/master/LICENSE) 6 | [![Build Status](https://img.shields.io/github/workflow/status/VenkoApp/venko/E2E/master)](https://github.com/VenkoApp/venko/actions/workflows/programs-e2e.yml?query=branch%3Amaster) 7 | [![Contributors](https://img.shields.io/github/contributors/VenkoApp/venko)](https://github.com/VenkoApp/venko/graphs/contributors) 8 | [![NPM](https://img.shields.io/npm/v/@venkoapp/venko)](https://www.npmjs.com/package/@venkoapp/venko) 9 | 10 |

11 | 12 |

13 | 14 | {{readme}} 15 | -------------------------------------------------------------------------------- /programs/venko/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /programs/venko/src/instructions/create_stream.rs: -------------------------------------------------------------------------------- 1 | //! Instruction handler for [crate::venko::create_stream]. 2 | 3 | use crate::*; 4 | use anchor_spl::token::{self, Mint, TokenAccount}; 5 | use vipers::{assert_keys_eq, invariant, Validate}; 6 | 7 | /// Accounts for [venko::create_stream]. 8 | #[derive(Accounts)] 9 | #[instruction(bump: u8)] 10 | pub struct CreateStream<'info> { 11 | /// [token::Mint] of the [Stream]. 12 | #[account(mut)] 13 | pub stream_mint: Account<'info, Mint>, 14 | /// [Stream] account. 15 | #[account( 16 | init, 17 | seeds = [ 18 | b"Stream", 19 | stream_mint.key().as_ref() 20 | ], 21 | bump = bump, 22 | payer = payer 23 | )] 24 | pub stream: Account<'info, Stream>, 25 | /// Underlying mint. 26 | pub underlying_mint: Box>, 27 | /// The [TokenAccount] holding the [Stream]'s tokens. 28 | /// Must be owned by the [Self::crate_token], and the amount should be > 0. 29 | pub underlying_tokens: Box>, 30 | /// Destination of the [Stream] tokens. 31 | #[account(mut)] 32 | pub destination: Account<'info, TokenAccount>, 33 | 34 | /// The [crate_token::CrateToken] to be created. 35 | #[account(mut)] 36 | pub crate_token: UncheckedAccount<'info>, 37 | /// Payer for the [Stream] account creation. 38 | #[account(mut)] 39 | pub payer: Signer<'info>, 40 | 41 | /// [System] program. 42 | pub system_program: Program<'info, System>, 43 | /// [crate_token] program. 44 | pub crate_token_program: Program<'info, crate_token::program::CrateToken>, 45 | /// SPL [token] program. 46 | pub token_program: Program<'info, token::Token>, 47 | } 48 | 49 | impl<'info> CreateStream<'info> { 50 | fn init_crate(&self, crate_bump: u8) -> ProgramResult { 51 | crate_token::cpi::new_crate( 52 | CpiContext::new( 53 | self.crate_token_program.to_account_info(), 54 | crate_token::cpi::accounts::NewCrate { 55 | crate_mint: self.stream_mint.to_account_info(), 56 | crate_token: self.crate_token.to_account_info(), 57 | 58 | // no fees 59 | fee_to_setter: self.system_program.to_account_info(), 60 | fee_setter_authority: self.system_program.to_account_info(), 61 | author_fee_to: self.system_program.to_account_info(), 62 | 63 | // authorities 64 | issue_authority: self.stream.to_account_info(), 65 | withdraw_authority: self.stream.to_account_info(), 66 | payer: self.payer.to_account_info(), 67 | system_program: self.system_program.to_account_info(), 68 | }, 69 | ), 70 | crate_bump, 71 | ) 72 | } 73 | 74 | /// Issue the [Stream] tokens. 75 | fn issue_tokens(&self, amount: u64) -> ProgramResult { 76 | let signer_seeds: &[&[&[u8]]] = stream_seeds!(self.stream); 77 | crate_token::cpi::issue( 78 | CpiContext::new( 79 | self.crate_token_program.to_account_info(), 80 | crate_token::cpi::accounts::Issue { 81 | crate_mint: self.stream_mint.to_account_info(), 82 | crate_token: self.crate_token.to_account_info(), 83 | 84 | // authorities 85 | issue_authority: self.stream.to_account_info(), 86 | 87 | mint_destination: self.destination.to_account_info(), 88 | author_fee_destination: self.destination.to_account_info(), 89 | protocol_fee_destination: self.destination.to_account_info(), 90 | token_program: self.token_program.to_account_info(), 91 | }, 92 | ) 93 | .with_signer(signer_seeds), 94 | amount, 95 | ) 96 | } 97 | 98 | fn init_stream( 99 | &mut self, 100 | stream_bump: u8, 101 | start_ts: i64, 102 | cliff_ts: i64, 103 | end_ts: i64, 104 | revoker: Pubkey, 105 | ) -> ProgramResult { 106 | let stream = &mut self.stream; 107 | stream.mint = self.stream_mint.key(); 108 | stream.bump = stream_bump; 109 | 110 | stream.revoker = revoker; 111 | stream.crate_token = self.crate_token.key(); 112 | stream.underlying_mint = self.underlying_tokens.mint.key(); 113 | stream.underlying_tokens = self.underlying_tokens.key(); 114 | 115 | stream.initial_amount = self.underlying_tokens.amount; 116 | stream.redeemed_amount = 0; 117 | 118 | stream.start_ts = start_ts; 119 | stream.cliff_ts = cliff_ts; 120 | stream.end_ts = end_ts; 121 | Ok(()) 122 | } 123 | } 124 | 125 | pub fn handler( 126 | ctx: Context, 127 | stream_bump: u8, 128 | crate_bump: u8, 129 | start_ts: i64, 130 | cliff_ts: i64, 131 | end_ts: i64, 132 | revoker: Pubkey, 133 | ) -> ProgramResult { 134 | invariant!(end_ts > start_ts, InvalidSchedule); 135 | 136 | invariant!(cliff_ts >= start_ts); 137 | invariant!(cliff_ts <= end_ts); 138 | 139 | let amount = ctx.accounts.underlying_tokens.amount; 140 | ctx.accounts.init_crate(crate_bump)?; 141 | ctx.accounts 142 | .init_stream(stream_bump, start_ts, cliff_ts, end_ts, revoker)?; 143 | ctx.accounts.issue_tokens(amount)?; 144 | 145 | let stream = &ctx.accounts.stream; 146 | emit!(StreamCreateEvent { 147 | stream: stream.key(), 148 | mint: stream.mint, 149 | amount: stream.initial_amount, 150 | start_ts: stream.start_ts, 151 | cliff_ts: stream.cliff_ts, 152 | end_ts: stream.end_ts, 153 | }); 154 | 155 | Ok(()) 156 | } 157 | 158 | #[event] 159 | pub struct StreamCreateEvent { 160 | #[index] 161 | pub stream: Pubkey, 162 | #[index] 163 | pub mint: Pubkey, 164 | pub amount: u64, 165 | pub start_ts: i64, 166 | pub cliff_ts: i64, 167 | pub end_ts: i64, 168 | } 169 | 170 | impl<'info> Validate<'info> for CreateStream<'info> { 171 | fn validate(&self) -> ProgramResult { 172 | assert_keys_eq!(self.stream_mint.mint_authority.unwrap(), self.crate_token); 173 | assert_keys_eq!(self.stream_mint.freeze_authority.unwrap(), self.crate_token); 174 | invariant!(self.stream_mint.supply == 0); 175 | 176 | assert_keys_eq!(self.underlying_tokens.owner, self.crate_token); 177 | invariant!(self.underlying_tokens.amount > 0); 178 | invariant!(self.underlying_tokens.delegate.is_none()); 179 | invariant!(self.underlying_tokens.close_authority.is_none()); 180 | 181 | assert_keys_eq!(self.underlying_tokens.mint, self.underlying_mint); 182 | invariant!(self.underlying_mint.decimals == self.stream_mint.decimals); 183 | 184 | Ok(()) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /programs/venko/src/instructions/mod.rs: -------------------------------------------------------------------------------- 1 | //! Instructions for Venko. 2 | 3 | pub mod create_stream; 4 | pub mod redeem; 5 | pub mod revoke; 6 | 7 | pub use create_stream::*; 8 | pub use redeem::*; 9 | pub use revoke::*; 10 | -------------------------------------------------------------------------------- /programs/venko/src/instructions/redeem.rs: -------------------------------------------------------------------------------- 1 | //! Instruction handler for [crate::venko::redeem]. 2 | 3 | use crate::*; 4 | use anchor_spl::token::{self, Burn, Mint, TokenAccount}; 5 | use vipers::{assert_keys_eq, invariant, unwrap_int, Validate}; 6 | 7 | /// Accounts for [venko::redeem]. 8 | #[derive(Accounts)] 9 | pub struct Redeem<'info> { 10 | /// [token::Mint] of the [Stream]. 11 | /// This account is `mut` because tokens are burned. 12 | #[account(mut)] 13 | pub stream_mint: Account<'info, Mint>, 14 | /// [Stream] account. 15 | #[account(mut)] 16 | pub stream: Box>, 17 | 18 | /// The [TokenAccount] holding the [Self::user_authority]'s 19 | /// stream tokens. 20 | #[account(mut)] 21 | pub source_stream_tokens: Account<'info, TokenAccount>, 22 | 23 | /// Underlying tokens of the [Stream]. 24 | #[account(mut)] 25 | pub underlying_tokens: Account<'info, TokenAccount>, 26 | /// Destination of the underlying tokens backing the [Stream]. 27 | #[account(mut)] 28 | pub destination_tokens: Account<'info, TokenAccount>, 29 | 30 | /// The [crate_token::CrateToken]. 31 | pub crate_token: Box>, 32 | 33 | /// User redeeming the tokens. 34 | pub user_authority: Signer<'info>, 35 | 36 | /// [System] program. 37 | pub system_program: Program<'info, System>, 38 | /// [crate_token] program. 39 | pub crate_token_program: Program<'info, crate_token::program::CrateToken>, 40 | /// SPL [token] program. 41 | pub token_program: Program<'info, token::Token>, 42 | } 43 | 44 | impl<'info> Redeem<'info> { 45 | fn amount_released(&self) -> Result { 46 | let amount_released = unwrap_int!(self 47 | .stream 48 | .available_for_withdrawal(Clock::get()?.unix_timestamp, self.underlying_tokens.amount)); 49 | Ok(amount_released) 50 | } 51 | 52 | fn redeem(&self, amount: u64) -> ProgramResult { 53 | let amount_released = self.amount_released()?; 54 | 55 | // Has the given amount released? 56 | invariant!(amount <= amount_released, InsufficientWithdrawalBalance); 57 | 58 | // redeem the crate tokens 59 | self.burn_stream_tokens(amount)?; 60 | self.withdraw_crate_tokens(amount)?; 61 | 62 | Ok(()) 63 | } 64 | 65 | fn burn_stream_tokens(&self, amount: u64) -> ProgramResult { 66 | token::burn( 67 | CpiContext::new( 68 | self.token_program.to_account_info(), 69 | Burn { 70 | mint: self.stream_mint.to_account_info(), 71 | to: self.source_stream_tokens.to_account_info(), 72 | authority: self.user_authority.to_account_info(), 73 | }, 74 | ), 75 | amount, 76 | ) 77 | } 78 | 79 | fn withdraw_crate_tokens(&self, amount: u64) -> ProgramResult { 80 | let signer_seeds: &[&[&[u8]]] = stream_seeds!(self.stream); 81 | crate_token::cpi::withdraw( 82 | CpiContext::new_with_signer( 83 | self.crate_token_program.to_account_info(), 84 | crate_token::cpi::accounts::Withdraw { 85 | crate_token: self.crate_token.to_account_info(), 86 | crate_underlying: self.underlying_tokens.to_account_info(), 87 | withdraw_authority: self.stream.to_account_info(), 88 | withdraw_destination: self.destination_tokens.to_account_info(), 89 | author_fee_destination: self.destination_tokens.to_account_info(), 90 | protocol_fee_destination: self.destination_tokens.to_account_info(), 91 | token_program: self.token_program.to_account_info(), 92 | }, 93 | signer_seeds, 94 | ), 95 | amount, 96 | ) 97 | } 98 | } 99 | 100 | pub fn handler(ctx: Context, amount: u64) -> ProgramResult { 101 | ctx.accounts.redeem(amount)?; 102 | 103 | let stream = &mut ctx.accounts.stream; 104 | stream.redeemed_amount = unwrap_int!(stream.redeemed_amount.checked_add(amount)); 105 | 106 | let amount_remaining = unwrap_int!(stream.initial_amount.checked_sub(stream.redeemed_amount)); 107 | 108 | emit!(RedeemEvent { 109 | stream: stream.key(), 110 | mint: stream.underlying_mint, 111 | amount, 112 | amount_remaining, 113 | }); 114 | 115 | Ok(()) 116 | } 117 | 118 | /// Emitted on [crate::venko::redeem]. 119 | #[event] 120 | pub struct RedeemEvent { 121 | /// The [Stream]. 122 | #[index] 123 | pub stream: Pubkey, 124 | /// Mint of the underlying token. 125 | #[index] 126 | pub mint: Pubkey, 127 | 128 | /// Total tokens redeemed 129 | pub amount: u64, 130 | /// Total tokens remaining 131 | pub amount_remaining: u64, 132 | } 133 | 134 | impl<'info> Validate<'info> for Redeem<'info> { 135 | fn validate(&self) -> ProgramResult { 136 | assert_keys_eq!(self.stream_mint, self.stream.mint); 137 | 138 | assert_keys_eq!(self.source_stream_tokens.owner, self.user_authority); 139 | assert_keys_eq!(self.source_stream_tokens.mint, self.stream.mint); 140 | invariant!( 141 | self.source_stream_tokens.amount > 0, 142 | InsufficientStreamTokens 143 | ); 144 | 145 | assert_keys_eq!(self.underlying_tokens, self.stream.underlying_tokens); 146 | assert_keys_eq!(self.destination_tokens.mint, self.stream.underlying_mint); 147 | 148 | assert_keys_eq!(self.crate_token, self.stream.crate_token); 149 | Ok(()) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /programs/venko/src/instructions/revoke.rs: -------------------------------------------------------------------------------- 1 | //! Instruction handler for [crate::venko::revoke]. 2 | 3 | use crate::*; 4 | use anchor_spl::token::{self, TokenAccount}; 5 | use vipers::{assert_keys_eq, invariant, Validate}; 6 | 7 | /// Accounts for [venko::revoke]. 8 | #[derive(Accounts)] 9 | pub struct Revoke<'info> { 10 | /// [Stream] account. 11 | #[account(mut)] 12 | pub stream: Box>, 13 | 14 | /// Crate token. 15 | pub crate_token: Box>, 16 | 17 | /// Underlying tokens of the [Stream]. 18 | #[account(mut)] 19 | pub underlying_tokens: Account<'info, TokenAccount>, 20 | /// Destination of the underlying tokens backing the [Stream]. 21 | #[account(mut)] 22 | pub destination_tokens: Account<'info, TokenAccount>, 23 | 24 | /// The [Stream::revoker]. 25 | pub revoker: Signer<'info>, 26 | 27 | /// [crate_token] program. 28 | pub crate_token_program: Program<'info, crate_token::program::CrateToken>, 29 | /// SPL [token] program. 30 | pub token_program: Program<'info, token::Token>, 31 | } 32 | 33 | impl<'info> Revoke<'info> { 34 | fn revoke(&mut self) -> ProgramResult { 35 | // redeem the crate tokens 36 | self.withdraw_all_crate_tokens()?; 37 | 38 | // invalidate the stream 39 | let stream = &mut self.stream; 40 | stream.redeemed_amount = stream.initial_amount; 41 | stream.end_ts = Clock::get()?.unix_timestamp; 42 | 43 | Ok(()) 44 | } 45 | 46 | fn withdraw_all_crate_tokens(&self) -> ProgramResult { 47 | let signer_seeds: &[&[&[u8]]] = stream_seeds!(self.stream); 48 | crate_token::cpi::withdraw( 49 | CpiContext::new_with_signer( 50 | self.crate_token_program.to_account_info(), 51 | crate_token::cpi::accounts::Withdraw { 52 | crate_token: self.crate_token.to_account_info(), 53 | crate_underlying: self.underlying_tokens.to_account_info(), 54 | withdraw_authority: self.stream.to_account_info(), 55 | withdraw_destination: self.destination_tokens.to_account_info(), 56 | author_fee_destination: self.destination_tokens.to_account_info(), 57 | protocol_fee_destination: self.destination_tokens.to_account_info(), 58 | token_program: self.token_program.to_account_info(), 59 | }, 60 | signer_seeds, 61 | ), 62 | self.underlying_tokens.amount, 63 | ) 64 | } 65 | } 66 | 67 | pub fn handler(ctx: Context) -> ProgramResult { 68 | ctx.accounts.revoke()?; 69 | 70 | let stream = &ctx.accounts.stream; 71 | emit!(RevokeEvent { 72 | stream: stream.key(), 73 | mint: stream.underlying_mint, 74 | revoker: ctx.accounts.revoker.key(), 75 | }); 76 | 77 | Ok(()) 78 | } 79 | 80 | /// Emitted on [crate::venko::revoke]. 81 | #[event] 82 | pub struct RevokeEvent { 83 | /// The [Stream]. 84 | #[index] 85 | pub stream: Pubkey, 86 | /// Mint of the underlying token. 87 | #[index] 88 | pub mint: Pubkey, 89 | /// Account that revoked the [Stream]. 90 | pub revoker: Pubkey, 91 | } 92 | 93 | impl<'info> Validate<'info> for Revoke<'info> { 94 | fn validate(&self) -> ProgramResult { 95 | invariant!(self.stream.revoker != Pubkey::default(), Irrevocable); 96 | assert_keys_eq!(self.stream.revoker, self.revoker, NotRevoker); 97 | 98 | assert_keys_eq!(self.crate_token, self.stream.crate_token); 99 | assert_keys_eq!(self.underlying_tokens, self.stream.underlying_tokens); 100 | assert_keys_eq!(self.destination_tokens.mint, self.stream.underlying_mint); 101 | Ok(()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /programs/venko/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Venko: Rails for realtime finance on Solana. 2 | //! 3 | //! # About 4 | //! 5 | //! Venko is a protocol for issuing streams of tokens. It is designed for a variety 6 | //! of usecases, including: 7 | //! 8 | //! - **Token lockups.** Issue team tokens over a schedule, irrevocably. 9 | //! - **Grants.** Issue revocable grants with a cliff and release schedule. 10 | //! - **Escrow.** Send tokens to someone with a cancellation period, allowing you to cancel the payment if it was sent to the wrong address. 11 | //! 12 | //! We're in active development. For the latest updates, please join our community: 13 | //! 14 | //! - Twitter: 15 | //! 16 | //! # Note 17 | //! 18 | //! - **Venko is in active development, so all APIs are subject to change.** 19 | //! - **This code is unaudited. Use at your own risk.** 20 | //! 21 | //! # Addresses 22 | //! 23 | //! Program addresses are the same on devnet, testnet, and mainnet-beta. 24 | //! 25 | //! - Venko: [`AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ`](https://explorer.solana.com/address/AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ) 26 | //! 27 | //! # Contribution 28 | //! 29 | //! Thank you for your interest in contributing to Venko Protocol! All contributions are welcome no matter how big or small. This includes 30 | //! (but is not limited to) filing issues, adding documentation, fixing bugs, creating examples, and implementing features. 31 | //! 32 | //! When contributing, please make sure your code adheres to some basic coding guidlines: 33 | //! 34 | //! - Code must be formatted with the configured formatters (e.g. `rustfmt` and `prettier`). 35 | //! - Comment lines should be no longer than 80 characters and written with proper grammar and punctuation. 36 | //! - Commit messages should be prefixed with the package(s) they modify. Changes affecting multiple packages should list all packages. In rare cases, changes may omit the package name prefix. 37 | //! 38 | //! # License 39 | //! 40 | //! Venko Protocol is licensed under the GNU Affero General Public License v3.0. 41 | #![deny(rustdoc::all)] 42 | #![allow(rustdoc::missing_doc_code_examples)] 43 | #![deny(clippy::unwrap_used)] 44 | 45 | mod macros; 46 | 47 | use anchor_lang::prelude::*; 48 | use vipers::Validate; 49 | 50 | mod instructions; 51 | mod state; 52 | 53 | pub use instructions::*; 54 | pub use state::*; 55 | 56 | declare_id!("AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ"); 57 | 58 | /// The [venko] program. 59 | #[program] 60 | pub mod venko { 61 | use super::*; 62 | 63 | /// Creates a new [Stream]. 64 | #[access_control(ctx.accounts.validate())] 65 | pub fn create_stream( 66 | ctx: Context, 67 | stream_bump: u8, 68 | crate_bump: u8, 69 | start_ts: i64, 70 | cliff_ts: i64, 71 | end_ts: i64, 72 | revoker: Pubkey, 73 | ) -> ProgramResult { 74 | instructions::create_stream::handler( 75 | ctx, 76 | stream_bump, 77 | crate_bump, 78 | start_ts, 79 | cliff_ts, 80 | end_ts, 81 | revoker, 82 | ) 83 | } 84 | 85 | /// Redeems [Stream] tokens for their underlying. 86 | #[access_control(ctx.accounts.validate())] 87 | pub fn redeem(ctx: Context, amount: u64) -> ProgramResult { 88 | instructions::redeem::handler(ctx, amount) 89 | } 90 | 91 | /// Revokes all underlying [Stream] tokens, invalidating them 92 | /// and sending all of the [Stream::underlying_tokens] to an address. 93 | /// 94 | /// Only the [Stream::revoker] may call this instruction. 95 | /// 96 | /// [Stream] tokens will still be in the user's wallet, so it is up to the 97 | /// [Stream] token holder to validate that the [Stream::underlying_tokens] account 98 | /// still holds the full balance of underlying tokens. 99 | #[access_control(ctx.accounts.validate())] 100 | pub fn revoke(ctx: Context) -> ProgramResult { 101 | instructions::revoke::handler(ctx) 102 | } 103 | } 104 | 105 | /// Errors. 106 | #[error] 107 | pub enum ErrorCode { 108 | #[msg("Stream must end after its start time.")] 109 | InvalidSchedule, 110 | #[msg("Insufficient withdrawal balance.")] 111 | InsufficientWithdrawalBalance, 112 | #[msg("Insufficient stream token balance.")] 113 | InsufficientStreamTokens, 114 | #[msg("Stream is irrevocable.")] 115 | Irrevocable, 116 | #[msg("Must be revoker to perform this operation.")] 117 | NotRevoker, 118 | } 119 | -------------------------------------------------------------------------------- /programs/venko/src/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macros 2 | 3 | /// Generates the signer seeds for a [crate::Stream]. 4 | #[macro_export] 5 | macro_rules! stream_seeds { 6 | ($stream: expr) => { 7 | &[&[ 8 | b"Stream" as &[u8], 9 | &$stream.mint.to_bytes(), 10 | &[$stream.bump], 11 | ]] 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /programs/venko/src/state.rs: -------------------------------------------------------------------------------- 1 | //! Struct definitions for accounts that hold state. 2 | 3 | use crate::*; 4 | use num_traits::ToPrimitive; 5 | 6 | /// A stream of tokens being sent, with a cliff and an optional [Self::revoker]. 7 | /// 8 | /// When a [Stream] is created, there is one token created for every underlying 9 | /// token backing the [Stream]. 10 | #[account] 11 | #[derive(Copy, Debug, Default)] 12 | pub struct Stream { 13 | /// The mint of the [Stream] token. 14 | pub mint: Pubkey, 15 | /// Bump seed. 16 | pub bump: u8, 17 | 18 | /// An optional account which may invalidate this stream and receive all of the underlying tokens. 19 | /// If the default [Pubkey] is used, it is considered to be irrevocable. 20 | pub revoker: Pubkey, 21 | /// The Crate Token. 22 | pub crate_token: Pubkey, 23 | /// The mint of the SPL token locked up. 24 | pub underlying_mint: Pubkey, 25 | /// Token account holding the underlying tokens. 26 | pub underlying_tokens: Pubkey, 27 | 28 | /// The starting balance of this release account, i.e., how much was 29 | /// originally deposited. 30 | pub initial_amount: u64, 31 | /// The total amount of tokens that have been redeemed from the [Stream]. 32 | pub redeemed_amount: u64, 33 | 34 | /// The time at which the [Stream] begins. 35 | pub start_ts: i64, 36 | /// The time at which the [Stream] starts paying out its tokens. 37 | pub cliff_ts: i64, 38 | /// The time at which all tokens are released. 39 | pub end_ts: i64, 40 | } 41 | 42 | impl Stream { 43 | /// Computes the amount of tokens available for withdrawal. 44 | /// The `remaining_amount` should be the total supply of the [Stream] token. 45 | pub fn available_for_withdrawal(&self, current_ts: i64, remaining_amount: u64) -> Option { 46 | Some(self.outstanding_released(current_ts)?.min(remaining_amount)) 47 | } 48 | 49 | /// The amount of outstanding locked tokens released. 50 | pub fn outstanding_released(&self, current_ts: i64) -> Option { 51 | self.total_released(current_ts)? 52 | .checked_sub(self.redeemed_amount) 53 | } 54 | 55 | /// Returns the total released amount up to the given ts, assuming zero 56 | /// withdrawals and zero funds sent to other programs. 57 | pub fn total_released(&self, current_ts: i64) -> Option { 58 | if current_ts <= self.cliff_ts { 59 | return Some(0); 60 | } 61 | 62 | if current_ts >= self.end_ts { 63 | return Some(self.initial_amount); 64 | } 65 | 66 | // Signed division not supported. 67 | let current_ts = current_ts.to_u64()?; 68 | let start_ts = self.start_ts.to_u64()?; 69 | let end_ts = self.end_ts.to_u64()?; 70 | 71 | if current_ts <= start_ts { 72 | return Some(0); 73 | } 74 | 75 | if current_ts >= end_ts { 76 | return Some(self.initial_amount); 77 | } 78 | 79 | (current_ts.checked_sub(start_ts)? as u128) 80 | .checked_mul(self.initial_amount.into())? 81 | .checked_div(end_ts.checked_sub(start_ts)?.into())? 82 | .to_u64() 83 | } 84 | } 85 | 86 | #[cfg(test)] 87 | #[allow(clippy::unwrap_used)] 88 | mod tests { 89 | use super::*; 90 | 91 | #[test] 92 | fn test_linear_unlock_not_started() { 93 | let release = &mut Stream::default(); 94 | release.start_ts = 100_000; 95 | release.end_ts = 200_000; 96 | release.initial_amount = 1_000_000; 97 | let amt = release.total_released(90_000).unwrap(); 98 | assert_eq!(amt, 0); 99 | } 100 | 101 | #[test] 102 | fn test_linear_unlock_finished() { 103 | let release = &mut Stream::default(); 104 | release.start_ts = 100_000; 105 | release.end_ts = 200_000; 106 | release.initial_amount = 1_000_000; 107 | let amt = release.total_released(290_000).unwrap(); 108 | assert_eq!(amt, 1_000_000); 109 | } 110 | 111 | #[test] 112 | fn test_linear_unlock_halfway() { 113 | let release = &mut Stream::default(); 114 | release.start_ts = 100_000; 115 | release.end_ts = 200_000; 116 | release.initial_amount = 1_000_000; 117 | let amt = release.total_released(150_000).unwrap(); 118 | assert_eq!(amt, 500_000); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /scripts/download-programs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | cd $(dirname $0)/.. 4 | 5 | mkdir -p artifacts/deploy/ 6 | 7 | curl -L https://github.com/DeployDAO/verified-program-artifacts/raw/verify-CrateProtocol__crate-v0.4.0/verifiable/crate_token.so \ 8 | >artifacts/deploy/crate_token.so 9 | -------------------------------------------------------------------------------- /scripts/generate-idl-types.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | shopt -s extglob 4 | 5 | cd $(dirname $0)/.. 6 | 7 | generate_declaration_file() { 8 | PROGRAM_SO=$1 9 | OUT_DIR=$2 10 | 11 | prog="$(basename $PROGRAM_SO .json)" 12 | OUT_PATH="$OUT_DIR/$prog.ts" 13 | if [ ! $(which gsed) ]; then 14 | PREFIX=$(echo $prog | sed -E 's/(^|_)([a-z])/\U\2/g') 15 | else 16 | PREFIX=$(echo $prog | gsed -E 's/(^|_)([a-z])/\U\2/g') 17 | fi 18 | typename="${PREFIX}IDL" 19 | rawName="${PREFIX}JSON" 20 | 21 | # types 22 | echo "export type $typename =" >>$OUT_PATH 23 | cat $PROGRAM_SO >>$OUT_PATH 24 | echo ";" >>$OUT_PATH 25 | 26 | # raw json 27 | echo "export const $rawName: $typename =" >>$OUT_PATH 28 | cat $PROGRAM_SO >>$OUT_PATH 29 | echo ";" >>$OUT_PATH 30 | 31 | # error type 32 | echo "import { generateErrorMap } from '@saberhq/anchor-contrib';" >>$OUT_PATH 33 | echo "export const ${PREFIX}Errors = generateErrorMap($rawName);" >>$OUT_PATH 34 | } 35 | 36 | generate_sdk_idls() { 37 | SDK_DIR=${1:-"./packages/sdk/src/idls"} 38 | IDL_JSONS=$2 39 | 40 | echo "Generating IDLs for the following programs:" 41 | echo $IDL_JSONS 42 | echo "" 43 | 44 | rm -rf $SDK_DIR 45 | mkdir -p $SDK_DIR 46 | if [ $(ls -l artifacts/idl/ | wc -l) -ne 0 ]; then 47 | for f in $IDL_JSONS; do 48 | generate_declaration_file $f $SDK_DIR 49 | done 50 | if [[ $RUN_ESLINT != "none" ]]; then 51 | yarn eslint --fix $SDK_DIR 52 | fi 53 | else 54 | echo "Warning: no IDLs found. Make sure you ran ./scripts/idl.sh first." 55 | fi 56 | } 57 | 58 | generate_sdk_idls ./src/idls 'artifacts/idl/*.json' 59 | -------------------------------------------------------------------------------- /scripts/parse-idls.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script generates the IDL JSONs without buildling the full packages. 4 | 5 | rm -fr artifacts/idl/ 6 | mkdir -p artifacts/idl/ 7 | 8 | for PROGRAM in $(find programs/ -maxdepth 3 -name lib.rs); do 9 | PROGRAM_NAME=$(dirname $PROGRAM | xargs dirname | xargs basename | tr '-' '_') 10 | echo "Parsing IDL for $PROGRAM_NAME" 11 | anchor idl parse --file $PROGRAM >artifacts/idl/$PROGRAM_NAME.json || { 12 | echo "Could not parse IDL" 13 | exit 1 14 | } 15 | done 16 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | import { buildCoderMap } from "@saberhq/anchor-contrib"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | 4 | import type { VenkoProgram, VenkoTypes } from "./programs"; 5 | import { VenkoJSON } from "./programs"; 6 | 7 | /** 8 | * Venko program types. 9 | */ 10 | export interface VenkoPrograms { 11 | Venko: VenkoProgram; 12 | } 13 | 14 | /** 15 | * Venko addresses. 16 | */ 17 | export const VENKO_ADDRESSES = { 18 | Venko: new PublicKey("AnatoLyYrd5iaAe36Lvq2oS4nuVDnRAb3KBVCARt4XiZ"), 19 | }; 20 | 21 | /** 22 | * Program IDLs. 23 | */ 24 | export const VENKO_IDLS = { 25 | Venko: VenkoJSON, 26 | }; 27 | 28 | /** 29 | * Coders. 30 | */ 31 | export const VENKO_CODERS = buildCoderMap<{ 32 | Venko: VenkoTypes; 33 | }>(VENKO_IDLS, VENKO_ADDRESSES); 34 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./constants"; 2 | export * from "./programs"; 3 | export * from "./sdk"; 4 | export * from "./wrappers"; 5 | -------------------------------------------------------------------------------- /src/programs/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./venko"; 2 | -------------------------------------------------------------------------------- /src/programs/venko.ts: -------------------------------------------------------------------------------- 1 | import type { AnchorTypes } from "@saberhq/anchor-contrib"; 2 | 3 | import type { VenkoIDL } from "../idls/venko"; 4 | 5 | export * from "../idls/venko"; 6 | 7 | export type VenkoTypes = AnchorTypes< 8 | VenkoIDL, 9 | { 10 | stream: StreamData; 11 | } 12 | >; 13 | 14 | type Accounts = VenkoTypes["Accounts"]; 15 | 16 | export type StreamData = Accounts["Stream"]; 17 | 18 | export type VenkoProgram = VenkoTypes["Program"]; 19 | -------------------------------------------------------------------------------- /src/sdk.ts: -------------------------------------------------------------------------------- 1 | import { newProgramMap } from "@saberhq/anchor-contrib"; 2 | import type { AugmentedProvider, Provider } from "@saberhq/solana-contrib"; 3 | import { SolanaAugmentedProvider } from "@saberhq/solana-contrib"; 4 | import type { Signer } from "@solana/web3.js"; 5 | 6 | import type { VenkoPrograms } from "./constants"; 7 | import { VENKO_ADDRESSES, VENKO_IDLS } from "./constants"; 8 | import { VenkoWrapper } from "./wrappers"; 9 | 10 | /** 11 | * Venko SDK. 12 | */ 13 | export class VenkoSDK { 14 | constructor( 15 | readonly provider: AugmentedProvider, 16 | readonly programs: VenkoPrograms 17 | ) {} 18 | 19 | /** 20 | * Creates a new instance of the SDK with the given keypair. 21 | */ 22 | withSigner(signer: Signer): VenkoSDK { 23 | return VenkoSDK.load({ 24 | provider: this.provider.withSigner(signer), 25 | }); 26 | } 27 | 28 | /** 29 | * Loads the SDK. 30 | * @returns 31 | */ 32 | static load({ provider }: { provider: Provider }): VenkoSDK { 33 | const programs: VenkoPrograms = newProgramMap( 34 | provider, 35 | VENKO_IDLS, 36 | VENKO_ADDRESSES 37 | ); 38 | return new VenkoSDK(new SolanaAugmentedProvider(provider), programs); 39 | } 40 | 41 | /** 42 | * Venko program helpers. 43 | */ 44 | get venko(): VenkoWrapper { 45 | return new VenkoWrapper(this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/wrappers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./venko"; 2 | -------------------------------------------------------------------------------- /src/wrappers/venko/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./math"; 2 | export * from "./pda"; 3 | export * from "./venko"; 4 | -------------------------------------------------------------------------------- /src/wrappers/venko/math.ts: -------------------------------------------------------------------------------- 1 | import { u64 } from "@saberhq/token-utils"; 2 | 3 | import type { StreamData } from "../../programs/venko"; 4 | 5 | /** 6 | * Computes the amount of tokens that may be redeemed on a Stream. 7 | * @param stream 8 | * @returns 9 | */ 10 | export const computeRedeemableAmount = (stream: StreamData): u64 => { 11 | const nowTs = new u64(Math.floor(new Date().getTime() / 1_000)); 12 | const startTs = stream.startTs; 13 | const cliffTs = stream.cliffTs; 14 | const endTs = stream.endTs; 15 | if (nowTs.lt(cliffTs) || nowTs.lt(startTs)) { 16 | return new u64(0); 17 | } 18 | if (nowTs.gte(endTs)) { 19 | return stream.initialAmount.sub(stream.redeemedAmount); 20 | } 21 | const max = nowTs 22 | .sub(startTs) 23 | .mul(stream.initialAmount) 24 | .div(endTs.sub(startTs)); 25 | return new u64(max.sub(stream.redeemedAmount)); 26 | }; 27 | -------------------------------------------------------------------------------- /src/wrappers/venko/pda.ts: -------------------------------------------------------------------------------- 1 | import { utils } from "@project-serum/anchor"; 2 | import { PublicKey } from "@solana/web3.js"; 3 | 4 | import { VENKO_ADDRESSES } from "../../constants"; 5 | 6 | /** 7 | * Finds the address of a Venko Stream. 8 | */ 9 | export const findStreamAddress = async ( 10 | mint: PublicKey 11 | ): Promise<[PublicKey, number]> => { 12 | return await PublicKey.findProgramAddress( 13 | [utils.bytes.utf8.encode("Stream"), mint.toBuffer()], 14 | VENKO_ADDRESSES.Venko 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /src/wrappers/venko/venko.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CRATE_ADDRESSES, 3 | generateCrateAddress, 4 | } from "@crateprotocol/crate-sdk"; 5 | import type { TransactionEnvelope } from "@saberhq/solana-contrib"; 6 | import type { TokenAmount } from "@saberhq/token-utils"; 7 | import { 8 | createATAInstruction, 9 | createInitMintInstructions, 10 | getATAAddress, 11 | getOrCreateATA, 12 | getOrCreateATAs, 13 | SPLToken, 14 | Token, 15 | TOKEN_PROGRAM_ID, 16 | } from "@saberhq/token-utils"; 17 | import type { Signer } from "@solana/web3.js"; 18 | import { Keypair, PublicKey, SystemProgram } from "@solana/web3.js"; 19 | import BN from "bn.js"; 20 | 21 | import { VENKO_CODERS } from "../.."; 22 | import type { StreamData, VenkoProgram } from "../../programs/venko"; 23 | import type { VenkoSDK } from "../../sdk"; 24 | import { findStreamAddress } from "./pda"; 25 | 26 | /** 27 | * Handles interacting with the Venko program. 28 | */ 29 | export class VenkoWrapper { 30 | readonly program: VenkoProgram; 31 | 32 | /** 33 | * Constructor for a {@link VenkoWrapper}. 34 | * @param sdk 35 | */ 36 | constructor(readonly sdk: VenkoSDK) { 37 | this.program = sdk.programs.Venko; 38 | } 39 | 40 | get provider() { 41 | return this.sdk.provider; 42 | } 43 | 44 | /** 45 | * Fetches a Stream. 46 | * @param key 47 | * @returns 48 | */ 49 | async fetchStream(key: PublicKey): Promise { 50 | return await this.program.account.stream.fetchNullable(key); 51 | } 52 | 53 | /** 54 | * Creates a Venko Stream. 55 | * @returns 56 | */ 57 | async createStream({ 58 | amount, 59 | startTS, 60 | cliffTS = startTS, 61 | endTS, 62 | mintKP = Keypair.generate(), 63 | revoker, 64 | owner = this.provider.wallet.publicKey, 65 | recipient = this.provider.wallet.publicKey, 66 | payer = this.provider.wallet.publicKey, 67 | }: { 68 | amount: TokenAmount; 69 | startTS: number; 70 | cliffTS?: number; 71 | endTS: number; 72 | mintKP?: Signer; 73 | revoker?: PublicKey; 74 | /** 75 | * Owner of the underlying tokens to be streamed. 76 | */ 77 | owner?: PublicKey; 78 | /** 79 | * Recipient of the Stream tokens. 80 | */ 81 | recipient?: PublicKey; 82 | /** 83 | * Payer of the initial tokens. 84 | */ 85 | payer?: PublicKey; 86 | }): Promise<{ 87 | stream: PublicKey; 88 | token: Token; 89 | tx: TransactionEnvelope; 90 | }> { 91 | const [stream, streamBump] = await findStreamAddress(mintKP.publicKey); 92 | const [crateToken, crateBump] = await generateCrateAddress( 93 | mintKP.publicKey 94 | ); 95 | const ownerUnderlyingATA = await getOrCreateATA({ 96 | provider: this.provider, 97 | mint: amount.token.mintAccount, 98 | owner, 99 | }); 100 | const recipientStreamATA = await getOrCreateATA({ 101 | provider: this.provider, 102 | mint: mintKP.publicKey, 103 | owner: recipient, 104 | }); 105 | const underlyingTokensATA = await getATAAddress({ 106 | mint: amount.token.mintAccount, 107 | owner: crateToken, 108 | }); 109 | const underlyingTokensIX = createATAInstruction({ 110 | address: underlyingTokensATA, 111 | mint: amount.token.mintAccount, 112 | owner: crateToken, 113 | payer, 114 | }); 115 | const endDate = new Date(endTS * 1_000); 116 | const token = Token.fromMint(mintKP.publicKey, amount.token.decimals, { 117 | ...amount.token.info, 118 | name: `Venko ${ 119 | amount.token.symbol 120 | } Stream (ends ${endDate.toLocaleString()})`, 121 | symbol: `v${amount.token.symbol}`, 122 | }); 123 | 124 | return { 125 | stream, 126 | token, 127 | tx: ( 128 | await createInitMintInstructions({ 129 | provider: this.provider, 130 | mintKP, 131 | decimals: amount.token.decimals, 132 | mintAuthority: crateToken, 133 | freezeAuthority: crateToken, 134 | }) 135 | ).combine( 136 | this.provider.newTX( 137 | [ 138 | recipientStreamATA.instruction, 139 | ownerUnderlyingATA.instruction, 140 | underlyingTokensIX, 141 | SPLToken.createTransferInstruction( 142 | TOKEN_PROGRAM_ID, 143 | ownerUnderlyingATA.address, 144 | underlyingTokensATA, 145 | owner, 146 | [], 147 | amount.toU64() 148 | ), 149 | VENKO_CODERS.Venko.encodeIX( 150 | "createStream", 151 | { 152 | streamBump, 153 | crateBump, 154 | startTs: new BN(startTS), 155 | cliffTs: new BN(cliffTS), 156 | endTs: new BN(endTS), 157 | revoker: revoker ?? PublicKey.default, 158 | }, 159 | { 160 | streamMint: mintKP.publicKey, 161 | stream, 162 | underlyingMint: amount.token.mintAccount, 163 | underlyingTokens: underlyingTokensATA, 164 | destination: recipientStreamATA.address, 165 | crateToken, 166 | payer, 167 | systemProgram: SystemProgram.programId, 168 | crateTokenProgram: CRATE_ADDRESSES.CrateToken, 169 | tokenProgram: TOKEN_PROGRAM_ID, 170 | } 171 | ), 172 | ], 173 | [mintKP] 174 | ) 175 | ), 176 | }; 177 | } 178 | 179 | /** 180 | * Redeems Stream tokens. 181 | * @returns 182 | */ 183 | async redeem({ 184 | amount, 185 | owner = this.provider.wallet.publicKey, 186 | recipient = this.provider.wallet.publicKey, 187 | }: { 188 | /** 189 | * Amount of Stream tokens to redeem. 190 | */ 191 | amount: TokenAmount; 192 | /** 193 | * Owner of the Stream tokens. 194 | */ 195 | owner?: PublicKey; 196 | /** 197 | * Recipient of the redeemed tokens. 198 | */ 199 | recipient?: PublicKey; 200 | }): Promise { 201 | const [stream] = await findStreamAddress(amount.token.mintAccount); 202 | const streamData = await this.fetchStream(stream); 203 | if (!streamData) { 204 | throw new Error(`stream not found: ${stream.toString()}`); 205 | } 206 | const ownerStreamATA = await getATAAddress({ 207 | mint: amount.token.mintAccount, 208 | owner, 209 | }); 210 | const recipientUnderlyingATA = await getOrCreateATA({ 211 | provider: this.provider, 212 | mint: streamData.underlyingMint, 213 | owner: recipient, 214 | }); 215 | return this.provider.newTX([ 216 | recipientUnderlyingATA.instruction, 217 | VENKO_CODERS.Venko.encodeIX( 218 | "redeem", 219 | { 220 | amount: amount.toU64(), 221 | }, 222 | { 223 | streamMint: amount.token.mintAccount, 224 | stream, 225 | sourceStreamTokens: ownerStreamATA, 226 | underlyingTokens: streamData.underlyingTokens, 227 | destinationTokens: recipientUnderlyingATA.address, 228 | crateToken: streamData.crateToken, 229 | userAuthority: owner, 230 | systemProgram: SystemProgram.programId, 231 | crateTokenProgram: CRATE_ADDRESSES.CrateToken, 232 | tokenProgram: TOKEN_PROGRAM_ID, 233 | } 234 | ), 235 | ]); 236 | } 237 | 238 | /** 239 | * Revokes a Stream. 240 | * @returns 241 | */ 242 | async revoke({ 243 | streamMint, 244 | owner = this.provider.wallet.publicKey, 245 | revoker = this.provider.wallet.publicKey, 246 | }: { 247 | /** 248 | * The mint of the Stream to revoke. 249 | */ 250 | streamMint: PublicKey; 251 | /** 252 | * Owner to send the tokens to. 253 | */ 254 | owner?: PublicKey; 255 | revoker?: PublicKey; 256 | }): Promise { 257 | const [stream] = await findStreamAddress(streamMint); 258 | const streamData = await this.fetchStream(stream); 259 | if (!streamData) { 260 | throw new Error(`stream not found: ${stream.toString()}`); 261 | } 262 | const ownerATAs = await getOrCreateATAs({ 263 | provider: this.provider, 264 | mints: { 265 | underlying: streamData.underlyingMint, 266 | }, 267 | owner, 268 | }); 269 | return this.provider.newTX([ 270 | ...ownerATAs.instructions, 271 | VENKO_CODERS.Venko.encodeIX( 272 | "revoke", 273 | {}, 274 | { 275 | stream, 276 | crateToken: streamData.crateToken, 277 | underlyingTokens: streamData.underlyingTokens, 278 | destinationTokens: ownerATAs.accounts.underlying, 279 | revoker, 280 | crateTokenProgram: CRATE_ADDRESSES.CrateToken, 281 | tokenProgram: TOKEN_PROGRAM_ID, 282 | } 283 | ), 284 | ]); 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /tests/spec-key.json: -------------------------------------------------------------------------------- 1 | [ 2 | 62, 228, 254, 246, 181, 122, 63, 241, 99, 240, 22, 5, 205, 3, 193, 133, 155, 3 | 35, 91, 8, 210, 192, 58, 199, 80, 3, 3, 106, 37, 144, 56, 123, 147, 7, 146, 4 | 34, 22, 184, 69, 221, 149, 46, 87, 198, 76, 0, 252, 120, 154, 181, 35, 55, 5 | 253, 85, 192, 116, 158, 100, 243, 202, 31, 141, 28, 53 6 | ] 7 | -------------------------------------------------------------------------------- /tests/venko.spec.ts: -------------------------------------------------------------------------------- 1 | import { expectTXTable } from "@saberhq/chai-solana"; 2 | import { 3 | createMint, 4 | getOrCreateATA, 5 | sleep, 6 | SPLToken, 7 | Token, 8 | TOKEN_PROGRAM_ID, 9 | TokenAmount, 10 | } from "@saberhq/token-utils"; 11 | import { Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js"; 12 | 13 | import { VenkoSDK } from "../src"; 14 | import { makeSDK } from "./workspace/workspace"; 15 | 16 | describe("Venko", () => { 17 | const { provider } = makeSDK(); 18 | 19 | const adminKP = Keypair.generate(); 20 | const adminSDK = VenkoSDK.load({ 21 | provider: provider.withSigner(adminKP), 22 | }); 23 | 24 | const recipientKP = Keypair.generate(); 25 | const recipientSDK = VenkoSDK.load({ 26 | provider: provider.withSigner(recipientKP), 27 | }); 28 | 29 | before(async () => { 30 | await ( 31 | await adminSDK.provider.requestAirdrop(LAMPORTS_PER_SOL * 10) 32 | ).wait(); 33 | await ( 34 | await recipientSDK.provider.requestAirdrop(LAMPORTS_PER_SOL * 10) 35 | ).wait(); 36 | }); 37 | 38 | it("should allow creating an irrevocable stream", async () => { 39 | const underlyingToken = Token.fromMint( 40 | await createMint(adminSDK.provider, undefined, 6), 41 | 6 42 | ); 43 | const amount = TokenAmount.parse(underlyingToken, "10"); 44 | 45 | const adminUnderlyingTokens = await getOrCreateATA({ 46 | provider: adminSDK.provider, 47 | owner: adminSDK.provider.wallet.publicKey, 48 | mint: underlyingToken.mintAccount, 49 | }); 50 | 51 | await expectTXTable( 52 | adminSDK.provider.newTX([ 53 | adminUnderlyingTokens.instruction, 54 | SPLToken.createMintToInstruction( 55 | TOKEN_PROGRAM_ID, 56 | underlyingToken.mintAccount, 57 | adminUnderlyingTokens.address, 58 | adminSDK.provider.wallet.publicKey, 59 | [], 60 | amount.toU64() 61 | ), 62 | ]) 63 | ).to.be.fulfilled; 64 | 65 | const nowTS = Math.floor(new Date().getTime() / 1_000); 66 | 67 | const { tx, token: streamToken } = await adminSDK.venko.createStream({ 68 | amount, 69 | startTS: nowTS, 70 | endTS: nowTS + 3, 71 | recipient: recipientKP.publicKey, 72 | }); 73 | await expectTXTable(tx, "create stream", { 74 | verbosity: "error", 75 | }).to.be.fulfilled; 76 | 77 | // wait for stream to be over... 78 | await sleep(5_000); 79 | 80 | const claimTX = await recipientSDK.venko.redeem({ 81 | amount: TokenAmount.parse(streamToken, "1"), 82 | }); 83 | await expectTXTable(claimTX, "redeem stream", { 84 | verbosity: "error", 85 | }).to.be.fulfilled; 86 | }); 87 | 88 | it("should allow creating a revocable stream", async () => { 89 | const underlyingToken = Token.fromMint( 90 | await createMint(adminSDK.provider, undefined, 6), 91 | 6 92 | ); 93 | const amount = TokenAmount.parse(underlyingToken, "10"); 94 | 95 | const adminUnderlyingTokens = await getOrCreateATA({ 96 | provider: adminSDK.provider, 97 | owner: adminSDK.provider.wallet.publicKey, 98 | mint: underlyingToken.mintAccount, 99 | }); 100 | 101 | await expectTXTable( 102 | adminSDK.provider.newTX([ 103 | adminUnderlyingTokens.instruction, 104 | SPLToken.createMintToInstruction( 105 | TOKEN_PROGRAM_ID, 106 | underlyingToken.mintAccount, 107 | adminUnderlyingTokens.address, 108 | adminSDK.provider.wallet.publicKey, 109 | [], 110 | amount.toU64() 111 | ), 112 | ]) 113 | ).to.be.fulfilled; 114 | 115 | const nowTS = Math.floor(new Date().getTime() / 1_000); 116 | 117 | const { tx, token: streamToken } = await adminSDK.venko.createStream({ 118 | amount, 119 | startTS: nowTS, 120 | endTS: nowTS + 3, 121 | recipient: recipientKP.publicKey, 122 | revoker: adminSDK.provider.wallet.publicKey, 123 | }); 124 | await expectTXTable(tx, "create stream", { 125 | verbosity: "error", 126 | }).to.be.fulfilled; 127 | 128 | // wait for stream to be over... 129 | await sleep(5_000); 130 | 131 | const claimTX = await recipientSDK.venko.redeem({ 132 | amount: TokenAmount.parse(streamToken, "1"), 133 | }); 134 | await expectTXTable(claimTX, "redeem stream", { 135 | verbosity: "error", 136 | }).to.be.fulfilled; 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /tests/workspace/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./workspace"; 2 | -------------------------------------------------------------------------------- /tests/workspace/workspace.ts: -------------------------------------------------------------------------------- 1 | import * as anchor from "@project-serum/anchor"; 2 | import { makeSaberProvider } from "@saberhq/anchor-contrib"; 3 | import { chaiSolana } from "@saberhq/chai-solana"; 4 | import chai from "chai"; 5 | 6 | import type { VenkoPrograms } from "../../src"; 7 | import { VenkoSDK } from "../../src"; 8 | 9 | chai.use(chaiSolana); 10 | 11 | export type Workspace = VenkoPrograms; 12 | 13 | export const makeSDK = (): VenkoSDK => { 14 | const anchorProvider = anchor.Provider.env(); 15 | anchor.setProvider(anchorProvider); 16 | const provider = makeSaberProvider(anchorProvider); 17 | return VenkoSDK.load({ 18 | provider, 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "noEmit": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "sourceMap": true, 9 | "inlineSources": true, 10 | "outDir": "dist/cjs/" 11 | }, 12 | "include": ["src/"] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.esm.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "compilerOptions": { 4 | "module": "ES2015", 5 | "outDir": "dist/esm/" 6 | }, 7 | "include": ["src/"] 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@saberhq/tsconfig/tsconfig.lib.json", 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "noErrorTruncation": true, 6 | "types": ["mocha"] 7 | }, 8 | "include": ["src/", "tests/"] 9 | } 10 | --------------------------------------------------------------------------------