Skip to content

Commit

Permalink
First version of SDK and CLI for config and bond accounts (#9)
Browse files Browse the repository at this point in the history
* [package.json] engine to nodejs 16 to fix lint error

* Testing added

staking

stake merge experiments

playing with stake accounts

sucessful merge

vote account creation

lockup merging

stake merging

next experiments with stake accounts

testing delegation and further

let' check merging of delegated stuff

finalization of merge testing

splitting merge testing

fixing localhost stuff on test

swithcing for pubkeys that with ownership of keys

config

continue with sdk

checking merge stuff

stake testing

next stuff

deposit bonds

next to merge sdk

sdk

orchestrating withdraw request

orchestrate stuff

basic testing for config state

test for configure config

event test for configure config

tessts

init bonds tests and fixing deserialization in program

* init bond test + semi check off

* init bond + configure bond test fixes

* configure bonds tests in bankrun

adding a test for fund bond

starting with a test for merge

[contract] changing the error handling per how anchor error class works

merge tests

[contract] disabling settlement instructions

merge stuff

[contract] adding TODO on checking activation for funding

cli for init and configure config

fixes

merge tests

cli config configure test

adding init bond cli + refactor test init config

cli tests in progress

config configure test cli

test with init bonds on cli

* adding cli test for init bond command

* [cli] adding init bond cli tests

* [cli] adding configure bond command

* fixing tests to run

* [readme] adding readme for programs

* [cli] show command for bond account

* [changelog] the file added with release 1.0.0

* [readme] small update
  • Loading branch information
ochaloup committed Dec 30, 2023
1 parent a72fa1b commit 1970224
Show file tree
Hide file tree
Showing 67 changed files with 6,520 additions and 341 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"semi": ["error", "never"],
"node/no-extraneous-import": ["error", {
"allowModules": ["@marinade.finance/jest-utils"]
}]
}],
"@typescript-eslint/no-extra-semi" : "off"
},
"settings": {
"node": {
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [1.0.0](https://github.com/marinade-finance/validator-bonds/compare/v1.0.0) (2023-12-31)


### Features

* SDK and CLI with init, configure and show `Config` and `Bond` accounts
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,43 @@ pnpm install
# building Anchor program + cli and sdk TS packages
pnpm build

# testing the SDK+CLI against the local validator running the program
# testing the SDK+CLI against the bankrun and local validator
pnpm test
# bankrun part of the tests
pnpm test:bankrun
# local validator part of the tests
pnpm test:validator
# cargo tests in rust code
pnpm test:cargo
```

### Contract deployment

```sh
anchor build --verifiable

# deploy
solana program deploy -v -ud \
--program-id vBoNdEvzMrSai7is21XgVYik65mqtaKXuSdMBJ1xkW4 \
-k [fee-payer-keypair]
--upgrade-authority [path-to-keypair] \
./target/verifiable/validator_bonds.so

# upgrade with SPL Gov authority (generic MNDE realm upgrade authority, governance 7iUtT...wtBZY)
solana -ud program write-buffer target/verifiable/validator_bonds.so
solana program set-buffer-authority --new-buffer-authority 6YAju4nd4t7kyuHV6NvVpMepMk11DgWyYjKVJUak2EEm <BUFFER_PUBKEY>

# publish IDL (account Du3XrzTNqhLt9gpui9LUogrLqCDrVC2HrtiNXHSJM58y)
anchor --provider.cluster devnet idl \
# init vBoNdEvzMrSai7is21XgVYik65mqtaKXuSdMBJ1xkW4 \
upgrade vBoNdEvzMrSai7is21XgVYik65mqtaKXuSdMBJ1xkW4 \
-f ./target/idl/validator_bonds.json

# check verifiable deployment (<BUFFER_PUBKEY> can be verified as well)
anchor --provider.cluster devnet \
verify -p validator_bonds \
vBoNdEvzMrSai7is21XgVYik65mqtaKXuSdMBJ1xkW4
```

// TODO: add table of authorities - what state means what authority
// TODO: add flow diagram how calls will be done
3 changes: 3 additions & 0 deletions Test.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
# recursive call: pnpm test -> anchor test -> pnpm _test
# using solana-bankrun for testing (--runInBand is needed, see https://github.com/kevinheavey/solana-bankrun/issues/2)
test = "pnpm _test"

[test.validator]
slots_per_epoch = "32"
5 changes: 2 additions & 3 deletions jest.config.bankrun.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
modulePathIgnorePatterns: ['<rootDir>/build/'],
testRegex: ['__tests__/bankrun/.*.spec.ts'],
testPathIgnorePatterns: ['.*utils.*'],
testRegex: ['__tests__/bankrun/.*'],
// globalSetup: // TODO: uncomment or remove
// '<rootDir>/packages/validator-bonds-sdk/__tests__/setup/globalSetup.ts'
setupFilesAfterEnv: [
// https://github.com/marinade-finance/marinade-ts-cli/blob/main/packages/lib/jest-utils/src/equalityTesters.ts
'<rootDir>/node_modules/@marinade.finance/jest-utils/src/equalityTesters',
],
}
3 changes: 2 additions & 1 deletion jest.config.test-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
modulePathIgnorePatterns: ['<rootDir>/build/'],
testRegex: ['__tests__/test-validator/.*'],
testRegex: ['__tests__/test-validator/.*.spec.ts'],
testPathIgnorePatterns: ['.*utils.*'],
testTimeout: 120000,
detectOpenHandles: true,
setupFilesAfterEnv: [
/// https://github.com/marinade-finance/marinade-ts-cli/blob/main/packages/lib/jest-utils/src/equalityTesters.ts
'<rootDir>/node_modules/@marinade.finance/jest-utils/src/equalityTesters',
],
}
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"compile": "pnpm anchor:build && tsc --project tsconfig.build.json",
"build": "pnpm compile",
"_test": "pnpm jest --config jest.config.test-validator.js -- \"$FILE\"",
"test:test-validator": "BROWSER= anchor test",
"test:validator": "anchor test",
"test:bankrun": "pnpm jest --config jest.config.bankrun.js --runInBand true -- \"$FILE\"",
"test:cargo": "cargo test --features no-entrypoint",
"test": "pnpm test:cargo && pnpm test:bankrun && pnpm test:test-validator",
"test": "pnpm test:cargo && pnpm test:bankrun && pnpm test:validator",
"cli": "ts-node ./packages/validator-bonds-cli/src/",
"lint:cargo": "cargo fmt -- --check && cargo clippy",
"lint:cargo-fix": "cargo fmt --all && cargo clippy --fix --allow-staged --allow-dirty",
Expand All @@ -17,7 +17,9 @@
"lint:ts-clean": "gts clean",
"lint:fix": "pnpm lint:ts-fix && pnpm lint:cargo-fix",
"lint": "pnpm lint:cargo && pnpm lint:ts",
"publish-sdk": "pnpm build && pnpm publish build/packages/validator-bonds-sdk"
"publish-sdk": "pnpm build && pnpm publish build/packages/validator-bonds-sdk",
"publish-cli": "pnpm build && pnpm publish build/packages/validator-bonds-cli",
"publish": "pnpm publish-sdk && pnpm publish-cli"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
Expand All @@ -29,7 +31,7 @@
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "4.9.5",
"@marinade.finance/jest-utils": "^2.0.18"
"@marinade.finance/jest-utils": "^2.0.20"
},
"pnpm": {
"peerDependencyRules": {
Expand Down
72 changes: 72 additions & 0 deletions packages/validator-bonds-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Validator Bonds CLI

CLI for Validator Bonds contract.

## Working with CLI

To install the CLI as global npm package

```bash
npm i -g @marinade.finance/validator-bonds-cli
validator-bonds --help
```

### Creating a bond

Any validator may create a bond account to protect the processing.
The bond account is bound to a validator vote account.

```sh
# bond account at mainnet
validator-bonds -um init-bond -k <fee-payer-keypair> \
--vote-account <vote-account-pubkey> --vote-account-withdrawer <vote-account-withdrawer-keypair> \
--bond-authority <authority-on-bond-account-pubkey> --rent-payer <rent-payer-account-keypair>

# to configure bond account properties
validator-bonds -um configure-bond --help
```

### Show the bond account

```sh
validator-bonds -um show-bond <bond-account-address> -f yaml
```



## `validator-bonds --help`

```sh
pnpm cli --help

> @ cli /home/chalda/marinade/validator-bonds
> ts-node ./packages/validator-bonds-cli/src/ "--help"

Usage: src [options] [command]

Options:
-V, --version output the version number
-u, --cluster <cluster> solana cluster URL, accepts shortcuts (d/devnet, m/mainnet) (default: "http://127.0.0.1:8899")
-c <cluster> alias for "-u, --cluster"
--commitment <commitment> Commitment (default: "confirmed")
-k, --keypair <keypair-or-ledger> Wallet keypair (path or ledger url in format usb://ledger/[<pubkey>][?key=<derivedPath>]) (default: ~/.config/solana/id.json)
--program-id <pubkey> Program id of validator bonds contract (default: vBoNdEvzMrSai7is21XgVYik65mqtaKXuSdMBJ1xkW4)
-s, --simulate Simulate (default: false)
-p, --print-only Print only mode, no execution, instructions are printed in base64 to output. This can be used for placing the admin commands to SPL
Governance UI by hand. (default: false)
--skip-preflight transaction execution flag "skip-preflight", see https://solanacookbook.com/guides/retrying-transactions.html#the-cost-of-skipping-preflight
(default: false)
-d, --debug printing more detailed information of the CLI execution (default: false)
-v, --verbose alias for --debug (default: false)
-h, --help display help for command

Commands:
init-config [options] Create a new config account.
configure-config [options] [config-account-address] Configure existing config account.
init-bond [options] Create a new bond account.
configure-bond [options] [bond-account-address] Configure existing bond account.
show-config [options] [address] Showing data of config account(s)
show-event [options] <event-data> Showing data of anchor event
show-bond [options] [address] Showing data of bond account(s)
help [command] display help for command
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { createTempFileKeypair } from '@marinade.finance/web3js-common'
import { shellMatchers } from '@marinade.finance/jest-utils'
import { Keypair, PublicKey } from '@solana/web3.js'
import {
ValidatorBondsProgram,
bondAddress,
getBond,
} from '@marinade.finance/validator-bonds-sdk'
import {
executeInitBondInstruction,
executeInitConfigInstruction,
} from '@marinade.finance/validator-bonds-sdk/__tests__/utils/testTransactions'
import {
AnchorExtendedProvider,
initTest,
} from '@marinade.finance/validator-bonds-sdk/__tests__/test-validator/testValidator'
import { createVoteAccount } from '@marinade.finance/validator-bonds-sdk/__tests__/utils/staking'

describe('Configure bond account using CLI', () => {
let provider: AnchorExtendedProvider
let program: ValidatorBondsProgram
let voteWithdrawerPath: string
let voteWithdrawerKeypair: Keypair
let voteWithdrawerCleanup: () => Promise<void>
let bondAuthorityPath: string
let bondAuthorityKeypair: Keypair
let bondAuthorityCleanup: () => Promise<void>
let configAccount: PublicKey
let bondAccount: PublicKey
let voteAccount: PublicKey

beforeAll(async () => {
shellMatchers()
;({ provider, program } = await initTest())
})

beforeEach(async () => {
;({
path: voteWithdrawerPath,
keypair: voteWithdrawerKeypair,
cleanup: voteWithdrawerCleanup,
} = await createTempFileKeypair())
;({
path: bondAuthorityPath,
keypair: bondAuthorityKeypair,
cleanup: bondAuthorityCleanup,
} = await createTempFileKeypair())
;({ configAccount } = await executeInitConfigInstruction({
program,
provider,
epochsToClaimSettlement: 1,
withdrawLockupEpochs: 2,
}))
expect(
provider.connection.getAccountInfo(configAccount)
).resolves.not.toBeNull()
;({ voteAccount } = await createVoteAccount(
provider,
undefined,
undefined,
voteWithdrawerKeypair
))
;({ bondAccount } = await executeInitBondInstruction(
program,
provider,
configAccount,
bondAuthorityKeypair,
voteAccount,
voteWithdrawerKeypair,
33
))
})

afterEach(async () => {
await bondAuthorityCleanup()
await voteWithdrawerCleanup()
})

it('configure bond account', async () => {
await (
expect([
'pnpm',
[
'cli',
'-u',
provider.connection.rpcEndpoint,
'--program-id',
program.programId.toBase58(),
'configure-bond',
bondAccount.toBase58(),
'--authority',
bondAuthorityPath,
'--revenue-share',
'42',
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any
).toHaveMatchingSpawnOutput({
code: 0,
// stderr: '',
stdout: /Bond account.*successfully configured/,
})

const [, bump] = bondAddress(configAccount, voteAccount, program.programId)
const bondsData1 = await getBond(program, bondAccount)
expect(bondsData1.config).toEqual(configAccount)
expect(bondsData1.validatorVoteAccount).toEqual(voteAccount)
expect(bondsData1.authority).toEqual(bondAuthorityKeypair.publicKey)
expect(bondsData1.revenueShare.hundredthBps).toEqual(42 * 10 ** 4)
expect(bondsData1.bump).toEqual(bump)

const newBondAuthority = PublicKey.unique()
await (
expect([
'pnpm',
[
'cli',
'-u',
provider.connection.rpcEndpoint,
'--program-id',
program.programId.toBase58(),
'configure-bond',
'--config',
configAccount.toBase58(),
'--vote-account',
voteAccount.toBase58(),
'--authority',
voteWithdrawerPath,
'--bond-authority',
newBondAuthority.toBase58(),
'--revenue-share',
43,
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any
).toHaveMatchingSpawnOutput({
code: 0,
// stderr: '',
stdout: /Bond account.*successfully configured/,
})

const bondsData2 = await getBond(program, bondAccount)
expect(bondsData2.authority).toEqual(newBondAuthority)
expect(bondsData2.revenueShare.hundredthBps).toEqual(43 * 10 ** 4)
})

it('configure bond in print-only mode', async () => {
await (
expect([
'pnpm',
[
'cli',
'-u',
provider.connection.rpcEndpoint,
'--program-id',
program.programId.toBase58(),
'configure-bond',
bondAccount.toBase58(),
'--authority',
bondAuthorityKeypair.publicKey.toBase58(),
'--bond-authority',
PublicKey.unique().toBase58(),
'--print-only',
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any
).toHaveMatchingSpawnOutput({
code: 0,
// stderr: '',
stdout: /successfully configured/,
})

expect((await getBond(program, bondAccount)).authority).toEqual(
bondAuthorityKeypair.publicKey
)
})
})
Loading

0 comments on commit 1970224

Please sign in to comment.