Merge branch 'feat/multisig-deploy'

This commit is contained in:
fiftyeightandeight
2024-03-08 11:33:48 +08:00
11 changed files with 3486 additions and 66 deletions

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@ coverage
costs-reports.json
node_modules
contracts_modules
plan.json
config.json

View File

@@ -1,5 +1,7 @@
(impl-trait .proposal-trait.proposal-trait)
(define-constant stx-bootstrap-amount u10000)
(define-public (execute (sender principal))
(begin
(try! (contract-call? .lisa-dao set-extensions (list

View File

@@ -52,52 +52,52 @@ plan:
- emulated-contract-publish:
contract-name: sip-010-trait-ft-standard
emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE
path: /Users/chanahn/githome/liquid-stacking/./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar
path: "./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar"
clarity-version: 1
- emulated-contract-publish:
contract-name: trait-sip-010
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/traits/trait-sip-010.clar
path: contracts_modules/alex_v1/traits/trait-sip-010.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: trait-flash-loan-user
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/traits/trait-flash-loan-user.clar
path: contracts_modules/alex_v1/traits/trait-flash-loan-user.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: trait-semi-fungible
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/traits/trait-semi-fungible.clar
path: contracts_modules/alex_v1/traits/trait-semi-fungible.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: alex-vault-v1-1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/alex-vault-v1-1.clar
path: contracts_modules/alex_v1/alex-vault-v1-1.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: trait-ownable
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/traits/trait-ownable.clar
path: contracts_modules/alex_v1/traits/trait-ownable.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: token-amm-swap-pool-v1-1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/pool-token/token-amm-swap-pool-v1-1.clar
path: contracts_modules/alex_v1/pool-token/token-amm-swap-pool-v1-1.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: amm-swap-pool-v1-1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/pool/amm-swap-pool-v1-1.clar
path: contracts_modules/alex_v1/pool/amm-swap-pool-v1-1.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: token-wstx
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/wrapped-token/token-wstx.clar
path: contracts_modules/alex_v1/wrapped-token/token-wstx.clar
clarity-version: 1
- emulated-contract-publish:
contract-name: trait-vault
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts_modules/alex_v1/traits/trait-vault.clar
path: contracts_modules/alex_v1/traits/trait-vault.clar
clarity-version: 1
epoch: "2.1"
- id: 1
@@ -105,127 +105,127 @@ plan:
- emulated-contract-publish:
contract-name: pox-fast-pool-v2
emulated-sender: SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP
path: /Users/chanahn/githome/liquid-stacking/./.cache/requirements/SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2.clar
path: "./.cache/requirements/SP21YTSM60CAY6D011EZVEVNKXVW8FVZE198XEFFP.pox-fast-pool-v2.clar"
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member10
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member11
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member12
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member13
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member14
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member15
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member16
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member17
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member18
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member19
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member2
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member20
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member3
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member4
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member5
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member6
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member7
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member8
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-member9
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-member.clar
path: contracts/strategies/fastpool/fastpool-member.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: strategy-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/strategy-trait.clar
path: contracts/traits/strategy-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-strategy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/strategies/fastpool/fastpool-strategy.clar
path: contracts/strategies/fastpool/fastpool-strategy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: extension-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/extension-trait.clar
path: contracts/traits/extension-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: proposal-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/proposal-trait.clar
path: contracts/traits/proposal-trait.clar
clarity-version: 2
epoch: "2.4"
- id: 2
@@ -233,127 +233,127 @@ plan:
- emulated-contract-publish:
contract-name: lisa-dao
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/lisa-dao.clar
path: contracts/lisa-dao.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: proxy-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/proxy-trait.clar
path: contracts/traits/proxy-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-vault
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/extensions/lqstx-vault.clar
path: contracts/extensions/lqstx-vault.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: fastpool-strategy-manager
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/extensions/fastpool-strategy-manager.clar
path: contracts/extensions/fastpool-strategy-manager.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: operators
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/extensions/operators.clar
path: contracts/extensions/operators.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: sip-010-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/sip-010-trait.clar
path: contracts/traits/sip-010-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: token-lisa
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/token-lisa.clar
path: contracts/token-lisa.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: boot
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/boot.clar
path: contracts/boot.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-mint-registry
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/lqstx-mint-registry.clar
path: contracts/lqstx-mint-registry.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-strategy-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/rebase-strategy-trait.clar
path: contracts/traits/rebase-strategy-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: stx-transfer-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/proxies/stx-transfer-proxy.clar
path: contracts/proxies/stx-transfer-proxy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: token-lqstx
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/token-lqstx.clar
path: contracts/token-lqstx.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: token-vlqstx
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/token-vlqstx.clar
path: contracts/token-vlqstx.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-mint-endpoint
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/extensions/lqstx-mint-endpoint.clar
path: contracts/extensions/lqstx-mint-endpoint.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lisa-rebase
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/extensions/lisa-rebase.clar
path: contracts/extensions/lisa-rebase.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lisa-transfer-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/proxies/lisa-transfer-proxy.clar
path: contracts/proxies/lisa-transfer-proxy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: lqstx-transfer-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/proxies/lqstx-transfer-proxy.clar
path: contracts/proxies/lqstx-transfer-proxy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: mock-strategy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/mocks/mock-strategy.clar
path: contracts/mocks/mock-strategy.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: mock-strategy-manager
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/mocks/mock-strategy-manager.clar
path: contracts/mocks/mock-strategy-manager.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-1
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/rules/rebase-1.clar
path: contracts/rules/rebase-1.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: rebase-mock
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/mocks/rebase-mock.clar
path: contracts/mocks/rebase-mock.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: regtest-boot
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/regtest-boot.clar
path: contracts/regtest-boot.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: sip-010-extensions-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/sip-010-extensions-trait.clar
path: contracts/traits/sip-010-extensions-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: sip-010-transferable-trait
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/traits/sip-010-transferable-trait.clar
path: contracts/traits/sip-010-transferable-trait.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: stx-transfer-many-proxy
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/proxies/stx-transfer-many-proxy.clar
path: contracts/proxies/stx-transfer-many-proxy.clar
clarity-version: 2
epoch: "2.4"
- id: 3
@@ -361,11 +361,11 @@ plan:
- emulated-contract-publish:
contract-name: token-wlqstx
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/wrapped-tokens/token-wlqstx.clar
path: contracts/wrapped-tokens/token-wlqstx.clar
clarity-version: 2
- emulated-contract-publish:
contract-name: treasury
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
path: /Users/chanahn/githome/liquid-stacking/contracts/treasury.clar
path: contracts/treasury.clar
clarity-version: 2
epoch: "2.4"

2974
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,13 @@
{
"name": "lisa-tests",
"name": "lisa",
"version": "1.0.0",
"main": "index.js",
"description": "Run unit tests on this project.",
"private": true,
"type": "module",
"scripts": {
"multisig-plan": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/create-multisig-deployment-plan.ts",
"multisig-sign": "node --no-warnings=ExperimentalWarning --loader ts-node/esm ./scripts/sign-multisig-deployment-plan.ts",
"setup:clarity": "./scripts/clarinet_manager.sh clean && ./scripts/clarinet_manager.sh install",
"test": "vitest run",
"test:report": "vitest run -- --coverage --costs",
@@ -16,9 +19,11 @@
"@hirosystems/clarinet-sdk": "^1.0.0",
"@stacks/transactions": "^6.9.0",
"chokidar-cli": "^3.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vitest": "^0.34.4",
"vitest-environment-clarinet": "^1.0.0"
"vitest-environment-clarinet": "^1.0.0",
"yaml": "^2.4.1"
}
}
}

View File

@@ -0,0 +1,35 @@
import {
deserializeTransaction,
// broadcastTransaction,
getNonce,
addressToString,
broadcastTransaction,
TxBroadcastResult,
} from "@stacks/transactions";
// import { bytesToHex } from '@stacks/common';
import { getNetwork, getStacksAddress } from "./config.ts";
import { readPlan, verboseLog } from "./utils.ts";
const network = getNetwork();
const address = getStacksAddress();
const additionalFeeMultiplier: bigint = 1n;
readPlan()
.then(plan => plan.map(tx => deserializeTransaction(tx)))
.then(async (plan) => {
const addressString = addressToString(address);
const currentNonce = await getNonce(addressString, network);
verboseLog(`${addressString} account nonce is ${currentNonce}`);
let broadcasts: Promise<TxBroadcastResult>[] = [];
plan.map(transaction => {
if (transaction.auth.spendingCondition.nonce < currentNonce)
return; // already broadcast that transaction
if (additionalFeeMultiplier > 1)
transaction.setFee(transaction.auth.spendingCondition.fee * additionalFeeMultiplier);
broadcasts.push(broadcastTransaction(transaction, network));
verboseLog(`Broadcasting ${transaction.txid()}`);
});
const broadcastResults = await Promise.all(broadcasts);
console.log(broadcastResults);
});

60
scripts/config.ts Normal file
View File

@@ -0,0 +1,60 @@
import fs from "fs";
import { hexToBytes } from '@stacks/common';
import { AddressHashMode, TransactionVersion, addressFromHashMode, createStacksPrivateKey, publicKeyFromBytes } from "@stacks/transactions";
import { c32addressDecode } from 'c32check';
import type { StacksNetworkName } from "@stacks/network";
const secretsFile = "config.json";
export type Config = {
secrets: string[],
pubkeys: string[],
address: string,
network: StacksNetworkName
};
let cache: Config | null = null;
export function loadConfig(): Config {
if (cache !== null)
return cache;
const content = fs.readFileSync(secretsFile, "utf-8");
let obj: Config | null = null;
try {
obj = JSON.parse(content);
}
catch (e) {
throw new Error(`${secretsFile} is not valid JSON`);
}
if (typeof obj !== "object")
throw new Error(`${secretsFile} config is not an object`);
if (obj?.secrets.constructor !== Array)
throw new Error(`${secretsFile} does not contain an array of secrets`);
for (let secret of obj.secrets)
if (typeof secret !== 'string' || (secret as string).length !== 33 * 2 || !(secret as string).endsWith('01'))
throw new Error(`Invalid secret in ${secretsFile}, all secrets should be hex-encoded 33 bytes ending with 01`);
cache = obj;
return obj;
}
export function getStacksPrivateKeys() {
const config = loadConfig();
return config.secrets.map(secretHex => createStacksPrivateKey(secretHex));
}
export function getStacksPubkeys() {
const config = loadConfig();
return config.pubkeys.map(pubkeyHex => publicKeyFromBytes(hexToBytes(pubkeyHex)));
}
export function getStacksAddress() {
const config = loadConfig();
const [_, hash160] = c32addressDecode(config.address);
return addressFromHashMode(AddressHashMode.SerializeP2WSH, TransactionVersion.Mainnet, hash160);
}
export function getNetwork() {
const config = loadConfig();
return config.network || "testnet";
}

View File

@@ -0,0 +1,197 @@
import {
makeUnsignedContractDeploy,
StacksPublicKey,
StacksTransaction,
AnchorMode,
AddressHashMode,
createMultiSigSpendingCondition,
addressToString,
Address,
makeUnsignedContractCall,
PostConditionMode,
createSTXPostCondition,
FungibleConditionCode,
ClarityValue,
contractPrincipalCV,
standardPrincipalCV,
} from "@stacks/transactions";
import type { StacksNetworkName } from "@stacks/network";
import { initSimnet } from "@hirosystems/clarinet-sdk";
import fs from "fs";
import { bytesToHex } from '@stacks/common';
import YAML from "yaml";
import { getNetwork, getStacksAddress, getStacksPubkeys } from "./config.ts";
import { assertSigner, planFile, verboseLog } from "./utils.js";
const manifestFile = "./Clarinet.toml";
const simnetDeployFile = "deployments/default.simnet-plan.yaml";
const network = getNetwork();
const address = getStacksAddress();
const pubKeys = getStacksPubkeys();
let nonce = 0;
const feeMultiplier = 1;
const multisigSpendConditionByteLength = 66; // don't change
type PlanItem = {
contractName: string,
codeBody: string,
path: string,
clarityVersion: number
};
async function deployPlan(): Promise<PlanItem[]> {
const simnet = await initSimnet(manifestFile);
simnet.getContractsInterfaces(); // creates simnet deploy plan
const simnetPlan = YAML.parse(fs.readFileSync(simnetDeployFile, "utf-8"));
const plan = simnetPlan.plan.batches.flatMap(
(batch: any) => batch.transactions.map((transaction: any) => {
const item = transaction['emulated-contract-publish'];
if (!(item.path as string).startsWith("contracts_modules/") && !(item.path as string).startsWith("./.cache/"))
return {
contractName: item['contract-name'],
codeBody: fs.readFileSync(item.path, 'utf-8'),
path: item.path,
clarityVersion: item['clarity-version']
};
return null;
})
).filter((item: any) => item !== null);
return plan;
}
// adding fields on the unsigned tx makes it easier to manage
function addPubkeyFields(tx: StacksTransaction, pubKeys: StacksPublicKey[]) {
for (const pk of pubKeys)
tx.appendPubkey(pk);
return tx;
}
async function createMultisigDeployTransaction(
contractName: string,
codeBody: string,
feeMultiplier: number,
nonce: number,
numSignatures: number,
pubkeys: StacksPublicKey[],
network: StacksNetworkName,
checkSigner: Address): Promise<StacksTransaction> {
const publicKeys = pubkeys.map(pk => bytesToHex(pk.data));
const tx = await makeUnsignedContractDeploy({
numSignatures,
publicKeys,
contractName,
codeBody,
network,
nonce,
fee: 1,
anchorMode: AnchorMode.OnChainOnly
});
// makeUnsignedContractDeploy() forces a AddressHashMode.SerializeP2SH spending condition, so we construct it manually
// and replace it.
tx.auth.spendingCondition = createMultiSigSpendingCondition(AddressHashMode.SerializeP2WSH, numSignatures, publicKeys, nonce, 1);
assertSigner(tx.auth.spendingCondition, checkSigner);
const calculatedFee = (tx.serialize().byteLength + multisigSpendConditionByteLength * pubKeys.length) * feeMultiplier;
tx.setFee(calculatedFee);
verboseLog(`Created multisig contract deploy transaction for ${contractName}`);
return tx;
}
async function createMultisigBootTransaction(
contractAddress: string,
contractName: string,
functionName: string,
functionArgs: ClarityValue[],
feeMultiplier: number,
nonce: number,
numSignatures: number,
pubkeys: StacksPublicKey[],
network: StacksNetworkName,
signer: Address,
stxSpendAmount: number): Promise<StacksTransaction> {
const publicKeys = pubkeys.map(pk => bytesToHex(pk.data));
const tx = await makeUnsignedContractCall({
numSignatures,
publicKeys,
contractAddress,
contractName,
functionName,
functionArgs,
network,
nonce,
fee: 1,
anchorMode: AnchorMode.OnChainOnly,
postConditionMode: PostConditionMode.Deny,
postConditions: [createSTXPostCondition(addressToString(signer), FungibleConditionCode.Equal, stxSpendAmount)]
});
// makeUnsignedContractCall() forces a AddressHashMode.SerializeP2SH spending condition, so we construct it manually
// and replace it.
tx.auth.spendingCondition = createMultiSigSpendingCondition(AddressHashMode.SerializeP2WSH, numSignatures, publicKeys, nonce, 1);
assertSigner(tx.auth.spendingCondition, signer);
const calculatedFee = (tx.serialize().byteLength + multisigSpendConditionByteLength * pubKeys.length) * feeMultiplier;
tx.setFee(calculatedFee);
verboseLog(`Created boot transaction`);
return tx;
}
async function findStxBootstrapAmount() {
const simnet = await initSimnet(manifestFile);
let boot: any = null;
try {
boot = simnet.getContractAST('boot');
}
catch (error) {
throw new Error(`Failed to read boot contract`);
}
return findStxBootstrapAmountAtom(boot.expressions);
}
function findStxBootstrapAmountAtom(items: any[]) {
for (let i = 0; i < items.length; ++i) {
const item = items[i];
if (item.expr?.List?.length === 3) {
let [a, b, c] = item.expr.List;
if (a.expr?.Atom === "define-constant" && b.expr?.Atom === "stx-bootstrap-amount")
return c.expr.LiteralValue.UInt;
}
else if (item.expr?.List) {
const result: any = findStxBootstrapAmountAtom(item.expr.List);
if (result !== null)
return result;
}
}
return null;
}
deployPlan()
.then(plan => Promise.all(plan.map(item => createMultisigDeployTransaction(item.contractName, item.codeBody, feeMultiplier, nonce++, pubKeys.length, pubKeys, network, address))))
.then(plan => plan.map(transaction => bytesToHex(addPubkeyFields(transaction, pubKeys).serialize())))
.then(async (plan) => {
const bootstrapStxAmount = await findStxBootstrapAmount();
if (bootstrapStxAmount === null)
throw new Error("Could not find stx-bootstrap-amount constant in boot contract");
verboseLog(`Boot contract STX bootstrap amount is ${bootstrapStxAmount}`);
const addressString = addressToString(address);
const tx = await createMultisigBootTransaction(
addressString,
"lisa-dao",
"construct",
[contractPrincipalCV(addressString, "lisa-dao"), standardPrincipalCV(addressString)],
feeMultiplier,
++nonce,
pubKeys.length,
pubKeys,
network,
address,
bootstrapStxAmount
);
plan.push(bytesToHex(addPubkeyFields(tx, pubKeys).serialize()));
return plan;
})
.then(plan => {
fs.writeFileSync(planFile, JSON.stringify(plan), "utf-8");
verboseLog(`Last nonce is ${nonce}`);
console.log(`Deploy plan written to ${planFile}`);
});

View File

@@ -0,0 +1,11 @@
import { AddressHashMode, AddressVersion, addressFromPublicKeys, addressToString, compressPublicKey, pubKeyfromPrivKey } from "@stacks/transactions";
import { loadConfig } from "./config.ts";
import { bytesToHex } from '@stacks/common';
const config = loadConfig();
const pubkeys = config.secrets.map(sk => compressPublicKey(pubKeyfromPrivKey(sk).data));
const multisigAddress = addressFromPublicKeys(AddressVersion.MainnetMultiSig, AddressHashMode.SerializeP2WSH, pubkeys.length, pubkeys);
console.log(pubkeys.map(pk => bytesToHex(pk.data)));
console.log(addressToString(multisigAddress));
console.log(multisigAddress);

View File

@@ -0,0 +1,93 @@
import {
TransactionSigner,
compressPublicKey,
pubKeyfromPrivKey,
MultiSigSpendingCondition,
deserializeTransaction,
StacksTransaction,
StacksPrivateKey,
StacksPublicKey,
Address,
// broadcastTransaction,
StacksMessageType,
} from "@stacks/transactions";
import { bytesToHex } from '@stacks/common';
import fs from "fs";
import { getStacksAddress, getStacksPrivateKeys, getStacksPubkeys } from "./config.ts";
import { assertSigner, equalByteArrays, readPlan, verboseLog } from "./utils.ts";
const planFile = "plan.json";
const privateKeys = getStacksPrivateKeys();
const address = getStacksAddress();
const pubKeys = getStacksPubkeys();
const pubKeysFromPrivate = privateKeys.map(sk => compressPublicKey(pubKeyfromPrivKey(sk.data).data));
function signTx(tx: StacksTransaction, privateKeys: StacksPrivateKey[], pubKeys: StacksPublicKey[], checkSigner: Address) {
const spendingCondition = tx.auth.spendingCondition as MultiSigSpendingCondition;
const signatureCount = spendingCondition.fields.reduce((sum, field) => sum + (field.contents.type === StacksMessageType.MessageSignature ? 1 : 0), 0);
if (signatureCount === spendingCondition.signaturesRequired) {
verboseLog(`Tried to sign tx ${tx.txid()} but it is already fully signed`);
return tx;
}
const signer = new TransactionSigner(tx);
const fields = spendingCondition.fields;
let signatures = 0;
for (let index = 0; index < fields.length; ++index) {
const field = fields[index];
if (field.contents.type !== StacksMessageType.PublicKey) {
++signatures;
continue;
}
const firstPubKey = field.contents.data as Uint8Array;
const matchingPubKeyIndex = pubKeysFromPrivate.findIndex(pubkey => equalByteArrays(pubkey.data, firstPubKey));
if (matchingPubKeyIndex === -1) {
verboseLog(`Next pubkey to sign tx ${tx.txid()} is ${bytesToHex(firstPubKey)}, but no private key is available for it. It is someone else's turn to sign.`);
break;
}
verboseLog(`Signing sighash ${tx.txid()} with key ${bytesToHex(pubKeysFromPrivate[matchingPubKeyIndex].data)}`);
// fields are always added to the end, so we have to remove it and manually move it to the right index
// we have to remove the old field first, otherwise signOrigin might fail if it gets more signatures than expected
fields.splice(index, 1);
signer.signOrigin(privateKeys[matchingPubKeyIndex]);
const newField = fields.pop()!;
fields.splice(index, 0, newField);
++signatures;
}
const fieldCount = (tx.auth.spendingCondition as MultiSigSpendingCondition).fields.length;
if (fieldCount !== pubKeys.length)
throw new Error(`Field count should be ${pubKeys.length} (num sigs + num unused pubkeys), but it is ${fieldCount}`);
assertSigner(tx.auth.spendingCondition, checkSigner);
if (signatures === spendingCondition.signaturesRequired)
verboseLog(`tx ${tx.txid()} is now fully signed`);
// try {
// const result = tx.verifyOrigin();
// console.log("verify origin", result);
// }
// catch (error) {
// console.error(error);
// throw new Error('Verify origin failed');
// }
return tx;
}
readPlan()
.then(plan => plan.map(tx => deserializeTransaction(tx)))
.then(plan => plan.map(tx => signTx(tx, privateKeys, pubKeys, address)))
.then(plan => {
fs.writeFileSync(planFile, JSON.stringify(plan.map(tx => bytesToHex(tx.serialize()))), "utf-8");
console.log(`Signed deploy plan written to ${planFile}`);
});

41
scripts/utils.ts Normal file
View File

@@ -0,0 +1,41 @@
import { Address, SpendingCondition, StacksPublicKey } from "@stacks/transactions";
import fs from "fs";
const verbose = true;
export const planFile = "plan.json";
export function verboseLog(...args: any[]) {
verbose && console.log.apply(null, args);
}
export function equalPubKeys(a: StacksPublicKey, b: StacksPublicKey) {
if (a.type !== b.type)
return false;
return equalByteArrays(a.data, b.data);
}
export function equalByteArrays(a: Uint8Array, b: Uint8Array) {
if (a.byteLength !== b.byteLength)
return false;
for (let i = 0; i < a.byteLength; ++i)
if (a[i] !== b[i])
return false;
return true;
}
export function assertSigner(spendingCondition: SpendingCondition, signer: Address) {
if (spendingCondition.signer !== signer.hash160)
throw new Error(`Signer mismatch, expected ${signer}, got ${spendingCondition.signer}`);
}
export async function readPlan() {
const content = await fs.promises.readFile(planFile, "utf-8");
const plan = JSON.parse(content);
if (plan.constructor !== Array)
throw new Error(`Plan corrupt, not an array`);
for (const entry of plan)
if (typeof entry !== "string")
throw new Error(`Plan corrupt, entry not a string: ${entry}`);
return plan;
}