Skip to content

Commit 9fbc606

Browse files
Merge pull request #394 from LIT-Protocol/feat/hyperliquid-ability
Feat: Init HyperLiquid Ability
2 parents a3bfd12 + 3f75831 commit 9fbc606

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+8153
-10
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ YELLOWSTONE_RPC_URL=https://yellowstone-rpc.litprotocol.com/
77
BASE_RPC_URL=
88
ETH_RPC_URL=
99
SOL_RPC_URL=
10+
ARBITRUM_RPC_URL=
1011

1112
TEST_FUNDER_PRIVATE_KEY=
1213
TEST_SOLANA_FUNDER_PRIVATE_KEY=
14+
1315
TEST_APP_MANAGER_PRIVATE_KEY=
1416
TEST_APP_DELEGATEE_PRIVATE_KEY=
1517
TEST_AGENT_WALLET_PKP_OWNER_PRIVATE_KEY=
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
ability-hyperliquid: major
3+
---
4+
5+
Initialize first version of the HyperLiquid Vincent Ability that allows for making spot buy and sell orders, perp longs and shorts, as well as deposits into the HyperLiquid bridge contract to open a HyperLiquid master account for a Vincent Agent Wallet.

nx.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"ability-debridge",
7070
"policy-send-counter",
7171
"ability-aerodrome-swap",
72+
"ability-hyperliquid",
7273
"e2e-test-utils"
7374
],
7475
"projectsRelationship": "independent",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Specifying this ENV in the root of the monorepo to reuse across Abilities will also work
2+
PINATA_JWT=
3+
4+
ARBITRUM_RPC_URL=
5+
6+
TEST_FUNDER_PRIVATE_KEY=
7+
8+
TEST_APP_MANAGER_PRIVATE_KEY=
9+
10+
TEST_APP_DELEGATEE_PRIVATE_KEY=
11+
12+
TEST_AGENT_WALLET_PKP_OWNER_PRIVATE_KEY=
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
**/**/vincent-contract-caller-config.json
2+
!.env.test.example
3+
test/test-config.json
4+
#src/generated/**/*
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Contributing to Vincent Ability Hyperliquid
2+
3+
This document provides guidelines for contributing to the Vincent Ability Hyperliquid project.
4+
5+
<!-- TODO: Add documentation -->

packages/apps/ability-hyperliquid/README.md

Lines changed: 808 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const denoFetch = (...args) => globalThis.fetch(...args);
2+
export default denoFetch;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
const esbuild = require('esbuild');
5+
const { polyfillNode } = require('@lit-protocol/esbuild-plugin-polyfill-node');
6+
const Hash = require('ipfs-only-hash');
7+
8+
function aliasFetch() {
9+
const shim = path.resolve(__dirname, 'deno-fetch-shim.js');
10+
11+
return {
12+
name: 'alias-fetch',
13+
setup(build) {
14+
build.onResolve({ filter: /^node-fetch$/ }, () => ({ path: shim }));
15+
build.onResolve({ filter: /^cross-fetch(\/.*)?$/ }, () => ({ path: shim }));
16+
},
17+
};
18+
}
19+
20+
const ensureDirectoryExistence = (filePath) => {
21+
const dirname = path.dirname(filePath);
22+
if (!fs.existsSync(dirname)) {
23+
fs.mkdirSync(dirname, { recursive: true });
24+
}
25+
};
26+
27+
function getBundledVincentAbilityCode() {
28+
return `/**
29+
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD.
30+
*/
31+
32+
import { asBundledVincentAbility } from '@lit-protocol/vincent-ability-sdk';
33+
import { vincentAbility } from '../lib/vincent-ability';
34+
import metadata from './vincent-ability-metadata.json';
35+
36+
if(!metadata.ipfsCid) {
37+
throw new Error('ipfsCid is not defined in metadata JSON file');
38+
}
39+
40+
export const bundledVincentAbility = asBundledVincentAbility(vincentAbility, metadata.ipfsCid);
41+
`;
42+
}
43+
44+
function litActionModuleCode({ ipfsCid, content }) {
45+
return `/**
46+
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD.
47+
* @type {string}
48+
*/
49+
const code = ${JSON.stringify(content)};
50+
module.exports = {
51+
"code": code,
52+
"ipfsCid": "${ipfsCid}",
53+
};
54+
`;
55+
}
56+
57+
function metadataJsonFile({ ipfsCid }) {
58+
return `{
59+
"ipfsCid": "${ipfsCid}"
60+
}
61+
`;
62+
}
63+
64+
const createBundledAbilityFile = {
65+
name: 'create-vincent-bundled-ability-file',
66+
setup(build) {
67+
build.initialOptions.write = false;
68+
69+
const sourceDir = path.dirname(build.initialOptions.entryPoints[0]);
70+
71+
console.log(sourceDir);
72+
build.onEnd(async (result) => {
73+
if (result.errors.length > 0) {
74+
console.error('Build failed with errors:', result.errors);
75+
return;
76+
}
77+
78+
const outputFile = result.outputFiles[0];
79+
const content = outputFile.text;
80+
const ipfsCid = await Hash.of(content);
81+
82+
// Write bundledAbility wrapper
83+
const bundledSource = getBundledVincentAbilityCode();
84+
const bundledPath = path.join(sourceDir, '../generated/vincent-bundled-ability.ts');
85+
fs.writeFileSync(bundledPath, bundledSource);
86+
87+
// Write metadata JSON
88+
const outputPath = path.dirname(path.resolve(outputFile.path));
89+
const metadataPath = path.join(outputPath, 'vincent-ability-metadata.json');
90+
const metadataContent = metadataJsonFile({ ipfsCid });
91+
fs.writeFileSync(metadataPath, metadataContent);
92+
});
93+
},
94+
};
95+
96+
const wrapIIFEInStringPlugin = {
97+
name: 'wrap-iife-in-string',
98+
setup(build) {
99+
build.initialOptions.write = false;
100+
101+
build.onEnd(async (result) => {
102+
if (result.errors.length > 0) {
103+
console.error('Build failed with errors:', result.errors);
104+
return;
105+
}
106+
107+
const outputFile = result.outputFiles[0];
108+
const content = outputFile.text;
109+
const ipfsCid = await Hash.of(content);
110+
111+
const wrapped = litActionModuleCode({ content, ipfsCid });
112+
const outputPath = path.resolve(outputFile.path);
113+
ensureDirectoryExistence(outputPath);
114+
fs.writeFileSync(outputPath, wrapped);
115+
});
116+
},
117+
};
118+
119+
(async () => {
120+
try {
121+
await esbuild
122+
.build({
123+
tsconfig: './tsconfig.lib.json',
124+
entryPoints: ['./src/lib/lit-action.ts'],
125+
bundle: true,
126+
minify: false,
127+
sourcemap: false,
128+
treeShaking: true,
129+
metafile: true,
130+
outdir: './src/generated/',
131+
plugins: [
132+
aliasFetch(),
133+
polyfillNode({
134+
globals: {
135+
Buffer: true,
136+
process: true,
137+
},
138+
modules: {
139+
crypto: true,
140+
http: true,
141+
https: true,
142+
stream: true,
143+
zlib: true,
144+
url: true,
145+
util: true,
146+
},
147+
}),
148+
wrapIIFEInStringPlugin,
149+
createBundledAbilityFile,
150+
],
151+
platform: 'browser',
152+
write: false,
153+
})
154+
.then((result) => {
155+
result.outputFiles.forEach((file) => {
156+
const bytes = file.text.length;
157+
const mbInBinary = (bytes / (1024 * 1024)).toFixed(4);
158+
const mbInDecimal = (bytes / 1_000_000).toFixed(4);
159+
160+
console.log(
161+
`✅ ${file.path.split('/').pop()}\n- ${mbInDecimal} MB (in decimal)\n- ${mbInBinary} MB (in binary)`,
162+
);
163+
});
164+
});
165+
166+
console.log('✅ Vincent ability built successfully');
167+
} catch (e) {
168+
console.error('❌ Error building Vincent ability: ', e);
169+
process.exit(1);
170+
}
171+
})();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const baseConfig = require('../../../eslint.config.js');
2+
3+
module.exports = [
4+
...baseConfig,
5+
{
6+
files: ['package.json'],
7+
rules: {
8+
'@nx/dependency-checks': [
9+
'error',
10+
{
11+
buildTargets: ['build'],
12+
checkVersionMismatches: true,
13+
ignoredFiles: [
14+
'{projectRoot}/eslint.config.{js,cjs,mjs}',
15+
'{projectRoot}/jest.config.{js,cjs,mjs,ts}',
16+
'{projectRoot}/vite.config.*',
17+
'{projectRoot}/esbuild.config.{js,cjs,mjs}',
18+
],
19+
ignoredDependencies: [
20+
// It's a peerDependency to ensure people don't try to use the wrong VincentAbilityClient with it -- not directly used.
21+
'@lit-protocol/vincent-app-sdk',
22+
],
23+
},
24+
],
25+
},
26+
},
27+
];

0 commit comments

Comments
 (0)