mirror of
https://github.com/alexgo-io/stacks-pyth-bridge.git
synced 2026-01-12 22:43:42 +08:00
feat: init tests with clarinet sdk and vitest
This commit is contained in:
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,5 +1,4 @@
|
||||
|
||||
{
|
||||
"deno.enable": true,
|
||||
"files.eol": "\n"
|
||||
"deno.enable": false,
|
||||
"files.eol": "\n"
|
||||
}
|
||||
|
||||
1412
package-lock.json
generated
1412
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -7,18 +7,15 @@
|
||||
"test": "unit-tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node --test",
|
||||
"coverage": "rimraf ./lcov.info; node --test "
|
||||
"test": "vitest run -c ./node_modules/obscurity-sdk/vitest.config.js",
|
||||
"test:coverage": "vitest run -c ./node_modules/obscurity-sdk/vitest.config.js -- --clarity-coverage true"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@stacks/transactions": "^6.5.4",
|
||||
"obscurity-sdk": "^0.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.4",
|
||||
"rimraf": "^5.0.1"
|
||||
"obscurity-sdk": "^0.4.0-rc6",
|
||||
"vitest": "^0.34.1"
|
||||
}
|
||||
}
|
||||
|
||||
103
tests/helpers.ts
103
tests/helpers.ts
@@ -1,69 +1,56 @@
|
||||
import { Clarinet, Tx, Chain, Account, types } from 'https://deno.land/x/clarinet@v1.6.0/index.ts';
|
||||
import { assertEquals } from 'https://deno.land/std@0.170.0/testing/asserts.ts';
|
||||
import { Clarinet, Tx, Chain, Account, types } from "https://deno.land/x/clarinet@v1.6.0/index.ts";
|
||||
import { assertEquals } from "https://deno.land/std@0.170.0/testing/asserts.ts";
|
||||
import { hexToBuffer } from "https://deno.land/x/hextools@v1.0.0/mod.ts";
|
||||
import { mainnet_valid_guardians_set_upgrades } from "./constants.ts";
|
||||
|
||||
export const executeGuardiansRotations = (chain: Chain, account: Account) => {
|
||||
const vaaRotation1 = hexToBuffer(mainnet_valid_guardians_set_upgrades[0].vaa);
|
||||
let publicKeysRotation1 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[0].keys) {
|
||||
publicKeysRotation1.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
const vaaRotation1 = hexToBuffer(mainnet_valid_guardians_set_upgrades[0].vaa);
|
||||
let publicKeysRotation1 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[0].keys) {
|
||||
publicKeysRotation1.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
|
||||
const vaaRotation2 = hexToBuffer(mainnet_valid_guardians_set_upgrades[1].vaa);
|
||||
let publicKeysRotation2 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[1].keys) {
|
||||
publicKeysRotation2.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
const vaaRotation2 = hexToBuffer(mainnet_valid_guardians_set_upgrades[1].vaa);
|
||||
let publicKeysRotation2 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[1].keys) {
|
||||
publicKeysRotation2.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
|
||||
const vaaRotation3 = hexToBuffer(mainnet_valid_guardians_set_upgrades[2].vaa);
|
||||
let publicKeysRotation3 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[2].keys) {
|
||||
publicKeysRotation3.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
const vaaRotation3 = hexToBuffer(mainnet_valid_guardians_set_upgrades[2].vaa);
|
||||
let publicKeysRotation3 = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[2].keys) {
|
||||
publicKeysRotation3.push(types.buff(hexToBuffer(key)));
|
||||
}
|
||||
|
||||
let block = chain.mineBlock([
|
||||
Tx.contractCall(
|
||||
"wormhole-core-v1",
|
||||
"update-guardians-set",
|
||||
[
|
||||
types.buff(vaaRotation1),
|
||||
types.list(
|
||||
publicKeysRotation1
|
||||
)
|
||||
],
|
||||
account.address),
|
||||
Tx.contractCall(
|
||||
"wormhole-core-v1",
|
||||
"update-guardians-set",
|
||||
[
|
||||
types.buff(vaaRotation2),
|
||||
types.list(
|
||||
publicKeysRotation2
|
||||
)
|
||||
],
|
||||
account.address),
|
||||
Tx.contractCall(
|
||||
"wormhole-core-v1",
|
||||
"update-guardians-set",
|
||||
[
|
||||
types.buff(vaaRotation3),
|
||||
types.list(
|
||||
publicKeysRotation3
|
||||
)
|
||||
],
|
||||
account.address),
|
||||
]);
|
||||
let block = chain.mineBlock([
|
||||
Tx.contractCall(
|
||||
"wormhole-core-dev-preview-1",
|
||||
"update-guardians-set",
|
||||
[types.buff(vaaRotation1), types.list(publicKeysRotation1)],
|
||||
account.address
|
||||
),
|
||||
Tx.contractCall(
|
||||
"wormhole-core-dev-preview-1",
|
||||
"update-guardians-set",
|
||||
[types.buff(vaaRotation2), types.list(publicKeysRotation2)],
|
||||
account.address
|
||||
),
|
||||
Tx.contractCall(
|
||||
"wormhole-core-dev-preview-1",
|
||||
"update-guardians-set",
|
||||
[types.buff(vaaRotation3), types.list(publicKeysRotation3)],
|
||||
account.address
|
||||
),
|
||||
]);
|
||||
|
||||
// assert: review returned data, contract state, and other requirements
|
||||
assertEquals(block.receipts.length, 3);
|
||||
const rotation1 = block.receipts[0].result;
|
||||
rotation1.expectOk()
|
||||
// assert: review returned data, contract state, and other requirements
|
||||
assertEquals(block.receipts.length, 3);
|
||||
const rotation1 = block.receipts[0].result;
|
||||
rotation1.expectOk();
|
||||
|
||||
const rotation2 = block.receipts[1].result;
|
||||
rotation2.expectOk()
|
||||
const rotation2 = block.receipts[1].result;
|
||||
rotation2.expectOk();
|
||||
|
||||
const rotation3 = block.receipts[2].result;
|
||||
rotation3.expectOk()
|
||||
const rotation3 = block.receipts[2].result;
|
||||
rotation3.expectOk();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,57 +1,61 @@
|
||||
|
||||
import { Clarinet, Tx, Chain, Account, types } from 'https://deno.land/x/clarinet@v1.6.0/index.ts';
|
||||
import { assertEquals, assertObjectMatch, assertArrayIncludes } from 'https://deno.land/std@0.170.0/testing/asserts.ts';
|
||||
import { Clarinet, Tx, Chain, Account, types } from "https://deno.land/x/clarinet@v1.6.0/index.ts";
|
||||
import {
|
||||
assertEquals,
|
||||
assertObjectMatch,
|
||||
assertArrayIncludes,
|
||||
} from "https://deno.land/std@0.170.0/testing/asserts.ts";
|
||||
import { hexToBuffer } from "https://deno.land/x/hextools@v1.0.0/mod.ts";
|
||||
|
||||
import { mainnet_valid_pfs } from "./constants.ts";
|
||||
import { executeGuardiansRotations } from "./helpers.ts";
|
||||
|
||||
Clarinet.test({
|
||||
name: "Ensure that valid price attestations can be ingested and recorded",
|
||||
fn(chain: Chain, accounts: Map<string, Account>) {
|
||||
// arrange: set up the chain, state, and other required elements
|
||||
const wallet_1 = accounts.get("wallet_1")!;
|
||||
executeGuardiansRotations(chain, wallet_1);
|
||||
name: "Ensure that valid price attestations can be ingested and recorded",
|
||||
fn(chain: Chain, accounts: Map<string, Account>) {
|
||||
// arrange: set up the chain, state, and other required elements
|
||||
const wallet_1 = accounts.get("wallet_1")!;
|
||||
executeGuardiansRotations(chain, wallet_1);
|
||||
|
||||
const vaaBytes = hexToBuffer(mainnet_valid_pfs[0]);
|
||||
const vaaBytes = hexToBuffer(mainnet_valid_pfs[0]);
|
||||
|
||||
const block = chain.mineBlock([
|
||||
Tx.contractCall(
|
||||
"pyth-oracle-v1",
|
||||
"update-prices-feeds",
|
||||
[
|
||||
types.list([types.buff(vaaBytes)])
|
||||
],
|
||||
wallet_1.address)
|
||||
]);
|
||||
const block = chain.mineBlock([
|
||||
Tx.contractCall(
|
||||
"pyth-oracle-dev-preview-1",
|
||||
"update-prices-feeds",
|
||||
[types.list([types.buff(vaaBytes)])],
|
||||
wallet_1.address
|
||||
),
|
||||
]);
|
||||
|
||||
assertEquals(block.receipts.length, 1);
|
||||
assertEquals(block.height, 3);
|
||||
const priceUpdate = block.receipts[0].result;
|
||||
// Ensure that the BTC_USD price feed id was the only updated feed
|
||||
assertArrayIncludes(priceUpdate.expectOk().expectList(),
|
||||
["0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"]
|
||||
);
|
||||
assertEquals(block.receipts.length, 1);
|
||||
assertEquals(block.height, 3);
|
||||
const priceUpdate = block.receipts[0].result;
|
||||
// Ensure that the BTC_USD price feed id was the only updated feed
|
||||
assertArrayIncludes(priceUpdate.expectOk().expectList(), [
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
|
||||
]);
|
||||
|
||||
const feedIdBtcUsd = hexToBuffer("0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43");
|
||||
const oracleResult = chain.callReadOnlyFn(
|
||||
"pyth-oracle-v1",
|
||||
"read-price-feed",
|
||||
[types.buff(feedIdBtcUsd)],
|
||||
wallet_1.address
|
||||
);
|
||||
assertObjectMatch(oracleResult.result.expectOk().expectTuple(), {
|
||||
"attestation-time": "u1686854317",
|
||||
"conf": "u2064471426",
|
||||
"ema-conf": "u1891952230",
|
||||
"ema-price": "2507095440000",
|
||||
"expo": "4294967288",
|
||||
"prev-conf": "u2064471426",
|
||||
"prev-price": "2515455528574",
|
||||
"prev-publish-time": "u1686854316",
|
||||
"price": "2515455528574",
|
||||
"publish-time": "u1686854317",
|
||||
"status": "u1"
|
||||
});
|
||||
},
|
||||
const feedIdBtcUsd = hexToBuffer(
|
||||
"0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
|
||||
);
|
||||
const oracleResult = chain.callReadOnlyFn(
|
||||
"pyth-oracle-dev-preview-1",
|
||||
"read-price-feed",
|
||||
[types.buff(feedIdBtcUsd)],
|
||||
wallet_1.address
|
||||
);
|
||||
assertObjectMatch(oracleResult.result.expectOk().expectTuple(), {
|
||||
"attestation-time": "u1686854317",
|
||||
conf: "u2064471426",
|
||||
"ema-conf": "u1891952230",
|
||||
"ema-price": "2507095440000",
|
||||
expo: "4294967288",
|
||||
"prev-conf": "u2064471426",
|
||||
"prev-price": "2515455528574",
|
||||
"prev-publish-time": "u1686854316",
|
||||
price: "2515455528574",
|
||||
"publish-time": "u1686854317",
|
||||
status: "u1",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ESNext"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["unit-tests"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import initVM from "obscurity-sdk";
|
||||
|
||||
let deployer;
|
||||
let sender;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {(vm: import("obscurity-sdk").ClarityVM) => any} fn
|
||||
*/
|
||||
export async function clarinetTest(name, fn) {
|
||||
const vm = await initVM();
|
||||
await vm.initSession(process.cwd(), "./Clarinet.toml");
|
||||
|
||||
const accounts = vm.getAccounts();
|
||||
deployer = accounts.get("deployer");
|
||||
sender = accounts.get("wallet_1");
|
||||
|
||||
fn(vm);
|
||||
|
||||
const lcov = vm.terminate();
|
||||
fs.appendFileSync(path.join(process.cwd(), "lcov.info"), lcov);
|
||||
}
|
||||
@@ -1,36 +1,31 @@
|
||||
// @ts-check
|
||||
|
||||
import { it } from "node:test";
|
||||
import { Cl } from "@stacks/transactions";
|
||||
import { mainnet_valid_guardians_set_upgrades, mainnet_valid_pfs } from "./constants.js";
|
||||
import { clarinetTest } from "./clarinetTest.js";
|
||||
import { Cl, ClarityValue } from "@stacks/transactions";
|
||||
import { describe, it } from "vitest";
|
||||
import { mainnet_valid_guardians_set_upgrades, mainnet_valid_pfs } from "./constants";
|
||||
|
||||
const pyth_oracle_v1_contract_name = "pyth-oracle-v1";
|
||||
const wormhole_core_v1_contract_name = "wormhole-core-v1";
|
||||
const pyth_oracle_v1_contract_name = "pyth-oracle-dev-preview-1";
|
||||
const wormhole_core_v1_contract_name = "wormhole-core-dev-preview-1";
|
||||
|
||||
clarinetTest("Pyth testsuite", (vm) => {
|
||||
describe("Pyth testsuite", () => {
|
||||
const accounts = vm.getAccounts();
|
||||
const deployer = accounts.get("deployer");
|
||||
const pyth_oracle_v1_contract_addr = `${deployer}.${pyth_oracle_v1_contract_name}`;
|
||||
const wormhole_core_v1_contract_addr = `${deployer}.${wormhole_core_v1_contract_name}`;
|
||||
const sender = accounts.get("wallet_1");
|
||||
if (!sender) throw new Error("invalid account");
|
||||
const sender = accounts.get("wallet_1")!;
|
||||
|
||||
it("ensure that legitimate price attestations are validated", () => {
|
||||
const vaaRotation1 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[0].vaa);
|
||||
let publicKeysRotation1 = [];
|
||||
let publicKeysRotation1: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[0].keys) {
|
||||
publicKeysRotation1.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
|
||||
const vaaRotation2 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[1].vaa);
|
||||
let publicKeysRotation2 = [];
|
||||
let publicKeysRotation2: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[1].keys) {
|
||||
publicKeysRotation2.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
|
||||
const vaaRotation3 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[2].vaa);
|
||||
let publicKeysRotation3 = [];
|
||||
let publicKeysRotation3: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[2].keys) {
|
||||
publicKeysRotation3.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
5
unit-tests/types/global.d.ts
vendored
Normal file
5
unit-tests/types/global.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { ClarityVM } from "obscurity-sdk";
|
||||
declare global {
|
||||
var vm: ClarityVM;
|
||||
}
|
||||
export {};
|
||||
@@ -1,37 +1,31 @@
|
||||
// @ts-check
|
||||
|
||||
import { it } from "node:test";
|
||||
import { Cl, ClarityValue } from "@stacks/transactions";
|
||||
import { describe, it } from "vitest";
|
||||
|
||||
import { Cl } from "@stacks/transactions";
|
||||
import { mainnet_valid_guardians_set_upgrades } from "./constants.js";
|
||||
import { clarinetTest } from "./clarinetTest.js";
|
||||
import { mainnet_valid_guardians_set_upgrades } from "./constants";
|
||||
|
||||
const pyth_oracle_v1_contract_name = "pyth-oracle-v1";
|
||||
const wormhole_core_v1_contract_name = "wormhole-core-v1";
|
||||
const wormhole_core_v1_contract_name = "wormhole-core-dev-preview-1";
|
||||
|
||||
clarinetTest("Wormhole testsuite", (vm) => {
|
||||
describe("Wormhole testsuite", () => {
|
||||
const accounts = vm.getAccounts();
|
||||
const deployer = accounts.get("deployer");
|
||||
const pyth_oracle_v1_contract_addr = `${deployer}.${pyth_oracle_v1_contract_name}`;
|
||||
const wormhole_core_v1_contract_addr = `${deployer}.${wormhole_core_v1_contract_name}`;
|
||||
const sender = accounts.get("wallet_1");
|
||||
if (!sender) throw new Error("invalid account");
|
||||
const sender = accounts.get("wallet_1")!;
|
||||
|
||||
it("ensure that guardians set can be rotated", () => {
|
||||
const vaaRotation1 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[0].vaa);
|
||||
let publicKeysRotation1 = [];
|
||||
let publicKeysRotation1: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[0].keys) {
|
||||
publicKeysRotation1.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
|
||||
const vaaRotation2 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[1].vaa);
|
||||
let publicKeysRotation2 = [];
|
||||
let publicKeysRotation2: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[1].keys) {
|
||||
publicKeysRotation2.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
|
||||
const vaaRotation3 = Cl.bufferFromHex(mainnet_valid_guardians_set_upgrades[2].vaa);
|
||||
let publicKeysRotation3 = [];
|
||||
let publicKeysRotation3: ClarityValue[] = [];
|
||||
for (let key of mainnet_valid_guardians_set_upgrades[2].keys) {
|
||||
publicKeysRotation3.push(Cl.bufferFromHex(key));
|
||||
}
|
||||
Reference in New Issue
Block a user