diff --git a/.github/actions/setup-anchor/action.yaml b/.github/actions/setup-anchor/action.yaml index 4428319..18c534c 100644 --- a/.github/actions/setup-anchor/action.yaml +++ b/.github/actions/setup-anchor/action.yaml @@ -12,6 +12,9 @@ runs: path: | ~/.cargo/bin/anchor key: anchor-cli-${{ runner.os }}-v0003-${{ env.ANCHOR_VERSION }}-${{ env.ANCHOR_SHA }} + - run: rustup install 1.79 && rustup default 1.79 + shell: bash + if: steps.cache-anchor-cli.outputs.cache-hit != 'true' # if ANCHOR_VERSION is 0, then install the anchor-cli from source - run: if [ $ANCHOR_VERSION -eq 0 ]; then cargo install --git https://github.com/coral-xyz/anchor --rev $ANCHOR_SHA anchor-cli --locked --force; else cargo install --git https://github.com/coral-xyz/anchor --tag "v$ANCHOR_VERSION" anchor-cli --locked; fi shell: bash diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml index 95cdfb8..90ef2f0 100644 --- a/.github/actions/setup/action.yaml +++ b/.github/actions/setup/action.yaml @@ -15,3 +15,4 @@ runs: shell: bash - run: git submodule update --init --recursive --depth 1 shell: bash + diff --git a/.github/workflows/develop-release-program.yaml b/.github/workflows/develop-release-program.yaml index a64b79f..43050c9 100644 --- a/.github/workflows/develop-release-program.yaml +++ b/.github/workflows/develop-release-program.yaml @@ -36,6 +36,7 @@ jobs: echo "programs_with_changes=$json" >> $GITHUB_OUTPUT build_programs: needs: [detect_changed_programs] + continue-on-error: true runs-on: ubuntu-latest if: needs.detect_changed_programs.outputs.programs_with_changes != '[]' && needs.detect_changed_programs.outputs.programs_with_changes != '' strategy: @@ -103,6 +104,7 @@ jobs: publish_programs: + continue-on-error: true needs: [detect_changed_programs, build_programs] runs-on: ubuntu-latest if: needs.detect_changed_programs.outputs.programs_with_changes != '[]' && needs.detect_changed_programs.outputs.programs_with_changes != '' diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c9d3f03..a15cb42 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -29,6 +29,7 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ key: cargo-${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + - run: cargo build --locked - run: cargo fmt -- --check - run: cargo clippy --all-targets -- -D warnings -A clippy::result_large_err -A clippy::too_many_arguments -A clippy::uninlined-format-args -A ambiguous_glob_reexports @@ -48,6 +49,7 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ key: cargo-${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + - run: cargo build --locked - run: cargo test --lib build: diff --git a/Anchor.toml b/Anchor.toml index 5b97ccf..45a57db 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -6,6 +6,7 @@ skip-lint = false proposal = "propFYxqmVcufMhk5esNMrexq2ogHbbC2kP9PU1qxKs" state_controller = "stcfiqW3fwD9QCd8Bqr1NBLrs7dftZHBQe7RiMMA4aM" token_voter = "tokvN2E37T6NgLi6uQ8uj32959TZPUf2Jo8dXjLKBjF" +nft_proxy = "nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p" nft_voter = "nftvLQ5t6xe2nQF1NBmBBmn15ed59tU6vSCkwQNEqdc" organization = "orgdXvHVLkWgBYerptASkAwkZAE563CJUu717dMNx5f" organization_wallet = "orgwPMqJs9xft8UefUdKfyBwg6GDnN6oLhpMaKa6nJg" diff --git a/CHANGELOG.md b/CHANGELOG.md index 271d853..0b04647 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) **Note:** Version bump only for package modular-governance @@ -11,7 +11,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline -## [0.0.10](https://github.com/helium/modular-governance/compare/v0.0.9...v0.0.10) (2024-03-28) +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + + + +## [0.0.8](https://github.com/helium/modular-governance/compare/v0.0.7...v0.0.8) (2023-11-10) + + + +## [0.0.7](https://github.com/helium/modular-governance/compare/v0.0.6...v0.0.7) (2023-11-07) + + + +## [0.0.6](https://github.com/helium/modular-governance/compare/v0.0.4...v0.0.6) (2023-11-06) **Note:** Version bump only for package modular-governance @@ -19,6 +31,20 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline +## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) + +**Note:** Version bump only for package modular-governance + + + + + +## [0.0.10](https://github.com/helium/modular-governance/compare/v0.0.9...v0.0.10) (2024-03-28) + +**Note:** Version bump only for package modular-governance + + + ## [0.0.9](https://github.com/helium/modular-governance/compare/v0.0.8...v0.0.9) (2024-03-13) **Note:** Version bump only for package modular-governance diff --git a/Cargo.lock b/Cargo.lock index 04b5485..de0d10e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -590,9 +590,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] @@ -605,7 +605,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -796,7 +796,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -807,7 +807,16 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.23", + "syn 2.0.72", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", ] [[package]] @@ -1226,13 +1235,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nft-proxy" +version = "0.0.1" +dependencies = [ + "anchor-lang", + "anchor-spl", + "bytemuck", + "time", +] + [[package]] name = "nft-voter" version = "0.1.0" dependencies = [ "anchor-lang", "anchor-spl", + "nft-proxy", "proposal", + "serde", + "time", ] [[package]] @@ -1246,6 +1268,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.3.3" @@ -1325,7 +1353,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -1347,6 +1375,7 @@ dependencies = [ "anchor-lang", "anchor-spl", "proposal", + "time", ] [[package]] @@ -1357,6 +1386,7 @@ dependencies = [ "anchor-spl", "organization", "proposal", + "time", ] [[package]] @@ -1424,6 +1454,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1451,9 +1487,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1464,6 +1500,7 @@ version = "0.1.1" dependencies = [ "anchor-lang", "anchor-spl", + "time", "vote-hook-interface", ] @@ -1478,9 +1515,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1665,9 +1702,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.167" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daf513456463b42aa1d94cff7e0c24d682b429f020b9afa4f5ba5c40a22b237" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -1683,13 +1720,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.167" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69b106b68bc8054f0e974e70d19984040f8a5cf9215ca82626ea4853f82c4b9" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -1722,7 +1759,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -1835,7 +1872,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -1966,7 +2003,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.23", + "syn 2.0.72", ] [[package]] @@ -2063,6 +2100,7 @@ dependencies = [ "anchor-lang", "anchor-spl", "proposal", + "time", ] [[package]] @@ -2090,9 +2128,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -2125,9 +2163,28 @@ checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tiny-bip39" version = "0.8.2" @@ -2169,6 +2226,8 @@ dependencies = [ "anchor-lang", "anchor-spl", "proposal", + "serde", + "time", ] [[package]] @@ -2256,6 +2315,7 @@ version = "0.1.0" dependencies = [ "anchor-lang", "anchor-spl", + "time", ] [[package]] @@ -2291,7 +2351,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", "wasm-bindgen-shared", ] @@ -2313,7 +2373,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2448,5 +2508,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.72", ] diff --git a/Cargo.toml b/Cargo.toml index 158be60..375394b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ codegen-units = 1 opt-level = 3 incremental = false codegen-units = 1 + +[workspace.dependencies] +time = "0.3.36" diff --git a/lerna.json b/lerna.json index 4bc0bae..1ff5f00 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ "packages/*" ], "useWorkspaces": true, - "version": "0.0.11" + "version": "0.0.13" } diff --git a/packages/docsite/CHANGELOG.md b/packages/docsite/CHANGELOG.md index 11ad048..803bfd5 100644 --- a/packages/docsite/CHANGELOG.md +++ b/packages/docsite/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package governance-docs + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + + + +## [0.0.8](https://github.com/helium/modular-governance/compare/v0.0.7...v0.0.8) (2023-11-10) + + + +## [0.0.7](https://github.com/helium/modular-governance/compare/v0.0.6...v0.0.7) (2023-11-07) + + + +## [0.0.6](https://github.com/helium/modular-governance/compare/v0.0.4...v0.0.6) (2023-11-06) + +**Note:** Version bump only for package governance-docs + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package governance-docs diff --git a/packages/docsite/package.json b/packages/docsite/package.json index 34c7cb3..4586957 100644 --- a/packages/docsite/package.json +++ b/packages/docsite/package.json @@ -1,6 +1,6 @@ { "name": "governance-docs", - "version": "0.0.11", + "version": "0.0.13", "private": true, "scripts": { "dev": "next dev", diff --git a/packages/docsite/src/pages/docs/api/nft-proxy-sdk.md b/packages/docsite/src/pages/docs/api/nft-proxy-sdk.md new file mode 100644 index 0000000..06a5a5f --- /dev/null +++ b/packages/docsite/src/pages/docs/api/nft-proxy-sdk.md @@ -0,0 +1,171 @@ +# Nft Proxy SDK + +{% callout title="Quick tip" %} +If you are looking for a quick start guide, check out the [Getting Started](/docs/learn/getting_started) guide. We also have some react examples [here](/docs/learn/react). +{% /callout %} + +## Instructions + +### initializeProxyConfigV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ------------- | ---------- | ------ | ---- | +| payer | mut | yes | | +| authority | immut | no | | +| proxyConfig | mut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | --------------------------- | ---- | +| args | InitializeProxyConfigArgsV0 | | + +### assignProxyV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ---------------------- | ---------- | ------ | ---------------------------------------------------------------------- | +| payer | mut | yes | | +| asset | immut | no | | +| approver | immut | yes | | +| voter | immut | no | or in the case of a primary proxy (first in the line), Pubkey::default | +| tokenAccount | immut | no | | +| proxyConfig | immut | no | | +| currentProxyAssignment | mut | no | | +| recipient | immut | no | | +| nextProxyAssignment | mut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ----------------- | ---- | +| args | AssignProxyArgsV0 | | + +### unassignProxyV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ---------------------- | ---------- | ------ | ---------------------------------------------------------------------- | +| rentRefund | mut | no | | +| asset | immut | no | | +| approver | immut | yes | | +| voter | immut | no | or in the case of a primary proxy (first in the line), Pubkey::default | +| tokenAccount | immut | no | | +| currentProxyAssignment | immut | no | | +| prevProxyAssignment | mut | no | | +| proxyAssignment | mut | no | | +| proxyConfig | immut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ---- | ---- | + +### updateProxyConfigV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ------------- | ---------- | ------ | ---- | +| payer | mut | yes | | +| authority | immut | no | | +| proxyConfig | mut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ----------------------- | ---- | +| args | UpdateProxyConfigArgsV0 | | + +### unassignExpiredProxyV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ------------------- | ---------- | ------ | ---- | +| rentRefund | mut | no | | +| prevProxyAssignment | mut | no | | +| proxyAssignment | mut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ---- | ---- | + +### closeExpiredProxyV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| --------------- | ---------- | ------ | ---- | +| rentRefund | mut | no | | +| proxyAssignment | mut | no | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ---- | ---- | + +## Accounts + +### ProxyConfigV0 + +| Field | Type | +| ------------ | --------- | +| authority | publicKey | +| name | string | +| maxProxyTime | i64 | +| seasons | SeasonV0 | + +### ProxyAssignmentV0 + +| Field | Type | +| -------------- | --------- | +| voter | publicKey | +| proxyConfig | publicKey | +| asset | publicKey | +| index | u16 | +| nextVoter | publicKey | +| rentRefund | publicKey | +| expirationTime | i64 | +| bumpSeed | u8 | + +## Types + +### AssignProxyArgsV0 + +| Field | Type | +| -------------- | ---- | +| expirationTime | i64 | + +### InitializeProxyConfigArgsV0 + +| Field | Type | +| ------------ | -------- | +| name | string | +| maxProxyTime | i64 | +| seasons | SeasonV0 | + +### UpdateProxyConfigArgsV0 + +| Field | Type | +| ------------ | --------------- | +| maxProxyTime | i64 | +| seasons | [object Object] | + +### SeasonV0 + +| Field | Type | +| ----- | ---- | +| start | i64 | +| end | i64 | diff --git a/packages/docsite/src/pages/docs/api/organization-wallet-sdk.md b/packages/docsite/src/pages/docs/api/organization-wallet-sdk.md index dd3e480..5bb0bae 100644 --- a/packages/docsite/src/pages/docs/api/organization-wallet-sdk.md +++ b/packages/docsite/src/pages/docs/api/organization-wallet-sdk.md @@ -61,6 +61,24 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | Name | Type | Docs | | ---- | ---- | ---- | +### updateOrganizationWalletV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| ------------------ | ---------- | ------ | ---- | +| payer | mut | yes | | +| organizationWallet | mut | no | | +| organization | immut | no | | +| authority | immut | yes | | +| systemProgram | immut | no | | + +#### Args + +| Name | Type | Docs | +| ---- | ------------------------------ | ---- | +| args | UpdateOrganizationWalletArgsV0 | | + ## Accounts ### OrganizationWalletV0 @@ -136,6 +154,13 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | disableExecutionOffset | u32 | | transaction | CompiledTransactionArgV0 | +### UpdateOrganizationWalletArgsV0 + +| Field | Type | +| --------------- | --------------- | +| name | string | +| proposalConfigs | [object Object] | + ### CompiledInstructionV0 | Field | Type | diff --git a/packages/docsite/src/pages/docs/api/proposal-sdk.md b/packages/docsite/src/pages/docs/api/proposal-sdk.md index 6463022..f19a69f 100644 --- a/packages/docsite/src/pages/docs/api/proposal-sdk.md +++ b/packages/docsite/src/pages/docs/api/proposal-sdk.md @@ -77,6 +77,21 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | ---- | ----------------- | ---- | | args | UpdateStateArgsV0 | | +### updateProposalConfigV0 + +#### Accounts + +| Name | Mutability | Signer | Docs | +| -------------- | ---------- | ------ | ---- | +| proposalConfig | mut | no | | +| authority | immut | yes | | + +#### Args + +| Name | Type | Docs | +| ---- | -------------------------- | ---- | +| args | UpdateProposalConfigArgsV0 | | + ## Accounts ### ProposalConfigV0 @@ -88,6 +103,7 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | onVoteHook | publicKey | | name | string | | bumpSeed | u8 | +| authority | publicKey | ### ProposalV0 @@ -116,6 +132,7 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | voteController | publicKey | | stateController | publicKey | | onVoteHook | publicKey | +| authority | publicKey | ### ChoiceArg @@ -135,6 +152,15 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc | choices | ChoiceArg | | tags | string | +### UpdateProposalConfigArgsV0 + +| Field | Type | +| --------------- | --------- | +| voteController | publicKey | +| stateController | publicKey | +| onVoteHook | publicKey | +| authority | publicKey | + ### UpdateStateArgsV0 | Field | Type | diff --git a/packages/modular-governance-hooks/CHANGELOG.md b/packages/modular-governance-hooks/CHANGELOG.md index 5e55b76..1216c73 100644 --- a/packages/modular-governance-hooks/CHANGELOG.md +++ b/packages/modular-governance-hooks/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/modular-governance-hooks + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/modular-governance-hooks + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/modular-governance-hooks diff --git a/packages/modular-governance-hooks/package.json b/packages/modular-governance-hooks/package.json index a8be150..f75c3a3 100644 --- a/packages/modular-governance-hooks/package.json +++ b/packages/modular-governance-hooks/package.json @@ -6,7 +6,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "React hooks for modular governance", "repository": { "type": "git", @@ -36,8 +36,8 @@ "@helium/account-fetch-cache": "^0.5.0", "@helium/account-fetch-cache-hooks": "^0.5.0", "@helium/helium-react-hooks": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11", - "@helium/organization-sdk": "^0.0.11", + "@helium/modular-governance-idls": "^0.0.13", + "@helium/organization-sdk": "^0.0.13", "@solana/web3.js": "^1.78.4" }, "devDependencies": { diff --git a/packages/modular-governance-idls/CHANGELOG.md b/packages/modular-governance-idls/CHANGELOG.md index eb85615..ed879f8 100644 --- a/packages/modular-governance-idls/CHANGELOG.md +++ b/packages/modular-governance-idls/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/modular-governance-idls + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/modular-governance-idls + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/modular-governance-idls diff --git a/packages/modular-governance-idls/package.json b/packages/modular-governance-idls/package.json index 4133004..91737fd 100644 --- a/packages/modular-governance-idls/package.json +++ b/packages/modular-governance-idls/package.json @@ -1,6 +1,6 @@ { "name": "@helium/modular-governance-idls", - "version": "0.0.11", + "version": "0.0.13", "description": "Exported idls", "publishConfig": { "access": "public", @@ -16,7 +16,7 @@ "lib" ], "exports": { - "./*": "./lib/esm/*" + "./*": "./*" }, "scripts": { "format": "prettier --write \"src/**/*.{ts,tsx}\"", diff --git a/packages/modular-governance-idls/packages/modular-governance-idls/tsconfig.esm.tsbuildinfo b/packages/modular-governance-idls/packages/modular-governance-idls/tsconfig.esm.tsbuildinfo new file mode 100644 index 0000000..bb8b3e9 --- /dev/null +++ b/packages/modular-governance-idls/packages/modular-governance-idls/tsconfig.esm.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../../../target/types/nft_proxy.ts","../../../../target/types/nft_voter.ts","../../../../target/types/organization.ts","../../../../target/types/organization_wallet.ts","../../../../target/types/proposal.ts","../../../../target/types/state_controller.ts","../../../../target/types/token_voter.ts","../../../../target/types/vote_hook_interface.ts","../../../../node_modules/@types/node/assert.d.ts","../../../../node_modules/@types/node/assert/strict.d.ts","../../../../node_modules/@types/node/globals.d.ts","../../../../node_modules/@types/node/async_hooks.d.ts","../../../../node_modules/@types/node/buffer.d.ts","../../../../node_modules/@types/node/child_process.d.ts","../../../../node_modules/@types/node/cluster.d.ts","../../../../node_modules/@types/node/console.d.ts","../../../../node_modules/@types/node/constants.d.ts","../../../../node_modules/@types/node/crypto.d.ts","../../../../node_modules/@types/node/dgram.d.ts","../../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../../node_modules/@types/node/dns.d.ts","../../../../node_modules/@types/node/dns/promises.d.ts","../../../../node_modules/@types/node/domain.d.ts","../../../../node_modules/@types/node/dom-events.d.ts","../../../../node_modules/@types/node/events.d.ts","../../../../node_modules/@types/node/fs.d.ts","../../../../node_modules/@types/node/fs/promises.d.ts","../../../../node_modules/@types/node/http.d.ts","../../../../node_modules/@types/node/http2.d.ts","../../../../node_modules/@types/node/https.d.ts","../../../../node_modules/@types/node/inspector.d.ts","../../../../node_modules/@types/node/module.d.ts","../../../../node_modules/@types/node/net.d.ts","../../../../node_modules/@types/node/os.d.ts","../../../../node_modules/@types/node/path.d.ts","../../../../node_modules/@types/node/perf_hooks.d.ts","../../../../node_modules/@types/node/process.d.ts","../../../../node_modules/@types/node/punycode.d.ts","../../../../node_modules/@types/node/querystring.d.ts","../../../../node_modules/@types/node/readline.d.ts","../../../../node_modules/@types/node/readline/promises.d.ts","../../../../node_modules/@types/node/repl.d.ts","../../../../node_modules/@types/node/stream.d.ts","../../../../node_modules/@types/node/stream/promises.d.ts","../../../../node_modules/@types/node/stream/consumers.d.ts","../../../../node_modules/@types/node/stream/web.d.ts","../../../../node_modules/@types/node/string_decoder.d.ts","../../../../node_modules/@types/node/test.d.ts","../../../../node_modules/@types/node/timers.d.ts","../../../../node_modules/@types/node/timers/promises.d.ts","../../../../node_modules/@types/node/tls.d.ts","../../../../node_modules/@types/node/trace_events.d.ts","../../../../node_modules/@types/node/tty.d.ts","../../../../node_modules/@types/node/url.d.ts","../../../../node_modules/@types/node/util.d.ts","../../../../node_modules/@types/node/v8.d.ts","../../../../node_modules/@types/node/vm.d.ts","../../../../node_modules/@types/node/wasi.d.ts","../../../../node_modules/@types/node/worker_threads.d.ts","../../../../node_modules/@types/node/zlib.d.ts","../../../../node_modules/@types/node/globals.global.d.ts","../../../../node_modules/@types/node/index.d.ts","../../../../node_modules/@types/bn.js/index.d.ts","../../../../node_modules/@types/chai/index.d.ts","../../../../node_modules/@types/chai-as-promised/index.d.ts","../../../../node_modules/@types/connect/index.d.ts","../../../../node_modules/@types/json5/index.d.ts","../../../../node_modules/@types/minimatch/index.d.ts","../../../../node_modules/@types/minimist/index.d.ts","../../../../node_modules/@types/mocha/index.d.ts","../../../../node_modules/@types/normalize-package-data/index.d.ts","../../../../node_modules/@types/parse-json/index.d.ts","../../../../node_modules/@types/pbkdf2/index.d.ts","../../../../node_modules/@types/secp256k1/index.d.ts","../../../../node_modules/@types/ws/index.d.ts"],"fileInfos":[{"version":"8730f4bf322026ff5229336391a18bcaa1f94d4f82416c8b2f3954e2ccaae2ba","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06","4b421cbfb3a38a27c279dec1e9112c3d1da296f77a1a85ddadf7e7a425d45d18","1fc5ab7a764205c68fa10d381b08417795fc73111d6dd16b5b1ed36badb743d9",{"version":"adb996790133eb33b33aadb9c09f15c2c575e71fb57a62de8bf74dbf59ec7dfb","affectsGlobalScope":true},{"version":"8cc8c5a3bac513368b0157f3d8b31cfdcfe78b56d3724f30f80ed9715e404af8","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"c5c05907c02476e4bde6b7e76a79ffcd948aedd14b6a8f56e4674221b0417398","affectsGlobalScope":true},{"version":"5f406584aef28a331c36523df688ca3650288d14f39c5d2e555c95f0d2ff8f6f","affectsGlobalScope":true},{"version":"22f230e544b35349cfb3bd9110b6ef37b41c6d6c43c3314a31bd0d9652fcec72","affectsGlobalScope":true},{"version":"7ea0b55f6b315cf9ac2ad622b0a7813315bb6e97bf4bb3fbf8f8affbca7dc695","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"eb26de841c52236d8222f87e9e6a235332e0788af8c87a71e9e210314300410a","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"81cac4cbc92c0c839c70f8ffb94eb61e2d32dc1c3cf6d95844ca099463cf37ea","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"d154ea5bb7f7f9001ed9153e876b2d5b8f5c2bb9ec02b3ae0d239ec769f1f2ae","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"9d57b2b5d15838ed094aa9ff1299eecef40b190722eb619bac4616657a05f951","affectsGlobalScope":true},{"version":"6c51b5dd26a2c31dbf37f00cfc32b2aa6a92e19c995aefb5b97a3a64f1ac99de","affectsGlobalScope":true},{"version":"6e7997ef61de3132e4d4b2250e75343f487903ddf5370e7ce33cf1b9db9a63ed","affectsGlobalScope":true},{"version":"2ad234885a4240522efccd77de6c7d99eecf9b4de0914adb9a35c0c22433f993","affectsGlobalScope":true},{"version":"5e5e095c4470c8bab227dbbc61374878ecead104c74ab9960d3adcccfee23205","affectsGlobalScope":true},{"version":"09aa50414b80c023553090e2f53827f007a301bc34b0495bfb2c3c08ab9ad1eb","affectsGlobalScope":true},{"version":"d7f680a43f8cd12a6b6122c07c54ba40952b0c8aa140dcfcf32eb9e6cb028596","affectsGlobalScope":true},{"version":"3787b83e297de7c315d55d4a7c546ae28e5f6c0a361b7a1dcec1f1f50a54ef11","affectsGlobalScope":true},{"version":"e7e8e1d368290e9295ef18ca23f405cf40d5456fa9f20db6373a61ca45f75f40","affectsGlobalScope":true},{"version":"faf0221ae0465363c842ce6aa8a0cbda5d9296940a8e26c86e04cc4081eea21e","affectsGlobalScope":true},{"version":"06393d13ea207a1bfe08ec8d7be562549c5e2da8983f2ee074e00002629d1871","affectsGlobalScope":true},{"version":"2768ef564cfc0689a1b76106c421a2909bdff0acbe87da010785adab80efdd5c","affectsGlobalScope":true},{"version":"b248e32ca52e8f5571390a4142558ae4f203ae2f94d5bac38a3084d529ef4e58","affectsGlobalScope":true},{"version":"fb4416144c1bf0323ccbc9afb0ab289c07312214e8820ad17d709498c865a3fe","affectsGlobalScope":true},{"version":"52d1bb7ab7a3306fd0375c8bff560feed26ed676a5b0457fa8027b563aecb9a4","affectsGlobalScope":true},{"version":"4c49cc5572d80ef350f929108b067de4c4b1999a973e2e4bcfe930ae982db608","signature":"29133ef9e5680a6ec1b7b580e4233d15c63ab1cb95bb52aeede5410cdb6b8eb2"},{"version":"eadfc6ff785ba5ada489d5d5d4a069dc197df0301b889ab80b5a9dbcde296fe1","signature":"a9d7c462b1c33a8607b393473faf17427c9470eaa228fcd92dfd2c813df9d390"},{"version":"7fa8ab21c2bb00ee455d14225819d7500ff0af2a32385514346f54c5d4b35cf0","signature":"91fee60e7136d3e7a986d33f5a9b281a9ca120615ece0d58cc823af2a640bd03"},{"version":"e999f73e9109ef7f47afd0911ae1774810ea3b71735368578c6909db721da024","signature":"6660fedad551695604e38684d324129da4c3c6872b220ae7aa51f7e5acf0dd8d"},{"version":"bbed6ec58ac8b2b0152f382dfb2a16fd6ff62e2f1ced0f7d51dfe63280476551","signature":"b790e6cd12a86356afff831d3cd8942892277cceedb9d58b6f68595232306aef"},{"version":"45d038aaf64065421a14b469c3d57b4b83d6d53aa5bce65ebd45d096f4be620f","signature":"0b1f072d4ccf0c8aede96d102c00ab99181d9ebf23d1c0328370aff6d0c9df1a"},{"version":"2eb961423bb717b36ae6c89167574dc0a36a7469bd999bd088c854c11f481108","signature":"7e7d62fa024ea32b3e9bb2f0e97e200654e52b6a01513d06489d876ee0064c2c"},{"version":"d3fc1a478c7ee31a2c0900394e6531c6b0df5aa9395bdc601c83697a0c78b0f5","signature":"4ecc1ccb0bb5e43a48a6bae3314e125ca4a043424d2729982a71cdb943a66156"},"587f13f1e8157bd8cec0adda0de4ef558bb8573daa9d518d1e2af38e87ecc91f","a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a",{"version":"bce910d9164785c9f0d4dcea4be359f5f92130c7c7833dea6138ab1db310a1f9","affectsGlobalScope":true},"7a435e0c814f58f23e9a0979045ec0ef5909aac95a70986e8bcce30c27dff228",{"version":"c81c51f43e343b6d89114b17341fb9d381c4ccbb25e0ee77532376052c801ba7","affectsGlobalScope":true},"db71be322f07f769200108aa19b79a75dd19a187c9dca2a30c4537b233aa2863","57135ce61976a8b1dadd01bb412406d1805b90db6e8ecb726d0d78e0b5f76050",{"version":"49479e21a040c0177d1b1bc05a124c0383df7a08a0726ad4d9457619642e875a","affectsGlobalScope":true},"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","f302f3a47d7758f67f2afc753b9375d6504dde05d2e6ecdb1df50abbb131fc89","3690133deae19c8127c5505fcb67b04bdc9eb053796008538a9b9abbb70d85aa","5b1c0a23f464f894e7c2b2b6c56df7b9afa60ed48c5345f8618d389a636b2108","be2b092f2765222757c6441b86c53a5ea8dfed47bbc43eab4c5fe37942c866b3","8e6b05abc98adba15e1ac78e137c64576c74002e301d682e66feb77a23907ab8","1ca735bb3d407b2af4fbee7665f3a0a83be52168c728cc209755060ba7ed67bd",{"version":"6b526a5ec4a401ca7c26cfe6a48e641d8f30af76673bad3b06a1b4504594a960","affectsGlobalScope":true},{"version":"b85c02e14ecb2a873dad5a1de72319b265160ba48f1b83661aeb3bba1366c1bc","affectsGlobalScope":true},"7a2ba0c9af860ac3e77b35ed01fd96d15986f17aa22fe40f188ae556fb1070df","fc3764040518a1008dd04bdc80964591b566b896283e00df85c95851c1f46237","55709608060f77965c270ac10ac646286589f1bd1cb174fff1778a2dd9a7ef31","790623a47c5eda62910098884ecb154dc0e5f3a23fc36c1bfb3b5b9ed44e2c2d","42b40e40f2a358cda332456214fad311e1806a6abf3cebaaac72496e07556642","354612fe1d49ecc9551ea3a27d94eef2887b64ef4a71f72ca444efe0f2f0ba80",{"version":"ac0c77cd7db52b3c278bdd1452ce754014835493d05b84535f46854fdc2063b2","affectsGlobalScope":true},"b9f36877501f2ce0e276e993c93cd2cf325e78d0409ec4612b1eb9d6a537e60b","5e2b91328a540a0933ab5c2203f4358918e6f0fe7505d22840a891a6117735f1","3abc3512fa04aa0230f59ea1019311fd8667bd935d28306311dccc8b17e79d5d",{"version":"14a50dafe3f45713f7f27cb6320dff07c6ac31678f07959c2134260061bf91ff","affectsGlobalScope":true},{"version":"19da7150ca062323b1db6311a6ef058c9b0a39cc64d836b5e9b75d301869653b","affectsGlobalScope":true},"1349077576abb41f0e9c78ec30762ff75b710208aff77f5fdcc6a8c8ce6289dd","e2ce82603102b5c0563f59fb40314cc1ff95a4d521a66ad14146e130ea80d89c","a3e0395220255a350aa9c6d56f882bfcb5b85c19fddf5419ec822cf22246a26d","c27b01e8ddff5cd280711af5e13aecd9a3228d1c256ea797dd64f8fdec5f7df5","898840e876dfd21843db9f2aa6ae38ba2eab550eb780ff62b894b9fbfebfae6b","0cab4d7d4edc40cd3af9eea7c3ed6d1016910c0954c49c4297e479bf3822a625","1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","785e5be57d4f20f290a20e7b0c6263f6c57fd6e51283050756cef07d6d651c68","44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","164deb2409ac5f4da3cd139dbcee7f7d66753d90363a4d7e2db8d8874f272270",{"version":"ffc62d73b4fa10ca8c59f8802df88efefe447025730a24ee977b60adedc5bf37","affectsGlobalScope":true},{"version":"ab294c4b7279318ee2a8fdf681305457ecc05970c94108d304933f18823eeac1","affectsGlobalScope":true},"ad08154d9602429522cac965a715fde27d421d69b24756c5d291877dda75353e","5bc85813bfcb6907cc3a960fec8734a29d7884e0e372515147720c5991b8bc22","812b25f798033c202baedf386a1ccc41f9191b122f089bffd10fdccce99fba11","993325544790073f77e945bee046d53988c0bc3ac5695c9cf8098166feb82661",{"version":"75dd741ca6a6c8d2437a6ca8349b64b816421dbf9fe82dd026afaba965576962","affectsGlobalScope":true},{"version":"0e08c360c9b5961ecb0537b703e253842b3ded53151ee07024148219b61a8baf","affectsGlobalScope":true},"2ce2210032ccaff7710e2abf6a722e62c54960458e73e356b6a365c93ab6ca66","92db194ef7d208d5e4b6242a3434573fd142a621ff996d84cc9dbba3553277d0","16a3080e885ed52d4017c902227a8d0d8daf723d062bec9e45627c6fdcd6699b",{"version":"0bd9543cd8fc0959c76fb8f4f5a26626c2ed62ef4be98fd857bce268066db0a2","affectsGlobalScope":true},"1ca6858a0cbcd74d7db72d7b14c5360a928d1d16748a55ecfa6bfaff8b83071b",{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true},"ebf3434b09c527078aa74139ff367fffa64fea32a01d6c06fb0a69b0ecadf43e","01f7828047b5c6703d3c601473618b448f5506a88fcac852638b0715c3abf4eb",{"version":"c3bc5d095c3c22fd20b5a6550b9c9a6d56c3ffbb87ef057ccce7764b6bed4428","affectsGlobalScope":true},{"version":"63e2182615c513e89bb8a3e749d08f7c379e86490fcdbf6d35f2c14b3507a6e8","affectsGlobalScope":true},"6d829824ead8999f87b6df21200df3c6150391b894b4e80662caa462bd48d073","96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","8841e2aa774b89bd23302dede20663306dc1b9902431ac64b24be8b8d0e3f649","209e814e8e71aec74f69686a9506dd7610b97ab59dcee9446266446f72a76d05",{"version":"3f6d6465811321abc30a1e5f667feed63e5b3917b3d6c8d6645daf96c75f97ba","affectsGlobalScope":true},"6fa0008bf91a4cc9c8963bace4bba0bd6865cbfa29c3e3ccc461155660fb113a","916be7d770b0ae0406be9486ac12eb9825f21514961dd050594c4b250617d5a8","a73a445c1e0a6d0f8b48e8eb22dc9d647896783a7f8991cbbc31c0d94bf1f5a2","3dce33e7eb25594863b8e615f14a45ab98190d85953436750644212d8a18c066","bc81aff061c53a7140270555f4b22da4ecfe8601e8027cf5aa175fbdc7927c31"],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationDir":"../../lib/types","declarationMap":true,"esModuleInterop":true,"module":99,"noEmitOnError":true,"outDir":"../../lib/esm","rootDir":"../../../../target/types","skipLibCheck":true,"sourceMap":true,"strict":false,"stripInternal":true,"target":99},"fileIdsList":[[97,104],[97,106],[97],[70,97,104],[51,97],[54,97],[55,60,88,97],[56,67,68,75,85,96,97],[56,57,67,75,97],[58,97],[59,60,68,76,97],[60,85,93,97],[61,63,67,75,97],[62,97],[63,64,97],[67,97],[65,67,97],[67,68,69,85,96,97],[67,68,69,82,85,88,97],[97,101],[63,67,70,75,85,96,97],[67,68,70,71,75,85,93,96,97],[70,72,85,93,96,97],[51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103],[67,73,97],[74,96,97],[63,67,75,85,97],[76,97],[77,97],[54,78,97],[79,95,97,101],[80,97],[81,97],[67,82,83,97],[82,84,97,99],[55,67,85,86,87,88,97],[55,85,87,97],[85,86,97],[88,97],[89,97],[85,97],[67,91,92,97],[91,92,97],[60,75,85,93,97],[94,97],[75,95,97],[55,70,81,96,97],[60,97],[85,97,98],[97,99],[97,100],[55,60,67,69,78,85,96,97,99,101],[85,97,102],[67,70,72,75,85,93,96,97,102,104]],"referencedMap":[[105,1],[107,2],[106,3],[108,4],[109,3],[110,3],[111,3],[112,3],[51,5],[52,5],[54,6],[55,7],[56,8],[57,9],[58,10],[59,11],[60,12],[61,13],[62,14],[63,15],[64,15],[66,16],[65,17],[67,16],[68,18],[69,19],[53,20],[103,3],[70,21],[71,22],[72,23],[104,24],[73,25],[74,26],[75,27],[76,28],[77,29],[78,30],[79,31],[80,32],[81,33],[82,34],[83,34],[84,35],[85,36],[87,37],[86,38],[88,39],[89,40],[90,41],[91,42],[92,43],[93,44],[94,45],[95,46],[96,47],[97,48],[98,49],[99,50],[100,51],[101,52],[102,53],[113,3],[114,3],[115,1],[116,1],[117,54],[9,3],[8,3],[2,3],[10,3],[11,3],[12,3],[13,3],[14,3],[15,3],[16,3],[17,3],[3,3],[4,3],[21,3],[18,3],[19,3],[20,3],[22,3],[23,3],[24,3],[5,3],[25,3],[26,3],[27,3],[28,3],[6,3],[32,3],[29,3],[30,3],[31,3],[33,3],[7,3],[34,3],[39,3],[40,3],[35,3],[36,3],[37,3],[38,3],[41,3],[1,3],[42,3],[43,3],[44,3],[45,3],[46,3],[47,3],[48,3],[49,3],[50,3]],"exportedModulesMap":[[105,1],[107,2],[106,3],[108,4],[109,3],[110,3],[111,3],[112,3],[51,5],[52,5],[54,6],[55,7],[56,8],[57,9],[58,10],[59,11],[60,12],[61,13],[62,14],[63,15],[64,15],[66,16],[65,17],[67,16],[68,18],[69,19],[53,20],[103,3],[70,21],[71,22],[72,23],[104,24],[73,25],[74,26],[75,27],[76,28],[77,29],[78,30],[79,31],[80,32],[81,33],[82,34],[83,34],[84,35],[85,36],[87,37],[86,38],[88,39],[89,40],[90,41],[91,42],[92,43],[93,44],[94,45],[95,46],[96,47],[97,48],[98,49],[99,50],[100,51],[101,52],[102,53],[113,3],[114,3],[115,1],[116,1],[117,54],[9,3],[8,3],[2,3],[10,3],[11,3],[12,3],[13,3],[14,3],[15,3],[16,3],[17,3],[3,3],[4,3],[21,3],[18,3],[19,3],[20,3],[22,3],[23,3],[24,3],[5,3],[25,3],[26,3],[27,3],[28,3],[6,3],[32,3],[29,3],[30,3],[31,3],[33,3],[7,3],[34,3],[39,3],[40,3],[35,3],[36,3],[37,3],[38,3],[41,3],[1,3],[42,3]],"semanticDiagnosticsPerFile":[105,107,106,108,109,110,111,112,51,52,54,55,56,57,58,59,60,61,62,63,64,66,65,67,68,69,53,103,70,71,72,104,73,74,75,76,77,78,79,80,81,82,83,84,85,87,86,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,113,114,115,116,117,9,8,2,10,11,12,13,14,15,16,17,3,4,21,18,19,20,22,23,24,5,25,26,27,28,6,32,29,30,31,33,7,34,39,40,35,36,37,38,41,1,42,43,44,45,46,47,48,49,50],"latestChangedDtsFile":"../../lib/types/vote_hook_interface.d.ts"},"version":"4.9.5"} \ No newline at end of file diff --git a/packages/nft-proxy-sdk/.gitignore b/packages/nft-proxy-sdk/.gitignore new file mode 100644 index 0000000..bd592bd --- /dev/null +++ b/packages/nft-proxy-sdk/.gitignore @@ -0,0 +1,5 @@ +npm-debug.log +dist/ +tmp/ +./node_modules +lib \ No newline at end of file diff --git a/packages/nft-proxy-sdk/CHANGELOG.md b/packages/nft-proxy-sdk/CHANGELOG.md new file mode 100644 index 0000000..2f3c931 --- /dev/null +++ b/packages/nft-proxy-sdk/CHANGELOG.md @@ -0,0 +1,24 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/nft-proxy-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/nft-proxy-sdk + + + + + +## [0.0.9](https://github.com/helium/modular-governance/compare/v0.0.8...v0.0.9) (2023-11-14) + +**Note:** Version bump only for package @helium/nft-proxy-sdk diff --git a/packages/nft-proxy-sdk/package.json b/packages/nft-proxy-sdk/package.json new file mode 100644 index 0000000..519a29b --- /dev/null +++ b/packages/nft-proxy-sdk/package.json @@ -0,0 +1,47 @@ +{ + "name": "@helium/nft-proxy-sdk", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "license": "Apache-2.0", + "version": "0.0.13", + "description": "Interface to the nft proxy smart contract", + "repository": { + "type": "git", + "url": "https://github.com/helium/modular-governance" + }, + "main": "./lib/cjs/index.js", + "module": "./lib/esm/src/index.js", + "types": "./lib/types/src/index.d.ts", + "sideEffects": false, + "files": [ + "lib" + ], + "exports": { + "import": "./lib/esm/src/index.js", + "require": "./lib/cjs/index.js", + "types": "./lib/types/src/index.d.ts" + }, + "scripts": { + "format": "prettier --write \"src/**/*.{ts,tsx}\"", + "precommit": "npx git-format-staged -f 'prettier --ignore-unknown --stdin --stdin-filepath \"{}\"' .", + "clean": "npx shx mkdir -p lib && npx shx rm -rf lib", + "package": "npx shx mkdir -p lib/cjs lib/esm", + "prebuild": "npm run clean && npm run package" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.28.0", + "@helium/anchor-resolvers": "^0.2.17", + "@helium/modular-governance-idls": "^0.0.10", + "@solana/spl-token": "^0.3.8" + }, + "devDependencies": { + "git-format-staged": "^2.1.3", + "ts-loader": "^9.2.3", + "typescript": "^4.3.5", + "yarn": "^1.22.18" + }, + "keywords": [], + "author": "" +} diff --git a/packages/nft-proxy-sdk/src/constants.ts b/packages/nft-proxy-sdk/src/constants.ts new file mode 100644 index 0000000..8cad7e6 --- /dev/null +++ b/packages/nft-proxy-sdk/src/constants.ts @@ -0,0 +1,3 @@ +import { PublicKey } from "@solana/web3.js"; + +export const PROGRAM_ID = new PublicKey("nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p"); diff --git a/packages/nft-proxy-sdk/src/index.ts b/packages/nft-proxy-sdk/src/index.ts new file mode 100644 index 0000000..890f815 --- /dev/null +++ b/packages/nft-proxy-sdk/src/index.ts @@ -0,0 +1,29 @@ +import { NftProxy } from "@helium/modular-governance-idls/lib/types/nft_proxy"; +import { AnchorProvider, Idl, Program } from "@coral-xyz/anchor"; +import { PublicKey } from "@solana/web3.js"; +import { PROGRAM_ID } from "./constants"; +import { nftProxyResolvers } from "./resolvers"; + +export * from "./constants"; +export * from "./pdas"; +export * from "./resolvers"; + +export async function init( + provider: AnchorProvider, + programId: PublicKey = PROGRAM_ID, + idl?: Idl | null +): Promise> { + if (!idl) { + idl = await Program.fetchIdl(programId, provider); + } + + const tokenVoter = new Program( + idl as NftProxy, + programId, + provider, + undefined, + () => nftProxyResolvers + ) as Program; + + return tokenVoter; +} diff --git a/packages/nft-proxy-sdk/src/pdas.ts b/packages/nft-proxy-sdk/src/pdas.ts new file mode 100644 index 0000000..86630d7 --- /dev/null +++ b/packages/nft-proxy-sdk/src/pdas.ts @@ -0,0 +1,29 @@ +import { PublicKey } from "@solana/web3.js"; +import { PROGRAM_ID } from "./constants"; + +export function proxyConfigKey( + name: string, + programId: PublicKey = PROGRAM_ID +): [PublicKey, number] { + return PublicKey.findProgramAddressSync( + [Buffer.from("proxy_config", "utf-8"), Buffer.from(name, "utf8")], + programId + ); +} + +export function proxyAssignmentKey( + proxyConfig: PublicKey, + mint: PublicKey, + voter: PublicKey, + programId: PublicKey = PROGRAM_ID +): [PublicKey, number] { + return PublicKey.findProgramAddressSync( + [ + Buffer.from("proxy_assignment", "utf-8"), + proxyConfig.toBuffer(), + mint.toBuffer(), + voter.toBuffer(), + ], + programId + ); +} diff --git a/packages/nft-proxy-sdk/src/resolvers.ts b/packages/nft-proxy-sdk/src/resolvers.ts new file mode 100644 index 0000000..032f717 --- /dev/null +++ b/packages/nft-proxy-sdk/src/resolvers.ts @@ -0,0 +1,40 @@ +import * as anchor from "@coral-xyz/anchor"; +import { combineResolvers, resolveIndividual } from "@helium/anchor-resolvers"; +import { PublicKey } from "@solana/web3.js"; +import { getAccount } from "@solana/spl-token"; + +export const nftProxyResolvers: anchor.CustomAccountResolver = + combineResolvers( + resolveIndividual( + async ({ path, provider, accounts, idlIx, programId }) => { + if ( + path[path.length - 1] === "tokenAccount" && + accounts.asset && + accounts.tokenAccount !== null + ) { + return ( + await provider.connection.getTokenLargestAccounts( + accounts.asset as PublicKey + ) + ).value[0].address; + } else if ( + path[path.length - 1] === "voter" && + (idlIx.name === "assignProxyV0" || + idlIx.name === "unassignProxyV0") && + accounts.tokenAccount && + accounts.approver + ) { + const ta = await getAccount( + provider.connection, + accounts.tokenAccount as PublicKey + ); + // Primary proxy, owner is default pubkey + if (ta.owner.equals(accounts.approver as PublicKey)) { + return PublicKey.default; + } + + return accounts.approver as PublicKey; + } + } + ) + ); diff --git a/packages/nft-proxy-sdk/tsconfig.cjs.json b/packages/nft-proxy-sdk/tsconfig.cjs.json new file mode 100644 index 0000000..5445b99 --- /dev/null +++ b/packages/nft-proxy-sdk/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.cjs.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/cjs" + } +} diff --git a/packages/nft-proxy-sdk/tsconfig.esm.json b/packages/nft-proxy-sdk/tsconfig.esm.json new file mode 100644 index 0000000..f2835b2 --- /dev/null +++ b/packages/nft-proxy-sdk/tsconfig.esm.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.esm.json", + "include": ["src"], + "compilerOptions": { + "outDir": "lib/esm", + "declarationDir": "lib/types" + } +} \ No newline at end of file diff --git a/packages/nft-proxy-sdk/tsconfig.json b/packages/nft-proxy-sdk/tsconfig.json new file mode 100644 index 0000000..c74ff59 --- /dev/null +++ b/packages/nft-proxy-sdk/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.root.json", + "references": [ + { + "path": "../modular-governance-idls" + }, + { + "path": "./tsconfig.cjs.json" + }, + { + "path": "./tsconfig.esm.json" + } + ] +} diff --git a/packages/nft-voter-sdk/CHANGELOG.md b/packages/nft-voter-sdk/CHANGELOG.md index 4245554..fe17e79 100644 --- a/packages/nft-voter-sdk/CHANGELOG.md +++ b/packages/nft-voter-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/nft-voter-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/nft-voter-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/nft-voter-sdk diff --git a/packages/nft-voter-sdk/package.json b/packages/nft-voter-sdk/package.json index 12ac8e6..23564a0 100644 --- a/packages/nft-voter-sdk/package.json +++ b/packages/nft-voter-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the nft voter smart contract", "repository": { "type": "git", @@ -33,7 +33,8 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11", + "@helium/modular-governance-idls": "^0.0.13", + "@helium/nft-proxy-sdk": "^0.0.13", "@solana/spl-token": "^0.3.8" }, "devDependencies": { diff --git a/packages/nft-voter-sdk/src/resolvers.ts b/packages/nft-voter-sdk/src/resolvers.ts index 1982c18..8f30d8a 100644 --- a/packages/nft-voter-sdk/src/resolvers.ts +++ b/packages/nft-voter-sdk/src/resolvers.ts @@ -2,6 +2,8 @@ import { ataResolver, combineResolvers, resolveIndividual } from "@helium/anchor import { PROGRAM_ID } from "./constants"; import * as anchor from "@coral-xyz/anchor"; import { PublicKey } from "@solana/web3.js"; +import { proxyAssignmentKey, nftProxyResolvers } from "@helium/nft-proxy-sdk"; +import { init } from "."; const METADATA_PROGRAM_ID = new PublicKey( "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" @@ -18,6 +20,7 @@ export const nftVoterProgramResolver: anchor.CustomAccountResolver = export const nftVoterResolvers: anchor.CustomAccountResolver = combineResolvers( nftVoterProgramResolver, + nftProxyResolvers, resolveIndividual(async ({ path, provider, accounts, programId }) => { if (path[path.length - 1] == "proposalProgram" && accounts.proposal) { const acct = await provider.connection.getAccountInfo( @@ -33,6 +36,14 @@ export const nftVoterResolvers: anchor.CustomAccountResolver = combineResol ], METADATA_PROGRAM_ID )[0]; + } else if (path[path.length - 1] == "proxy_assignment" && accounts.nftVoter && accounts.owner && accounts.mint) { + const program = await init(provider as any, programId) + const nftVoter = await program.account.nftVoterV0.fetch(accounts.nftVoter as PublicKey) + return proxyAssignmentKey( + nftVoter.proxyConfig, + accounts.mint as PublicKey, + accounts.owner as PublicKey, + )[0] } }), ataResolver({ diff --git a/packages/nft-voter-sdk/tsconfig.json b/packages/nft-voter-sdk/tsconfig.json index c74ff59..3c002bc 100644 --- a/packages/nft-voter-sdk/tsconfig.json +++ b/packages/nft-voter-sdk/tsconfig.json @@ -4,6 +4,9 @@ { "path": "../modular-governance-idls" }, + { + "path": "../nft-proxy-sdk" + }, { "path": "./tsconfig.cjs.json" }, diff --git a/packages/organization-sdk/CHANGELOG.md b/packages/organization-sdk/CHANGELOG.md index f118a42..df13737 100644 --- a/packages/organization-sdk/CHANGELOG.md +++ b/packages/organization-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/organization-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/organization-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/organization-sdk diff --git a/packages/organization-sdk/package.json b/packages/organization-sdk/package.json index e6f1ff1..e434350 100644 --- a/packages/organization-sdk/package.json +++ b/packages/organization-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the organization smart contract", "repository": { "type": "git", @@ -33,8 +33,8 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11", - "@helium/proposal-sdk": "^0.0.11" + "@helium/modular-governance-idls": "^0.0.13", + "@helium/proposal-sdk": "^0.0.13" }, "devDependencies": { "git-format-staged": "^2.1.3", diff --git a/packages/organization-wallet-sdk/CHANGELOG.md b/packages/organization-wallet-sdk/CHANGELOG.md index be81352..f40b2c0 100644 --- a/packages/organization-wallet-sdk/CHANGELOG.md +++ b/packages/organization-wallet-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/organization-wallet-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/organization-wallet-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/organization-wallet-sdk diff --git a/packages/organization-wallet-sdk/package.json b/packages/organization-wallet-sdk/package.json index ca5d3da..51e87c8 100644 --- a/packages/organization-wallet-sdk/package.json +++ b/packages/organization-wallet-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the organization wallet smart contract", "repository": { "type": "git", @@ -33,8 +33,8 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11", - "@helium/proposal-sdk": "^0.0.11" + "@helium/modular-governance-idls": "^0.0.13", + "@helium/proposal-sdk": "^0.0.13" }, "devDependencies": { "git-format-staged": "^2.1.3", diff --git a/packages/proposal-sdk/CHANGELOG.md b/packages/proposal-sdk/CHANGELOG.md index 6ea2649..6fee964 100644 --- a/packages/proposal-sdk/CHANGELOG.md +++ b/packages/proposal-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/proposal-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/proposal-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/proposal-sdk diff --git a/packages/proposal-sdk/package.json b/packages/proposal-sdk/package.json index e4c599d..f8cf5b0 100644 --- a/packages/proposal-sdk/package.json +++ b/packages/proposal-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the proposal smart contract", "repository": { "type": "git", @@ -33,7 +33,7 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11" + "@helium/modular-governance-idls": "^0.0.13" }, "devDependencies": { "git-format-staged": "^2.1.3", diff --git a/packages/state-controller-sdk/CHANGELOG.md b/packages/state-controller-sdk/CHANGELOG.md index a5c04cd..e98ce91 100644 --- a/packages/state-controller-sdk/CHANGELOG.md +++ b/packages/state-controller-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/state-controller-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/state-controller-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/state-controller-sdk diff --git a/packages/state-controller-sdk/package.json b/packages/state-controller-sdk/package.json index c62f464..aef9dc4 100644 --- a/packages/state-controller-sdk/package.json +++ b/packages/state-controller-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the state controller smart contract", "repository": { "type": "git", @@ -33,7 +33,7 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11" + "@helium/modular-governance-idls": "^0.0.13" }, "devDependencies": { "git-format-staged": "^2.1.3", diff --git a/packages/token-voter-sdk/CHANGELOG.md b/packages/token-voter-sdk/CHANGELOG.md index 7b358f7..d3ed73a 100644 --- a/packages/token-voter-sdk/CHANGELOG.md +++ b/packages/token-voter-sdk/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.0.13](https://github.com/helium/modular-governance/compare/v0.0.12...v0.0.13) (2024-09-06) + +**Note:** Version bump only for package @helium/token-voter-sdk + + + + + +## [0.0.12](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.12) (2024-08-12) + +**Note:** Version bump only for package @helium/token-voter-sdk + + + + + ## [0.0.11](https://github.com/helium/modular-governance/compare/v0.0.10...v0.0.11) (2024-06-17) **Note:** Version bump only for package @helium/token-voter-sdk diff --git a/packages/token-voter-sdk/package.json b/packages/token-voter-sdk/package.json index 9949404..419cbef 100644 --- a/packages/token-voter-sdk/package.json +++ b/packages/token-voter-sdk/package.json @@ -5,7 +5,7 @@ "registry": "https://registry.npmjs.org/" }, "license": "Apache-2.0", - "version": "0.0.11", + "version": "0.0.13", "description": "Interface to the token voter smart contract", "repository": { "type": "git", @@ -33,7 +33,7 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.0", "@helium/anchor-resolvers": "^0.5.0", - "@helium/modular-governance-idls": "^0.0.11", + "@helium/modular-governance-idls": "^0.0.13", "@solana/spl-token": "^0.3.8" }, "devDependencies": { diff --git a/programs/nft_proxy/Cargo.toml b/programs/nft_proxy/Cargo.toml new file mode 100644 index 0000000..a0c2dca --- /dev/null +++ b/programs/nft_proxy/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "nft-proxy" +version = "0.0.1" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "nft_proxy" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] +devnet = [] + +[dependencies] +anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["init-if-needed"] } +anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["token"] } +bytemuck = "1.14.0" +time = "0.3.36" + diff --git a/programs/nft_proxy/Xargo.toml b/programs/nft_proxy/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/programs/nft_proxy/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/programs/nft_proxy/src/error.rs b/programs/nft_proxy/src/error.rs new file mode 100644 index 0000000..b03917f --- /dev/null +++ b/programs/nft_proxy/src/error.rs @@ -0,0 +1,21 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum ErrorCode { + #[msg("The specified expiration time exceeds the maximum allowed for this proxy configuration")] + ExpirationExceedsMax, + #[msg("The specified expiration time exceeds the maximum allowed for this season")] + ExpirationExceedsSeasonMax, + #[msg("The specified expiration time has already passed")] + ExpirationPast, + #[msg("The specified expiration time exceeds the expiration of the existing delegatio")] + ExpirationExceedsPreceedingProxy, + #[msg("The seasons are not sorted")] + SeasonsNotSorted, + #[msg("The data size increase is not valid")] + InvalidDataIncrease, + #[msg("The expiration time is invalid")] + ExpirationTimeInvalid, + #[msg("The specified expiration time has not passed")] + ExpirationNotPast, +} diff --git a/programs/nft_proxy/src/instructions/assign_proxy_v0.rs b/programs/nft_proxy/src/instructions/assign_proxy_v0.rs new file mode 100644 index 0000000..92a153c --- /dev/null +++ b/programs/nft_proxy/src/instructions/assign_proxy_v0.rs @@ -0,0 +1,156 @@ +use crate::error::ErrorCode; +use anchor_lang::prelude::*; +use anchor_spl::token::{Mint, TokenAccount}; + +use crate::state::{ProxyAssignmentV0, ProxyConfigV0}; + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct AssignProxyArgsV0 { + pub expiration_time: i64, +} + +#[derive(Accounts)] +pub struct AssignProxyV0<'info> { + /// CHECK: Paying the rent for proxys + #[account(mut)] + pub payer: Signer<'info>, + #[account( + // Either match the current proxy, or if it is being initialized we will set it later + // This works because asset can only be Pubkey default when this is a new account + constraint = current_proxy_assignment.asset == asset.key() || current_proxy_assignment.asset == Pubkey::default(), + constraint = asset.supply == 1, + constraint = asset.decimals == 0 + )] + pub asset: Box>, + #[account( + constraint = current_proxy_assignment.voter == approver.key() || match token_account.as_ref() { + Some(token_account) => token_account.owner == approver.key(), + None => false + } + )] + pub approver: Signer<'info>, + /// CHECK: This is the voter of the current proxy. May be the same as approver, + /// or in the case of a primary proxy (first in the line), Pubkey::default + #[account( + constraint = (current_proxy_assignment.index != 0 && current_proxy_assignment.voter == voter.key()) + || (current_proxy_assignment.index == 0 && voter.key() == Pubkey::default()) + )] + pub voter: AccountInfo<'info>, + #[account( + constraint = token_account.mint == asset.key(), + constraint = token_account.amount == 1, + )] + pub token_account: Option>, + pub proxy_config: Box>, + #[account( + // We init if needed here because in the case of the original + // position owner delegating, this wont yet exist. + init_if_needed, + payer = payer, + // Note that voter part of the PDA key for the first proxy is Pubkey::default. This ensures + // that the holder can freely transfer the NFT without an disruption to the line. There is + // exactly 1 primary proxy per NFT. + seeds = [b"proxy_assignment", proxy_config.key().as_ref(), asset.key().as_ref(), voter.key().as_ref()], + space = ProxyAssignmentV0::INIT_SPACE + 60, + bump, + // You can only proxy when it is not currently proxied to someone else. + // Recall the proxy before re-delegating if necessary. + constraint = current_proxy_assignment.next_voter == Pubkey::default() || current_proxy_assignment.next_voter == recipient.key() + )] + pub current_proxy_assignment: Box>, + /// CHECK: The wallet being delegated to + #[account( + // No creating loops! Cannot delegate back to the original position owner + // This is just best effort, loops don't break the system. Someone could, theoretically, + // delegate to someone and then transfer that NFT to them. + constraint = match token_account.as_ref() { + Some(token_account) => recipient.key() != token_account.owner, + None => true + } + )] + pub recipient: AccountInfo<'info>, + #[account( + init_if_needed, + payer = payer, + seeds = [b"proxy_assignment", proxy_config.key().as_ref(), asset.key().as_ref(), recipient.key().as_ref()], + space = ProxyAssignmentV0::INIT_SPACE + 60, + bump, + )] + pub next_proxy_assignment: Box>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context, args: AssignProxyArgsV0) -> Result<()> { + require_gt!(args.expiration_time, 0, ErrorCode::ExpirationTimeInvalid); + let curr_ts = Clock::get().unwrap().unix_timestamp; + let total_proxy_time = args + .expiration_time + .checked_sub(curr_ts) + .ok_or_else(|| error!(ErrorCode::ExpirationPast))?; + + require_gt!( + ctx.accounts.proxy_config.max_proxy_time, + total_proxy_time, + ErrorCode::ExpirationExceedsMax + ); + require_gt!(total_proxy_time, 0, ErrorCode::ExpirationTimeInvalid); + + if let Some(current_season) = ctx.accounts.proxy_config.get_current_season(curr_ts) { + require_gt!( + current_season.end, + args.expiration_time, + ErrorCode::ExpirationExceedsSeasonMax + ); + } + + ctx + .accounts + .current_proxy_assignment + .set_inner(ProxyAssignmentV0 { + index: ctx.accounts.current_proxy_assignment.index, + asset: ctx.accounts.asset.key(), + proxy_config: ctx.accounts.proxy_config.key(), + voter: ctx.accounts.voter.key(), + next_voter: ctx.accounts.recipient.key(), + rent_refund: if ctx.accounts.current_proxy_assignment.rent_refund == Pubkey::default() { + ctx.accounts.payer.key() + } else { + ctx.accounts.current_proxy_assignment.rent_refund + }, + bump_seed: ctx.bumps["current_proxy_assignment"], + // If this is a recursive proxy (ie not the initial proxy), use the existing expiration time + expiration_time: if ctx.accounts.current_proxy_assignment.expiration_time > 0 + && ctx.accounts.current_proxy_assignment.voter != Pubkey::default() + { + ctx.accounts.current_proxy_assignment.expiration_time + } else { + args.expiration_time + }, + }); + + require_gte!( + ctx.accounts.current_proxy_assignment.expiration_time, + args.expiration_time, + ErrorCode::ExpirationExceedsPreceedingProxy + ); + + ctx + .accounts + .next_proxy_assignment + .set_inner(ProxyAssignmentV0 { + index: ctx.accounts.current_proxy_assignment.index + 1, + asset: ctx.accounts.asset.key(), + proxy_config: ctx.accounts.proxy_config.key(), + voter: ctx.accounts.recipient.key(), + next_voter: Pubkey::default(), + rent_refund: if ctx.accounts.next_proxy_assignment.rent_refund == Pubkey::default() { + ctx.accounts.payer.key() + } else { + ctx.accounts.next_proxy_assignment.rent_refund + }, + bump_seed: ctx.bumps["next_proxy_assignment"], + expiration_time: args.expiration_time, + }); + + Ok(()) +} diff --git a/programs/nft_proxy/src/instructions/close_expired_proxy_v0.rs b/programs/nft_proxy/src/instructions/close_expired_proxy_v0.rs new file mode 100644 index 0000000..375943f --- /dev/null +++ b/programs/nft_proxy/src/instructions/close_expired_proxy_v0.rs @@ -0,0 +1,26 @@ +use crate::error::ErrorCode; +use anchor_lang::prelude::*; + +use crate::state::*; + +// Allow anyone to permissionlessly close expired proxies at 0 index and refund to users +#[derive(Accounts)] +pub struct CloseExpiredProxyV0<'info> { + /// CHECK: Receiving rent for closing + #[account(mut)] + pub rent_refund: AccountInfo<'info>, + #[account( + mut, + close = rent_refund, + has_one = rent_refund, + constraint = proxy_assignment.index == 0, + constraint = proxy_assignment.next_voter == Pubkey::default(), + constraint = proxy_assignment.expiration_time < Clock::get().unwrap().unix_timestamp @ ErrorCode::ExpirationNotPast, + )] + pub proxy_assignment: Box>, + pub system_program: Program<'info, System>, +} + +pub fn handler(_ctx: Context) -> Result<()> { + Ok(()) +} diff --git a/programs/nft_proxy/src/instructions/initialize_proxy_config_v0.rs b/programs/nft_proxy/src/instructions/initialize_proxy_config_v0.rs new file mode 100644 index 0000000..06946ca --- /dev/null +++ b/programs/nft_proxy/src/instructions/initialize_proxy_config_v0.rs @@ -0,0 +1,51 @@ +use crate::error::ErrorCode; +use crate::state::{ProxyConfigV0, SeasonV0}; +use anchor_lang::prelude::*; + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct InitializeProxyConfigArgsV0 { + pub name: String, + pub max_proxy_time: i64, + pub seasons: Vec, +} + +#[derive(Accounts)] +#[instruction(args: InitializeProxyConfigArgsV0)] +pub struct InitializeProxyConfigV0<'info> { + #[account(mut)] + pub payer: Signer<'info>, + /// CHECK: The authority of this config + pub authority: AccountInfo<'info>, + #[account( + init, + payer = payer, + space = 60 + std::mem::size_of::() + args.name.len() + args.seasons.len() * 16, + seeds = [b"proxy_config".as_ref(), args.name.as_bytes()], + bump + )] + pub proxy_config: Account<'info, ProxyConfigV0>, + pub system_program: Program<'info, System>, +} + +pub fn handler( + ctx: Context, + args: InitializeProxyConfigArgsV0, +) -> Result<()> { + if !args + .seasons + .iter() + .zip(args.seasons.iter().skip(1)) + .all(|(a, b)| a.start <= b.start && a.end <= b.end) + { + return Err(error!(ErrorCode::SeasonsNotSorted)); + } + + ctx.accounts.proxy_config.set_inner(ProxyConfigV0 { + authority: ctx.accounts.authority.key(), + name: args.name, + max_proxy_time: args.max_proxy_time, + seasons: args.seasons, + }); + + Ok(()) +} diff --git a/programs/nft_proxy/src/instructions/mod.rs b/programs/nft_proxy/src/instructions/mod.rs new file mode 100644 index 0000000..f9825e1 --- /dev/null +++ b/programs/nft_proxy/src/instructions/mod.rs @@ -0,0 +1,13 @@ +pub mod assign_proxy_v0; +pub mod close_expired_proxy_v0; +pub mod initialize_proxy_config_v0; +pub mod unassign_expired_proxy_v0; +pub mod unassign_proxy_v0; +pub mod update_proxy_config_v0; + +pub use assign_proxy_v0::*; +pub use close_expired_proxy_v0::*; +pub use initialize_proxy_config_v0::*; +pub use unassign_expired_proxy_v0::*; +pub use unassign_proxy_v0::*; +pub use update_proxy_config_v0::*; diff --git a/programs/nft_proxy/src/instructions/unassign_expired_proxy_v0.rs b/programs/nft_proxy/src/instructions/unassign_expired_proxy_v0.rs new file mode 100644 index 0000000..a85924f --- /dev/null +++ b/programs/nft_proxy/src/instructions/unassign_expired_proxy_v0.rs @@ -0,0 +1,34 @@ +use crate::error::ErrorCode; +use anchor_lang::prelude::*; + +use crate::state::*; + +// Allow anyone to permissionlessly close expired proxies and refund to users +#[derive(Accounts)] +pub struct UnassignExpiredProxyV0<'info> { + /// CHECK: Receiving rent for closing + #[account(mut)] + pub rent_refund: AccountInfo<'info>, + #[account( + mut, + constraint = prev_proxy_assignment.next_voter == proxy_assignment.voter, + constraint = prev_proxy_assignment.asset == proxy_assignment.asset, + )] + pub prev_proxy_assignment: Box>, + #[account( + mut, + close = rent_refund, + has_one = rent_refund, + constraint = proxy_assignment.index > prev_proxy_assignment.index, + constraint = proxy_assignment.next_voter == Pubkey::default(), + constraint = proxy_assignment.expiration_time < Clock::get().unwrap().unix_timestamp @ ErrorCode::ExpirationNotPast, + )] + pub proxy_assignment: Box>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context) -> Result<()> { + ctx.accounts.prev_proxy_assignment.next_voter = Pubkey::default(); + + Ok(()) +} diff --git a/programs/nft_proxy/src/instructions/unassign_proxy_v0.rs b/programs/nft_proxy/src/instructions/unassign_proxy_v0.rs new file mode 100644 index 0000000..b8ba38e --- /dev/null +++ b/programs/nft_proxy/src/instructions/unassign_proxy_v0.rs @@ -0,0 +1,69 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{Mint, TokenAccount}; + +use crate::state::{ProxyAssignmentV0, ProxyConfigV0}; + +// Anyone who helds a `ProxyV0` on this asset +// may undelegate it, so long as they have an earlier proxy index than or equal the position +// This means someone can also undelegate from themselves +#[derive(Accounts)] +pub struct UnassignProxyV0<'info> { + /// CHECK: Receiving rent for closing + #[account(mut)] + pub rent_refund: AccountInfo<'info>, + #[account( + constraint = asset.supply == 1, + constraint = asset.decimals == 0 + )] + pub asset: Box>, + #[account( + constraint = current_proxy_assignment.voter == approver.key() || match token_account.as_ref() { + Some(token_account) => token_account.owner == approver.key(), + None => false + } + )] + pub approver: Signer<'info>, + /// CHECK: This is the voter of the current proxy. May be the same as approver, + /// or in the case of a primary proxy (first in the line), Pubkey::default + #[account( + constraint = (current_proxy_assignment.index != 0 && current_proxy_assignment.voter == voter.key()) + || (current_proxy_assignment.index == 0 && voter.key() == Pubkey::default()) + )] + pub voter: AccountInfo<'info>, + #[account( + constraint = token_account.mint == asset.key(), + constraint = token_account.amount == 1, + )] + pub token_account: Option>, + #[account( + has_one = proxy_config, + has_one = voter, + has_one = asset, + )] + pub current_proxy_assignment: Box>, + #[account( + mut, + has_one = proxy_config, + constraint = prev_proxy_assignment.next_voter == proxy_assignment.voter, + constraint = prev_proxy_assignment.asset == current_proxy_assignment.asset, + )] + pub prev_proxy_assignment: Box>, + #[account( + mut, + close = rent_refund, + has_one = proxy_config, + has_one = rent_refund, + constraint = proxy_assignment.index >= current_proxy_assignment.index, + constraint = proxy_assignment.asset == current_proxy_assignment.asset, + constraint = proxy_assignment.next_voter == Pubkey::default(), + )] + pub proxy_assignment: Box>, + pub proxy_config: Box>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context) -> Result<()> { + ctx.accounts.prev_proxy_assignment.next_voter = Pubkey::default(); + + Ok(()) +} diff --git a/programs/nft_proxy/src/instructions/update_proxy_config_v0.rs b/programs/nft_proxy/src/instructions/update_proxy_config_v0.rs new file mode 100644 index 0000000..ee19795 --- /dev/null +++ b/programs/nft_proxy/src/instructions/update_proxy_config_v0.rs @@ -0,0 +1,51 @@ +use crate::error::ErrorCode; +use crate::resize_to_fit::resize_to_fit; +use crate::state::{ProxyConfigV0, SeasonV0}; +use anchor_lang::prelude::*; + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct UpdateProxyConfigArgsV0 { + pub max_proxy_time: Option, + pub seasons: Option>, +} + +#[derive(Accounts)] +#[instruction(args: UpdateProxyConfigArgsV0)] +pub struct UpdateProxyConfigV0<'info> { + #[account(mut)] + pub payer: Signer<'info>, + /// CHECK: The authority of this config + pub authority: AccountInfo<'info>, + #[account( + mut, + has_one = authority + )] + pub proxy_config: Account<'info, ProxyConfigV0>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context, args: UpdateProxyConfigArgsV0) -> Result<()> { + if let Some(seasons) = args.seasons { + if !seasons + .iter() + .zip(seasons.iter().skip(1)) + .all(|(a, b)| a.start <= b.start && a.end <= b.end) + { + return Err(error!(ErrorCode::SeasonsNotSorted)); + } + + ctx.accounts.proxy_config.seasons = seasons; + } + + if let Some(max_proxy_time) = args.max_proxy_time { + ctx.accounts.proxy_config.max_proxy_time = max_proxy_time; + } + + resize_to_fit( + &ctx.accounts.payer.to_account_info(), + &ctx.accounts.system_program.to_account_info(), + &ctx.accounts.proxy_config, + )?; + + Ok(()) +} diff --git a/programs/nft_proxy/src/lib.rs b/programs/nft_proxy/src/lib.rs new file mode 100644 index 0000000..f10bced --- /dev/null +++ b/programs/nft_proxy/src/lib.rs @@ -0,0 +1,45 @@ +use anchor_lang::prelude::*; + +declare_id!("nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p"); + +pub mod error; +pub mod instructions; +pub mod resize_to_fit; +pub mod state; + +pub use instructions::*; + +#[program] +pub mod nft_proxy { + use super::*; + + pub fn initialize_proxy_config_v0( + ctx: Context, + args: InitializeProxyConfigArgsV0, + ) -> Result<()> { + initialize_proxy_config_v0::handler(ctx, args) + } + + pub fn assign_proxy_v0(ctx: Context, args: AssignProxyArgsV0) -> Result<()> { + assign_proxy_v0::handler(ctx, args) + } + + pub fn unassign_proxy_v0(ctx: Context) -> Result<()> { + unassign_proxy_v0::handler(ctx) + } + + pub fn update_proxy_config_v0( + ctx: Context, + args: UpdateProxyConfigArgsV0, + ) -> Result<()> { + update_proxy_config_v0::handler(ctx, args) + } + + pub fn unassign_expired_proxy_v0(ctx: Context) -> Result<()> { + unassign_expired_proxy_v0::handler(ctx) + } + + pub fn close_expired_proxy_v0(ctx: Context) -> Result<()> { + close_expired_proxy_v0::handler(ctx) + } +} diff --git a/programs/nft_proxy/src/resize_to_fit.rs b/programs/nft_proxy/src/resize_to_fit.rs new file mode 100644 index 0000000..a4746be --- /dev/null +++ b/programs/nft_proxy/src/resize_to_fit.rs @@ -0,0 +1,54 @@ +use crate::error::ErrorCode; +use std::io::Write; + +use anchor_lang::{ + prelude::*, + solana_program::{entrypoint::MAX_PERMITTED_DATA_INCREASE, program::invoke, system_instruction}, +}; + +pub struct IgnoreWriter { + pub total: usize, +} + +impl Write for IgnoreWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.total += buf.len(); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +/// Resizes the account to the size of the struct +pub fn resize_to_fit<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone>( + payer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + account: &Account<'info, T>, +) -> Result<()> { + let rent = Rent::get()?; + let writer = &mut IgnoreWriter { total: 0 }; + account.try_serialize(writer)?; + let new_size = writer.total + 64; // Pad enough for two pubkeys so deserialize doesn't fail + let new_minimum_balance = rent.minimum_balance(new_size); + let lamports_diff = new_minimum_balance.saturating_sub(account.to_account_info().lamports()); + let old_size = account.to_account_info().data.borrow().len(); + + if new_size > old_size && (new_size - old_size) > MAX_PERMITTED_DATA_INCREASE { + return Err(error!(ErrorCode::InvalidDataIncrease)); + } + msg!("Resizing to {} with lamports {}", new_size, lamports_diff); + invoke( + &system_instruction::transfer(payer.key, &account.key(), lamports_diff), + &[ + payer.clone(), + account.to_account_info().clone(), + system_program.clone(), + ], + )?; + + account.to_account_info().realloc(new_size, false)?; + + Ok(()) +} diff --git a/programs/nft_proxy/src/state.rs b/programs/nft_proxy/src/state.rs new file mode 100644 index 0000000..c3e4903 --- /dev/null +++ b/programs/nft_proxy/src/state.rs @@ -0,0 +1,74 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(Default)] +pub struct ProxyConfigV0 { + pub authority: Pubkey, + pub name: String, + // Max time to delegate in seconds + pub max_proxy_time: i64, + // Optionally sync proxys to seasons, + // so that they all expire at pre-defined intervals. Creating an election cycle + pub seasons: Vec, +} + +// Seasons may overlap, the code will always take the latest `end` +// This allows you to have a season that starts before the previous season ends, +// allowing re-assignment before expiration. +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] +pub struct SeasonV0 { + pub start: i64, + pub end: i64, +} + +impl ProxyConfigV0 { + // Binary search for the timestamp closest to but after `unix_time` + pub fn get_current_season(&self, unix_time: i64) -> Option { + if self.seasons.is_empty() { + return None; + } + + let mut ans: Option = None; + let mut low: usize = 0; + let mut high: usize = self.seasons.len() - 1; + + while low <= high { + let middle = (high + low) / 2; + if let Some(current) = self.seasons.get(middle) { + // Move to the right side if target time is greater + if current.start <= unix_time { + ans = Some(current.clone()); + low = middle + 1; + } else { + if middle == 0 { + break; + } + high = middle - 1; + } + } else { + break; + } + } + + ans + } +} + +// Forms an on chain linked list of proxy voters +#[account] +#[derive(Default, InitSpace)] +pub struct ProxyAssignmentV0 { + pub voter: Pubkey, + pub proxy_config: Pubkey, + pub asset: Pubkey, + // Current index in the proxy chain. + pub index: u16, + // If this is the last in the line, Pubkey::default. + pub next_voter: Pubkey, + // The address of the account that paid for rent. Rent on closing + // proxys always goes to the key who originally paid for them. + pub rent_refund: Pubkey, + // Unix timestamp in seconds that this proxy expires + pub expiration_time: i64, + pub bump_seed: u8, +} diff --git a/programs/nft_voter/Cargo.toml b/programs/nft_voter/Cargo.toml index c217330..d24e162 100644 --- a/programs/nft_voter/Cargo.toml +++ b/programs/nft_voter/Cargo.toml @@ -15,8 +15,12 @@ no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] devnet = [] +serde-feature = ["serde"] [dependencies] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["init-if-needed"] } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["token"] } -proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } \ No newline at end of file +proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } +nft-proxy = { path = "../nft_proxy", features = ["cpi"] } +serde = { version = "1.0", features = ["derive"], optional = true } +time = "0.3.36" \ No newline at end of file diff --git a/programs/nft_voter/src/instructions/initialize_nft_voter_v0.rs b/programs/nft_voter/src/instructions/initialize_nft_voter_v0.rs index b933f0b..eaf913f 100644 --- a/programs/nft_voter/src/instructions/initialize_nft_voter_v0.rs +++ b/programs/nft_voter/src/instructions/initialize_nft_voter_v0.rs @@ -1,6 +1,7 @@ use crate::state::*; use anchor_lang::prelude::*; use anchor_spl::token::Mint; +use nft_proxy::state::ProxyConfigV0; #[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)] pub struct InitializeNftVoterArgsV0 { @@ -14,6 +15,7 @@ pub struct InitializeNftVoterV0<'info> { /// CHECK: Payer #[account(mut)] pub payer: Signer<'info>, + pub proxy_config: Option>, #[account( init, payer = payer, @@ -27,11 +29,18 @@ pub struct InitializeNftVoterV0<'info> { } pub fn handler(ctx: Context, args: InitializeNftVoterArgsV0) -> Result<()> { + let proxy_config = ctx + .accounts + .proxy_config + .clone() + .map(|k| k.key()) + .unwrap_or_default(); ctx.accounts.nft_voter.set_inner(NftVoterV0 { bump_seed: ctx.bumps["nft_voter"], name: args.name, authority: args.authority, collection: ctx.accounts.collection.key(), + proxy_config, }); Ok(()) diff --git a/programs/nft_voter/src/instructions/mod.rs b/programs/nft_voter/src/instructions/mod.rs index 4eda5d4..302be0f 100644 --- a/programs/nft_voter/src/instructions/mod.rs +++ b/programs/nft_voter/src/instructions/mod.rs @@ -1,7 +1,13 @@ pub mod initialize_nft_voter_v0; +pub mod proxied_relinquish_vote_v0; +pub mod proxied_vote_v0; pub mod relinquish_vote_v0; +pub mod update_nft_voter_v0; pub mod vote_v0; pub use initialize_nft_voter_v0::*; +pub use proxied_relinquish_vote_v0::*; +pub use proxied_vote_v0::*; pub use relinquish_vote_v0::*; +pub use update_nft_voter_v0::*; pub use vote_v0::*; diff --git a/programs/nft_voter/src/instructions/proxied_relinquish_vote_v0.rs b/programs/nft_voter/src/instructions/proxied_relinquish_vote_v0.rs new file mode 100644 index 0000000..3d3d90d --- /dev/null +++ b/programs/nft_voter/src/instructions/proxied_relinquish_vote_v0.rs @@ -0,0 +1,107 @@ +use crate::{error::ErrorCode, metaplex::MetadataAccount, RelinquishVoteArgsV0}; +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use nft_proxy::state::ProxyAssignmentV0; +use proposal::{ProposalConfigV0, ProposalV0}; + +use crate::{nft_voter_seeds, state::*}; + +#[derive(Accounts)] +pub struct ProxiedRelinquishVoteV0<'info> { + /// CHECK: You're getting sol why do you care? + /// Account to receive sol rent_refund if marker is closed + #[account(mut)] + pub rent_refund: AccountInfo<'info>, + #[account( + mut, + seeds = [b"marker", nft_voter.key().as_ref(), mint.key().as_ref(), proposal.key().as_ref()], + bump = marker.bump_seed, + has_one = nft_voter, + has_one = rent_refund + )] + pub marker: Account<'info, VoteMarkerV0>, + pub nft_voter: Account<'info, NftVoterV0>, + pub voter: Signer<'info>, + pub mint: Box>, + #[account( + seeds = ["metadata".as_bytes(), MetadataAccount::owner().as_ref(), mint.key().as_ref()], + seeds::program = MetadataAccount::owner(), + bump, + constraint = metadata.collection.as_ref().map(|col| col.verified && col.key == nft_voter.collection).unwrap_or_else(|| false) + )] + pub metadata: Box>, + #[account( + has_one = voter, + constraint = proxy_assignment.proxy_config == nft_voter.proxy_config, + constraint = proxy_assignment.index <= marker.proxy_index, + constraint = proxy_assignment.expiration_time > Clock::get().unwrap().unix_timestamp, + )] + pub proxy_assignment: Box>, + #[account( + mut, + has_one = proposal_config, + owner = proposal_program.key(), + )] + pub proposal: Account<'info, ProposalV0>, + #[account( + has_one = on_vote_hook, + has_one = state_controller, + owner = proposal_program.key() + )] + pub proposal_config: Account<'info, ProposalConfigV0>, + /// CHECK: Checked via cpi + #[account(mut)] + pub state_controller: AccountInfo<'info>, + /// CHECK: Checked via has_one + pub on_vote_hook: AccountInfo<'info>, + /// CHECK: Checked via constraint + #[account( + constraint = *proposal.to_account_info().owner == proposal_program.key() + )] + pub proposal_program: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context, args: RelinquishVoteArgsV0) -> Result<()> { + let marker = &mut ctx.accounts.marker; + marker.proposal = ctx.accounts.proposal.key(); + marker.voter = ctx.accounts.voter.key(); + + require!( + marker.choices.iter().any(|choice| *choice == args.choice), + ErrorCode::NoVoteForThisChoice + ); + + marker.choices = marker + .choices + .clone() + .into_iter() + .filter(|c| *c != args.choice) + .collect::>(); + + proposal::cpi::vote_v0( + CpiContext::new_with_signer( + ctx.accounts.proposal_program.to_account_info(), + proposal::cpi::accounts::VoteV0 { + voter: ctx.accounts.voter.to_account_info(), + vote_controller: ctx.accounts.nft_voter.to_account_info(), + state_controller: ctx.accounts.state_controller.to_account_info(), + proposal_config: ctx.accounts.proposal_config.to_account_info(), + proposal: ctx.accounts.proposal.to_account_info(), + on_vote_hook: ctx.accounts.on_vote_hook.to_account_info(), + }, + &[nft_voter_seeds!(ctx.accounts.nft_voter)], + ), + proposal::VoteArgsV0 { + remove_vote: true, + choice: args.choice, + weight: 1_u128, + }, + )?; + + if marker.choices.is_empty() { + marker.close(ctx.accounts.rent_refund.to_account_info())?; + } + + Ok(()) +} diff --git a/programs/nft_voter/src/instructions/proxied_vote_v0.rs b/programs/nft_voter/src/instructions/proxied_vote_v0.rs new file mode 100644 index 0000000..eda361b --- /dev/null +++ b/programs/nft_voter/src/instructions/proxied_vote_v0.rs @@ -0,0 +1,110 @@ +use crate::{error::ErrorCode, metaplex::MetadataAccount, VoteArgsV0}; +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use nft_proxy::state::ProxyAssignmentV0; +use proposal::{ProposalConfigV0, ProposalV0}; + +use crate::{nft_voter_seeds, state::*}; + +#[derive(Accounts)] +pub struct ProxyVoteV0<'info> { + #[account(mut)] + pub payer: Signer<'info>, + #[account( + init_if_needed, + payer = payer, + space = 8 + 60 + std::mem::size_of::(), + seeds = [b"marker", nft_voter.key().as_ref(), mint.key().as_ref(), proposal.key().as_ref()], + bump + )] + pub marker: Box>, + #[account( + has_one = voter, + constraint = proxy_assignment.proxy_config == nft_voter.proxy_config, + // only the current or earlier delegates can change vote. Or if proposal not set, this was an `init` for the marker + constraint = proxy_assignment.index <= marker.proxy_index || marker.proposal == Pubkey::default(), + constraint = proxy_assignment.expiration_time > Clock::get().unwrap().unix_timestamp, + )] + pub proxy_assignment: Box>, + pub nft_voter: Box>, + pub voter: Signer<'info>, + pub mint: Box>, + #[account( + seeds = ["metadata".as_bytes(), MetadataAccount::owner().as_ref(), mint.key().as_ref()], + seeds::program = MetadataAccount::owner(), + bump, + constraint = metadata.collection.as_ref().map(|col| col.verified && col.key == nft_voter.collection).unwrap_or_else(|| false) + )] + pub metadata: Box>, + #[account( + mut, + has_one = proposal_config, + owner = proposal_program.key(), + )] + pub proposal: Account<'info, ProposalV0>, + #[account( + has_one = on_vote_hook, + has_one = state_controller, + owner = proposal_program.key() + )] + pub proposal_config: Account<'info, ProposalConfigV0>, + /// CHECK: Checked via cpi + #[account(mut)] + pub state_controller: AccountInfo<'info>, + /// CHECK: Checked via has_one + pub on_vote_hook: AccountInfo<'info>, + /// CHECK: Checked via constraint + #[account( + constraint = *proposal.to_account_info().owner == proposal_program.key() + )] + pub proposal_program: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context, args: VoteArgsV0) -> Result<()> { + let marker = &mut ctx.accounts.marker; + if marker.rent_refund == Pubkey::default() { + marker.rent_refund = ctx.accounts.payer.key(); + } + marker.proposal = ctx.accounts.proposal.key(); + marker.bump_seed = ctx.bumps["marker"]; + marker.voter = ctx.accounts.voter.key(); + marker.nft_voter = ctx.accounts.nft_voter.key(); + marker.mint = ctx.accounts.mint.key(); + marker.proxy_index = ctx.accounts.proxy_assignment.index; + + // Don't allow voting for the same choice twice. + require!( + marker.choices.iter().all(|choice| *choice != args.choice), + ErrorCode::AlreadyVoted + ); + require_gt!( + ctx.accounts.proposal.max_choices_per_voter, + marker.choices.len() as u16, + ErrorCode::MaxChoicesExceeded + ); + + marker.choices.push(args.choice); + + proposal::cpi::vote_v0( + CpiContext::new_with_signer( + ctx.accounts.proposal_program.to_account_info(), + proposal::cpi::accounts::VoteV0 { + voter: ctx.accounts.voter.to_account_info(), + vote_controller: ctx.accounts.nft_voter.to_account_info(), + state_controller: ctx.accounts.state_controller.to_account_info(), + proposal_config: ctx.accounts.proposal_config.to_account_info(), + proposal: ctx.accounts.proposal.to_account_info(), + on_vote_hook: ctx.accounts.on_vote_hook.to_account_info(), + }, + &[nft_voter_seeds!(ctx.accounts.nft_voter)], + ), + proposal::VoteArgsV0 { + remove_vote: false, + choice: args.choice, + weight: 1_u128, + }, + )?; + + Ok(()) +} diff --git a/programs/nft_voter/src/instructions/relinquish_vote_v0.rs b/programs/nft_voter/src/instructions/relinquish_vote_v0.rs index ebfed91..ccf999a 100644 --- a/programs/nft_voter/src/instructions/relinquish_vote_v0.rs +++ b/programs/nft_voter/src/instructions/relinquish_vote_v0.rs @@ -15,12 +15,13 @@ pub struct RelinquishVoteV0<'info> { /// CHECK: You're getting sol why do you care? /// Account to receive sol refund if marker is closed #[account(mut)] - pub refund: AccountInfo<'info>, + pub rent_refund: AccountInfo<'info>, #[account( mut, seeds = [b"marker", nft_voter.key().as_ref(), mint.key().as_ref(), proposal.key().as_ref()], bump = marker.bump_seed, - has_one = nft_voter + has_one = nft_voter, + has_one = rent_refund )] pub marker: Account<'info, VoteMarkerV0>, pub nft_voter: Account<'info, NftVoterV0>, @@ -102,7 +103,7 @@ pub fn handler(ctx: Context, args: RelinquishVoteArgsV0) -> Re )?; if marker.choices.is_empty() { - marker.close(ctx.accounts.refund.to_account_info())?; + marker.close(ctx.accounts.rent_refund.to_account_info())?; } Ok(()) diff --git a/programs/nft_voter/src/instructions/update_nft_voter_v0.rs b/programs/nft_voter/src/instructions/update_nft_voter_v0.rs new file mode 100644 index 0000000..f561475 --- /dev/null +++ b/programs/nft_voter/src/instructions/update_nft_voter_v0.rs @@ -0,0 +1,27 @@ +use crate::state::*; +use anchor_lang::prelude::*; +use nft_proxy::state::ProxyConfigV0; + +#[derive(Accounts)] +pub struct UpdateNftVoterV0<'info> { + pub authority: Signer<'info>, + pub proxy_config: Option>, + /// CHECK: Set if setting the new auth + pub new_authority: Option>, + #[account( + has_one = authority + )] + pub nft_voter: Box>, +} + +pub fn handler(ctx: Context) -> Result<()> { + if let Some(proxy_config) = &ctx.accounts.proxy_config { + ctx.accounts.nft_voter.proxy_config = proxy_config.key(); + } + + if let Some(authority) = &ctx.accounts.new_authority { + ctx.accounts.nft_voter.authority = authority.key() + } + + Ok(()) +} diff --git a/programs/nft_voter/src/instructions/vote_v0.rs b/programs/nft_voter/src/instructions/vote_v0.rs index 44e1506..13b5133 100644 --- a/programs/nft_voter/src/instructions/vote_v0.rs +++ b/programs/nft_voter/src/instructions/vote_v0.rs @@ -64,15 +64,17 @@ pub struct VoteV0<'info> { } pub fn handler(ctx: Context, args: VoteArgsV0) -> Result<()> { - msg!("I started"); let marker = &mut ctx.accounts.marker; + if marker.rent_refund == Pubkey::default() { + marker.rent_refund = ctx.accounts.payer.key(); + } marker.proposal = ctx.accounts.proposal.key(); marker.bump_seed = ctx.bumps["marker"]; marker.voter = ctx.accounts.voter.key(); marker.nft_voter = ctx.accounts.nft_voter.key(); marker.mint = ctx.accounts.mint.key(); + marker.proxy_index = 0; - msg!("I set"); // Don't allow voting for the same choice twice. require!( marker.choices.iter().all(|choice| *choice != args.choice), @@ -85,7 +87,6 @@ pub fn handler(ctx: Context, args: VoteArgsV0) -> Result<()> { ); marker.choices.push(args.choice); - msg!("I vote"); proposal::cpi::vote_v0( CpiContext::new_with_signer( diff --git a/programs/nft_voter/src/lib.rs b/programs/nft_voter/src/lib.rs index 6a9b73e..fab36b5 100644 --- a/programs/nft_voter/src/lib.rs +++ b/programs/nft_voter/src/lib.rs @@ -30,4 +30,19 @@ pub mod nft_voter { pub fn vote_v0(ctx: Context, args: VoteArgsV0) -> Result<()> { vote_v0::handler(ctx, args) } + + pub fn proxied_relinquish_vote_v0( + ctx: Context, + args: RelinquishVoteArgsV0, + ) -> Result<()> { + proxied_relinquish_vote_v0::handler(ctx, args) + } + + pub fn proxied_vote_v0(ctx: Context, args: VoteArgsV0) -> Result<()> { + proxied_vote_v0::handler(ctx, args) + } + + pub fn update_nft_voter_v0(ctx: Context) -> Result<()> { + update_nft_voter_v0::handler(ctx) + } } diff --git a/programs/nft_voter/src/state.rs b/programs/nft_voter/src/state.rs index 81ed136..eb75bfa 100644 --- a/programs/nft_voter/src/state.rs +++ b/programs/nft_voter/src/state.rs @@ -8,6 +8,7 @@ pub struct NftVoterV0 { #[max_len(32)] pub name: String, pub bump_seed: u8, + pub proxy_config: Pubkey, } #[account] @@ -19,6 +20,11 @@ pub struct VoteMarkerV0 { pub mint: Pubkey, pub choices: Vec, pub bump_seed: u8, + // Keep track of which proxy index voted on this marker, + // earlier delegators can override + pub proxy_index: u16, + // Ensure the refund goes to whoever paid to create the marker when closing + pub rent_refund: Pubkey, } #[macro_export] diff --git a/programs/organization/Cargo.toml b/programs/organization/Cargo.toml index 490da0e..2c79734 100644 --- a/programs/organization/Cargo.toml +++ b/programs/organization/Cargo.toml @@ -20,4 +20,5 @@ devnet = [] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } +time = "0.3.36" diff --git a/programs/organization_wallet/Cargo.toml b/programs/organization_wallet/Cargo.toml index bd275cf..7114f7a 100644 --- a/programs/organization_wallet/Cargo.toml +++ b/programs/organization_wallet/Cargo.toml @@ -21,3 +21,4 @@ anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } organization = { path = "../organization", features = ["no-entrypoint", "cpi"] } +time = "0.3.36" diff --git a/programs/proposal/Cargo.toml b/programs/proposal/Cargo.toml index b469e40..2669ca9 100644 --- a/programs/proposal/Cargo.toml +++ b/programs/proposal/Cargo.toml @@ -20,3 +20,4 @@ devnet = [] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } vote-hook-interface = { path = "../vote_hook_interface", features = ["no-entrypoint", "cpi"] } +time = "0.3.36" \ No newline at end of file diff --git a/programs/state_controller/Cargo.toml b/programs/state_controller/Cargo.toml index 586db01..e96e378 100644 --- a/programs/state_controller/Cargo.toml +++ b/programs/state_controller/Cargo.toml @@ -20,4 +20,5 @@ devnet = [] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } +time = "0.3.36" diff --git a/programs/token_voter/Cargo.toml b/programs/token_voter/Cargo.toml index 9d366f4..a04d371 100644 --- a/programs/token_voter/Cargo.toml +++ b/programs/token_voter/Cargo.toml @@ -15,8 +15,11 @@ no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] devnet = [] +serde-feature = ["serde"] [dependencies] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["init-if-needed"] } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism", features = ["token"] } -proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } \ No newline at end of file +proposal = { path = "../proposal", features = ["no-entrypoint", "cpi"] } +serde = { version = "1.0", features = ["derive"], optional = true } +time = "0.3.36" \ No newline at end of file diff --git a/programs/vote_hook_interface/Cargo.toml b/programs/vote_hook_interface/Cargo.toml index 37486d8..e6a4eb2 100644 --- a/programs/vote_hook_interface/Cargo.toml +++ b/programs/vote_hook_interface/Cargo.toml @@ -19,3 +19,4 @@ devnet = [] [dependencies] anchor-lang = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } anchor-spl = { git = "https://github.com/ChewingGlass/anchor", branch = "bugfix/cpi-polymorphism" } +time = "0.3.36" diff --git a/scripts/generate-idl-docs.ts b/scripts/generate-idl-docs.ts index 1da2157..2bde2d3 100644 --- a/scripts/generate-idl-docs.ts +++ b/scripts/generate-idl-docs.ts @@ -106,7 +106,7 @@ If you are looking for a quick start guide, check out the [Getting Started](/doc ## Types `; - types.forEach((type) => { + types?.forEach((type) => { mdFile += `### ${type.name} `; diff --git a/tests/nft-voter.ts b/tests/nft-voter.ts index b3aae1e..915b537 100644 --- a/tests/nft-voter.ts +++ b/tests/nft-voter.ts @@ -5,11 +5,17 @@ import { PROGRAM_ID as PROPOSAL_PID, init as initProposal, } from "@helium/proposal-sdk"; +import { + PROGRAM_ID as DEL_PID, + init as initNftProxy, + proxyAssignmentKey, +} from "@helium/nft-proxy-sdk"; import { Metaplex, walletAdapterIdentity } from "@metaplex-foundation/js"; import { Keypair, PublicKey } from "@solana/web3.js"; import { BN } from "bn.js"; import { expect } from "chai"; import { NftVoter } from "../target/types/nft_voter"; +import { NftProxy } from "../target/types/nft_proxy"; import { Proposal } from "../target/types/proposal"; import { ensureIdls, makeid } from "./utils"; @@ -19,6 +25,8 @@ describe("nft-voter", () => { const me = provider.wallet.publicKey; let proposalProgram: Program; let program: Program; + let proxyProgram: Program; + const metaplex = new Metaplex(provider.connection); metaplex.use(walletAdapterIdentity(provider.wallet)); @@ -33,9 +41,15 @@ describe("nft-voter", () => { PROPOSAL_PID, anchor.workspace.Proposal.idl ); + proxyProgram = await initNftProxy( + provider, + DEL_PID, + anchor.workspace.NftProxy.idl + ); }); describe("with proposal", () => { + let proxyConfig: PublicKey | undefined; let proposalConfig: PublicKey | undefined; let proposal: PublicKey | undefined; let nftVoter: PublicKey | undefined; @@ -67,6 +81,24 @@ describe("nft-voter", () => { }) ).nft.address; + ({ + pubkeys: { proxyConfig }, + } = await proxyProgram.methods + .initializeProxyConfigV0({ + maxProxyTime: new BN(1000000000000), + name: makeid(10), + seasons: [ + { + start: new BN(0), + end: new BN(new Date().valueOf() / 1000 + 100000), + }, + ], + }) + .accounts({ + authority: me, + }) + .rpcAndKeys()); + ({ pubkeys: { nftVoter }, } = await program.methods @@ -76,8 +108,10 @@ describe("nft-voter", () => { }) .accounts({ collection, + proxyConfig, }) .rpcAndKeys({ skipPreflight: true })); + ({ pubkeys: { proposalConfig }, } = await proposalProgram.methods @@ -142,7 +176,7 @@ describe("nft-voter", () => { .relinquishVoteV0({ choice: 0, }) - .accounts({ mint, proposal, refund: me, nftVoter }) + .accounts({ mint, proposal, nftVoter }) .rpc({ skipPreflight: true }); acct = await proposalProgram.account.proposalV0.fetch(proposal!); @@ -150,5 +184,162 @@ describe("nft-voter", () => { markerA = await program.account.voteMarkerV0.fetchNullable(marker!); expect(markerA).to.be.null; }); + + describe("with proxy", () => { + let proxy = Keypair.generate(); + + beforeEach(async () => { + await proxyProgram.methods + .assignProxyV0({ + expirationTime: new BN(new Date().valueOf() / 1000 + 10000), + }) + .accounts({ + proxyConfig, + asset: mint, + recipient: proxy.publicKey, + }) + .rpc({ skipPreflight: true }); + }); + + it("allows voting on and relinquishing votes on the proposal", async () => { + const proxyAssignment = proxyAssignmentKey( + proxyConfig!, + mint, + proxy.publicKey + )[0]; + const { + pubkeys: { marker }, + } = await program.methods + .proxiedVoteV0({ + choice: 0, + }) + .accounts({ + mint, + proposal, + nftVoter, + voter: proxy.publicKey, + proxyAssignment, + }) + .signers([proxy]) + .rpcAndKeys({ skipPreflight: true }); + + let acct = await proposalProgram.account.proposalV0.fetch(proposal!); + expect(acct.choices[0].weight.toNumber()).to.eq(1); + let markerA = await program.account.voteMarkerV0.fetchNullable(marker!); + expect(markerA?.choices).to.deep.eq([0]); + + await program.methods + .proxiedRelinquishVoteV0({ + choice: 0, + }) + .accounts({ + mint, + proposal, + nftVoter, + voter: proxy.publicKey, + proxyAssignment, + }) + .signers([proxy]) + .rpc({ skipPreflight: true }); + + acct = await proposalProgram.account.proposalV0.fetch(proposal!); + expect(acct.choices[0].weight.toNumber()).to.eq(0); + markerA = await program.account.voteMarkerV0.fetchNullable(marker!); + expect(markerA).to.be.null; + }); + + it("allows earlier proxies to change the vote", async () => { + const { + pubkeys: { marker }, + } = await program.methods + .proxiedVoteV0({ + choice: 0, + }) + .accounts({ + mint, + proposal, + nftVoter, + voter: proxy.publicKey, + proxyAssignment: proxyAssignmentKey( + proxyConfig!, + mint, + proxy.publicKey + )[0], + }) + .signers([proxy]) + .rpcAndKeys({ skipPreflight: true }); + + let acct = await proposalProgram.account.proposalV0.fetch(proposal!); + expect(acct.choices[0].weight.toNumber()).to.eq(1); + let markerA = await program.account.voteMarkerV0.fetchNullable(marker!); + expect(markerA?.choices).to.deep.eq([0]); + expect(markerA?.proxyIndex).to.eq(1); + + await program.methods + .relinquishVoteV0({ + choice: 0, + }) + .accounts({ + mint, + proposal, + nftVoter, + }) + .rpc({ skipPreflight: true }); + + acct = await proposalProgram.account.proposalV0.fetch(proposal!); + expect(acct.choices[0].weight.toNumber()).to.eq(0); + markerA = await program.account.voteMarkerV0.fetchNullable(marker!); + expect(markerA).to.be.null; + + await program.methods + .voteV0({ + choice: 1, + }) + .accounts({ + mint, + proposal, + nftVoter, + }) + .rpcAndKeys({ skipPreflight: true }); + + acct = await proposalProgram.account.proposalV0.fetch(proposal!); + expect(acct.choices[1].weight.toNumber()).to.eq(1); + markerA = await program.account.voteMarkerV0.fetchNullable(marker!); + expect(markerA?.choices).to.deep.eq([1]); + expect(markerA?.proxyIndex).to.eq(0); + }); + + it("allows the original owner to unassign proxy", async () => { + const toUnassignProxy = proxyAssignmentKey( + proxyConfig!, + mint, + proxy.publicKey + )[0]; + const myProxy = proxyAssignmentKey( + proxyConfig!, + mint, + PublicKey.default + )[0]; + await proxyProgram.methods + .unassignProxyV0() + .accounts({ + proxyAssignment: toUnassignProxy, + prevProxyAssignment: myProxy, + currentProxyAssignment: myProxy, + }) + .rpc({ skipPreflight: true }); + + expect( + ( + await proxyProgram.account.proxyAssignmentV0.fetch(myProxy) + ).nextVoter.toBase58() + ).to.eq(PublicKey.default.toBase58()); + expect( + await proxyProgram.account.proxyAssignmentV0.fetchNullable( + toUnassignProxy + ) + ).to.be.null; + }); + }); }); }); diff --git a/tests/utils.ts b/tests/utils.ts index a3def03..bcae82f 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,5 +1,7 @@ import { execSync } from "child_process"; +export const ANCHOR_PATH = process.env.ANCHOR_PATH || "anchor"; + export async function ensureIdls() { let programs = [ { @@ -18,25 +20,29 @@ export async function ensureIdls() { name: "nft_voter", pid: "nftvLQ5t6xe2nQF1NBmBBmn15ed59tU6vSCkwQNEqdc", }, + { + name: "nft_proxy", + pid: "nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p", + }, { name: "organization", pid: "orgdXvHVLkWgBYerptASkAwkZAE563CJUu717dMNx5f", }, { name: "organization_wallet", - pid: "orgwPMqJs9xft8UefUdKfyBwg6GDnN6oLhpMaKa6nJg" - } + pid: "orgwPMqJs9xft8UefUdKfyBwg6GDnN6oLhpMaKa6nJg", + }, ]; await Promise.all( programs.map(async (program) => { try { execSync( - `anchor idl init --filepath ${__dirname}/../target/idl/${program.name}.json ${program.pid}`, + `${ANCHOR_PATH} idl init --filepath ${__dirname}/../target/idl/${program.name}.json ${program.pid}`, { stdio: "inherit", shell: "/bin/bash" } ); } catch { execSync( - `anchor idl upgrade --filepath ${__dirname}/../target/idl/${program.name}.json ${program.pid}`, + `${ANCHOR_PATH} idl upgrade --filepath ${__dirname}/../target/idl/${program.name}.json ${program.pid}`, { stdio: "inherit", shell: "/bin/bash" } ); } diff --git a/tsconfig.json b/tsconfig.json index 587b096..9c0ea7a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,9 @@ { "path": "./packages/nft-voter-sdk" }, + { + "path": "./packages/nft-proxy-sdk" + }, { "path": "./packages/modular-governance-hooks" } diff --git a/yarn.lock b/yarn.lock index 39931a0..c1363be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -538,6 +538,14 @@ "@solana/spl-token" "^0.3.6" "@solana/web3.js" "^1.43.4" +"@helium/anchor-resolvers@^0.2.17": + version "0.2.21" + resolved "https://registry.yarnpkg.com/@helium/anchor-resolvers/-/anchor-resolvers-0.2.21.tgz#8cd13bca3e7af83ffff3ab754dcf9f788d26e57e" + integrity sha512-rz3GJaULGmokjrq63v4sy683PMUkL31jrK5wVX01tzCYbI1woC9vISoPd3oSSuauZqQXdBhhQ49GKrpzi49JbA== + dependencies: + "@solana/spl-token" "^0.3.6" + "@solana/web3.js" "^1.43.4" + "@helium/anchor-resolvers@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@helium/anchor-resolvers/-/anchor-resolvers-0.4.3.tgz#6d7afba53b5e58d265e3f2d482521f2eef664c5e" @@ -568,6 +576,14 @@ pako "^2.0.3" react-async-hook "^4.0.0" +"@helium/modular-governance-idls@^0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@helium/modular-governance-idls/-/modular-governance-idls-0.0.10.tgz#8384cdca7c44949cbe33c776b44cca668a704315" + integrity sha512-fMDYhCnU18uCKzkeD8pFED3ubkKzeqw58EUZt7Qk4mxWQGM4KJ3qd1L9dp5jh9F4pVWohZ2d5EK5VqakC8JVGg== + dependencies: + "@coral-xyz/anchor" "^0.28.0" + "@solana/web3.js" "^1.78.4" + "@helium/spl-utils@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@helium/spl-utils/-/spl-utils-0.4.3.tgz#9da76c006182e1e8a356234e6c583b1b09a733ed"