Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ vaultHistory.json
*.txt
dist
test*.ts
!test/test_smoke.ts
install-state.gz
.yarn
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,22 @@
"resolutions": {
"@mysten/sui": "^1.30.0"
},
"overrides": {
"@mysten/kiosk": {
"@mysten/sui": "^1.30.0"
}
},
"devDependencies": {
"@types/camelcase-keys-deep": "^0.1.2",
"@types/crypto-js": "^4.2.2",
"@types/mocha": "^10.0.6",
"@types/node-rsa": "^1.1.4",
"mocha": "^10.4.0",
"prettier": "^3.0.0",
"rimraf": "^5.0.5",
"slack": "^11.0.2",
"tsc-alias": "^1.8.10",
"ts-mocha": "^10.0.0",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.6"
},
Expand All @@ -38,8 +47,8 @@
"dist"
],
"scripts": {
"build": "rm -rf dist && tsc -p tsconfig.build.json && tsc-alias",
"test": "rm -rf dist && tsc -p tsconfig.build.json && ts-mocha test/test*.ts",
"build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias",
"test": "tsc -p tsconfig.build.json && ts-mocha -r tsconfig-paths/register -p tsconfig.json \"test/test*.ts\"",
"publish": "yarn build && npm publish"
},
"repository": {
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from "./load_env";
export * from "./mint";
export * from "./tools";
export * from "./typusConfig";
export * from "./typusConfigBranch";
export * from "./oracle";
6 changes: 5 additions & 1 deletion src/utils/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export async function updateOracleWithSignatureTx(

let oracleData: Omit<TypusOracleData, "success"> | null = null;
try {
const result = await axios.get<TypusOracleData>(`https://asia-east1-aqueous-freedom-378103.cloudfunctions.net/get-price?pair=${tokenType}`)
const pair = encodeURIComponent(tokenType);
const result = await axios.get<TypusOracleData>(
`https://asia-east1-aqueous-freedom-378103.cloudfunctions.net/get-price?pair=${pair}`,
{ timeout: 30_000 }
);
if (result.data) {
oracleData = parseFullTypusOracleData(result.data);
}
Expand Down
20 changes: 14 additions & 6 deletions src/utils/typusConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import camelcaseKeysDeep from "camelcase-keys-deep";
import * as fs from "fs";
import { assertSafeTypusConfigBranch } from "src/utils/typusConfigBranch";

export class TypusConfig {
network: "MAINNET" | "TESTNET";
Expand All @@ -18,14 +19,18 @@ export class TypusConfig {
return TypusConfig.parse(JSON.parse(fs.readFileSync(path, "utf-8")));
}
static async default(network: "MAINNET" | "TESTNET", customRpcEndpoint: string | null, branch = "main"): Promise<TypusConfig> {
assertSafeTypusConfigBranch(branch);
switch (network) {
case "MAINNET": {
const url = `https://raw.githubusercontent.com/Typus-Lab/typus-config/${branch}/config-mainnet.json`;
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to load typus mainnet config: HTTP ${res.status} ${url}`);
}
let typusConfig = JSON.parse(
JSON.stringify(
camelcaseKeysDeep(
await (
await fetch(`https://raw.githubusercontent.com/Typus-Lab/typus-config/${branch}/config-mainnet.json`)
).json()
await res.json()
)
)
);
Expand All @@ -35,12 +40,15 @@ export class TypusConfig {
return typusConfig;
}
case "TESTNET": {
const url = `https://raw.githubusercontent.com/Typus-Lab/typus-config/${branch}/config-testnet.json`;
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to load typus testnet config: HTTP ${res.status} ${url}`);
}
let typusConfig = JSON.parse(
JSON.stringify(
camelcaseKeysDeep(
await (
await fetch(`https://raw.githubusercontent.com/Typus-Lab/typus-config/${branch}/config-testnet.json`)
).json()
await res.json()
)
)
);
Expand Down
15 changes: 15 additions & 0 deletions src/utils/typusConfigBranch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* GitHub raw URLs embed `branch` in the path; reject values that could alter
* the request (path traversal, odd encodings) or are implausibly long.
*/
export function assertSafeTypusConfigBranch(branch: string): void {
if (!branch || branch.length > 256) {
throw new Error("typus-config branch must be a non-empty string at most 256 characters");
}
if (branch.includes("..") || branch.includes("%")) {
throw new Error("typus-config branch contains invalid characters");
}
if (!/^[a-zA-Z0-9/_.-]+$/.test(branch)) {
throw new Error("typus-config branch must match git ref characters (alphanumeric, /, _, ., -)");
}
}
39 changes: 39 additions & 0 deletions test/test_smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import assert from "assert";
import { assertSafeTypusConfigBranch } from "src/utils/typusConfigBranch";
import { parseFullTypusOracleData, type TypusOracleData } from "src/utils/oracle";

describe("typus-config branch validation", () => {
it("accepts normal branch names", () => {
assertSafeTypusConfigBranch("main");
assertSafeTypusConfigBranch("release/1.2");
});

it("rejects path traversal and encoded slashes", () => {
assert.throws(() => assertSafeTypusConfigBranch("main/../other"), /invalid/);
assert.throws(() => assertSafeTypusConfigBranch("x%2fy"), /invalid/);
});
});

describe("oracle payload parsing", () => {
it("returns parsed data when success is true", () => {
const raw: TypusOracleData = {
success: true,
data: {
price: "1",
volume: "1",
server_ts_ms: 0,
local_ts_ms: 0,
twap: "1",
},
signed: { pair: "p", price: "1", twap: "1", timestamp: 1, signature: "0x" },
};
const out = parseFullTypusOracleData(raw);
assert.ok(out);
assert.strictEqual(out?.signed.pair, "p");
});

it("returns null when success is false", () => {
const raw = { success: false } as TypusOracleData;
assert.strictEqual(parseFullTypusOracleData(raw), null);
});
});
4 changes: 3 additions & 1 deletion tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
"rootDir": "." /* Specify the root folder within your source files. */,
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
"baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
"paths": {} /* Specify a set of entries that re-map imports to additional lookup locations. */,
"paths": {
"src/*": ["src/*"]
} /* Specify a set of entries that re-map imports to additional lookup locations. */,
"rootDirs": ["src"] /* Allow multiple folders to be treated as one when resolving modules. */,
// "types": ["node", "mocha"],
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
Expand Down
Loading